Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e757ab24 authored by Jackal Guo's avatar Jackal Guo
Browse files

Grant package visibility to dependent library

Packages should be granted visibility to packages that they list in
their <uses-library> tags.

Bug: 174856119
Test: atest AppsFilterTest
Test: manual test by using an application without permission nor tag
      <queries> and try to get the package info of the package which
      declares the library.
Change-Id: Idce9c457e238c4a34a8bdca089ce5f86b7f62177
parent b8407d69
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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,
+117 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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 =