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

Commit 9eec7522 authored by Paul Hu's avatar Paul Hu Committed by Automerger Merge Worker
Browse files

Merge "Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting from PermissionMonitor" am: 59dc4f0a

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1689572

Change-Id: I5515f041b783e36ca439e2b7b1d77e93ee329be0
parents 1fb74740 59dc4f0a
Loading
Loading
Loading
Loading
+41 −16
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivitySettingsManager;
import android.net.INetd;
import android.net.UidRange;
import android.net.Uri;
@@ -49,6 +50,7 @@ import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.system.OsConstants;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -105,6 +107,14 @@ public class PermissionMonitor {
    @GuardedBy("this")
    private final Set<Integer> mAllApps = new HashSet<>();

    // A set of apps which are allowed to use restricted networks. These apps can't hold the
    // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be signature|privileged
    // apps. However, these apps should still be able to use restricted networks under certain
    // conditions (e.g. government app using emergency services). So grant netd system permission
    // to uids whose package name is listed in APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting.
    @GuardedBy("this")
    private final Set<String> mAppsAllowedOnRestrictedNetworks = new ArraySet<>();

    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -165,6 +175,11 @@ public class PermissionMonitor {
                mIntentReceiver, intentFilter, null /* broadcastPermission */,
                null /* scheduler */);

        // Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
        // mAppsAllowedOnRestrictedNetworks.
        updateAppsAllowedOnRestrictedNetworks(
                ConnectivitySettingsManager.getAppsAllowedOnRestrictedNetworks(mContext));

        List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
                | MATCH_ANY_USER);
        if (apps == null) {
@@ -219,11 +234,33 @@ public class PermissionMonitor {
        sendPackagePermissionsToNetd(netdPermsUids);
    }

    @VisibleForTesting
    void updateAppsAllowedOnRestrictedNetworks(final Set<String> apps) {
        mAppsAllowedOnRestrictedNetworks.clear();
        mAppsAllowedOnRestrictedNetworks.addAll(apps);
    }

    @VisibleForTesting
    static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
        return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
    }

    @VisibleForTesting
    boolean isCarryoverPackage(final ApplicationInfo appInfo) {
        if (appInfo == null) return false;
        return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
                // Backward compatibility for b/114245686, on devices that launched before Q daemons
                // and apps running as the system UID are exempted from this check.
                || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
    }

    @VisibleForTesting
    boolean isAppAllowedOnRestrictedNetworks(@NonNull final PackageInfo app) {
        // Check whether package name is in allowed on restricted networks app list. If so, this app
        // can have netd system permission.
        return mAppsAllowedOnRestrictedNetworks.contains(app.packageName);
    }

    @VisibleForTesting
    boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
        if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
@@ -241,22 +278,10 @@ public class PermissionMonitor {

    @VisibleForTesting
    boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
        // TODO : remove this check in the future(b/31479477). All apps should just
        // TODO : remove carryover package check in the future(b/31479477). All apps should just
        //  request the appropriate permission for their use case since android Q.
        if (app.applicationInfo != null) {
            // Backward compatibility for b/114245686, on devices that launched before Q daemons
            // and apps running as the system UID are exempted from this check.
            if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
                return true;
            }

            if (app.applicationInfo.targetSdkVersion < VERSION_Q
                    && isVendorApp(app.applicationInfo)) {
                return true;
            }
        }

        return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
        return isCarryoverPackage(app.applicationInfo) || isAppAllowedOnRestrictedNetworks(app)
                || hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
                || hasPermission(app, NETWORK_STACK)
                || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
    }
+111 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;

import static com.android.server.connectivity.PermissionMonitor.NETWORK;
@@ -68,12 +69,18 @@ import android.os.Build;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.util.ArraySet;
import android.util.SparseIntArray;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.util.test.FakeSettingsProvider;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -120,6 +127,7 @@ public class PermissionMonitorTest {
    @Mock private SystemConfigManager mSystemConfigManager;

    private PermissionMonitor mPermissionMonitor;
    private MockContentResolver mContentResolver;

    @Before
    public void setUp() throws Exception {
@@ -137,16 +145,33 @@ public class PermissionMonitorTest {
        doReturn(UserHandle.ALL).when(asUserCtx).getUser();
        when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);

        FakeSettingsProvider.clearSettingsProvider();
        mContentResolver = new MockContentResolver();
        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        when(mContext.getContentResolver()).thenReturn(mContentResolver);

        mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));

        when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
        mPermissionMonitor.startMonitoring();
    }

    @After
    public void tearDown() throws Exception {
        FakeSettingsProvider.clearSettingsProvider();
    }

    private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
            String... permissions) {
        return hasRestrictedNetworkPermission(
                partition, targetSdkVersion, "" /* packageName */, uid, permissions);
    }

    private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion,
            String packageName, int uid, String... permissions) {
        final PackageInfo packageInfo =
                packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
        packageInfo.packageName = packageName;
        packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
        packageInfo.applicationInfo.uid = uid;
        return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
@@ -280,6 +305,8 @@ public class PermissionMonitorTest {
                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
        assertFalse(hasRestrictedNetworkPermission(
                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
        assertTrue(hasRestrictedNetworkPermission(
                PARTITION_SYSTEM, VERSION_P, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK));

        assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
        assertFalse(hasRestrictedNetworkPermission(
@@ -324,6 +351,90 @@ public class PermissionMonitorTest {
                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
    }

    @Test
    public void testHasRestrictedNetworkPermissionAppAllowedOnRestrictedNetworks() {
        mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
                new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
        assertTrue(hasRestrictedNetworkPermission(
                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
        assertTrue(hasRestrictedNetworkPermission(
                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
        assertTrue(hasRestrictedNetworkPermission(
                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));

        assertFalse(hasRestrictedNetworkPermission(
                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1));
        assertFalse(hasRestrictedNetworkPermission(
                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE));
        assertFalse(hasRestrictedNetworkPermission(
                PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CONNECTIVITY_INTERNAL));

    }

    private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
        final PackageInfo packageInfo = packageInfoWithPermissions(
                REQUESTED_PERMISSION_GRANTED, new String[] {}, partition);
        packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
        packageInfo.applicationInfo.uid = uid;
        return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
    }

    @Test
    public void testIsCarryoverPackage() {
        doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
        assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
        assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
        assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));

        doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
        assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
        assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));

        assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
        assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
        assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
    }

    private boolean wouldBeAppAllowedOnRestrictedNetworks(String packageName) {
        final PackageInfo packageInfo = new PackageInfo();
        packageInfo.packageName = packageName;
        return mPermissionMonitor.isAppAllowedOnRestrictedNetworks(packageInfo);
    }

    @Test
    public void testIsAppAllowedOnRestrictedNetworks() {
        mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(new ArraySet<>());
        assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
        assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));

        mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
                new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
        assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
        assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));

        mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
                new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
        assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
        assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));

        mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
                new ArraySet<>(new String[] { "com.android.test" }));
        assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
        assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
    }

    private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
            String... permissions) throws Exception {
        when(mPackageManager.getPackageInfo(eq(name), anyInt()))