Merge "PermissionMonitor: Limit preinstalled apps network permissions"
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index e471c7d..7b8571c 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -24,6 +24,7 @@
 import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 
+import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -34,6 +35,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.net.Uri;
+import android.os.Build;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -155,9 +157,8 @@
     }
 
     @VisibleForTesting
-    boolean isPreinstalledSystemApp(PackageInfo app) {
-        int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
-        return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0;
+    static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
+        return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
     }
 
     @VisibleForTesting
@@ -177,7 +178,13 @@
     }
 
     private boolean hasRestrictedNetworkPermission(PackageInfo app) {
-        if (isPreinstalledSystemApp(app)) return true;
+        // TODO : remove this 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
+                && app.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q
+                && isVendorApp(app.applicationInfo)) {
+            return true;
+        }
         return hasPermission(app, CONNECTIVITY_INTERNAL)
                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
     }
@@ -186,13 +193,8 @@
         // This function defines what it means to hold the permission to use
         // background networks.
         return hasPermission(app, CHANGE_NETWORK_STATE)
-                || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)
-                || hasPermission(app, CONNECTIVITY_INTERNAL)
                 || hasPermission(app, NETWORK_STACK)
-                // TODO : remove this check (b/31479477). Not all preinstalled apps should
-                // have access to background networks, they should just request the appropriate
-                // permission for their use case from the list above.
-                || isPreinstalledSystemApp(app);
+                || hasRestrictedNetworkPermission(app);
     }
 
     public boolean hasUseBackgroundNetworksPermission(int uid) {
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index f025f41..4dc63f2 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -21,7 +21,9 @@
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+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_VENDOR;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 
 import static org.junit.Assert.assertFalse;
@@ -34,6 +36,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.os.Build;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -48,6 +51,10 @@
 public class PermissionMonitorTest {
     private static final int MOCK_UID = 10001;
     private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" };
+    private static final String PARTITION_SYSTEM = "system";
+    private static final String PARTITION_OEM = "oem";
+    private static final String PARTITION_PRODUCT = "product";
+    private static final String PARTITION_VENDOR = "vendor";
 
     @Mock private Context mContext;
     @Mock private PackageManager mPackageManager;
@@ -62,39 +69,53 @@
         mPermissionMonitor = new PermissionMonitor(mContext, null);
     }
 
-    private void expectPermission(String[] permissions, boolean preinstalled) throws Exception {
-        final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled);
+    private void expectPermission(String[] permissions, String partition,
+            int targetSdkVersion) throws Exception {
+        final PackageInfo packageInfo = packageInfoWithPermissions(permissions, partition);
+        packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
         when(mPackageManager.getPackageInfoAsUser(
                 eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
     }
 
-    private PackageInfo packageInfoWithPermissions(String[] permissions, boolean preinstalled) {
+    private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
         final PackageInfo packageInfo = new PackageInfo();
         packageInfo.requestedPermissions = permissions;
         packageInfo.applicationInfo = new ApplicationInfo();
-        packageInfo.applicationInfo.flags = preinstalled ? FLAG_SYSTEM : 0;
+        int privateFlags = 0;
+        switch (partition) {
+            case PARTITION_OEM:
+                privateFlags = PRIVATE_FLAG_OEM;
+                break;
+            case PARTITION_PRODUCT:
+                privateFlags = PRIVATE_FLAG_PRODUCT;
+                break;
+            case PARTITION_VENDOR:
+                privateFlags = PRIVATE_FLAG_VENDOR;
+                break;
+        }
+        packageInfo.applicationInfo.privateFlags = privateFlags;
         return packageInfo;
     }
 
     @Test
     public void testHasPermission() {
-        PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
+        PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
         assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
         assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
         assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
         assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
 
         app = packageInfoWithPermissions(new String[] {
-                CHANGE_NETWORK_STATE, NETWORK_STACK
-            }, false);
+            CHANGE_NETWORK_STATE, NETWORK_STACK
+        }, PARTITION_SYSTEM);
         assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
         assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
         assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
         assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
 
         app = packageInfoWithPermissions(new String[] {
-                CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
-            }, false);
+            CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
+        }, PARTITION_SYSTEM);
         assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
         assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
         assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
@@ -102,35 +123,64 @@
     }
 
     @Test
-    public void testIsPreinstalledSystemApp() {
-        PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
-        assertFalse(mPermissionMonitor.isPreinstalledSystemApp(app));
-
-        app = packageInfoWithPermissions(new String[] {}, true);
-        assertTrue(mPermissionMonitor.isPreinstalledSystemApp(app));
+    public void testIsVendorApp() {
+        PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
+        assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
+        app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM);
+        assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
+        app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT);
+        assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
+        app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR);
+        assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
     }
 
     @Test
     public void testHasUseBackgroundNetworksPermission() throws Exception {
-        expectPermission(new String[] { CHANGE_NETWORK_STATE }, false);
+        expectPermission(new String[] { CHANGE_NETWORK_STATE },
+            PARTITION_SYSTEM, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { NETWORK_STACK }, PARTITION_SYSTEM, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CONNECTIVITY_INTERNAL },
+            PARTITION_SYSTEM, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
+            PARTITION_SYSTEM, Build.VERSION_CODES.P);
         assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
 
-        expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, false);
+        expectPermission(new String[] { CHANGE_NETWORK_STATE },
+            PARTITION_VENDOR, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { NETWORK_STACK },
+            PARTITION_VENDOR, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CONNECTIVITY_INTERNAL },
+            PARTITION_VENDOR, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
+            PARTITION_VENDOR, Build.VERSION_CODES.P);
         assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
 
-        // TODO : make this false when b/31479477 is fixed
-        expectPermission(new String[] {}, true);
-        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
-        expectPermission(new String[] { CHANGE_WIFI_STATE }, true);
-        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
-
-        expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, true);
-        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
-
-        expectPermission(new String[] {}, false);
+        expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.P);
         assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CHANGE_WIFI_STATE },
+            PARTITION_SYSTEM, Build.VERSION_CODES.P);
+        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CHANGE_WIFI_STATE },
+            PARTITION_VENDOR, Build.VERSION_CODES.P);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
 
-        expectPermission(new String[] { CHANGE_WIFI_STATE }, false);
+        expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.Q);
+        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { 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));
     }
 }