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
This commit is contained in:
Zoran Jovanovic
2019-02-17 22:54:47 +01:00
committed by Todd Kennedy
parent 44b84de84c
commit c6d79cd0da
3 changed files with 95 additions and 2 deletions

View File

@@ -25,6 +25,8 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.om.OverlayManager;
import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -103,6 +105,7 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
private final int mRequestRemoveDeviceAdmin; private final int mRequestRemoveDeviceAdmin;
private final DevicePolicyManager mDpm; private final DevicePolicyManager mDpm;
private final UserManager mUserManager; private final UserManager mUserManager;
private final OverlayManager mOverlayManager;
private final PackageManager mPm; private final PackageManager mPm;
private final SettingsActivity mActivity; private final SettingsActivity mActivity;
private final InstrumentedPreferenceFragment mFragment; private final InstrumentedPreferenceFragment mFragment;
@@ -136,6 +139,7 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mPm = activity.getPackageManager(); mPm = activity.getPackageManager();
mOverlayManager = activity.getSystemService(OverlayManager.class);
mPackageName = packageName; mPackageName = packageName;
mActivity = activity; mActivity = activity;
mFragment = fragment; mFragment = fragment;
@@ -435,6 +439,28 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
enabled = false; 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); mButtonsPref.setButton2Enabled(enabled);
} }

View File

@@ -640,10 +640,18 @@ public class AppInfoDashboardFragment extends DashboardFragment
final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() { final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (mFinishing) {
return;
}
final String packageName = intent.getData().getSchemeSpecificPart(); final String packageName = intent.getData().getSchemeSpecificPart();
if (!mFinishing && (mAppEntry == null || mAppEntry.info == null if (mAppEntry == null
|| TextUtils.equals(mAppEntry.info.packageName, packageName))) { || mAppEntry.info == null
|| TextUtils.equals(mAppEntry.info.packageName, packageName)) {
onPackageRemoved(); onPackageRemoved();
} else if (mAppEntry.info.isResourceOverlay()
&& TextUtils.equals(mPackageInfo.overlayTarget, packageName)) {
refreshUi();
} }
} }
}; };

View File

@@ -39,9 +39,12 @@ import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.om.OverlayManager;
import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.UserManager; import android.os.UserManager;
import android.view.View; import android.view.View;
@@ -70,11 +73,15 @@ import org.robolectric.util.ReflectionHelpers;
public class AppButtonsPreferenceControllerTest { public class AppButtonsPreferenceControllerTest {
private static final String PACKAGE_NAME = "com.android.settings"; 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 String RESOURCE_STRING = "string";
private static final boolean ALL_USERS = false; private static final boolean ALL_USERS = false;
private static final boolean DISABLE_AFTER_INSTALL = true; private static final boolean DISABLE_AFTER_INSTALL = true;
private static final int REQUEST_UNINSTALL = 0; private static final int REQUEST_UNINSTALL = 0;
private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1; 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) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private SettingsActivity mSettingsActivity; private SettingsActivity mSettingsActivity;
@Mock @Mock
@@ -88,6 +95,8 @@ public class AppButtonsPreferenceControllerTest {
@Mock @Mock
private ApplicationInfo mAppInfo; private ApplicationInfo mAppInfo;
@Mock @Mock
private OverlayManager mOverlayManager;
@Mock
private PackageManager mPackageManger; private PackageManager mPackageManger;
@Mock @Mock
private DevicePolicyManager mDpm; private DevicePolicyManager mDpm;
@@ -113,6 +122,8 @@ public class AppButtonsPreferenceControllerTest {
doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE); doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE);
doReturn(mPackageManger).when(mSettingsActivity).getPackageManager(); doReturn(mPackageManger).when(mSettingsActivity).getPackageManager();
doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE); doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE);
doReturn(mOverlayManager).when(mSettingsActivity).
getSystemService(OverlayManager.class);
doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt()); doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt());
when(mSettingsActivity.getApplication()).thenReturn(mApplication); when(mSettingsActivity.getApplication()).thenReturn(mApplication);
when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING); when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING);
@@ -276,6 +287,41 @@ public class AppButtonsPreferenceControllerTest {
verify(mButtonPrefs).setButton2Enabled(false); 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 @Test
public void updateForceStopButton_HasActiveAdmins_setButtonDisable() { public void updateForceStopButton_HasActiveAdmins_setButtonDisable() {
doReturn(true).when(mDpm).packageHasActiveAdmins(anyString()); doReturn(true).when(mDpm).packageHasActiveAdmins(anyString());
@@ -418,4 +464,17 @@ public class AppButtonsPreferenceControllerTest {
return pref; 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 */);
}
} }