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

Commit 2bd31dbd authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Install non-EA providers once user is unlocked.

When starting encryption-aware apps while the device is locked, we
can only spin up ContentProviders that have been marked as
encryption-aware.  Once the user is unlocked, we need to go back and
install non-encryption-aware providers in already running apps.

Fix bugs in getPackageInfo() where only one of the various MATCH_
flags was being consulted (!).  Move matching logic to single unified
location in PackageUserState so we have consistent behavior.

Fix another class of bugs where Safe Mode wasn't correctly filtering
package details (!).  These bugs are fixed by splicing in the new
MATCH_SYSTEM_ONLY flag as part of state-based flag mutation that was
added for encryption.

Bug: 25944787
Change-Id: I39c8da74b1f9ba944cc817176983f50ba322329c
parent 3ea44a52
Loading
Loading
Loading
Loading
+36 −68
Original line number Diff line number Diff line
@@ -464,91 +464,59 @@ public class PackageParser {
            }
        }
        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
            int N = p.activities.size();
            final int N = p.activities.size();
            if (N > 0) {
                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                    pi.activities = new ActivityInfo[N];
                } else {
                int num = 0;
                final ActivityInfo[] res = new ActivityInfo[N];
                for (int i = 0; i < N; i++) {
                        if (p.activities.get(i).info.enabled) num++;
                    }
                    pi.activities = new ActivityInfo[num];
                }
                for (int i=0, j=0; i<N; i++) {
                    final Activity activity = p.activities.get(i);
                    if (activity.info.enabled
                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                        pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
                                state, userId);
                    final Activity a = p.activities.get(i);
                    if (state.isMatch(a.info, flags)) {
                        res[num++] = generateActivityInfo(a, flags, state, userId);
                    }
                }
                pi.activities = ArrayUtils.trimToSize(res, num);
            }
        }
        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
            int N = p.receivers.size();
            final int N = p.receivers.size();
            if (N > 0) {
                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                    pi.receivers = new ActivityInfo[N];
                } else {
                int num = 0;
                final ActivityInfo[] res = new ActivityInfo[N];
                for (int i = 0; i < N; i++) {
                        if (p.receivers.get(i).info.enabled) num++;
                    }
                    pi.receivers = new ActivityInfo[num];
                }
                for (int i=0, j=0; i<N; i++) {
                    final Activity activity = p.receivers.get(i);
                    if (activity.info.enabled
                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags,
                                state, userId);
                    final Activity a = p.receivers.get(i);
                    if (state.isMatch(a.info, flags)) {
                        res[num++] = generateActivityInfo(a, flags, state, userId);
                    }
                }
                pi.receivers = ArrayUtils.trimToSize(res, num);
            }
        }
        if ((flags & PackageManager.GET_SERVICES) != 0) {
            int N = p.services.size();
            final int N = p.services.size();
            if (N > 0) {
                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                    pi.services = new ServiceInfo[N];
                } else {
                int num = 0;
                final ServiceInfo[] res = new ServiceInfo[N];
                for (int i = 0; i < N; i++) {
                        if (p.services.get(i).info.enabled) num++;
                    }
                    pi.services = new ServiceInfo[num];
                }
                for (int i=0, j=0; i<N; i++) {
                    final Service service = p.services.get(i);
                    if (service.info.enabled
                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags,
                                state, userId);
                    final Service s = p.services.get(i);
                    if (state.isMatch(s.info, flags)) {
                        res[num++] = generateServiceInfo(s, flags, state, userId);
                    }
                }
                pi.services = ArrayUtils.trimToSize(res, num);
            }
        }
        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
            int N = p.providers.size();
            final int N = p.providers.size();
            if (N > 0) {
                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                    pi.providers = new ProviderInfo[N];
                } else {
                int num = 0;
                final ProviderInfo[] res = new ProviderInfo[N];
                for (int i = 0; i < N; i++) {
                        if (p.providers.get(i).info.enabled) num++;
                    }
                    pi.providers = new ProviderInfo[num];
                }
                for (int i=0, j=0; i<N; i++) {
                    final Provider provider = p.providers.get(i);
                    if (provider.info.enabled
                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags,
                                state, userId);
                    final Provider pr = p.providers.get(i);
                    if (state.isMatch(pr.info, flags)) {
                        res[num++] = generateProviderInfo(pr, flags, state, userId);
                    }
                }
                pi.providers = ArrayUtils.trimToSize(res, num);
            }
        }
        if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
+80 −4
Original line number Diff line number Diff line
@@ -17,9 +17,20 @@
package android.content.pm;

import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;

import android.util.ArraySet;

import com.android.internal.util.ArrayUtils;

/**
 * Per-user state information about a package.
 * @hide
@@ -58,12 +69,77 @@ public class PackageUserState {
        hidden = o.hidden;
        suspended = o.suspended;
        lastDisableAppCaller = o.lastDisableAppCaller;
        disabledComponents = o.disabledComponents != null
                ? new ArraySet<>(o.disabledComponents) : null;
        enabledComponents = o.enabledComponents != null
                ? new ArraySet<>(o.enabledComponents) : null;
        disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
        enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
        blockUninstall = o.blockUninstall;
        domainVerificationStatus = o.domainVerificationStatus;
        appLinkGeneration = o.appLinkGeneration;
    }

    /**
     * Test if this package is installed.
     */
    public boolean isInstalled(int flags) {
        return (this.installed && !this.hidden)
                || (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
    }

    /**
     * Test if the given component is considered installed, enabled and a match
     * for the given flags.
     */
    public boolean isMatch(ComponentInfo componentInfo, int flags) {
        if (!isInstalled(flags)) return false;
        if (!isEnabled(componentInfo, flags)) return false;

        if ((flags & MATCH_SYSTEM_ONLY) != 0) {
            if (!componentInfo.applicationInfo.isSystemApp()) {
                return false;
            }
        }

        final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
                && !componentInfo.encryptionAware;
        final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
                && componentInfo.encryptionAware;
        return matchesUnaware || matchesAware;
    }

    /**
     * Test if the given component is considered enabled.
     */
    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
        if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
            return true;
        }

        // First check if the overall package is disabled; if the package is
        // enabled then fall through to check specific component
        switch (this.enabled) {
            case COMPONENT_ENABLED_STATE_DISABLED:
            case COMPONENT_ENABLED_STATE_DISABLED_USER:
                return false;
            case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
                if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
                    return false;
                }
            case COMPONENT_ENABLED_STATE_DEFAULT:
                if (!componentInfo.applicationInfo.enabled) {
                    return false;
                }
            case COMPONENT_ENABLED_STATE_ENABLED:
                break;
        }

        // Check if component has explicit state before falling through to
        // the manifest default
        if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) {
            return true;
        }
        if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) {
            return false;
        }

        return componentInfo.enabled;
    }
}
+15 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import libcore.util.EmptyArray;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;

/**
@@ -372,6 +373,10 @@ public class ArrayUtils {
        return (array != null) ? array.clone() : null;
    }

    public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {
        return (array != null) ? new ArraySet<T>(array) : null;
    }

    public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
        if (cur == null) {
            cur = new ArraySet<>();
@@ -420,6 +425,16 @@ public class ArrayUtils {
        return (cur != null) ? cur.contains(val) : false;
    }

    public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) {
        if (array == null || size == 0) {
            return null;
        } else if (array.length == size) {
            return array;
        } else {
            return Arrays.copyOf(array, size);
        }
    }

    /**
     * Returns true if the two ArrayLists are equal with respect to the objects they contain.
     * The objects must be in the same order and be reference equal (== not .equals()).
+41 −2
Original line number Diff line number Diff line
@@ -255,7 +255,9 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.GET_PROVIDERS;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -1954,8 +1956,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                break;
            }
            case SYSTEM_USER_UNLOCK_MSG: {
                mSystemServiceManager.unlockUser(msg.arg1);
                mRecentTasks.cleanupLocked(msg.arg1);
                final int userId = msg.arg1;
                mSystemServiceManager.unlockUser(userId);
                mRecentTasks.cleanupLocked(userId);
                installEncryptionUnawareProviders(userId);
                break;
            }
            case SYSTEM_USER_CURRENT_MSG: {
@@ -10825,6 +10829,41 @@ public final class ActivityManagerService extends ActivityManagerNative
        //mUsageStatsService.monitorPackages();
    }
    /**
     * When a user is unlocked, we need to install encryption-unaware providers
     * belonging to any running apps.
     */
    private void installEncryptionUnawareProviders(int userId) {
        synchronized (this) {
            final int NP = mProcessNames.getMap().size();
            for (int ip = 0; ip < NP; ip++) {
                final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
                final int NA = apps.size();
                for (int ia = 0; ia < NA; ia++) {
                    final ProcessRecord app = apps.valueAt(ia);
                    if (app.userId != userId || app.thread == null) continue;
                    final int NG = app.pkgList.size();
                    for (int ig = 0; ig < NG; ig++) {
                        try {
                            final String pkgName = app.pkgList.keyAt(ig);
                            final PackageInfo pkgInfo = AppGlobals.getPackageManager()
                                    .getPackageInfo(pkgName,
                                            GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE, userId);
                            if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
                                for (ProviderInfo provInfo : pkgInfo.providers) {
                                    Log.v(TAG, "Installing " + provInfo);
                                    app.thread.scheduleInstallProvider(provInfo);
                                }
                            }
                        } catch (RemoteException ignored) {
                        }
                    }
                }
            }
        }
    }
    /**
     * Allows apps to retrieve the MIME type of a URI.
     * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
+10 −20
Original line number Diff line number Diff line
@@ -3119,7 +3119,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    /**
     * Update given flags based on encryption status of current user.
     */
    private int updateFlagsForEncryption(int flags, int userId) {
    private int updateFlags(int flags, int userId) {
        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
                | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) {
            // Caller expressed an explicit opinion about what encryption
@@ -3133,6 +3133,12 @@ public class PackageManagerService extends IPackageManager.Stub {
                flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
            }
        }
        // Safe mode means we should ignore any third-party apps
        if (mSafeMode) {
            flags |= PackageManager.MATCH_SYSTEM_ONLY;
        }
        return flags;
    }
@@ -3160,7 +3166,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
                    + " with flags 0x" + Integer.toHexString(flags), new Throwable());
        }
        return updateFlagsForEncryption(flags, userId);
        return updateFlags(flags, userId);
    }
    /**
@@ -3192,7 +3198,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
                    + " with flags 0x" + Integer.toHexString(flags), new Throwable());
        }
        return updateFlagsForEncryption(flags, userId);
        return updateFlags(flags, userId);
    }
    /**
@@ -5916,8 +5922,6 @@ public class PackageManagerService extends IPackageManager.Stub {
                    : null;
            return ps != null
                    && mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)
                    && (!mSafeMode || (provider.info.applicationInfo.flags
                            &ApplicationInfo.FLAG_SYSTEM) != 0)
                    ? PackageParser.generateProviderInfo(provider, flags,
                            ps.readUserState(userId), userId)
                    : null;
@@ -5972,9 +5976,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                        && (processName == null
                                || (p.info.processName.equals(processName)
                                        && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
                        && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)
                        && (!mSafeMode
                                || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
                        && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
                    if (finalList == null) {
                        finalList = new ArrayList<ProviderInfo>(3);
                    }
@@ -9240,10 +9242,6 @@ public class PackageManagerService extends IPackageManager.Stub {
                return null;
            }
            final PackageParser.Activity activity = info.activity;
            if (mSafeMode && (activity.info.applicationInfo.flags
                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
                return null;
            }
            PackageSetting ps = (PackageSetting) activity.owner.mExtras;
            if (ps == null) {
                return null;
@@ -9464,10 +9462,6 @@ public class PackageManagerService extends IPackageManager.Stub {
                return null;
            }
            final PackageParser.Service service = info.service;
            if (mSafeMode && (service.info.applicationInfo.flags
                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
                return null;
            }
            PackageSetting ps = (PackageSetting) service.owner.mExtras;
            if (ps == null) {
                return null;
@@ -9687,10 +9681,6 @@ public class PackageManagerService extends IPackageManager.Stub {
                return null;
            }
            final PackageParser.Provider provider = info.provider;
            if (mSafeMode && (provider.info.applicationInfo.flags
                    & ApplicationInfo.FLAG_SYSTEM) == 0) {
                return null;
            }
            PackageSetting ps = (PackageSetting) provider.owner.mExtras;
            if (ps == null) {
                return null;
Loading