Loading services/core/java/com/android/server/pm/AppsFilter.java +47 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,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. Loading Loading @@ -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; Loading Loading @@ -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--) { Loading Loading @@ -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)) { Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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, Loading services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +117 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -412,6 +417,118 @@ public class AppsFilterTest { SYSTEM_USER)); } @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 = Loading Loading
services/core/java/com/android/server/pm/AppsFilter.java +47 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,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. Loading Loading @@ -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; Loading Loading @@ -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--) { Loading Loading @@ -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)) { Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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, Loading
services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +117 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -412,6 +417,118 @@ public class AppsFilterTest { SYSTEM_USER)); } @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 = Loading