OSDN Git Service

Install non-EA providers once user is unlocked.
authorJeff Sharkey <jsharkey@android.com>
Sat, 9 Jan 2016 23:58:14 +0000 (16:58 -0700)
committerJeff Sharkey <jsharkey@android.com>
Sun, 10 Jan 2016 02:28:09 +0000 (19:28 -0700)
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

core/java/android/content/pm/PackageParser.java
core/java/android/content/pm/PackageUserState.java
core/java/com/android/internal/util/ArrayUtils.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/Settings.java

index 1349662..a0df610 100644 (file)
@@ -463,92 +463,60 @@ public class PackageParser {
                 p.featureGroups.toArray(pi.featureGroups);
             }
         }
-        if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
-            int N = p.activities.size();
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            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;
-                    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);
+                int num = 0;
+                final ActivityInfo[] res = new ActivityInfo[N];
+                for (int i = 0; i < N; i++) {
+                    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();
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            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;
-                    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);
+                int num = 0;
+                final ActivityInfo[] res = new ActivityInfo[N];
+                for (int i = 0; i < N; i++) {
+                    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();
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            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;
-                    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);
+                int num = 0;
+                final ServiceInfo[] res = new ServiceInfo[N];
+                for (int i = 0; i < N; i++) {
+                    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();
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            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;
-                    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);
+                int num = 0;
+                final ProviderInfo[] res = new ProviderInfo[N];
+                for (int i = 0; i < N; i++) {
+                    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) {
index 91fdf7f..38e0044 100644 (file)
 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;
+    }
 }
index 16bf9dd..ca1334c 100644 (file)
@@ -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()).
index f21eba1..d733229 100644 (file)
@@ -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: {
@@ -10826,6 +10830,41 @@ public final class ActivityManagerService extends ActivityManagerNative
     }
 
     /**
+     * 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
      * users, then it does not need permission to access the ContentProvider.
index 870ae89..0d045d1 100644 (file)
@@ -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;
index 3f9ce7a..1a79d3c 100644 (file)
@@ -3799,63 +3799,11 @@ final class Settings {
     }
 
     boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
-        return isEnabledLPr(componentInfo, flags, userId)
-                && isMatchLPr(componentInfo, flags);
-    }
-
-    private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
-        if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
-            return true;
-        }
-        final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
-        if (PackageManagerService.DEBUG_SETTINGS) {
-            Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = "
-                    + componentInfo.packageName + " componentName = " + componentInfo.name);
-            Log.v(PackageManagerService.TAG, "enabledComponents: "
-                    + compToString(packageSettings.getEnabledComponents(userId)));
-            Log.v(PackageManagerService.TAG, "disabledComponents: "
-                    + compToString(packageSettings.getDisabledComponents(userId)));
-        }
-        if (packageSettings == null) {
-            return false;
-        }
-        PackageUserState ustate = packageSettings.readUserState(userId);
-        if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) != 0) {
-            if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
-                return true;
-            }
-        }
-        if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED
-                || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
-                || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
-                || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
-                    && ustate.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
-            return false;
-        }
-        if (ustate.enabledComponents != null
-                && ustate.enabledComponents.contains(componentInfo.name)) {
-            return true;
-        }
-        if (ustate.disabledComponents != null
-                && ustate.disabledComponents.contains(componentInfo.name)) {
-            return false;
-        }
-        return componentInfo.enabled;
-    }
-
-    private boolean isMatchLPr(ComponentInfo componentInfo, int flags) {
-        if ((flags & MATCH_SYSTEM_ONLY) != 0) {
-            final PackageSetting ps = mPackages.get(componentInfo.packageName);
-            if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-                return false;
-            }
-        }
+        final PackageSetting ps = mPackages.get(componentInfo.packageName);
+        if (ps == null) 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;
+        final PackageUserState userState = ps.readUserState(userId);
+        return userState.isMatch(componentInfo, flags);
     }
 
     String getInstallerPackageNameLPr(String packageName) {