diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/AppsFilter.java | 47 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java | 117 |
2 files changed, 164 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 1acbabda9e19..ca8202f5f94b 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -105,6 +105,12 @@ public class AppsFilter implements Watchable, Snappable { private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>(); /** + * A mapping from the set of App IDs that query other App IDs via library name to the + * list of packages that they can see. + */ + private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>(); + + /** * Executor for running reasonably short background tasks such as building the initial * visibility cache. */ @@ -239,6 +245,7 @@ public class AppsFilter implements Watchable, Snappable { Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable); Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage); Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent); + Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary); mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute; mForceQueryable.addAll(orig.mForceQueryable); mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames; @@ -508,6 +515,22 @@ public class AppsFilter implements Watchable, Snappable { return false; } + private static boolean canQueryViaUsesLibrary(AndroidPackage querying, + AndroidPackage potentialTarget) { + if (potentialTarget.getLibraryNames().isEmpty()) { + return false; + } + final List<String> libNames = potentialTarget.getLibraryNames(); + for (int i = 0, size = libNames.size(); i < size; i++) { + final String libName = libNames.get(i); + if (querying.getUsesLibraries().contains(libName) + || querying.getUsesOptionalLibraries().contains(libName)) { + return true; + } + } + return false; + } + private static boolean matchesProviders( Set<String> queriesAuthorities, AndroidPackage potentialTarget) { for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) { @@ -707,6 +730,9 @@ public class AppsFilter implements Watchable, Snappable { || canQueryAsInstaller(existingSetting, newPkg)) { mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); } + if (canQueryViaUsesLibrary(existingPkg, newPkg)) { + mQueryableViaUsesLibrary.add(existingSetting.appId, newPkgSetting.appId); + } } // now we'll evaluate our new package's ability to see existing packages if (!mForceQueryable.contains(existingSetting.appId)) { @@ -718,6 +744,9 @@ public class AppsFilter implements Watchable, Snappable { || canQueryAsInstaller(newPkgSetting, existingPkg)) { mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); } + if (canQueryViaUsesLibrary(newPkg, existingPkg)) { + mQueryableViaUsesLibrary.add(newPkgSetting.appId, existingSetting.appId); + } } // if either package instruments the other, mark both as visible to one another if (newPkgSetting.pkg != null && existingSetting.pkg != null @@ -1035,6 +1064,10 @@ public class AppsFilter implements Watchable, Snappable { for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); } + mQueryableViaUsesLibrary.remove(setting.appId); + for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) { + mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i), setting.appId); + } mForceQueryable.remove(setting.appId); @@ -1315,6 +1348,18 @@ public class AppsFilter implements Watchable, Snappable { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary"); + if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "queryable for library users"); + } + return false; + } + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -1394,6 +1439,8 @@ public class AppsFilter implements Watchable, Snappable { filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId), mImplicitlyQueryable, " ", expandPackages); } + pw.println(" queryable via uses-library:"); + dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages); } private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId, diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 9a52643b57f2..9f428c7cbded 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -31,6 +31,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; +import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.content.pm.parsing.ParsingPackage; @@ -141,6 +142,10 @@ public class AppsFilterTest { return pkg(packageName).addReceiver(receiver); } + private static ParsingPackage pkgWithSharedLibrary(String packageName, String libName) { + return pkg(packageName).addLibraryName(libName); + } + private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) { ParsedActivity activity = new ParsedActivity(); activity.setPackageName(packageName); @@ -413,6 +418,118 @@ public class AppsFilterTest { } @Test + public void testNoUsesLibrary_Filters() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package"), DUMMY_CALLING_APPID); + + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesLibrary_DoesntFilter() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesLibrary("com.some.shared_library"), + DUMMY_CALLING_APPID); + + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesOptionalLibrary_DoesntFilter() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesOptionalLibrary("com.some.shared_library"), + DUMMY_CALLING_APPID); + + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception { + final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, + new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, + mMockExecutor); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(); + + final Signature mockSignature = Mockito.mock(Signature.class); + final SigningDetails mockSigningDetails = new SigningDetails( + new Signature[]{mockSignature}, + SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithSharedLibrary("com.some.package", "com.some.shared_library"), + DUMMY_TARGET_APPID, + setting -> setting.setSigningDetails(mockSigningDetails) + .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package_a").setSharedUserId("com.some.uid"), + DUMMY_CALLING_APPID); + simulateAddPackage(appsFilter, pkg("com.some.other.package_b") + .setSharedUserId("com.some.uid").addUsesLibrary("com.some.shared_library"), + DUMMY_CALLING_APPID); + + // Although package_a doesn't use library, it should be granted visibility. It's because + // package_a shares userId with package_b, and package_b uses that shared library. + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test public void testForceQueryable_SystemDoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, |