Merge "Refactor PackageParser (11/n)"
This commit is contained in:
@@ -723,6 +723,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
|
||||
|
||||
@Override
|
||||
public ParsingPackageImpl addImplicitPermission(String permission) {
|
||||
addUsesPermission(new ParsedUsesPermission(permission, 0 /*usesPermissionFlags*/));
|
||||
this.implicitPermissions = CollectionUtils.add(this.implicitPermissions,
|
||||
TextUtils.safeIntern(permission));
|
||||
return this;
|
||||
|
||||
@@ -74,6 +74,7 @@ import android.content.pm.parsing.result.ParseInput;
|
||||
import android.content.pm.parsing.result.ParseInput.DeferredError;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
import android.content.pm.parsing.result.ParseTypeImpl;
|
||||
import android.content.pm.permission.CompatibilityPermissionInfo;
|
||||
import android.content.pm.split.DefaultSplitAssetLoader;
|
||||
import android.content.pm.split.SplitAssetDependencyLoader;
|
||||
import android.content.pm.split.SplitAssetLoader;
|
||||
@@ -904,7 +905,7 @@ public class ParsingPackageUtils {
|
||||
);
|
||||
}
|
||||
|
||||
convertNewPermissions(pkg);
|
||||
convertCompatPermissions(pkg);
|
||||
|
||||
convertSplitPermissions(pkg);
|
||||
|
||||
@@ -2790,31 +2791,16 @@ public class ParsingPackageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void convertNewPermissions(ParsingPackage pkg) {
|
||||
final int NP = PackageParser.NEW_PERMISSIONS.length;
|
||||
StringBuilder newPermsMsg = null;
|
||||
for (int ip = 0; ip < NP; ip++) {
|
||||
final PackageParser.NewPermissionInfo npi
|
||||
= PackageParser.NEW_PERMISSIONS[ip];
|
||||
if (pkg.getTargetSdkVersion() >= npi.sdkVersion) {
|
||||
private static void convertCompatPermissions(ParsingPackage pkg) {
|
||||
for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) {
|
||||
final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i];
|
||||
if (pkg.getTargetSdkVersion() >= info.sdkVersion) {
|
||||
break;
|
||||
}
|
||||
if (!pkg.getRequestedPermissions().contains(npi.name)) {
|
||||
if (newPermsMsg == null) {
|
||||
newPermsMsg = new StringBuilder(128);
|
||||
newPermsMsg.append(pkg.getPackageName());
|
||||
newPermsMsg.append(": compat added ");
|
||||
} else {
|
||||
newPermsMsg.append(' ');
|
||||
}
|
||||
newPermsMsg.append(npi.name);
|
||||
pkg.addUsesPermission(new ParsedUsesPermission(npi.name, 0))
|
||||
.addImplicitPermission(npi.name);
|
||||
if (!pkg.getRequestedPermissions().contains(info.name)) {
|
||||
pkg.addImplicitPermission(info.name);
|
||||
}
|
||||
}
|
||||
if (newPermsMsg != null) {
|
||||
Slog.i(TAG, newPermsMsg.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void convertSplitPermissions(ParsingPackage pkg) {
|
||||
@@ -2830,8 +2816,7 @@ public class ParsingPackageUtils {
|
||||
for (int in = 0; in < newPerms.size(); in++) {
|
||||
final String perm = newPerms.get(in);
|
||||
if (!requestedPermissions.contains(perm)) {
|
||||
pkg.addUsesPermission(new ParsedUsesPermission(perm, 0))
|
||||
.addImplicitPermission(perm);
|
||||
pkg.addImplicitPermission(perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.pm.permission;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.parsing.component.ParsedUsesPermission;
|
||||
|
||||
/**
|
||||
* Implements compatibility support for permissions, and old applications
|
||||
* will be automatically granted it.
|
||||
*
|
||||
* Compatibility permissions are permissions that are automatically granted to
|
||||
* packages that target an SDK prior to when the permission was introduced.
|
||||
* Sometimes the platform makes breaking behaviour changes and hides the legacy
|
||||
* behaviour behind a permission. In these instances, we ensure applications
|
||||
* targeting older platform versions are implicitly granted the correct set of
|
||||
* permissions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class CompatibilityPermissionInfo extends ParsedUsesPermission {
|
||||
|
||||
public final int sdkVersion;
|
||||
|
||||
/**
|
||||
* List of new permissions that have been added since 1.0.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final CompatibilityPermissionInfo[] COMPAT_PERMS =
|
||||
new CompatibilityPermissionInfo[]{
|
||||
new CompatibilityPermissionInfo(Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
android.os.Build.VERSION_CODES.DONUT, 0 /*usesPermissionFlags*/),
|
||||
new CompatibilityPermissionInfo(Manifest.permission.READ_PHONE_STATE,
|
||||
android.os.Build.VERSION_CODES.DONUT, 0 /*usesPermissionFlags*/)
|
||||
};
|
||||
|
||||
private CompatibilityPermissionInfo(String name, int sdkVersion,
|
||||
@UsesPermissionFlags int usesPermissionFlags) {
|
||||
super(name, usesPermissionFlags);
|
||||
this.sdkVersion = sdkVersion;
|
||||
}
|
||||
}
|
||||
@@ -82,13 +82,13 @@ import android.content.pm.PackageManager.PermissionGroupInfoFlags;
|
||||
import android.content.pm.PackageManager.PermissionInfoFlags;
|
||||
import android.content.pm.PackageManager.PermissionWhitelistFlags;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.SigningDetails;
|
||||
import android.content.pm.parsing.component.ParsedPermission;
|
||||
import android.content.pm.parsing.component.ParsedPermissionGroup;
|
||||
import android.content.pm.permission.CompatibilityPermissionInfo;
|
||||
import android.content.pm.permission.SplitPermissionInfoParcelable;
|
||||
import android.metrics.LogMaker;
|
||||
import android.os.AsyncTask;
|
||||
@@ -2822,7 +2822,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
// Except... if this is a permission that was added
|
||||
// to the platform (note: need to only do this when
|
||||
// updating the platform).
|
||||
if (!isNewPlatformPermissionForPackage(perm, pkg)) {
|
||||
if (!isCompatPlatformPermissionForPackage(perm, pkg)) {
|
||||
shouldGrantNormalPermission = false;
|
||||
}
|
||||
}
|
||||
@@ -3358,14 +3358,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
|
||||
private static boolean isCompatPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
|
||||
boolean allowed = false;
|
||||
final int NP = PackageParser.NEW_PERMISSIONS.length;
|
||||
for (int ip=0; ip<NP; ip++) {
|
||||
final PackageParser.NewPermissionInfo npi
|
||||
= PackageParser.NEW_PERMISSIONS[ip];
|
||||
if (npi.name.equals(perm)
|
||||
&& pkg.getTargetSdkVersion() < npi.sdkVersion) {
|
||||
for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) {
|
||||
final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i];
|
||||
if (info.name.equals(perm)
|
||||
&& pkg.getTargetSdkVersion() < info.sdkVersion) {
|
||||
allowed = true;
|
||||
Log.i(TAG, "Auto-granting " + perm + " to old pkg "
|
||||
+ pkg.getPackageName());
|
||||
|
||||
@@ -117,6 +117,7 @@ android_test {
|
||||
":PackageParserTestApp2",
|
||||
":PackageParserTestApp3",
|
||||
":PackageParserTestApp4",
|
||||
":PackageParserTestApp5",
|
||||
":apex.test",
|
||||
":test.rebootless_apex_v1",
|
||||
":test.rebootless_apex_v2",
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.android.server.pm;
|
||||
|
||||
import static android.content.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
|
||||
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -25,6 +29,7 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
@@ -83,6 +88,7 @@ import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -106,6 +112,7 @@ public class PackageParserTest {
|
||||
private static final String TEST_APP2_APK = "PackageParserTestApp2.apk";
|
||||
private static final String TEST_APP3_APK = "PackageParserTestApp3.apk";
|
||||
private static final String TEST_APP4_APK = "PackageParserTestApp4.apk";
|
||||
private static final String TEST_APP5_APK = "PackageParserTestApp5.apk";
|
||||
private static final String PACKAGE_NAME = "com.android.servicestests.apps.packageparserapp";
|
||||
|
||||
@Before
|
||||
@@ -506,6 +513,56 @@ public class PackageParserTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseModernPackageHasNoCompatPermissions() throws Exception {
|
||||
final File testFile = extractFile(TEST_APP1_APK);
|
||||
try {
|
||||
final ParsedPackage pkg = new TestPackageParser2()
|
||||
.parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
|
||||
final List<String> compatPermissions =
|
||||
Arrays.stream(COMPAT_PERMS).map(p -> p.name).collect(toList());
|
||||
assertWithMessage(
|
||||
"Compatibility permissions shouldn't be added into uses permissions.")
|
||||
.that(pkg.getUsesPermissions().stream().map(p -> p.name).collect(toList()))
|
||||
.containsNoneIn(compatPermissions);
|
||||
assertWithMessage(
|
||||
"Compatibility permissions shouldn't be added into requested permissions.")
|
||||
.that(pkg.getRequestedPermissions()).containsNoneIn(compatPermissions);
|
||||
assertWithMessage(
|
||||
"Compatibility permissions shouldn't be added into implicit permissions.")
|
||||
.that(pkg.getImplicitPermissions()).containsNoneIn(compatPermissions);
|
||||
} finally {
|
||||
testFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLegacyPackageHasCompatPermissions() throws Exception {
|
||||
final File testFile = extractFile(TEST_APP5_APK);
|
||||
try {
|
||||
final ParsedPackage pkg = new TestPackageParser2()
|
||||
.parsePackage(testFile, 0 /*flags*/, false /*useCaches*/);
|
||||
assertWithMessage(
|
||||
"Compatibility permissions should be added into uses permissions.")
|
||||
.that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
|
||||
.allMatch(pkg.getUsesPermissions().stream().map(p -> p.name)
|
||||
.collect(toList())::contains))
|
||||
.isTrue();
|
||||
assertWithMessage(
|
||||
"Compatibility permissions should be added into requested permissions.")
|
||||
.that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
|
||||
.allMatch(pkg.getRequestedPermissions()::contains))
|
||||
.isTrue();
|
||||
assertWithMessage(
|
||||
"Compatibility permissions should be added into implicit permissions.")
|
||||
.that(Arrays.stream(COMPAT_PERMS).map(p -> p.name)
|
||||
.allMatch(pkg.getImplicitPermissions()::contains))
|
||||
.isTrue();
|
||||
} finally {
|
||||
testFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A trivial subclass of package parser that only caches the package name, and throws away
|
||||
* all other information.
|
||||
|
||||
@@ -74,3 +74,17 @@ android_test_helper_app {
|
||||
resource_dirs: ["res"],
|
||||
manifest: "AndroidManifestApp4.xml",
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "PackageParserTestApp5",
|
||||
sdk_version: "current",
|
||||
srcs: ["**/*.java"],
|
||||
dex_preopt: {
|
||||
enabled: false,
|
||||
},
|
||||
optimize: {
|
||||
enabled: false,
|
||||
},
|
||||
resource_dirs: ["res"],
|
||||
manifest: "AndroidManifestApp5.xml",
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.servicestests.apps.packageparserapp" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="3"
|
||||
android:targetSdkVersion="3" />
|
||||
|
||||
<application>
|
||||
<activity android:name=".TestActivity"
|
||||
android:exported="true" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
Reference in New Issue
Block a user