diff options
21 files changed, 229 insertions, 54 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 61c7ec6411c6..c598ac12dd41 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1216,6 +1216,7 @@ package android { field public static final int opticalInsetLeft = 16844168; // 0x1010588 field public static final int opticalInsetRight = 16844170; // 0x101058a field public static final int opticalInsetTop = 16844169; // 0x1010589 + field @FlaggedApi("android.content.pm.sdk_lib_independence") public static final int optional; field public static final int order = 16843242; // 0x10101ea field public static final int orderInCategory = 16843231; // 0x10101df field public static final int ordering = 16843490; // 0x10102e2 diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index fdd2aa1fe5fa..25ba72551b04 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -142,8 +142,10 @@ public final class SharedLibraryInfo implements Parcelable { mName = parcel.readString8(); mVersion = parcel.readLong(); mType = parcel.readInt(); - mDeclaringPackage = parcel.readParcelable(null, android.content.pm.VersionedPackage.class); - mDependentPackages = parcel.readArrayList(null, android.content.pm.VersionedPackage.class); + mDeclaringPackage = + parcel.readParcelable(null, android.content.pm.VersionedPackage.class); + mDependentPackages = + parcel.readArrayList(null, android.content.pm.VersionedPackage.class); mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR); mIsNative = parcel.readBoolean(); } diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java index 4ed361f24439..6c09b7c04fa7 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java @@ -112,7 +112,7 @@ public interface ParsingPackage { ParsingPackage addUsesOptionalNativeLibrary(String libraryName); ParsingPackage addUsesSdkLibrary(String libraryName, long versionMajor, - String[] certSha256Digests); + String[] certSha256Digests, boolean usesSdkLibrariesOptional); ParsingPackage addUsesStaticLibrary(String libraryName, long version, String[] certSha256Digests); diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java index 4e4f26cd6ad6..f86595f1ea7b 100644 --- a/core/java/com/android/server/pm/pkg/AndroidPackage.java +++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java @@ -1340,6 +1340,15 @@ public interface AndroidPackage { @Nullable long[] getUsesSdkLibrariesVersionsMajor(); + + /** + * @see R.styleable#AndroidManifestUsesSdkLibrary_optional + * @hide + */ + @Immutable.Ignore + @Nullable + boolean[] getUsesSdkLibrariesOptional(); + /** * TODO(b/135203078): Move static library stuff to an inner data class * diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index f8546b73a37e..596cfe5a695d 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2515,6 +2515,10 @@ <attr name="versionMajor" format="integer" /> <!-- The SHA-256 digest of the SDK library signing certificate. --> <attr name="certDigest" format="string" /> + <!-- Specify whether the SDK is optional. The default is false, false means app can be + installed even if the SDK library doesn't exist, and the SDK library can be uninstalled + when the app is still installed. --> + <attr name="optional" format="boolean" /> </declare-styleable> <!-- The <code>static-library</code> tag declares that this apk is providing itself diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index b12f30242e80..f10e7f8c337e 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -115,6 +115,8 @@ <!-- @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @hide @SystemApi --> <public name="isVirtualDeviceOnly"/> + <!-- @FlaggedApi("android.content.pm.sdk_lib_independence") --> + <public name="optional"/> </staging-public-group> <staging-public-group type="id" first-id="0x01bc0000"> diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index 92d469ccbfac..c36c8caf8b19 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -405,9 +405,19 @@ public interface Computer extends PackageDataSnapshot { boolean isInstallDisabledForPackage(@NonNull String packageName, int uid, @UserIdInt int userId); - @Nullable - List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo, - @PackageManager.PackageInfoFlagsBits long flags, int callingUid, @UserIdInt int userId); + /** + * Returns a Pair that contains a list of packages that depend on the target library and the + * package library dependency information. The List<VersionedPackage> indicates a list of + * packages that depend on the target library, it may be null if no package depends on + * the target library. The List<Boolean> indicates whether each VersionedPackage in + * the List<VersionedPackage> optionally depends on the target library, where true means + * optional and false means required. It may be null if no package depends on + * the target library or without dependency information, e.g. uses-static-library. + */ + @NonNull + Pair<List<VersionedPackage>, List<Boolean>> getPackagesUsingSharedLibrary( + @NonNull SharedLibraryInfo libInfo, @PackageManager.PackageInfoFlagsBits long flags, + int callingUid, @UserIdInt int userId); @Nullable ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries( diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 139c7c0849b0..df7ceda3b2f9 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -3862,11 +3862,13 @@ public class ComputerEngine implements Computer { Binder.restoreCallingIdentity(identity); } + var usingSharedLibraryPair = + getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId); SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(), libInfo.getPackageName(), libInfo.getAllCodePaths(), libInfo.getName(), libInfo.getLongVersion(), libInfo.getType(), declaringPackage, - getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId), + usingSharedLibraryPair.first, (libInfo.getDependencies() == null ? null : new ArrayList<>(libInfo.getDependencies())), @@ -3935,13 +3937,15 @@ public class ComputerEngine implements Computer { return false; } + @Override - public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo, - @PackageManager.PackageInfoFlagsBits long flags, int callingUid, - @UserIdInt int userId) { + public Pair<List<VersionedPackage>, List<Boolean>> getPackagesUsingSharedLibrary( + @NonNull SharedLibraryInfo libInfo, @PackageManager.PackageInfoFlagsBits long flags, + int callingUid, @UserIdInt int userId) { List<VersionedPackage> versionedPackages = null; final ArrayMap<String, ? extends PackageStateInternal> packageStates = getPackageStates(); final int packageCount = packageStates.size(); + List<Boolean> usesLibsOptional = null; for (int i = 0; i < packageCount; i++) { PackageStateInternal ps = packageStates.valueAt(i); if (ps == null) { @@ -3958,12 +3962,15 @@ public class ComputerEngine implements Computer { libInfo.isStatic() ? ps.getUsesStaticLibraries() : ps.getUsesSdkLibraries(); final long[] libsVersions = libInfo.isStatic() ? ps.getUsesStaticLibrariesVersions() : ps.getUsesSdkLibrariesVersionsMajor(); + final boolean[] libsOptional = libInfo.isSdk() + ? ps.getUsesSdkLibrariesOptional() : null; final int libIdx = ArrayUtils.indexOf(libs, libName); if (libIdx < 0) { continue; } if (libsVersions[libIdx] != libInfo.getLongVersion()) { + // Not expected StaticLib/SdkLib version continue; } if (shouldFilterApplication(ps, callingUid, userId)) { @@ -3972,6 +3979,9 @@ public class ComputerEngine implements Computer { if (versionedPackages == null) { versionedPackages = new ArrayList<>(); } + if (usesLibsOptional == null) { + usesLibsOptional = new ArrayList<>(); + } // If the dependent is a static shared lib, use the public package name String dependentPackageName = ps.getPackageName(); if (ps.getPkg() != null && ps.getPkg().isStaticSharedLibrary()) { @@ -3979,6 +3989,7 @@ public class ComputerEngine implements Computer { } versionedPackages.add(new VersionedPackage(dependentPackageName, ps.getVersionCode())); + usesLibsOptional.add(libsOptional != null && libsOptional[libIdx]); } else if (ps.getPkg() != null) { if (ArrayUtils.contains(ps.getPkg().getUsesLibraries(), libName) || ArrayUtils.contains(ps.getPkg().getUsesOptionalLibraries(), libName)) { @@ -3994,7 +4005,7 @@ public class ComputerEngine implements Computer { } } - return versionedPackages; + return new Pair<>(versionedPackages, usesLibsOptional); } @Nullable @@ -4053,13 +4064,14 @@ public class ComputerEngine implements Computer { Binder.restoreCallingIdentity(identity); } + var usingSharedLibraryPair = + getPackagesUsingSharedLibrary(libraryInfo, flags, callingUid, userId); SharedLibraryInfo resultLibraryInfo = new SharedLibraryInfo( libraryInfo.getPath(), libraryInfo.getPackageName(), libraryInfo.getAllCodePaths(), libraryInfo.getName(), libraryInfo.getLongVersion(), libraryInfo.getType(), libraryInfo.getDeclaringPackage(), - getPackagesUsingSharedLibrary( - libraryInfo, flags, callingUid, userId), + usingSharedLibraryPair.first, libraryInfo.getDependencies() == null ? null : new ArrayList<>(libraryInfo.getDependencies()), libraryInfo.isNative()); diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 80e6c833dfb2..93836266d1f4 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -18,7 +18,6 @@ package com.android.server.pm; import static android.Manifest.permission.CONTROL_KEYGUARD; import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS; -import static android.content.pm.Flags.sdkLibIndependence; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; @@ -40,6 +39,7 @@ import android.app.ApplicationExitInfo; import android.app.ApplicationPackageManager; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.Flags; import android.content.pm.IPackageDeleteObserver2; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; @@ -72,8 +72,6 @@ import com.android.server.wm.ActivityTaskManagerInternal; import dalvik.system.VMRuntime; -import java.util.List; - /** * Deletes a package. Uninstall if installed, or at least deletes the base directory if it's called * from a failed installation. Fixes user state after deletion. @@ -181,16 +179,36 @@ final class DeletePackageHelper { } if (libraryInfo != null) { + boolean flagSdkLibIndependence = Flags.sdkLibIndependence(); for (int currUserId : allUsers) { if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) { continue; } - List<VersionedPackage> libClientPackages = - computer.getPackagesUsingSharedLibrary(libraryInfo, - MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId); - boolean allowSdkLibIndependence = - (pkg.getSdkLibraryName() != null) && sdkLibIndependence(); - if (!ArrayUtils.isEmpty(libClientPackages) && !allowSdkLibIndependence) { + var libClientPackagesPair = computer.getPackagesUsingSharedLibrary( + libraryInfo, MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId); + var libClientPackages = libClientPackagesPair.first; + var libClientOptional = libClientPackagesPair.second; + // We by default don't allow removing a package if the host lib is still be + // used by other client packages + boolean allowLibIndependence = false; + // Only when the sdkLibIndependence flag is enabled we will respect the + // "optional" attr in uses-sdk-library. Only allow to remove sdk-lib host + // package if no required clients depend on it + if ((pkg.getSdkLibraryName() != null) + && !ArrayUtils.isEmpty(libClientPackages) + && !ArrayUtils.isEmpty(libClientOptional) + && (libClientPackages.size() == libClientOptional.size()) + && flagSdkLibIndependence) { + allowLibIndependence = true; + for (int i = 0; i < libClientPackages.size(); i++) { + boolean usesSdkLibOptional = libClientOptional.get(i); + if (!usesSdkLibOptional) { + allowLibIndependence = false; + break; + } + } + } + if (!ArrayUtils.isEmpty(libClientPackages) && !allowLibIndependence) { Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName() + " hosting lib " + libraryInfo.getName() + " version " + libraryInfo.getLongVersion() + " used by " + libClientPackages diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f27c462700be..2880f84c6445 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7113,9 +7113,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService if (info == null) { continue; } - final List<VersionedPackage> dependents = - computer.getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID, - userId); + var usingSharedLibraryPair = computer.getPackagesUsingSharedLibrary(info, 0, + Process.SYSTEM_UID, userId); + final List<VersionedPackage> dependents = usingSharedLibraryPair.first; if (dependents == null) { continue; } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 174df44c4263..7d0a1f6afe1d 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -123,11 +123,15 @@ public class PackageSetting extends SettingBase implements PackageStateInternal @Nullable private Map<String, Set<String>> mimeGroups; + // TODO(b/314036181): encapsulate all these fields for usesSdk, instead of having three + // separate arrays. @Nullable private String[] usesSdkLibraries; @Nullable private long[] usesSdkLibrariesVersionsMajor; + @Nullable + private boolean[] usesSdkLibrariesOptional; @Nullable private String[] usesStaticLibraries; @@ -701,6 +705,9 @@ public class PackageSetting extends SettingBase implements PackageStateInternal usesSdkLibrariesVersionsMajor = other.usesSdkLibrariesVersionsMajor != null ? Arrays.copyOf(other.usesSdkLibrariesVersionsMajor, other.usesSdkLibrariesVersionsMajor.length) : null; + usesSdkLibrariesOptional = other.usesSdkLibrariesOptional != null + ? Arrays.copyOf(other.usesSdkLibrariesOptional, + other.usesSdkLibrariesOptional.length) : null; usesStaticLibraries = other.usesStaticLibraries != null ? Arrays.copyOf(other.usesStaticLibraries, @@ -1344,6 +1351,12 @@ public class PackageSetting extends SettingBase implements PackageStateInternal @NonNull @Override + public boolean[] getUsesSdkLibrariesOptional() { + return usesSdkLibrariesOptional == null ? EmptyArray.BOOLEAN : usesSdkLibrariesOptional; + } + + @NonNull + @Override public String[] getUsesStaticLibraries() { return usesStaticLibraries == null ? EmptyArray.STRING : usesStaticLibraries; } @@ -1444,6 +1457,12 @@ public class PackageSetting extends SettingBase implements PackageStateInternal return this; } + public PackageSetting setUsesSdkLibrariesOptional(boolean[] usesSdkLibrariesOptional) { + this.usesSdkLibrariesOptional = usesSdkLibrariesOptional; + onChanged(); + return this; + } + public PackageSetting setUsesStaticLibraries(String[] usesStaticLibraries) { this.usesStaticLibraries = usesStaticLibraries; onChanged(); diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java index 53b84e66840b..31a63e07b66c 100644 --- a/services/core/java/com/android/server/pm/ScanPackageUtils.java +++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java @@ -218,7 +218,8 @@ final class ScanPackageUtils { parsedPackage.getLongVersionCode(), pkgFlags, pkgPrivateFlags, user, true /*allowInstall*/, instantApp, virtualPreload, isStoppedSystemApp, UserManagerService.getInstance(), usesSdkLibraries, - parsedPackage.getUsesSdkLibrariesVersionsMajor(), usesStaticLibraries, + parsedPackage.getUsesSdkLibrariesVersionsMajor(), + parsedPackage.getUsesSdkLibrariesOptional(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), newDomainSetId, parsedPackage.getTargetSdkVersion(), parsedPackage.getRestrictUpdateHash()); @@ -240,6 +241,7 @@ final class ScanPackageUtils { PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting), UserManagerService.getInstance(), usesSdkLibraries, parsedPackage.getUsesSdkLibrariesVersionsMajor(), + parsedPackage.getUsesSdkLibrariesOptional(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(), newDomainSetId, parsedPackage.getTargetSdkVersion(), parsedPackage.getRestrictUpdateHash()); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 2cbf714792f7..75d88da059b5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -106,6 +106,7 @@ import com.android.server.LocalServices; import com.android.server.backup.PreferredActivityBackupHelper; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.permission.LegacyPermissionDataProvider; import com.android.server.pm.permission.LegacyPermissionSettings; import com.android.server.pm.permission.LegacyPermissionState; @@ -339,6 +340,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile private static final String ATTR_DISTRACTION_FLAGS = "distraction_flags"; private static final String ATTR_SUSPENDED = "suspended"; private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package"; + + private static final String ATTR_OPTIONAL = "optional"; /** * @deprecated Legacy attribute, kept only for upgrading from P builds. */ @@ -942,6 +945,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile ret.setLongVersionCode(p.getVersionCode()); ret.setUsesSdkLibraries(p.getUsesSdkLibraries()); ret.setUsesSdkLibrariesVersionsMajor(p.getUsesSdkLibrariesVersionsMajor()); + ret.setUsesSdkLibrariesOptional(p.getUsesSdkLibrariesOptional()); ret.setUsesStaticLibraries(p.getUsesStaticLibraries()); ret.setUsesStaticLibrariesVersions(p.getUsesStaticLibrariesVersions()); ret.setMimeGroups(p.getMimeGroups()); @@ -1061,9 +1065,9 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile UserHandle installUser, boolean allowInstall, boolean instantApp, boolean virtualPreload, boolean isStoppedSystemApp, UserManagerService userManager, String[] usesSdkLibraries, long[] usesSdkLibrariesVersions, - String[] usesStaticLibraries, long[] usesStaticLibrariesVersions, - Set<String> mimeGroupNames, @NonNull UUID domainSetId, - int targetSdkVersion, byte[] restrictUpdatedHash) { + boolean[] usesSdkLibrariesOptional, String[] usesStaticLibraries, + long[] usesStaticLibrariesVersions, Set<String> mimeGroupNames, + @NonNull UUID domainSetId, int targetSdkVersion, byte[] restrictUpdatedHash) { final PackageSetting pkgSetting; if (originalPkg != null) { if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " @@ -1079,6 +1083,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile .setLongVersionCode(versionCode) .setUsesSdkLibraries(usesSdkLibraries) .setUsesSdkLibrariesVersionsMajor(usesSdkLibrariesVersions) + .setUsesSdkLibrariesOptional(usesSdkLibrariesOptional) .setUsesStaticLibraries(usesStaticLibraries) .setUsesStaticLibrariesVersions(usesStaticLibrariesVersions) // Update new package state. @@ -1096,6 +1101,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile pkgPrivateFlags, domainSetId) .setUsesSdkLibraries(usesSdkLibraries) .setUsesSdkLibrariesVersionsMajor(usesSdkLibrariesVersions) + .setUsesSdkLibrariesOptional(usesSdkLibrariesOptional) .setUsesStaticLibraries(usesStaticLibraries) .setUsesStaticLibrariesVersions(usesStaticLibrariesVersions) .setLegacyNativeLibraryPath(legacyNativeLibraryPath) @@ -1218,6 +1224,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags, @NonNull UserManagerService userManager, @Nullable String[] usesSdkLibraries, @Nullable long[] usesSdkLibrariesVersions, + @Nullable boolean[] usesSdkLibrariesOptional, @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions, @Nullable Set<String> mimeGroupNames, @NonNull UUID domainSetId, int targetSdkVersion, byte[] restrictUpdatedHash) @@ -1277,12 +1284,17 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile .setRestrictUpdateHash(restrictUpdatedHash); // Update SDK library dependencies if needed. if (usesSdkLibraries != null && usesSdkLibrariesVersions != null - && usesSdkLibraries.length == usesSdkLibrariesVersions.length) { + && usesSdkLibrariesOptional != null + && usesSdkLibraries.length == usesSdkLibrariesVersions.length + && usesSdkLibraries.length == usesSdkLibrariesOptional.length) { pkgSetting.setUsesSdkLibraries(usesSdkLibraries) - .setUsesSdkLibrariesVersionsMajor(usesSdkLibrariesVersions); + .setUsesSdkLibrariesVersionsMajor(usesSdkLibrariesVersions) + .setUsesSdkLibrariesOptional(usesSdkLibrariesOptional); } else { pkgSetting.setUsesSdkLibraries(null) - .setUsesSdkLibrariesVersionsMajor(null); + .setUsesSdkLibrariesVersionsMajor(null) + .setUsesSdkLibrariesOptional(null); + } // Update static shared library dependencies if needed. @@ -2537,12 +2549,15 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile throws IOException, XmlPullParserException { String libName = parser.getAttributeValue(null, ATTR_NAME); long libVersion = parser.getAttributeLong(null, ATTR_VERSION, -1); + boolean optional = parser.getAttributeBoolean(null, ATTR_OPTIONAL, true); if (libName != null && libVersion >= 0) { outPs.setUsesSdkLibraries(ArrayUtils.appendElement(String.class, outPs.getUsesSdkLibraries(), libName)); outPs.setUsesSdkLibrariesVersionsMajor(ArrayUtils.appendLong( outPs.getUsesSdkLibrariesVersionsMajor(), libVersion)); + outPs.setUsesSdkLibrariesOptional(PackageImpl.appendBoolean( + outPs.getUsesSdkLibrariesOptional(), optional)); } XmlUtils.skipCurrentTag(parser); @@ -2564,7 +2579,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile } void writeUsesSdkLibLPw(TypedXmlSerializer serializer, String[] usesSdkLibraries, - long[] usesSdkLibraryVersions) throws IOException { + long[] usesSdkLibraryVersions, boolean[] usesSdkLibrariesOptional) throws IOException { if (ArrayUtils.isEmpty(usesSdkLibraries) || ArrayUtils.isEmpty(usesSdkLibraryVersions) || usesSdkLibraries.length != usesSdkLibraryVersions.length) { return; @@ -2573,9 +2588,11 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile for (int i = 0; i < libCount; i++) { final String libName = usesSdkLibraries[i]; final long libVersion = usesSdkLibraryVersions[i]; + boolean libOptional = usesSdkLibrariesOptional[i]; serializer.startTag(null, TAG_USES_SDK_LIB); serializer.attribute(null, ATTR_NAME, libName); serializer.attributeLong(null, ATTR_VERSION, libVersion); + serializer.attributeBoolean(null, ATTR_OPTIONAL, libOptional); serializer.endTag(null, TAG_USES_SDK_LIB); } } @@ -3106,7 +3123,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile } writeUsesSdkLibLPw(serializer, pkg.getUsesSdkLibraries(), - pkg.getUsesSdkLibrariesVersionsMajor()); + pkg.getUsesSdkLibrariesVersionsMajor(), pkg.getUsesSdkLibrariesOptional()); + writeUsesStaticLibLPw(serializer, pkg.getUsesStaticLibraries(), pkg.getUsesStaticLibrariesVersions()); @@ -3206,7 +3224,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile } writeUsesSdkLibLPw(serializer, pkg.getUsesSdkLibraries(), - pkg.getUsesSdkLibrariesVersionsMajor()); + pkg.getUsesSdkLibrariesVersionsMajor(), pkg.getUsesSdkLibrariesOptional()); writeUsesStaticLibLPw(serializer, pkg.getUsesStaticLibraries(), pkg.getUsesStaticLibrariesVersions()); @@ -5091,12 +5109,14 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile List<String> usesSdkLibraries = pkg.getUsesSdkLibraries(); long[] usesSdkLibrariesVersionsMajor = pkg.getUsesSdkLibrariesVersionsMajor(); + boolean[] usesSdkLibrariesOptional = pkg.getUsesSdkLibrariesOptional(); if (usesSdkLibraries.size() > 0) { pw.print(prefix); pw.println(" usesSdkLibraries:"); for (int i = 0, size = usesSdkLibraries.size(); i < size; ++i) { pw.print(prefix); pw.print(" "); pw.print(usesSdkLibraries.get(i)); pw.print(" version:"); - pw.println(usesSdkLibrariesVersionsMajor[i]); + pw.println(usesSdkLibrariesVersionsMajor[i]); pw.print(" optional:"); + pw.println(usesSdkLibrariesOptional[i]); } } diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java index 9384c13e583b..94495bf462f2 100644 --- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java +++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java @@ -16,7 +16,6 @@ package com.android.server.pm; -import static android.content.pm.Flags.sdkLibIndependence; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST; @@ -28,6 +27,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; +import android.content.pm.Flags; import android.content.pm.PackageManager; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; @@ -82,6 +82,8 @@ import java.util.function.BiConsumer; public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable, Snappable { private static final boolean DEBUG_SHARED_LIBRARIES = false; + private static final String LIBRARY_TYPE_SDK = "sdk"; + /** * Apps targeting Android S and above need to declare dependencies to the public native * shared libraries that are defined by the device maker using {@code uses-native-library} tag @@ -798,8 +800,9 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable // Remove the shared library overlays from its dependent packages. for (int currentUserId : mPm.mUserManager.getUserIds()) { - final List<VersionedPackage> dependents = snapshot.getPackagesUsingSharedLibrary( - libraryInfo, 0, Process.SYSTEM_UID, currentUserId); + var usingSharedLibraryPair = snapshot.getPackagesUsingSharedLibrary(libraryInfo, 0, + Process.SYSTEM_UID, currentUserId); + final List<VersionedPackage> dependents = usingSharedLibraryPair.first; if (dependents == null) { continue; } @@ -921,42 +924,43 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable // duplicates. ArrayList<SharedLibraryInfo> usesLibraryInfos = null; if (!pkg.getUsesLibraries().isEmpty()) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, null, pkg.getPackageName(), "shared", true, pkg.getTargetSdkVersion(), null, availablePackages, newLibraries); } if (!pkg.getUsesStaticLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(), pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(), - pkg.getPackageName(), "static shared", true, pkg.getTargetSdkVersion(), - usesLibraryInfos, availablePackages, newLibraries); + null, pkg.getPackageName(), "static shared", true, + pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, newLibraries); } if (!pkg.getUsesOptionalLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), null, null, - pkg.getPackageName(), "shared", false, pkg.getTargetSdkVersion(), + null, pkg.getPackageName(), "shared", false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, newLibraries); } if (platformCompat.isChangeEnabledInternal(ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES, pkg.getPackageName(), pkg.getTargetSdkVersion())) { if (!pkg.getUsesNativeLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesNativeLibraries(), null, - null, pkg.getPackageName(), "native shared", true, + null, null, pkg.getPackageName(), "native shared", true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, newLibraries); } if (!pkg.getUsesOptionalNativeLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalNativeLibraries(), - null, null, pkg.getPackageName(), "native shared", false, + null, null, null, pkg.getPackageName(), "native shared", false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, newLibraries); } } if (!pkg.getUsesSdkLibraries().isEmpty()) { // Allow installation even if sdk-library dependency doesn't exist - boolean required = !sdkLibIndependence(); + boolean required = !Flags.sdkLibIndependence(); usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesSdkLibraries(), pkg.getUsesSdkLibrariesVersionsMajor(), pkg.getUsesSdkLibrariesCertDigests(), - pkg.getPackageName(), "sdk", required, pkg.getTargetSdkVersion(), + pkg.getUsesSdkLibrariesOptional(), + pkg.getPackageName(), LIBRARY_TYPE_SDK, required, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, newLibraries); } return usesLibraryInfos; @@ -965,6 +969,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable private ArrayList<SharedLibraryInfo> collectSharedLibraryInfos( @NonNull List<String> requestedLibraries, @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests, + @Nullable boolean[] libsOptional, @NonNull String packageName, @NonNull String libraryType, boolean required, int targetSdk, @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries, @NonNull final Map<String, AndroidPackage> availablePackages, @@ -981,7 +986,10 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable libName, libVersion, mSharedLibraries, newLibraries); } if (libraryInfo == null) { - if (required) { + // Only allow app be installed if the app specifies the sdk-library dependency is + // optional + if (required || (LIBRARY_TYPE_SDK.equals(libraryType) && (libsOptional != null + && !libsOptional[i]))) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires unavailable " + libraryType + " library " + libName + "; failing!"); diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java index 85d95eab2958..da58d47edbfe 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java @@ -267,6 +267,8 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, @Nullable private String[][] usesSdkLibrariesCertDigests; @Nullable + private boolean[] usesSdkLibrariesOptional; + @Nullable @DataClass.ParcelWith(ForInternedString.class) private String sharedUserId; private int sharedUserLabel; @@ -718,16 +720,33 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, @Override public PackageImpl addUsesSdkLibrary(String libraryName, long versionMajor, - String[] certSha256Digests) { + String[] certSha256Digests, boolean usesSdkLibrariesOptional) { this.usesSdkLibraries = CollectionUtils.add(this.usesSdkLibraries, TextUtils.safeIntern(libraryName)); this.usesSdkLibrariesVersionsMajor = ArrayUtils.appendLong( this.usesSdkLibrariesVersionsMajor, versionMajor, true); this.usesSdkLibrariesCertDigests = ArrayUtils.appendElement(String[].class, this.usesSdkLibrariesCertDigests, certSha256Digests, true); + this.usesSdkLibrariesOptional = appendBoolean(this.usesSdkLibrariesOptional, + usesSdkLibrariesOptional); return this; } + /** + * Adds value to given array if not already present, providing set-like + * behavior. + */ + public static boolean[] appendBoolean(@Nullable boolean[] cur, boolean val) { + if (cur == null) { + return new boolean[] { val }; + } + final int N = cur.length; + boolean[] ret = new boolean[N + 1]; + System.arraycopy(cur, 0, ret, 0, N); + ret[N] = val; + return ret; + } + @Override public PackageImpl addUsesStaticLibrary(String libraryName, long version, String[] certSha256Digests) { @@ -1468,6 +1487,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, @Override public long[] getUsesSdkLibrariesVersionsMajor() { return usesSdkLibrariesVersionsMajor; } + @Nullable + @Override + public boolean[] getUsesSdkLibrariesOptional() { + return usesSdkLibrariesOptional; + } + @NonNull @Override public List<String> getUsesStaticLibraries() { @@ -3126,6 +3151,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, dest.writeStringArray(this.usesSdkLibrariesCertDigests[index]); } } + dest.writeBooleanArray(this.usesSdkLibrariesOptional); sForInternedString.parcel(this.sharedUserId, dest, flags); dest.writeInt(this.sharedUserLabel); @@ -3278,6 +3304,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, } } } + this.usesSdkLibrariesOptional = in.createBooleanArray(); this.sharedUserId = sForInternedString.unparcel(in); this.sharedUserLabel = in.readInt(); diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java index 10b59c7230f6..a7ae4ebcb2eb 100644 --- a/services/core/java/com/android/server/pm/pkg/PackageState.java +++ b/services/core/java/com/android/server/pm/pkg/PackageState.java @@ -322,6 +322,14 @@ public interface PackageState { long[] getUsesSdkLibrariesVersionsMajor(); /** + * @see R.styleable#AndroidManifestUsesSdkLibrary_optional + * @hide + */ + @Immutable.Ignore + @NonNull + boolean[] getUsesSdkLibrariesOptional(); + + /** * @see R.styleable#AndroidManifestUsesStaticLibrary * @hide */ diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java index 722350a0d7fb..aa0fb2734382 100644 --- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java +++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java @@ -2598,6 +2598,8 @@ public class ParsingPackageUtils { R.styleable.AndroidManifestUsesSdkLibrary_versionMajor, -1); String certSha256Digest = sa.getNonResourceString(R.styleable .AndroidManifestUsesSdkLibrary_certDigest); + boolean optional = + sa.getBoolean(R.styleable.AndroidManifestUsesSdkLibrary_optional, false); // Since an APK providing a static shared lib can only provide the lib - fail if // malformed @@ -2641,7 +2643,8 @@ public class ParsingPackageUtils { System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, 1, additionalCertSha256Digests.length); - return input.success(pkg.addUsesSdkLibrary(lname, versionMajor, certSha256Digests)); + return input.success( + pkg.addUsesSdkLibrary(lname, versionMajor, certSha256Digests, optional)); } finally { sa.recycle(); } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java index a0dc2b68415c..f07e820bf8b3 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -817,12 +817,14 @@ public class PackageManagerSettingsTests { ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" }); ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 }); + ps1.setUsesSdkLibrariesOptional(new boolean[] {true}); ps1.setFlags(ps1.getFlags() | ApplicationInfo.FLAG_SYSTEM); settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1); assertThat(settingsUnderTest.disableSystemPackageLPw(PACKAGE_NAME_1, false), is(true)); ps2.setUsesSdkLibraries(new String[] { "com.example.sdk.two" }); ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 }); + ps2.setUsesSdkLibrariesOptional(new boolean[] {false}); settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2); settingsUnderTest.writeLPr(computer, /*sync=*/true); @@ -838,19 +840,30 @@ public class PackageManagerSettingsTests { Truth.assertThat(readPs1).isNotNull(); Truth.assertThat(readPs1.getUsesSdkLibraries()).isNotNull(); Truth.assertThat(readPs1.getUsesSdkLibrariesVersionsMajor()).isNotNull(); + Truth.assertThat(readPs1.getUsesSdkLibrariesOptional()).isNotNull(); Truth.assertThat(readPs2).isNotNull(); Truth.assertThat(readPs2.getUsesSdkLibraries()).isNotNull(); Truth.assertThat(readPs2.getUsesSdkLibrariesVersionsMajor()).isNotNull(); + Truth.assertThat(readPs2.getUsesSdkLibrariesOptional()).isNotNull(); List<Long> ps1VersionsAsList = new ArrayList<>(); for (long version : ps1.getUsesSdkLibrariesVersionsMajor()) { ps1VersionsAsList.add(version); } + List<Boolean> ps1RequireAsList = new ArrayList<>(); + for (boolean optional : ps1.getUsesSdkLibrariesOptional()) { + ps1RequireAsList.add(optional); + } + List<Long> ps2VersionsAsList = new ArrayList<>(); for (long version : ps2.getUsesSdkLibrariesVersionsMajor()) { ps2VersionsAsList.add(version); } + List<Boolean> ps2RequireAsList = new ArrayList<>(); + for (boolean optional : ps2.getUsesSdkLibrariesOptional()) { + ps2RequireAsList.add(optional); + } Truth.assertThat(readPs1.getUsesSdkLibraries()).asList() .containsExactlyElementsIn(ps1.getUsesSdkLibraries()).inOrder(); @@ -858,11 +871,17 @@ public class PackageManagerSettingsTests { Truth.assertThat(readPs1.getUsesSdkLibrariesVersionsMajor()).asList() .containsExactlyElementsIn(ps1VersionsAsList).inOrder(); + Truth.assertThat(readPs1.getUsesSdkLibrariesOptional()).asList() + .containsExactlyElementsIn(ps1RequireAsList).inOrder(); + Truth.assertThat(readPs2.getUsesSdkLibraries()).asList() .containsExactlyElementsIn(ps2.getUsesSdkLibraries()).inOrder(); Truth.assertThat(readPs2.getUsesSdkLibrariesVersionsMajor()).asList() .containsExactlyElementsIn(ps2VersionsAsList).inOrder(); + + Truth.assertThat(readPs2.getUsesSdkLibrariesOptional()).asList() + .containsExactlyElementsIn(ps2RequireAsList).inOrder(); } @Test @@ -1047,6 +1066,7 @@ public class PackageManagerSettingsTests { UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/, @@ -1087,6 +1107,7 @@ public class PackageManagerSettingsTests { UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/, @@ -1129,6 +1150,7 @@ public class PackageManagerSettingsTests { UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/, @@ -1167,6 +1189,7 @@ public class PackageManagerSettingsTests { UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/, @@ -1214,6 +1237,7 @@ public class PackageManagerSettingsTests { UserManagerService.getInstance(), null /*usesSdkLibraries*/, null /*usesSdkLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/, @@ -1263,6 +1287,7 @@ public class PackageManagerSettingsTests { null /*usesSdkLibrariesVersions*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*mimeGroups*/, UUID.randomUUID(), 34 /*targetSdkVersion*/, @@ -1311,6 +1336,7 @@ public class PackageManagerSettingsTests { null /*usesSdkLibrariesVersions*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*mimeGroups*/, UUID.randomUUID(), 34 /*targetSdkVersion*/, @@ -1356,6 +1382,7 @@ public class PackageManagerSettingsTests { null /*usesSdkLibrariesVersions*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/, + null /*usesSdkLibrariesOptional*/, null /*mimeGroups*/, UUID.randomUUID(), 34 /*targetSdkVersion*/, diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java index ea88ec25b26e..a62cd4fc5fc2 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java @@ -1062,7 +1062,7 @@ public class PackageParserTest { .addProtectedBroadcast("foo8") .setSdkLibraryName("sdk12") .setSdkLibVersionMajor(42) - .addUsesSdkLibrary("sdk23", 200, new String[]{"digest2"}) + .addUsesSdkLibrary("sdk23", 200, new String[]{"digest2"}, true) .setStaticSharedLibraryName("foo23") .setStaticSharedLibraryVersion(100) .addUsesStaticLibrary("foo23", 100, new String[]{"digest"}) diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java index decb44c2cd9b..6202908cdfbf 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java @@ -599,8 +599,8 @@ public class ScanTests { .setVolumeUuid(UUID_ONE.toString()) .addUsesStaticLibrary("some.static.library", 234L, new String[]{"testCert1"}) .addUsesStaticLibrary("some.other.static.library", 456L, new String[]{"testCert2"}) - .addUsesSdkLibrary("some.sdk.library", 123L, new String[]{"testCert3"}) - .addUsesSdkLibrary("some.other.sdk.library", 789L, new String[]{"testCert4"}) + .addUsesSdkLibrary("some.sdk.library", 123L, new String[]{"testCert3"}, false) + .addUsesSdkLibrary("some.other.sdk.library", 789L, new String[]{"testCert4"}, true) .hideAsParsed()) .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib") .setVersionCodeMajor(1) @@ -628,6 +628,7 @@ public class ScanTests { assertThat(pkgSetting.getUsesSdkLibraries(), arrayContaining("some.sdk.library", "some.other.sdk.library")); assertThat(pkgSetting.getUsesSdkLibrariesVersionsMajor(), is(new long[]{123L, 789L})); + assertThat(pkgSetting.getUsesSdkLibrariesOptional(), is(new boolean[]{false, true})); assertThat(pkgSetting.getPkg(), is(scanResult.mRequest.mParsedPackage)); assertThat(pkgSetting.getPath(), is(new File(createCodePath(packageName)))); assertThat(pkgSetting.getVersionCode(), diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt index 170faf61858b..09b66c11d200 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt @@ -127,6 +127,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag "getUsesSdkLibraries", "getUsesSdkLibrariesVersionsMajor", "getUsesSdkLibrariesCertDigests", + "getUsesSdkLibrariesOptional", // Tested through addUsesStaticLibrary "addUsesStaticLibrary", "getUsesStaticLibraries", @@ -608,7 +609,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag .setSplitHasCode(1, false) .setSplitClassLoaderName(0, "testSplitClassLoaderNameZero") .setSplitClassLoaderName(1, "testSplitClassLoaderNameOne") - .addUsesSdkLibrary("testSdk", 2L, arrayOf("testCertDigest1")) + .addUsesSdkLibrary("testSdk", 2L, arrayOf("testCertDigest1"), true) .addUsesStaticLibrary("testStatic", 3L, arrayOf("testCertDigest2")) override fun finalizeObject(parcelable: Parcelable) { @@ -661,6 +662,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag expect.that(after.usesSdkLibrariesCertDigests!!.size).isEqualTo(1) expect.that(after.usesSdkLibrariesCertDigests!![0]).asList() .containsExactly("testCertDigest1") + expect.that(after.usesSdkLibrariesOptional).asList().containsExactly(true) expect.that(after.usesStaticLibraries).containsExactly("testStatic") expect.that(after.usesStaticLibrariesVersions).asList().containsExactly(3L) |