diff --git a/services/core/java/com/android/server/pm/AppStateHelper.java b/services/core/java/com/android/server/pm/AppStateHelper.java index 32479ee459ffb..1a2b01eb11c5e 100644 --- a/services/core/java/com/android/server/pm/AppStateHelper.java +++ b/services/core/java/com/android/server/pm/AppStateHelper.java @@ -37,7 +37,7 @@ import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import java.util.ArrayList; -import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -159,13 +159,21 @@ public class AppStateHelper { return false; } - private static boolean containsAny(Collection list, Collection which) { - if (list.isEmpty()) { - return false; - } - for (var element : which) { - if (list.contains(element)) { + /** + * True if {@code arr} contains any element in {@code which}. + * Both {@code arr} and {@code which} must be sorted in advance. + */ + private static boolean containsAny(String[] arr, List which) { + int s1 = arr.length; + int s2 = which.size(); + for (int i = 0, j = 0; i < s1 && j < s2; ) { + int val = arr[i].compareTo(which.get(j)); + if (val == 0) { return true; + } else if (val < 0) { + ++i; + } else { + ++j; } } return false; @@ -174,9 +182,9 @@ public class AppStateHelper { private void addLibraryDependency(ArraySet results, List libPackageNames) { var pmInternal = LocalServices.getService(PackageManagerInternal.class); - var libraryNames = new ArraySet(); - var staticSharedLibraryNames = new ArraySet(); - var sdkLibraryNames = new ArraySet(); + var libraryNames = new ArrayList(); + var staticSharedLibraryNames = new ArrayList(); + var sdkLibraryNames = new ArrayList(); for (var packageName : libPackageNames) { var pkg = pmInternal.getAndroidPackage(packageName); if (pkg == null) { @@ -199,11 +207,19 @@ public class AppStateHelper { return; } - pmInternal.forEachPackage(pkg -> { - if (containsAny(pkg.getUsesLibraries(), libraryNames) - || containsAny(pkg.getUsesOptionalLibraries(), libraryNames) - || containsAny(pkg.getUsesStaticLibraries(), staticSharedLibraryNames) - || containsAny(pkg.getUsesSdkLibraries(), sdkLibraryNames)) { + Collections.sort(libraryNames); + Collections.sort(sdkLibraryNames); + Collections.sort(staticSharedLibraryNames); + + pmInternal.forEachPackageState(pkgState -> { + var pkg = pkgState.getPkg(); + if (pkg == null) { + return; + } + if (containsAny(pkg.getUsesLibrariesSorted(), libraryNames) + || containsAny(pkg.getUsesOptionalLibrariesSorted(), libraryNames) + || containsAny(pkg.getUsesStaticLibrariesSorted(), staticSharedLibraryNames) + || containsAny(pkg.getUsesSdkLibrariesSorted(), sdkLibraryNames)) { results.add(pkg.getPackageName()); } }); diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java index 8d43fe7b5f273..9eca7d651deae 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java @@ -16,6 +16,8 @@ package com.android.server.pm.parsing.pkg; +import android.annotation.NonNull; + import com.android.internal.content.om.OverlayConfig; import com.android.server.pm.pkg.AndroidPackage; @@ -31,5 +33,15 @@ import com.android.server.pm.pkg.AndroidPackage; */ public interface AndroidPackageInternal extends AndroidPackage, OverlayConfig.PackageProvider.Package { + @NonNull + String[] getUsesLibrariesSorted(); + @NonNull + String[] getUsesOptionalLibrariesSorted(); + + @NonNull + String[] getUsesSdkLibrariesSorted(); + + @NonNull + String[] getUsesStaticLibrariesSorted(); } 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 e361c93329727..ed9382b42206e 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 @@ -93,6 +93,7 @@ import libcore.util.EmptyArray; import java.io.File; import java.security.PublicKey; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -404,6 +405,15 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, private List mSplits; + @NonNull + private String[] mUsesLibrariesSorted; + @NonNull + private String[] mUsesOptionalLibrariesSorted; + @NonNull + private String[] mUsesSdkLibrariesSorted; + @NonNull + private String[] mUsesStaticLibrariesSorted; + @NonNull public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) { @@ -1377,6 +1387,19 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return usesLibraries; } + @NonNull + @Override + public String[] getUsesLibrariesSorted() { + if (mUsesLibrariesSorted == null) { + // Note lazy-sorting here doesn't break immutability because it always + // return the same content. In the case of multi-threading, data race in accessing + // mUsesLibrariesSorted might result in unnecessary creation of sorted copies + // which is OK because the case is quite rare. + mUsesLibrariesSorted = sortLibraries(usesLibraries); + } + return mUsesLibrariesSorted; + } + @NonNull @Override public List getUsesNativeLibraries() { @@ -1389,6 +1412,15 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return usesOptionalLibraries; } + @NonNull + @Override + public String[] getUsesOptionalLibrariesSorted() { + if (mUsesOptionalLibrariesSorted == null) { + mUsesOptionalLibrariesSorted = sortLibraries(usesOptionalLibraries); + } + return mUsesOptionalLibrariesSorted; + } + @NonNull @Override public List getUsesOptionalNativeLibraries() { @@ -1405,6 +1437,15 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, @Override public List getUsesSdkLibraries() { return usesSdkLibraries; } + @NonNull + @Override + public String[] getUsesSdkLibrariesSorted() { + if (mUsesSdkLibrariesSorted == null) { + mUsesSdkLibrariesSorted = sortLibraries(usesSdkLibraries); + } + return mUsesSdkLibrariesSorted; + } + @Nullable @Override public String[][] getUsesSdkLibrariesCertDigests() { return usesSdkLibrariesCertDigests; } @@ -1419,6 +1460,15 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return usesStaticLibraries; } + @NonNull + @Override + public String[] getUsesStaticLibrariesSorted() { + if (mUsesStaticLibrariesSorted == null) { + mUsesStaticLibrariesSorted = sortLibraries(usesStaticLibraries); + } + return mUsesStaticLibrariesSorted; + } + @Nullable @Override public String[][] getUsesStaticLibrariesCertDigests() { @@ -2650,6 +2700,16 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return this; } + private static String[] sortLibraries(List libraryNames) { + int size = libraryNames.size(); + if (size == 0) { + return EmptyArray.STRING; + } + var arr = libraryNames.toArray(EmptyArray.STRING); + Arrays.sort(arr); + return arr; + } + private void assignDerivedFields2() { mBaseAppInfoFlags = PackageInfoUtils.appInfoFlags(this, null); mBaseAppInfoPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null); 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 1619856e005ab..f0e3f3f508a5c 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 @@ -89,6 +89,10 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag "sortReceivers", "sortServices", "setAllComponentsDirectBootAware", + "getUsesLibrariesSorted", + "getUsesOptionalLibrariesSorted", + "getUsesSdkLibrariesSorted", + "getUsesStaticLibrariesSorted", // Tested through setting minor/major manually "setLongVersionCode", "getLongVersionCode",