From c6d79cd0da5d06f8e1ed685f135837c73bef2011 Mon Sep 17 00:00:00 2001 From: Zoran Jovanovic Date: Sun, 17 Feb 2019 22:54:47 +0100 Subject: [PATCH] Don't allow RRO uninstall if overlay is enabled System RROs can never be uninstalled. Also, enabled RRO, i.e. RRO applied to their target packages, must not be uninstalled by end-user because that may be dangerous to the configuration of its target package. Disabled RROs, i.e. RRO not applied to their target packages, are free to be uninstalled to reclaim space. Bug: 124556507 Test: manual + `make RunSettingsRoboTests ROBOTEST_FILTER=AppButtonsPreferenceControllerTest` Change-Id: Ib6bd2765c8cb88a5887de817a08a1541eaee0cab --- .../AppButtonsPreferenceController.java | 26 ++++++++ .../appinfo/AppInfoDashboardFragment.java | 12 +++- .../AppButtonsPreferenceControllerTest.java | 59 +++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index 56d53358aa5..7339f2132b2 100644 --- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -25,6 +25,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.om.OverlayManager; +import android.content.om.OverlayInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -103,6 +105,7 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp private final int mRequestRemoveDeviceAdmin; private final DevicePolicyManager mDpm; private final UserManager mUserManager; + private final OverlayManager mOverlayManager; private final PackageManager mPm; private final SettingsActivity mActivity; private final InstrumentedPreferenceFragment mFragment; @@ -136,6 +139,7 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); mPm = activity.getPackageManager(); + mOverlayManager = activity.getSystemService(OverlayManager.class); mPackageName = packageName; mActivity = activity; mFragment = fragment; @@ -435,6 +439,28 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp enabled = false; } + // Resource overlays can be uninstalled iff they are public + // (installed on /data) and disabled. ("Enabled" means they + // are in use by resource management.) If they are + // system/vendor, they can never be uninstalled. :-( + if (mAppEntry.info.isResourceOverlay()) { + if (isBundled) { + enabled = false; + } else { + String pkgName = mAppEntry.info.packageName; + UserHandle user = UserHandle.getUserHandleForUid(mAppEntry.info.uid); + OverlayInfo overlayInfo = mOverlayManager.getOverlayInfo(pkgName, user); + if (overlayInfo != null && overlayInfo.isEnabled()) { + ApplicationsState.AppEntry targetEntry = + mState.getEntry(overlayInfo.targetPackageName, + UserHandle.getUserId(mAppEntry.info.uid)); + if (targetEntry != null) { + enabled = false; + } + } + } + } + mButtonsPref.setButton2Enabled(enabled); } diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 183d3843447..766fa50acc5 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -640,10 +640,18 @@ public class AppInfoDashboardFragment extends DashboardFragment final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + if (mFinishing) { + return; + } + final String packageName = intent.getData().getSchemeSpecificPart(); - if (!mFinishing && (mAppEntry == null || mAppEntry.info == null - || TextUtils.equals(mAppEntry.info.packageName, packageName))) { + if (mAppEntry == null + || mAppEntry.info == null + || TextUtils.equals(mAppEntry.info.packageName, packageName)) { onPackageRemoved(); + } else if (mAppEntry.info.isResourceOverlay() + && TextUtils.equals(mPackageInfo.overlayTarget, packageName)) { + refreshUi(); } } }; diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java index 6d9430ccd26..ff33d26ea21 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java @@ -39,9 +39,12 @@ import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; +import android.content.om.OverlayManager; +import android.content.om.OverlayInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.os.RemoteException; import android.os.UserManager; import android.view.View; @@ -70,11 +73,15 @@ import org.robolectric.util.ReflectionHelpers; public class AppButtonsPreferenceControllerTest { private static final String PACKAGE_NAME = "com.android.settings"; + private static final String RRO_PACKAGE_NAME = "com.android.settings.overlay"; private static final String RESOURCE_STRING = "string"; private static final boolean ALL_USERS = false; private static final boolean DISABLE_AFTER_INSTALL = true; private static final int REQUEST_UNINSTALL = 0; private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1; + private static final OverlayInfo OVERLAY_DISABLED = createFakeOverlay("overlay", false, 1); + private static final OverlayInfo OVERLAY_ENABLED = createFakeOverlay("overlay", true, 1); + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private SettingsActivity mSettingsActivity; @Mock @@ -88,6 +95,8 @@ public class AppButtonsPreferenceControllerTest { @Mock private ApplicationInfo mAppInfo; @Mock + private OverlayManager mOverlayManager; + @Mock private PackageManager mPackageManger; @Mock private DevicePolicyManager mDpm; @@ -113,6 +122,8 @@ public class AppButtonsPreferenceControllerTest { doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE); doReturn(mPackageManger).when(mSettingsActivity).getPackageManager(); doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE); + doReturn(mOverlayManager).when(mSettingsActivity). + getSystemService(OverlayManager.class); doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt()); when(mSettingsActivity.getApplication()).thenReturn(mApplication); when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING); @@ -276,6 +287,41 @@ public class AppButtonsPreferenceControllerTest { verify(mButtonPrefs).setButton2Enabled(false); } + @Test + public void updateUninstallButton_isSystemRro_setButtonDisable() { + mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + + when(mAppInfo.isResourceOverlay()).thenReturn(true); + + mController.updateUninstallButton(); + + verify(mButtonPrefs).setButton2Enabled(false); + } + + @Test + public void updateUninstallButton_isNonSystemRro_setButtonDisable() + throws RemoteException { + when(mAppInfo.isResourceOverlay()).thenReturn(true); + when(mOverlayManager.getOverlayInfo(anyString(), any())) + .thenReturn(OVERLAY_ENABLED); + + mController.updateUninstallButton(); + + verify(mButtonPrefs).setButton2Enabled(false); + } + + @Test + public void updateUninstallButton_isNonSystemRro_setButtonEnable() + throws RemoteException { + when(mAppInfo.isResourceOverlay()).thenReturn(true); + when(mOverlayManager.getOverlayInfo(anyString(), any())) + .thenReturn(OVERLAY_DISABLED); + + mController.updateUninstallButton(); + + verify(mButtonPrefs).setButton2Enabled(true); + } + @Test public void updateForceStopButton_HasActiveAdmins_setButtonDisable() { doReturn(true).when(mDpm).packageHasActiveAdmins(anyString()); @@ -418,4 +464,17 @@ public class AppButtonsPreferenceControllerTest { return pref; } + + private static OverlayInfo createFakeOverlay(String pkg, boolean enabled, int priority) { + final int state = (enabled) ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED; + return new OverlayInfo(pkg /* packageName */, + "target.package" /* targetPackageName */, + "theme" /* targetOverlayableName */, + "category", /* category */ + "package", /* baseCodePath */ + state, + 0 /* userId */, + priority, + false /* isStatic */); + } }