Loading core/java/com/android/server/SystemConfig.java +27 −27 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.modules.utils.build.UnboundedSdkLevel; import libcore.io.IoUtils; import libcore.util.EmptyArray; Loading Loading @@ -126,7 +127,7 @@ public class SystemConfig { * * <p>0 means not specified. */ public final int onBootclasspathSince; public final String onBootclasspathSince; /** * SDK version this library was removed from the BOOTCLASSPATH. Loading @@ -138,7 +139,7 @@ public class SystemConfig { * * <p>0 means not specified. */ public final int onBootclasspathBefore; public final String onBootclasspathBefore; /** * Declares whether this library can be safely ignored from <uses-library> tags. Loading @@ -155,19 +156,19 @@ public class SystemConfig { @VisibleForTesting public SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) { this(name, filename, dependencies, 0 /* onBootclasspathSince */, 0 /* onBootclasspathBefore */, isNative); this(name, filename, dependencies, null /* onBootclasspathSince */, null /* onBootclasspathBefore */, isNative); } @VisibleForTesting public SharedLibraryEntry(String name, String filename, String[] dependencies, int onBootclasspathSince, int onBootclassPathBefore) { this(name, filename, dependencies, onBootclasspathSince, onBootclassPathBefore, String onBootclasspathSince, String onBootclasspathBefore) { this(name, filename, dependencies, onBootclasspathSince, onBootclasspathBefore, false /* isNative */); } SharedLibraryEntry(String name, String filename, String[] dependencies, int onBootclasspathSince, int onBootclasspathBefore, boolean isNative) { String onBootclasspathSince, String onBootclasspathBefore, boolean isNative) { this.name = name; this.filename = filename; this.dependencies = dependencies; Loading @@ -175,16 +176,14 @@ public class SystemConfig { 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; // this entry can be ignored if either: // - onBootclasspathSince is set and we are at or past that SDK // - onBootclasspathBefore is set and we are before that SDK canBeSafelyIgnored = (this.onBootclasspathSince != null && UnboundedSdkLevel.isAtLeast(this.onBootclasspathSince)) || (this.onBootclasspathBefore != null && !UnboundedSdkLevel.isAtLeast(this.onBootclasspathBefore)); } } Loading Loading @@ -878,10 +877,8 @@ public class SystemConfig { 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); String minDeviceSdk = parser.getAttributeValue(null, "min-device-sdk"); String maxDeviceSdk = parser.getAttributeValue(null, "max-device-sdk"); if (lname == null) { Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + parser.getPositionDescription()); Loading @@ -889,15 +886,18 @@ public class SystemConfig { Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " + parser.getPositionDescription()); } else { boolean allowedMinSdk = minDeviceSdk <= Build.VERSION.SDK_INT; boolean allowedMinSdk = minDeviceSdk == null || UnboundedSdkLevel.isAtLeast( minDeviceSdk); boolean allowedMaxSdk = maxDeviceSdk == 0 || maxDeviceSdk >= Build.VERSION.SDK_INT; maxDeviceSdk == null || UnboundedSdkLevel.isAtMost( maxDeviceSdk); final boolean exists = new File(lfile).exists(); if (allowedMinSdk && allowedMaxSdk && exists) { int bcpSince = XmlUtils.readIntAttribute(parser, "on-bootclasspath-since", 0); int bcpBefore = XmlUtils.readIntAttribute(parser, "on-bootclasspath-before", 0); String bcpSince = parser.getAttributeValue(null, "on-bootclasspath-since"); String bcpBefore = parser.getAttributeValue(null, "on-bootclasspath-before"); SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, ldependency == null ? new String[0] : ldependency.split(":"), Loading services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java +21 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.pm.parsing.library; import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.UnboundedSdkLevel; import com.android.server.SystemConfig; import com.android.server.pm.parsing.pkg.ParsedPackage; Loading Loading @@ -51,8 +52,11 @@ public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater { private void updateSharedLibraryForPackage(SystemConfig.SharedLibraryEntry entry, ParsedPackage parsedPackage) { if (entry.onBootclasspathBefore != 0 && parsedPackage.getTargetSdkVersion() < entry.onBootclasspathBefore) { if (entry.onBootclasspathBefore != null && isTargetSdkAtMost( parsedPackage.getTargetSdkVersion(), entry.onBootclasspathBefore) && UnboundedSdkLevel.isAtLeast(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); Loading @@ -64,4 +68,19 @@ public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater { removeLibrary(parsedPackage, entry.name); } } private static boolean isTargetSdkAtMost(int targetSdk, String onBcpBefore) { if (isCodename(onBcpBefore)) { return targetSdk < 10000; } return targetSdk < Integer.parseInt(onBcpBefore); } private static boolean isCodename(String version) { if (version.length() == 0) { throw new IllegalArgumentException(); } // assume Android codenames start with upper case letters. return Character.isUpperCase((version.charAt(0))); } } services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java +103 −14 Original line number Diff line number Diff line Loading @@ -41,6 +41,8 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTest { private static final String SDK_INT_PLUS_ONE = "" + (Build.VERSION.SDK_INT + 1); private static final String SDK_INT_PLUS_TWO = "" + (Build.VERSION.SDK_INT + 2); private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries = new ArrayMap<>(8); Loading @@ -51,14 +53,19 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes 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); insertLibrary("foo", null, null); insertLibrary("fooBcpSince30", "30", null); insertLibrary("fooBcpBefore30", null, "30"); // simulate libraries being added to the BCP in a future release insertLibrary("fooSinceFuture", SDK_INT_PLUS_ONE, null); insertLibrary("fooSinceFutureCodename", "Z", null); // simulate libraries being removed from the BCP in a future release insertLibrary("fooBcpBeforeFuture", null, SDK_INT_PLUS_ONE); insertLibrary("fooBcpBeforeFutureCodename", null, "Z"); } private void insertLibrary(String libraryName, int onBootclasspathSince, int onBootclasspathBefore) { private void insertLibrary(String libraryName, String onBootclasspathSince, String onBootclasspathBefore) { mSharedLibraries.put(libraryName, new SystemConfig.SharedLibraryEntry( libraryName, "foo.jar", Loading Loading @@ -112,7 +119,7 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes } @Test public void testBcpSince11kNotAppliedWithoutLibrary() { public void testBcpSinceFutureNotAppliedWithoutLibrary() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .hideAsParsed()); Loading @@ -128,15 +135,17 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes } @Test public void testBcpSince11kNotAppliedWithLibrary() { public void testBcpSinceFutureNotAppliedWithLibrary() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .addUsesLibrary("fooFromFuture") .addUsesLibrary("fooSinceFuture") .addUsesLibrary("fooSinceFutureCodename") .hideAsParsed()); AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .addUsesLibrary("fooFromFuture") .addUsesLibrary("fooSinceFuture") .addUsesLibrary("fooSinceFutureCodename") .hideAsParsed()) .hideAsFinal(); Loading Loading @@ -183,7 +192,7 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedPast() { insertLibrary("fooBcpRemovedThenAdded", 30, 28); insertLibrary("fooBcpRemovedThenAdded", "30", "28"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.N) Loading @@ -207,7 +216,8 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedMiddle_targetQ() { insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_ONE, "30"); insertLibrary("fooBcpRemovedThenAddedCodename", "Z", "30"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) Loading @@ -217,6 +227,7 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary("fooBcpRemovedThenAdded") .addUsesLibrary("fooBcpBefore30") .addUsesLibrary("fooBcpRemovedThenAddedCodename") .hideAsParsed()) .hideAsFinal(); Loading @@ -232,7 +243,8 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedMiddle_targetR() { insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_ONE, "30"); insertLibrary("fooBcpRemovedThenAddedCodename", "Z", "30"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) Loading @@ -256,7 +268,8 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedMiddle_targetR_usingLib() { insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_ONE, "30"); insertLibrary("fooBcpRemovedThenAddedCodename", "Z", "30"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) Loading @@ -274,6 +287,82 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes 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. Both things happening in future SDKs. */ @Test public void testBcpRemovedThenAddedFuture() { insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_TWO, SDK_INT_PLUS_ONE); 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 still in the BCP 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. Both things happening in future SDKs. */ @Test public void testBcpRemovedThenAddedFuture_usingLib() { insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_TWO, SDK_INT_PLUS_ONE); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .addUsesLibrary("fooBcpRemovedThenAdded") .hideAsParsed()); AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .hideAsParsed()) .hideAsFinal(); // in this example, we are at the point where the library was removed from the BCP checkBackwardsCompatibility(before, after); } @Test public void testBcpBeforeFuture() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .addUsesLibrary("fooBcpBeforeFuture") .addUsesLibrary("fooBcpBeforeFutureCodename") .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 was removed from the BCP checkBackwardsCompatibility(before, after); } @Test public void testBcpBeforeFuture_futureTargetSdk() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .addUsesLibrary("fooBcpBeforeFuture") .addUsesLibrary("fooBcpBeforeFutureCodename") .hideAsParsed()); AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .hideAsParsed()) .hideAsFinal(); // in this example, we are at the point where the library was removed from the BCP checkBackwardsCompatibility(before, after); } private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, () -> new ApexSharedLibraryUpdater(mSharedLibraries)); Loading services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +42 −12 Original line number Diff line number Diff line Loading @@ -439,8 +439,30 @@ public class SystemConfigTest { parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); assertThat(entry.onBootclasspathBefore).isEqualTo(10); assertThat(entry.onBootclasspathSince).isEqualTo(20); assertThat(entry.onBootclasspathBefore).isEqualTo("10"); assertThat(entry.onBootclasspathSince).isEqualTo("20"); } /** * Tests that readPermissions works correctly for a library with on-bootclasspath-before * and on-bootclasspath-since that uses codenames. */ @Test public void readPermissions_allowLibs_parsesSimpleLibraryWithCodenames() throws IOException { String contents = "<permissions>\n" + " <library \n" + " name=\"foo\"\n" + " file=\"" + mFooJar + "\"\n" + " on-bootclasspath-before=\"Q\"\n" + " on-bootclasspath-since=\"W\"\n" + " />\n\n" + " </permissions>"; parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); assertThat(entry.onBootclasspathBefore).isEqualTo("Q"); assertThat(entry.onBootclasspathSince).isEqualTo("W"); } /** Loading @@ -461,8 +483,8 @@ public class SystemConfigTest { parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); assertThat(entry.onBootclasspathBefore).isEqualTo(10); assertThat(entry.onBootclasspathSince).isEqualTo(20); assertThat(entry.onBootclasspathBefore).isEqualTo("10"); assertThat(entry.onBootclasspathSince).isEqualTo("20"); } /** Loading Loading @@ -543,12 +565,20 @@ public class SystemConfigTest { */ @Test public void readPermissions_allowLibs_allowsCurrentMaxSdk() throws IOException { // depending on whether this test is running before or after finalization, we need to // pass a different parameter String parameter; if ("REL".equals(Build.VERSION.CODENAME)) { parameter = "" + Build.VERSION.SDK_INT; } else { parameter = "ZZZ"; } String contents = "<permissions>\n" + " <library \n" + " name=\"foo\"\n" + " file=\"" + mFooJar + "\"\n" + " max-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" + " max-device-sdk=\"" + parameter + "\"\n" + " />\n\n" + " </permissions>"; parseSharedLibraries(contents); Loading Loading
core/java/com/android/server/SystemConfig.java +27 −27 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.modules.utils.build.UnboundedSdkLevel; import libcore.io.IoUtils; import libcore.util.EmptyArray; Loading Loading @@ -126,7 +127,7 @@ public class SystemConfig { * * <p>0 means not specified. */ public final int onBootclasspathSince; public final String onBootclasspathSince; /** * SDK version this library was removed from the BOOTCLASSPATH. Loading @@ -138,7 +139,7 @@ public class SystemConfig { * * <p>0 means not specified. */ public final int onBootclasspathBefore; public final String onBootclasspathBefore; /** * Declares whether this library can be safely ignored from <uses-library> tags. Loading @@ -155,19 +156,19 @@ public class SystemConfig { @VisibleForTesting public SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) { this(name, filename, dependencies, 0 /* onBootclasspathSince */, 0 /* onBootclasspathBefore */, isNative); this(name, filename, dependencies, null /* onBootclasspathSince */, null /* onBootclasspathBefore */, isNative); } @VisibleForTesting public SharedLibraryEntry(String name, String filename, String[] dependencies, int onBootclasspathSince, int onBootclassPathBefore) { this(name, filename, dependencies, onBootclasspathSince, onBootclassPathBefore, String onBootclasspathSince, String onBootclasspathBefore) { this(name, filename, dependencies, onBootclasspathSince, onBootclasspathBefore, false /* isNative */); } SharedLibraryEntry(String name, String filename, String[] dependencies, int onBootclasspathSince, int onBootclasspathBefore, boolean isNative) { String onBootclasspathSince, String onBootclasspathBefore, boolean isNative) { this.name = name; this.filename = filename; this.dependencies = dependencies; Loading @@ -175,16 +176,14 @@ public class SystemConfig { 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; // this entry can be ignored if either: // - onBootclasspathSince is set and we are at or past that SDK // - onBootclasspathBefore is set and we are before that SDK canBeSafelyIgnored = (this.onBootclasspathSince != null && UnboundedSdkLevel.isAtLeast(this.onBootclasspathSince)) || (this.onBootclasspathBefore != null && !UnboundedSdkLevel.isAtLeast(this.onBootclasspathBefore)); } } Loading Loading @@ -878,10 +877,8 @@ public class SystemConfig { 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); String minDeviceSdk = parser.getAttributeValue(null, "min-device-sdk"); String maxDeviceSdk = parser.getAttributeValue(null, "max-device-sdk"); if (lname == null) { Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + parser.getPositionDescription()); Loading @@ -889,15 +886,18 @@ public class SystemConfig { Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " + parser.getPositionDescription()); } else { boolean allowedMinSdk = minDeviceSdk <= Build.VERSION.SDK_INT; boolean allowedMinSdk = minDeviceSdk == null || UnboundedSdkLevel.isAtLeast( minDeviceSdk); boolean allowedMaxSdk = maxDeviceSdk == 0 || maxDeviceSdk >= Build.VERSION.SDK_INT; maxDeviceSdk == null || UnboundedSdkLevel.isAtMost( maxDeviceSdk); final boolean exists = new File(lfile).exists(); if (allowedMinSdk && allowedMaxSdk && exists) { int bcpSince = XmlUtils.readIntAttribute(parser, "on-bootclasspath-since", 0); int bcpBefore = XmlUtils.readIntAttribute(parser, "on-bootclasspath-before", 0); String bcpSince = parser.getAttributeValue(null, "on-bootclasspath-since"); String bcpBefore = parser.getAttributeValue(null, "on-bootclasspath-before"); SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, ldependency == null ? new String[0] : ldependency.split(":"), Loading
services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java +21 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.pm.parsing.library; import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.UnboundedSdkLevel; import com.android.server.SystemConfig; import com.android.server.pm.parsing.pkg.ParsedPackage; Loading Loading @@ -51,8 +52,11 @@ public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater { private void updateSharedLibraryForPackage(SystemConfig.SharedLibraryEntry entry, ParsedPackage parsedPackage) { if (entry.onBootclasspathBefore != 0 && parsedPackage.getTargetSdkVersion() < entry.onBootclasspathBefore) { if (entry.onBootclasspathBefore != null && isTargetSdkAtMost( parsedPackage.getTargetSdkVersion(), entry.onBootclasspathBefore) && UnboundedSdkLevel.isAtLeast(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); Loading @@ -64,4 +68,19 @@ public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater { removeLibrary(parsedPackage, entry.name); } } private static boolean isTargetSdkAtMost(int targetSdk, String onBcpBefore) { if (isCodename(onBcpBefore)) { return targetSdk < 10000; } return targetSdk < Integer.parseInt(onBcpBefore); } private static boolean isCodename(String version) { if (version.length() == 0) { throw new IllegalArgumentException(); } // assume Android codenames start with upper case letters. return Character.isUpperCase((version.charAt(0))); } }
services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java +103 −14 Original line number Diff line number Diff line Loading @@ -41,6 +41,8 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTest { private static final String SDK_INT_PLUS_ONE = "" + (Build.VERSION.SDK_INT + 1); private static final String SDK_INT_PLUS_TWO = "" + (Build.VERSION.SDK_INT + 2); private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries = new ArrayMap<>(8); Loading @@ -51,14 +53,19 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes 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); insertLibrary("foo", null, null); insertLibrary("fooBcpSince30", "30", null); insertLibrary("fooBcpBefore30", null, "30"); // simulate libraries being added to the BCP in a future release insertLibrary("fooSinceFuture", SDK_INT_PLUS_ONE, null); insertLibrary("fooSinceFutureCodename", "Z", null); // simulate libraries being removed from the BCP in a future release insertLibrary("fooBcpBeforeFuture", null, SDK_INT_PLUS_ONE); insertLibrary("fooBcpBeforeFutureCodename", null, "Z"); } private void insertLibrary(String libraryName, int onBootclasspathSince, int onBootclasspathBefore) { private void insertLibrary(String libraryName, String onBootclasspathSince, String onBootclasspathBefore) { mSharedLibraries.put(libraryName, new SystemConfig.SharedLibraryEntry( libraryName, "foo.jar", Loading Loading @@ -112,7 +119,7 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes } @Test public void testBcpSince11kNotAppliedWithoutLibrary() { public void testBcpSinceFutureNotAppliedWithoutLibrary() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .hideAsParsed()); Loading @@ -128,15 +135,17 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes } @Test public void testBcpSince11kNotAppliedWithLibrary() { public void testBcpSinceFutureNotAppliedWithLibrary() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .addUsesLibrary("fooFromFuture") .addUsesLibrary("fooSinceFuture") .addUsesLibrary("fooSinceFutureCodename") .hideAsParsed()); AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .addUsesLibrary("fooFromFuture") .addUsesLibrary("fooSinceFuture") .addUsesLibrary("fooSinceFutureCodename") .hideAsParsed()) .hideAsFinal(); Loading Loading @@ -183,7 +192,7 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedPast() { insertLibrary("fooBcpRemovedThenAdded", 30, 28); insertLibrary("fooBcpRemovedThenAdded", "30", "28"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.N) Loading @@ -207,7 +216,8 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedMiddle_targetQ() { insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_ONE, "30"); insertLibrary("fooBcpRemovedThenAddedCodename", "Z", "30"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.Q) Loading @@ -217,6 +227,7 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes .setTargetSdkVersion(Build.VERSION_CODES.Q) .addUsesLibrary("fooBcpRemovedThenAdded") .addUsesLibrary("fooBcpBefore30") .addUsesLibrary("fooBcpRemovedThenAddedCodename") .hideAsParsed()) .hideAsFinal(); Loading @@ -232,7 +243,8 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedMiddle_targetR() { insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_ONE, "30"); insertLibrary("fooBcpRemovedThenAddedCodename", "Z", "30"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) Loading @@ -256,7 +268,8 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes */ @Test public void testBcpRemovedThenAddedMiddle_targetR_usingLib() { insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_ONE, "30"); insertLibrary("fooBcpRemovedThenAddedCodename", "Z", "30"); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) Loading @@ -274,6 +287,82 @@ public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTes 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. Both things happening in future SDKs. */ @Test public void testBcpRemovedThenAddedFuture() { insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_TWO, SDK_INT_PLUS_ONE); 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 still in the BCP 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. Both things happening in future SDKs. */ @Test public void testBcpRemovedThenAddedFuture_usingLib() { insertLibrary("fooBcpRemovedThenAdded", SDK_INT_PLUS_TWO, SDK_INT_PLUS_ONE); ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .addUsesLibrary("fooBcpRemovedThenAdded") .hideAsParsed()); AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .hideAsParsed()) .hideAsFinal(); // in this example, we are at the point where the library was removed from the BCP checkBackwardsCompatibility(before, after); } @Test public void testBcpBeforeFuture() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Build.VERSION_CODES.R) .addUsesLibrary("fooBcpBeforeFuture") .addUsesLibrary("fooBcpBeforeFutureCodename") .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 was removed from the BCP checkBackwardsCompatibility(before, after); } @Test public void testBcpBeforeFuture_futureTargetSdk() { ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .addUsesLibrary("fooBcpBeforeFuture") .addUsesLibrary("fooBcpBeforeFutureCodename") .hideAsParsed()); AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) .setTargetSdkVersion(Integer.parseInt(SDK_INT_PLUS_ONE)) .hideAsParsed()) .hideAsFinal(); // in this example, we are at the point where the library was removed from the BCP checkBackwardsCompatibility(before, after); } private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, () -> new ApexSharedLibraryUpdater(mSharedLibraries)); Loading
services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +42 −12 Original line number Diff line number Diff line Loading @@ -439,8 +439,30 @@ public class SystemConfigTest { parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); assertThat(entry.onBootclasspathBefore).isEqualTo(10); assertThat(entry.onBootclasspathSince).isEqualTo(20); assertThat(entry.onBootclasspathBefore).isEqualTo("10"); assertThat(entry.onBootclasspathSince).isEqualTo("20"); } /** * Tests that readPermissions works correctly for a library with on-bootclasspath-before * and on-bootclasspath-since that uses codenames. */ @Test public void readPermissions_allowLibs_parsesSimpleLibraryWithCodenames() throws IOException { String contents = "<permissions>\n" + " <library \n" + " name=\"foo\"\n" + " file=\"" + mFooJar + "\"\n" + " on-bootclasspath-before=\"Q\"\n" + " on-bootclasspath-since=\"W\"\n" + " />\n\n" + " </permissions>"; parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); assertThat(entry.onBootclasspathBefore).isEqualTo("Q"); assertThat(entry.onBootclasspathSince).isEqualTo("W"); } /** Loading @@ -461,8 +483,8 @@ public class SystemConfigTest { parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); assertThat(entry.onBootclasspathBefore).isEqualTo(10); assertThat(entry.onBootclasspathSince).isEqualTo(20); assertThat(entry.onBootclasspathBefore).isEqualTo("10"); assertThat(entry.onBootclasspathSince).isEqualTo("20"); } /** Loading Loading @@ -543,12 +565,20 @@ public class SystemConfigTest { */ @Test public void readPermissions_allowLibs_allowsCurrentMaxSdk() throws IOException { // depending on whether this test is running before or after finalization, we need to // pass a different parameter String parameter; if ("REL".equals(Build.VERSION.CODENAME)) { parameter = "" + Build.VERSION.SDK_INT; } else { parameter = "ZZZ"; } String contents = "<permissions>\n" + " <library \n" + " name=\"foo\"\n" + " file=\"" + mFooJar + "\"\n" + " max-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" + " max-device-sdk=\"" + parameter + "\"\n" + " />\n\n" + " </permissions>"; parseSharedLibraries(contents); Loading