diff options
| author | 2020-03-23 17:00:51 +0000 | |
|---|---|---|
| committer | 2020-03-24 12:28:07 +0000 | |
| commit | 97bb33b93c6fe7eda2029be0496f451b40f2adc0 (patch) | |
| tree | 5528838a911dddea7b8b67376544428663cf00cb | |
| parent | 5562d464c6cab06544294bbc823df89d30579bbf (diff) | |
Suspend newly installed apps when personal apps are suspended
Also make use of PackageManager.getUnsuspendablePackages() which
already takes care of launcher and dialer packages and some
other critical apps, like package verifier, package
[un-]installer, etc.
For newly installed packages it PackageManager.getUnsuspendableApps()
seems to be sufficient since that app won't be critical for the
functioning of the device.
Test: Test: atest
OrgOwnedProfileOwnerTest#testPersonalAppsSuspensionInstalledApp
Bug: 149394138
Change-Id: Ic3196dbfdd5c506e708563d305a42494391dc878
4 files changed, 73 insertions, 67 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 51cfa31ae4cf..c4458b30c2db 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2429,7 +2429,7 @@ public class DevicePolicyManager { PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT }) @Retention(RetentionPolicy.SOURCE) - public @interface PersonalAppSuspensionReason {} + public @interface PersonalAppsSuspensionReason {} /** * Return true if the given administrator component is currently active (enabled) in the system. @@ -11961,7 +11961,7 @@ public class DevicePolicyManager { * {@link #PERSONAL_APPS_NOT_SUSPENDED} if apps are not suspended. * @see #setPersonalAppsSuspended */ - public @PersonalAppSuspensionReason int getPersonalAppsSuspendedReasons( + public @PersonalAppsSuspensionReason int getPersonalAppsSuspendedReasons( @NonNull ComponentName admin) { throwIfParentInstance("getPersonalAppsSuspendedReasons"); if (mService != null) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 9f151cf073bd..370469ebe840 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -7088,7 +7088,7 @@ public abstract class PackageManager { * Returns any packages in a given set of packages that cannot be suspended via a call to {@link * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, * SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical - * packages to keep the device in a functioning state, e.g. the default dialer. + * packages to keep the device in a functioning state, e.g. the default dialer and launcher. * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this API. * * <p> @@ -7106,7 +7106,7 @@ public abstract class PackageManager { @RequiresPermission(Manifest.permission.SUSPEND_APPS) @NonNull public String[] getUnsuspendablePackages(@NonNull String[] packageNames) { - throw new UnsupportedOperationException("canSuspendPackages not implemented"); + throw new UnsupportedOperationException("getUnsuspendablePackages not implemented"); } /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 740c5cb3e75a..023a1e8ede9f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -136,7 +136,7 @@ import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager.PasswordComplexity; -import android.app.admin.DevicePolicyManager.PersonalAppSuspensionReason; +import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DeviceStateCache; import android.app.admin.FactoryResetProtectionPolicy; @@ -935,10 +935,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { handlePackagesChanged(null /* check all admins */, userHandle); - } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action) - || (Intent.ACTION_PACKAGE_ADDED.equals(action) - && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) { + } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle); + } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle); + } else { + handleNewPackageInstalled(intent.getData().getSchemeSpecificPart(), userHandle); + } } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle); @@ -2028,6 +2032,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } + private void handleNewPackageInstalled(String packageName, int userHandle) { + // If personal apps were suspended by the admin, suspend the newly installed one. + if (!getUserData(userHandle).mAppsSuspended) { + return; + } + final String[] packagesToSuspend = { packageName }; + // Check if package is considered not suspendable? + if (mInjector.getPackageManager(userHandle) + .getUnsuspendablePackages(packagesToSuspend).length != 0) { + Slog.i(LOG_TAG, "Newly installed package is unsuspendable: " + packageName); + return; + } + try { + mIPackageManager.setPackagesSuspendedAsUser(packagesToSuspend, true /*suspend*/, + null, null, null, PLATFORM_PACKAGE_NAME, userHandle); + } catch (RemoteException ignored) { + // shouldn't happen. + } + } + /** * Unit test will subclass it to inject mocks. */ @@ -2110,6 +2134,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return mContext.getPackageManager(); } + PackageManager getPackageManager(int userId) { + return mContext + .createContextAsUser(UserHandle.of(userId), 0 /* flags */).getPackageManager(); + } + PowerManagerInternal getPowerManagerInternal() { return LocalServices.getService(PowerManagerInternal.class); } @@ -15650,7 +15679,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public @PersonalAppSuspensionReason int getPersonalAppsSuspendedReasons(ComponentName who) { + public @PersonalAppsSuspensionReason int getPersonalAppsSuspendedReasons(ComponentName who) { synchronized (getLockObject()) { final ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, @@ -15669,7 +15698,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private @PersonalAppSuspensionReason int makeSuspensionReasons( + private @PersonalAppsSuspensionReason int makeSuspensionReasons( boolean explicit, boolean timeout) { int result = PERSONAL_APPS_NOT_SUSPENDED; if (explicit) { @@ -15793,7 +15822,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void applyPersonalAppsSuspension( - int profileUserId, @PersonalAppSuspensionReason int suspensionState) { + int profileUserId, @PersonalAppsSuspensionReason int suspensionState) { final boolean suspended = getUserData(UserHandle.USER_SYSTEM).mAppsSuspended; final boolean shouldSuspend = suspensionState != PERSONAL_APPS_NOT_SUSPENDED; if (suspended != shouldSuspend) { @@ -15813,8 +15842,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mInjector.binderWithCleanCallingIdentity(() -> { try { final String[] appsToSuspend = - new PersonalAppsSuspensionHelper(mContext, mInjector.getPackageManager()) - .getPersonalAppsForSuspension(userId); + new PersonalAppsSuspensionHelper( + mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */)) + .getPersonalAppsForSuspension(); final String[] failedPackages = mIPackageManager.setPackagesSuspendedAsUser( appsToSuspend, suspended, null, null, null, PLATFORM_PACKAGE_NAME, userId); if (!ArrayUtils.isEmpty(failedPackages)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java index 180acc85e5f6..d9db17eba887 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java @@ -20,7 +20,6 @@ import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -32,7 +31,7 @@ import android.os.IBinder; import android.os.ServiceManager; import android.provider.Settings; import android.text.TextUtils; -import android.util.Log; +import android.util.ArraySet; import android.util.Slog; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; @@ -43,7 +42,6 @@ import com.android.server.inputmethod.InputMethodManagerInternal; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -56,18 +54,21 @@ public class PersonalAppsSuspensionHelper { private final Context mContext; private final PackageManager mPackageManager; - public PersonalAppsSuspensionHelper(Context context, PackageManager packageManager) { + /** + * @param context Context for the user whose apps should to be suspended. + */ + public PersonalAppsSuspensionHelper(Context context) { mContext = context; - mPackageManager = packageManager; + mPackageManager = context.getPackageManager(); } /** * @return List of packages that should be suspended to limit personal use. */ - String[] getPersonalAppsForSuspension(@UserIdInt int userId) { + String[] getPersonalAppsForSuspension() { final List<PackageInfo> installedPackageInfos = - mPackageManager.getInstalledPackagesAsUser(0 /* flags */, userId); - final Set<String> result = new HashSet<>(); + mPackageManager.getInstalledPackages(0 /* flags */); + final Set<String> result = new ArraySet<>(); for (final PackageInfo packageInfo : installedPackageInfos) { final ApplicationInfo info = packageInfo.applicationInfo; if ((!info.isSystemApp() && !info.isUpdatedSystemApp()) @@ -77,11 +78,15 @@ public class PersonalAppsSuspensionHelper { } result.removeAll(getCriticalPackages()); result.removeAll(getSystemLauncherPackages()); - result.removeAll(getAccessibilityServices(userId)); - result.removeAll(getInputMethodPackages(userId)); - result.remove(getActiveLauncherPackages(userId)); - result.remove(getDialerPackage(userId)); - result.remove(getSettingsPackageName(userId)); + result.removeAll(getAccessibilityServices()); + result.removeAll(getInputMethodPackages()); + result.remove(getSettingsPackageName()); + + final String[] unsuspendablePackages = + mPackageManager.getUnsuspendablePackages(result.toArray(new String[0])); + for (final String pkg : unsuspendablePackages) { + result.remove(pkg); + } Slog.i(LOG_TAG, "Packages subject to suspension: " + String.join(",", result)); return result.toArray(new String[0]); @@ -104,7 +109,6 @@ public class PersonalAppsSuspensionHelper { final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName, 0); if (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp()) { - Log.d(LOG_TAG, "Not suspending system launcher package: " + packageName); result.add(packageName); } } catch (PackageManager.NameNotFoundException e) { @@ -114,81 +118,53 @@ public class PersonalAppsSuspensionHelper { return result; } - private List<String> getAccessibilityServices(int userId) { + private List<String> getAccessibilityServices() { final List<AccessibilityServiceInfo> accessibilityServiceInfos = - getAccessibilityManagerForUser(userId) + getAccessibilityManagerForUser(mContext.getUserId()) .getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK); final List<String> result = new ArrayList<>(); for (final AccessibilityServiceInfo serviceInfo : accessibilityServiceInfos) { final ComponentName componentName = ComponentName.unflattenFromString(serviceInfo.getId()); if (componentName != null) { - final String packageName = componentName.getPackageName(); - Slog.d(LOG_TAG, "Not suspending a11y service: " + packageName); - result.add(packageName); + result.add(componentName.getPackageName()); } } return result; } - private List<String> getInputMethodPackages(int userId) { - final List<InputMethodInfo> enabledImes = - InputMethodManagerInternal.get().getEnabledInputMethodListAsUser(userId); + private List<String> getInputMethodPackages() { + final List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get() + .getEnabledInputMethodListAsUser(mContext.getUserId()); final List<String> result = new ArrayList<>(); for (final InputMethodInfo info : enabledImes) { - Slog.d(LOG_TAG, "Not suspending IME: " + info.getPackageName()); result.add(info.getPackageName()); } return result; } @Nullable - private String getActiveLauncherPackages(int userId) { - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_HOME); - intent.addCategory(Intent.CATEGORY_DEFAULT); - return getPackageNameForIntent("active launcher", intent, userId); - } - - @Nullable - private String getSettingsPackageName(int userId) { + private String getSettingsPackageName() { final Intent intent = new Intent(Settings.ACTION_SETTINGS); intent.addCategory(Intent.CATEGORY_DEFAULT); - return getPackageNameForIntent("settings", intent, userId); - } - - @Nullable - private String getDialerPackage(int userId) { - final Intent intent = new Intent(Intent.ACTION_DIAL); - intent.addCategory(Intent.CATEGORY_DEFAULT); - return getPackageNameForIntent("dialer", intent, userId); - } - - @Nullable - private String getPackageNameForIntent(String name, Intent intent, int userId) { - final ResolveInfo resolveInfo = - mPackageManager.resolveActivityAsUser(intent, /* flags= */ 0, userId); + final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, /* flags= */ 0); if (resolveInfo != null) { - final String packageName = resolveInfo.activityInfo.packageName; - Slog.d(LOG_TAG, "Not suspending " + name + " package: " + packageName); - return packageName; + return resolveInfo.activityInfo.packageName; } return null; } private List<String> getCriticalPackages() { - final List<String> result = Arrays.asList(mContext.getResources() + return Arrays.asList(mContext.getResources() .getStringArray(R.array.config_packagesExemptFromSuspension)); - Slog.d(LOG_TAG, "Not suspending critical packages: " + String.join(",", result)); - return result; } private boolean hasLauncherIntent(String packageName) { final Intent intentToResolve = new Intent(Intent.ACTION_MAIN); intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER); intentToResolve.setPackage(packageName); - final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities( - intentToResolve, PackageManager.GET_UNINSTALLED_PACKAGES); + final List<ResolveInfo> resolveInfos = + mPackageManager.queryIntentActivities(intentToResolve, /* flags= */ 0); return resolveInfos != null && !resolveInfos.isEmpty(); } |