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

Commit 3b0f5ea2 authored by paulhu's avatar paulhu
Browse files

Support backward compatibility for restricted network permission

Some native daemons legacy design work with SYSTEM_UID. If none of
SYSTEM_UID apps declare the restricted network permission, it will
result in permission denial in daemons. Allow SYSTEM_UID in the
devices shipped before Q to support backward compatibility.

Bug:114245686
Test: 1. runtest frameworks-net
      2. atest FrameworksNetTests
      3. Native daemons with SYSTEM_UID can work normally

Change-Id: I6f3f0d83bcae74ef5389535b528af3baf649fa48
parent e3a989f7
Loading
Loading
Loading
Loading
+21 −6
Original line number Original line Diff line number Diff line
@@ -23,6 +23,8 @@ import static android.Manifest.permission.NETWORK_STACK;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
@@ -64,6 +66,7 @@ public class PermissionMonitor {
    private static final boolean DBG = true;
    private static final boolean DBG = true;
    private static final Boolean SYSTEM = Boolean.TRUE;
    private static final Boolean SYSTEM = Boolean.TRUE;
    private static final Boolean NETWORK = Boolean.FALSE;
    private static final Boolean NETWORK = Boolean.FALSE;
    private static final int VERSION_Q = Build.VERSION_CODES.Q;


    private final Context mContext;
    private final Context mContext;
    private final PackageManager mPackageManager;
    private final PackageManager mPackageManager;
@@ -87,7 +90,7 @@ public class PermissionMonitor {
            public void onReceive(Context context, Intent intent) {
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                String action = intent.getAction();
                int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                int appUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                int appUid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
                Uri appData = intent.getData();
                Uri appData = intent.getData();
                String appName = appData != null ? appData.getSchemeSpecificPart() : null;
                String appName = appData != null ? appData.getSchemeSpecificPart() : null;


@@ -127,7 +130,7 @@ public class PermissionMonitor {
        }
        }


        for (PackageInfo app : apps) {
        for (PackageInfo app : apps) {
            int uid = app.applicationInfo != null ? app.applicationInfo.uid : -1;
            int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
            if (uid < 0) {
            if (uid < 0) {
                continue;
                continue;
            }
            }
@@ -161,6 +164,11 @@ public class PermissionMonitor {
        return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
        return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
    }
    }


    @VisibleForTesting
    int getDeviceFirstSdkInt() {
        return Build.VERSION.FIRST_SDK_INT;
    }

    @VisibleForTesting
    @VisibleForTesting
    boolean hasPermission(PackageInfo app, String permission) {
    boolean hasPermission(PackageInfo app, String permission) {
        if (app.requestedPermissions != null) {
        if (app.requestedPermissions != null) {
@@ -180,11 +188,18 @@ public class PermissionMonitor {
    private boolean hasRestrictedNetworkPermission(PackageInfo app) {
    private boolean hasRestrictedNetworkPermission(PackageInfo app) {
        // TODO : remove this check in the future(b/31479477). All apps should just
        // TODO : remove this check in the future(b/31479477). All apps should just
        // request the appropriate permission for their use case since android Q.
        // request the appropriate permission for their use case since android Q.
        if (app.applicationInfo != null
        if (app.applicationInfo != null) {
                && app.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q
            // 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 && getDeviceFirstSdkInt() < VERSION_Q) {
                return true;
            }

            if (app.applicationInfo.targetSdkVersion < VERSION_Q
                    && isVendorApp(app.applicationInfo)) {
                    && isVendorApp(app.applicationInfo)) {
                return true;
                return true;
            }
            }
        }
        return hasPermission(app, CONNECTIVITY_INTERNAL)
        return hasPermission(app, CONNECTIVITY_INTERNAL)
                || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
                || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
    }
    }
+60 −51
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.os.Process.SYSTEM_UID;


import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
@@ -55,26 +56,41 @@ public class PermissionMonitorTest {
    private static final String PARTITION_OEM = "oem";
    private static final String PARTITION_OEM = "oem";
    private static final String PARTITION_PRODUCT = "product";
    private static final String PARTITION_PRODUCT = "product";
    private static final String PARTITION_VENDOR = "vendor";
    private static final String PARTITION_VENDOR = "vendor";
    private static final int VERSION_P = Build.VERSION_CODES.P;
    private static final int VERSION_Q = Build.VERSION_CODES.Q;


    @Mock private Context mContext;
    @Mock private Context mContext;
    @Mock private PackageManager mPackageManager;
    @Mock private PackageManager mPackageManager;


    private PermissionMonitor mPermissionMonitor;
    private PermissionMonitor mPermissionMonitor;
    private int mMockFirstSdkInt;


    @Before
    @Before
    public void setUp() throws Exception {
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mPackageManager.getPackagesForUid(MOCK_UID)).thenReturn(MOCK_PACKAGE_NAMES);
        when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(MOCK_PACKAGE_NAMES);
        mPermissionMonitor = new PermissionMonitor(mContext, null);
        // Try to use spy() here for stubbing getDeviceFirstSdkInt value but the spies are loaded
        // by a custom class loader that's different from the loader used for loading the real
        // thing. That means those two classes are not in the same package, so a package private
        // method is not accessible. Hence, using override method to control FIRST_SDK_INT value
        // instead of spy function for testing.
        mPermissionMonitor = new PermissionMonitor(mContext, null) {
            @Override
            int getDeviceFirstSdkInt() {
                return mMockFirstSdkInt;
            }
        };
    }
    }


    private void expectPermission(String[] permissions, String partition,
    private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
            int targetSdkVersion) throws Exception {
            String... permission) throws Exception {
        final PackageInfo packageInfo = packageInfoWithPermissions(permissions, partition);
        final PackageInfo packageInfo = packageInfoWithPermissions(permission, partition);
        packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
        packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
        packageInfo.applicationInfo.uid = uid;
        when(mPackageManager.getPackageInfoAsUser(
        when(mPackageManager.getPackageInfoAsUser(
                eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
                eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
        return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
    }
    }


    private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
    private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
@@ -136,51 +152,44 @@ public class PermissionMonitorTest {


    @Test
    @Test
    public void testHasUseBackgroundNetworksPermission() throws Exception {
    public void testHasUseBackgroundNetworksPermission() throws Exception {
        expectPermission(new String[] { CHANGE_NETWORK_STATE },
        assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID));
            PARTITION_SYSTEM, Build.VERSION_CODES.P);
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, NETWORK_STACK));
        expectPermission(new String[] { NETWORK_STACK }, PARTITION_SYSTEM, Build.VERSION_CODES.P);
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID,
        expectPermission(new String[] { CONNECTIVITY_INTERNAL },
                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
            PARTITION_SYSTEM, Build.VERSION_CODES.P);
        assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));

        expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
        assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID));
            PARTITION_SYSTEM, Build.VERSION_CODES.P);
        assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
    }


        expectPermission(new String[] { CHANGE_NETWORK_STATE },
    @Test
            PARTITION_VENDOR, Build.VERSION_CODES.P);
    public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception {
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        mMockFirstSdkInt = VERSION_P;
        expectPermission(new String[] { NETWORK_STACK },
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
            PARTITION_VENDOR, Build.VERSION_CODES.P);
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID,
        expectPermission(new String[] { CONNECTIVITY_INTERNAL },
                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
            PARTITION_VENDOR, Build.VERSION_CODES.P);

        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        mMockFirstSdkInt = VERSION_Q;
        expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
        assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
            PARTITION_VENDOR, Build.VERSION_CODES.P);
        assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID,

                CONNECTIVITY_USE_RESTRICTED_NETWORKS));
        expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.P);
    }
        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));

        expectPermission(new String[] { CHANGE_WIFI_STATE },
    @Test
            PARTITION_SYSTEM, Build.VERSION_CODES.P);
    public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception {
        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID));
        expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.P);
        assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE));
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, NETWORK_STACK));
        expectPermission(new String[] { CHANGE_WIFI_STATE },
        assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL));
            PARTITION_VENDOR, Build.VERSION_CODES.P);
        assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID,
        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
                CONNECTIVITY_USE_RESTRICTED_NETWORKS));

        assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE));
        expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.Q);

        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID));
        expectPermission(new String[] { CHANGE_WIFI_STATE },
        assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE));
            PARTITION_SYSTEM, Build.VERSION_CODES.Q);
        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.Q);
        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
        expectPermission(new String[] { CHANGE_WIFI_STATE },
            PARTITION_VENDOR, Build.VERSION_CODES.Q);
        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
    }
    }
}
}