Parse new xml attributes used for updatable shared libraries am: 5c228ca3e9 am: 7936aaf92e
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1926341 Change-Id: I7ae71734b45022e40403df1f1ec7d4290fb61d76
This commit is contained in:
@@ -112,17 +112,74 @@ public class SystemConfig {
|
||||
public final String name;
|
||||
public final String filename;
|
||||
public final String[] dependencies;
|
||||
|
||||
/**
|
||||
* SDK version this library was added to the BOOTCLASSPATH.
|
||||
*
|
||||
* <p>At the SDK level specified in this field and higher, the apps' uses-library tags for
|
||||
* this library will be ignored, since the library is always available on BOOTCLASSPATH.
|
||||
*
|
||||
* <p>0 means not specified.
|
||||
*/
|
||||
public final int onBootclasspathSince;
|
||||
|
||||
/**
|
||||
* SDK version this library was removed from the BOOTCLASSPATH.
|
||||
*
|
||||
* <p>At the SDK level specified in this field and higher, this library needs to be
|
||||
* explicitly added by apps. For compatibility reasons, when an app
|
||||
* targets an SDK less than the value of this attribute, this library is automatically
|
||||
* added.
|
||||
*
|
||||
* <p>0 means not specified.
|
||||
*/
|
||||
public final int onBootclasspathBefore;
|
||||
|
||||
/**
|
||||
* Declares whether this library can be safely ignored from <uses-library> tags.
|
||||
*
|
||||
* <p> This can happen if the library initially had to be explicitly depended-on using that
|
||||
* tag but has since been moved to the BOOTCLASSPATH which means now is always available
|
||||
* and the tag is no longer required.
|
||||
*/
|
||||
public final boolean canBeSafelyIgnored;
|
||||
|
||||
public final boolean isNative;
|
||||
|
||||
SharedLibraryEntry(String name, String filename, String[] dependencies) {
|
||||
this(name, filename, dependencies, false /* isNative */);
|
||||
|
||||
@VisibleForTesting
|
||||
public SharedLibraryEntry(String name, String filename, String[] dependencies,
|
||||
boolean isNative) {
|
||||
this(name, filename, dependencies, 0 /* onBootclasspathSince */,
|
||||
0 /* onBootclasspathBefore */, isNative);
|
||||
}
|
||||
|
||||
SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) {
|
||||
@VisibleForTesting
|
||||
public SharedLibraryEntry(String name, String filename, String[] dependencies,
|
||||
int onBootclasspathSince, int onBootclassPathBefore) {
|
||||
this(name, filename, dependencies, onBootclasspathSince, onBootclassPathBefore,
|
||||
false /* isNative */);
|
||||
}
|
||||
|
||||
SharedLibraryEntry(String name, String filename, String[] dependencies,
|
||||
int onBootclasspathSince, int onBootclasspathBefore, boolean isNative) {
|
||||
this.name = name;
|
||||
this.filename = filename;
|
||||
this.dependencies = dependencies;
|
||||
this.onBootclasspathSince = onBootclasspathSince;
|
||||
this.onBootclasspathBefore = onBootclasspathBefore;
|
||||
this.isNative = isNative;
|
||||
|
||||
canBeSafelyIgnored = this.onBootclasspathSince != 0
|
||||
&& isSdkAtLeast(this.onBootclasspathSince);
|
||||
}
|
||||
|
||||
private static boolean isSdkAtLeast(int level) {
|
||||
if ("REL".equals(Build.VERSION.CODENAME)) {
|
||||
return Build.VERSION.SDK_INT >= level;
|
||||
}
|
||||
return level == Build.VERSION_CODES.CUR_DEVELOPMENT
|
||||
|| Build.VERSION.SDK_INT >= level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,11 +849,17 @@ public class SystemConfig {
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
} break;
|
||||
case "updatable-library":
|
||||
// "updatable-library" is meant to behave exactly like "library"
|
||||
case "library": {
|
||||
if (allowLibs) {
|
||||
String lname = parser.getAttributeValue(null, "name");
|
||||
String lfile = parser.getAttributeValue(null, "file");
|
||||
String ldependency = parser.getAttributeValue(null, "dependency");
|
||||
int minDeviceSdk = XmlUtils.readIntAttribute(parser, "min-device-sdk",
|
||||
0);
|
||||
int maxDeviceSdk = XmlUtils.readIntAttribute(parser, "max-device-sdk",
|
||||
0);
|
||||
if (lname == null) {
|
||||
Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
|
||||
+ parser.getPositionDescription());
|
||||
@@ -804,10 +867,20 @@ public class SystemConfig {
|
||||
Slog.w(TAG, "<" + name + "> without file in " + permFile + " at "
|
||||
+ parser.getPositionDescription());
|
||||
} else {
|
||||
//Log.i(TAG, "Got library " + lname + " in " + lfile);
|
||||
SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,
|
||||
ldependency == null ? new String[0] : ldependency.split(":"));
|
||||
mSharedLibraries.put(lname, entry);
|
||||
boolean allowedMinSdk = minDeviceSdk <= Build.VERSION.SDK_INT;
|
||||
boolean allowedMaxSdk =
|
||||
maxDeviceSdk == 0 || maxDeviceSdk >= Build.VERSION.SDK_INT;
|
||||
if (allowedMinSdk && allowedMaxSdk) {
|
||||
int bcpSince = XmlUtils.readIntAttribute(parser,
|
||||
"on-bootclasspath-since", 0);
|
||||
int bcpBefore = XmlUtils.readIntAttribute(parser,
|
||||
"on-bootclasspath-before", 0);
|
||||
SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,
|
||||
ldependency == null
|
||||
? new String[0] : ldependency.split(":"),
|
||||
bcpSince, bcpBefore);
|
||||
mSharedLibraries.put(lname, entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logNotAllowedInPartition(name, permFile, parser);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 com.android.server.pm.parsing.library;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.SystemConfig;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
|
||||
/**
|
||||
* Updates packages to add or remove dependencies on shared libraries as per attributes
|
||||
* in the library declaration
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater {
|
||||
|
||||
/**
|
||||
* ArrayMap like the one you find in {@link SystemConfig}. The keys are the library names.
|
||||
*/
|
||||
private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries;
|
||||
|
||||
public ApexSharedLibraryUpdater(
|
||||
ArrayMap<String, SystemConfig.SharedLibraryEntry> sharedLibraries) {
|
||||
mSharedLibraries = sharedLibraries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
|
||||
final int builtInLibCount = mSharedLibraries.size();
|
||||
for (int i = 0; i < builtInLibCount; i++) {
|
||||
updateSharedLibraryForPackage(mSharedLibraries.valueAt(i), parsedPackage);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSharedLibraryForPackage(SystemConfig.SharedLibraryEntry entry,
|
||||
ParsedPackage parsedPackage) {
|
||||
if (entry.onBootclasspathBefore != 0
|
||||
&& parsedPackage.getTargetSdkVersion() < entry.onBootclasspathBefore) {
|
||||
// this package targets an API where this library was in the BCP, so add
|
||||
// the library transparently in case the package is using it
|
||||
prefixRequiredLibrary(parsedPackage, entry.name);
|
||||
}
|
||||
|
||||
if (entry.canBeSafelyIgnored) {
|
||||
// the library is now present in the BCP and always available; we don't need to add
|
||||
// it a second time
|
||||
removeLibrary(parsedPackage, entry.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import android.content.pm.PackageParser;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.SystemConfig;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -63,6 +64,11 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
|
||||
|
||||
boolean bootClassPathContainsATB = !addUpdaterForAndroidTestBase(packageUpdaters);
|
||||
|
||||
// ApexSharedLibraryUpdater should be the last one, to allow modifications introduced by
|
||||
// mainline after dessert release.
|
||||
packageUpdaters.add(new ApexSharedLibraryUpdater(
|
||||
SystemConfig.getInstance().getSharedLibraries()));
|
||||
|
||||
PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
|
||||
.toArray(new PackageSharedLibraryUpdater[0]);
|
||||
INSTANCE = new PackageBackwardCompatibility(
|
||||
@@ -106,6 +112,11 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
|
||||
|
||||
private final PackageSharedLibraryUpdater[] mPackageUpdaters;
|
||||
|
||||
@VisibleForTesting
|
||||
PackageSharedLibraryUpdater[] getPackageUpdaters() {
|
||||
return mPackageUpdaters;
|
||||
}
|
||||
|
||||
private PackageBackwardCompatibility(
|
||||
boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
|
||||
this.mBootClassPathContainsATB = bootClassPathContainsATB;
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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 com.android.server.pm.parsing.library;
|
||||
|
||||
import android.os.Build;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.SystemConfig;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
|
||||
/**
|
||||
* Test for {@link ApexSharedLibraryUpdater}
|
||||
*/
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
@RunWith(JUnit4.class)
|
||||
public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTest {
|
||||
|
||||
private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries =
|
||||
new ArrayMap<>(8);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
installSharedLibraries();
|
||||
}
|
||||
|
||||
private void installSharedLibraries() throws Exception {
|
||||
mSharedLibraries.clear();
|
||||
insertLibrary("foo", 0, 0);
|
||||
insertLibrary("fooBcpSince30", 30, 0);
|
||||
insertLibrary("fooBcpBefore30", 0, 30);
|
||||
insertLibrary("fooFromFuture", Build.VERSION.SDK_INT + 2, 0);
|
||||
}
|
||||
|
||||
private void insertLibrary(String libraryName, int onBootclasspathSince,
|
||||
int onBootclasspathBefore) {
|
||||
mSharedLibraries.put(libraryName, new SystemConfig.SharedLibraryEntry(
|
||||
libraryName,
|
||||
"foo.jar",
|
||||
new String[0] /* dependencies */,
|
||||
onBootclasspathSince,
|
||||
onBootclasspathBefore
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegularAppOnRPlus() {
|
||||
// platform Q should have changes (tested below)
|
||||
|
||||
// these should have no changes
|
||||
checkNoChanges(Build.VERSION_CODES.R);
|
||||
checkNoChanges(Build.VERSION_CODES.S);
|
||||
checkNoChanges(Build.VERSION_CODES.TIRAMISU);
|
||||
checkNoChanges(Build.VERSION_CODES.CUR_DEVELOPMENT);
|
||||
}
|
||||
|
||||
private void checkNoChanges(int targetSdkVersion) {
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(targetSdkVersion)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(targetSdkVersion)
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBcpSince30Applied() {
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.addUsesLibrary("fooBcpSince30")
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// note: target sdk is not what matters in this logic. It's the system SDK
|
||||
// should be removed because on 30+ (R+) it is implicit
|
||||
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBcpSince11kNotAppliedWithoutLibrary() {
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// note: target sdk is not what matters in this logic. It's the system SDK
|
||||
// nothing should change because the implicit from is only from a future platform release
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBcpSince11kNotAppliedWithLibrary() {
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.addUsesLibrary("fooFromFuture")
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.addUsesLibrary("fooFromFuture")
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// note: target sdk is not what matters in this logic. It's the system SDK
|
||||
// nothing should change because the implicit from is only from a future platform release
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBcpBefore30NotApplied() {
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// should not be affected because it is still in the BCP in 30 / R
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBcpBefore30Applied() {
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.Q)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.Q)
|
||||
.addUsesLibrary("fooBcpBefore30")
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// should be present because this was in BCP in 29 / Q
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a library that was first removed from the BCP [to a mainline module] and later was
|
||||
* moved back to the BCP via a mainline module update. All of this happening before the current
|
||||
* SDK.
|
||||
*/
|
||||
@Test
|
||||
public void testBcpRemovedThenAddedPast() {
|
||||
insertLibrary("fooBcpRemovedThenAdded", 30, 28);
|
||||
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.N)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.N)
|
||||
.addUsesLibrary("fooBcpBefore30")
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// the library is now in the BOOTCLASSPATH (for the second time) so it doesn't need to be
|
||||
// listed
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a library that was first removed from the BCP [to a mainline module] and later was
|
||||
* moved back to the BCP via a mainline module update. The first part happening before the
|
||||
* current SDK and the second part after.
|
||||
*/
|
||||
@Test
|
||||
public void testBcpRemovedThenAddedMiddle_targetQ() {
|
||||
insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30);
|
||||
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.Q)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.Q)
|
||||
.addUsesLibrary("fooBcpRemovedThenAdded")
|
||||
.addUsesLibrary("fooBcpBefore30")
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// in this example, we are at the point where the library is not in the BOOTCLASSPATH.
|
||||
// Because the app targets Q / 29 (when this library was in the BCP) then we need to add it
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a library that was first removed from the BCP [to a mainline module] and later was
|
||||
* moved back to the BCP via a mainline module update. The first part happening before the
|
||||
* current SDK and the second part after.
|
||||
*/
|
||||
@Test
|
||||
public void testBcpRemovedThenAddedMiddle_targetR() {
|
||||
insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30);
|
||||
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// in this example, we are at the point where the library is not in the BOOTCLASSPATH.
|
||||
// Because the app targets R/30 (when this library was removed from the BCP) then we don't
|
||||
//need to add it
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a library that was first removed from the BCP [to a mainline module] and later was
|
||||
* moved back to the BCP via a mainline module update. The first part happening before the
|
||||
* current SDK and the second part after.
|
||||
*/
|
||||
@Test
|
||||
public void testBcpRemovedThenAddedMiddle_targetR_usingLib() {
|
||||
insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30);
|
||||
|
||||
ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.addUsesLibrary("fooBcpRemovedThenAdded")
|
||||
.hideAsParsed());
|
||||
|
||||
AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
|
||||
.setTargetSdkVersion(Build.VERSION_CODES.R)
|
||||
.addUsesLibrary("fooBcpRemovedThenAdded")
|
||||
.hideAsParsed())
|
||||
.hideAsFinal();
|
||||
|
||||
// in this example, we are at the point where the library is not in the BOOTCLASSPATH.
|
||||
// Because the app wants to use the library, it needs to be present
|
||||
checkBackwardsCompatibility(before, after);
|
||||
}
|
||||
|
||||
private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
|
||||
checkBackwardsCompatibility(before, after,
|
||||
() -> new ApexSharedLibraryUpdater(mSharedLibraries));
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_T
|
||||
import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
|
||||
import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.pm.parsing.ParsingPackage;
|
||||
import android.os.Build;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
@@ -182,6 +184,22 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate
|
||||
checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that ApexSharedLibraryUpdater is the last updater in the list of package updaters
|
||||
* used by PackageBackwardCompatibility.
|
||||
*
|
||||
* This is required so mainline can add and remove libraries installed by the platform updaters.
|
||||
*/
|
||||
@Test
|
||||
public void testApexPackageUpdaterOrdering() {
|
||||
PackageBackwardCompatibility instance =
|
||||
(PackageBackwardCompatibility) PackageBackwardCompatibility.getInstance();
|
||||
PackageSharedLibraryUpdater[] updaterArray = instance.getPackageUpdaters();
|
||||
|
||||
PackageSharedLibraryUpdater lastUpdater = updaterArray[updaterArray.length - 1];
|
||||
assertThat(lastUpdater).isInstanceOf(ApexSharedLibraryUpdater.class);
|
||||
}
|
||||
|
||||
private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
|
||||
checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.testng.Assert.expectThrows;
|
||||
|
||||
import android.os.Build;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -329,6 +330,164 @@ public class SystemConfigTest {
|
||||
assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions works correctly for a library with on-bootclasspath-before
|
||||
* and on-bootclasspath-since.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_parsesSimpleLibrary() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " on-bootclasspath-before=\"10\"\n"
|
||||
+ " on-bootclasspath-since=\"20\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertFooIsOnlySharedLibrary();
|
||||
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
|
||||
assertThat(entry.onBootclasspathBefore).isEqualTo(10);
|
||||
assertThat(entry.onBootclasspathSince).isEqualTo(20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions works correctly for a library using the new
|
||||
* {@code updatable-library} tag.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_parsesUpdatableLibrary() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <updatable-library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " on-bootclasspath-before=\"10\"\n"
|
||||
+ " on-bootclasspath-since=\"20\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertFooIsOnlySharedLibrary();
|
||||
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
|
||||
assertThat(entry.onBootclasspathBefore).isEqualTo(10);
|
||||
assertThat(entry.onBootclasspathSince).isEqualTo(20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions for a library with {@code min-device-sdk} lower than the current
|
||||
* SDK results in the library being added to the shared libraries.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_allowsOldMinSdk() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " min-device-sdk=\"30\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertFooIsOnlySharedLibrary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions for a library with {@code min-device-sdk} equal to the current
|
||||
* SDK results in the library being added to the shared libraries.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_allowsCurrentMinSdk() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " min-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertFooIsOnlySharedLibrary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions for a library with {@code min-device-sdk} greater than the current
|
||||
* SDK results in the library being ignored.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_ignoresMinSdkInFuture() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " min-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertThat(mSysConfig.getSharedLibraries()).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions for a library with {@code max-device-sdk} less than the current
|
||||
* SDK results in the library being ignored.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_ignoredOldMaxSdk() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " max-device-sdk=\"30\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertThat(mSysConfig.getSharedLibraries()).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions for a library with {@code max-device-sdk} equal to the current
|
||||
* SDK results in the library being added to the shared libraries.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_allowsCurrentMaxSdk() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " max-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertFooIsOnlySharedLibrary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that readPermissions for a library with {@code max-device-sdk} greater than the current
|
||||
* SDK results in the library being added to the shared libraries.
|
||||
*/
|
||||
@Test
|
||||
public void readPermissions_allowLibs_allowsMaxSdkInFuture() throws IOException {
|
||||
String contents =
|
||||
"<permissions>\n"
|
||||
+ " <library \n"
|
||||
+ " name=\"foo\"\n"
|
||||
+ " file=\"foo.jar\"\n"
|
||||
+ " max-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n"
|
||||
+ " />\n\n"
|
||||
+ " </permissions>";
|
||||
parseSharedLibraries(contents);
|
||||
assertFooIsOnlySharedLibrary();
|
||||
}
|
||||
|
||||
private void parseSharedLibraries(String contents) throws IOException {
|
||||
File folder = createTempSubfolder("permissions_folder");
|
||||
createTempFile(folder, "permissions.xml", contents);
|
||||
readPermissions(folder, /* permissionFlag = ALLOW_LIBS */ 0x02);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates folderName/fileName in the mTemporaryFolder and fills it with the contents.
|
||||
*
|
||||
@@ -366,4 +525,11 @@ public class SystemConfigTest {
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
private void assertFooIsOnlySharedLibrary() {
|
||||
assertThat(mSysConfig.getSharedLibraries().size()).isEqualTo(1);
|
||||
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
|
||||
assertThat(entry.name).isEqualTo("foo");
|
||||
assertThat(entry.filename).isEqualTo("foo.jar");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user