diff options
| author | 2016-01-09 16:58:14 -0700 | |
|---|---|---|
| committer | 2016-01-09 19:28:09 -0700 | |
| commit | 2bd31dbd023a11d90061c7b6831dd06454c928af (patch) | |
| tree | 3588c5aed6f3f6d70f9b5e712deeeef9ef80470c | |
| parent | 3ea44a52f00d0e359d48969663e6691a5d8bdae7 (diff) | |
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
6 files changed, 186 insertions, 150 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 134966248f94..a0df610c7428 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -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) { diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 91fdf7f71f10..38e0044ea74c 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -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; + } } diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 16bf9dd2900b..ca1334c6e6cc 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -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()). diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f21eba1460ec..d7332296a93f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 870ae892d435..0d045d13bc50 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 3f9ce7a64aae..1a79d3c3e733 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -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) { |