Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 732edc3e authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Kill uid when REQUEST_INSTALL_PACKAGES is denied

Process privileges like open fds need to be revoked, when this
permission is denied by the user.

Test: Manually verified by checking logs.
Robotest:
atest SettingsRoboTests:ExternalSourcesDetailsTest

Bug: 133504844
Change-Id: I81da0b3a5d6c54e392828829d1a2c43488439504
parent 13cbb2ee
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.applications.appinfo;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;

import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -29,6 +30,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.applications.AppInfoWithHeader;
@@ -44,6 +46,7 @@ public class ExternalSourcesDetails extends AppInfoWithHeader

    private AppStateInstallAppsBridge mAppBridge;
    private AppOpsManager mAppOpsManager;
    private ActivityManager mActivityManager;
    private UserManager mUserManager;
    private RestrictedSwitchPreference mSwitchPref;
    private InstallAppsState mInstallAppsState;
@@ -55,6 +58,7 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
        final Context context = getActivity();
        mAppBridge = new AppStateInstallAppsBridge(context, mState, null);
        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        mActivityManager = context.getSystemService(ActivityManager.class);
        mUserManager = UserManager.get(context);

        addPreferencesFromResource(R.xml.external_sources_details);
@@ -99,10 +103,21 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
                : R.string.app_permission_summary_not_allowed);
    }

    private void setCanInstallApps(boolean newState) {
    @VisibleForTesting
    void setCanInstallApps(boolean newState) {
        mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
                mPackageInfo.applicationInfo.uid, mPackageName,
                newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
        if (!newState) {
            killApp(mPackageInfo.applicationInfo.uid);
        }
    }

    private void killApp(int uid) {
        if (UserHandle.isCore(uid)) {
            return;
        }
        mActivityManager.killUid(uid, "User denied OP_REQUEST_INSTALL_PACKAGES");
    }

    @Override
+47 −0
Original line number Diff line number Diff line
@@ -19,11 +19,17 @@ package com.android.settings.applications.appinfo;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
@@ -55,6 +61,10 @@ public class ExternalSourcesDetailsTest {
    @Mock
    private UserManager mUserManager;
    @Mock
    private ActivityManager mActivityManager;
    @Mock
    private AppOpsManager mAppOpsManager;
    @Mock
    private RestrictedSwitchPreference mSwitchPref;
    @Mock
    private RestrictedPreferenceHelper mHelper;
@@ -69,9 +79,46 @@ public class ExternalSourcesDetailsTest {

        mFragment = new ExternalSourcesDetails();
        ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
        ReflectionHelpers.setField(mFragment, "mActivityManager", mActivityManager);
        ReflectionHelpers.setField(mFragment, "mAppOpsManager", mAppOpsManager);
        ReflectionHelpers.setField(mFragment, "mSwitchPref", mSwitchPref);
    }

    @Test
    public void setCanInstallApps_false_shouldKillNonCoreUid() {
        int mockUid = 23456;
        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);

        mPackageInfo.applicationInfo = new ApplicationInfo();
        mPackageInfo.applicationInfo.uid = mockUid;
        assertThat(UserHandle.isCore(mockUid)).isFalse();
        mFragment.setCanInstallApps(false);
        verify(mActivityManager).killUid(eq(mockUid), anyString());
    }

    @Test
    public void setCanInstallApps_false_shouldNotKillCoreUid() {
        int mockUid = 1234;
        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);

        mPackageInfo.applicationInfo = new ApplicationInfo();
        mPackageInfo.applicationInfo.uid = mockUid;
        assertThat(UserHandle.isCore(mockUid)).isTrue();
        mFragment.setCanInstallApps(false);
        verify(mActivityManager, never()).killUid(eq(mockUid), anyString());
    }

    @Test
    public void setCanInstallApps_true_shouldNotKillUid() {
        int mockUid = 23456;
        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);

        mPackageInfo.applicationInfo = new ApplicationInfo();
        mPackageInfo.applicationInfo.uid = mockUid;
        mFragment.setCanInstallApps(true);
        verify(mActivityManager, never()).killUid(eq(mockUid), anyString());
    }

    @Test
    public void refreshUi_noPackageInfo_shouldReturnFalseAndNoCrash() {
        mFragment.refreshUi();