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) {
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
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;
+ }
}
import java.lang.reflect.Array;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
/**
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<>();
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()).
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;
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: {
}
/**
+ * 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.
/**
* 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
flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
}
}
+
+ // Safe mode means we should ignore any third-party apps
+ if (mSafeMode) {
+ flags |= PackageManager.MATCH_SYSTEM_ONLY;
+ }
+
return flags;
}
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);
}
/**
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);
}
/**
: 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;
&& (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);
}
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;
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;
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;
}
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) {