Default permissions for carrier apps.
Jeff Davidson [Mon, 22 Jun 2015 23:52:29 +0000 (16:52 -0700)]
Provide the current list of carrier apps to PackageManager when we are
queried for them as part of granting default permissions. Trigger an
evaluation of default permissions whenever we are enabling a new
carrier app due to a change in SIM state (e.g. new carrier privilege
rules).

Bug: 21696731
Change-Id: I3d6d61712acb554878edeb5ee172887da16ef851

src/java/com/android/internal/telephony/CarrierAppUtils.java
src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java

index de7fc40..408bcf3 100644 (file)
@@ -26,6 +26,9 @@ import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Utilities for handling carrier applications.
  * @hide
@@ -49,6 +52,8 @@ public final class CarrierAppUtils {
      * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
      * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED.
      *
+     * When enabling a carrier app we also grant it default permissions.
+     *
      * This method is idempotent and is safe to be called at any time; it should be called once at
      * system startup prior to any application running, as well as any time the set of carrier
      * privileged apps may have changed.
@@ -69,22 +74,15 @@ public final class CarrierAppUtils {
     public static void disableCarrierAppsUntilPrivileged(String callingPackage,
             IPackageManager packageManager, TelephonyManager telephonyManager, int userId,
             String[] systemCarrierAppsDisabledUntilUsed) {
-        if (systemCarrierAppsDisabledUntilUsed == null
-                || systemCarrierAppsDisabledUntilUsed.length == 0) {
+        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
+                userId, systemCarrierAppsDisabledUntilUsed);
+        if (candidates == null || candidates.isEmpty()) {
             return;
         }
         try {
-            for (String packageName : systemCarrierAppsDisabledUntilUsed) {
-                ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
-                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
-                if (ai == null) {
-                    // No app found for packageName
-                    continue;
-                }
-                boolean isSystemPackage = (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-                if (!isSystemPackage) {
-                    continue;
-                }
+            boolean anyAppsEnabled = false;
+            for (ApplicationInfo ai : candidates) {
+                String packageName = ai.packageName;
                 boolean hasPrivileges =
                         telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
                                 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
@@ -93,6 +91,7 @@ public final class CarrierAppUtils {
                         || ai.enabledSetting ==
                                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
                     Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId);
+                    anyAppsEnabled = true;
                     packageManager.setApplicationEnabledSetting(packageName,
                             PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userId,
                             callingPackage);
@@ -105,8 +104,94 @@ public final class CarrierAppUtils {
                             callingPackage);
                 }
             }
+
+            if (anyAppsEnabled) {
+                // Since we enabled at least one app, ensure we grant default permissions to those
+                // apps.
+                packageManager.grantDefaultPermissions(userId);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Could not reach PackageManager", e);
+        }
+    }
+
+    /**
+     * Returns the list of "default" carrier apps.
+     *
+     * This is the subset of apps returned by
+     * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier
+     * privileges per the SIM(s) inserted in the device.
+     */
+    public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager,
+            TelephonyManager telephonyManager, int userId) {
+        // Get all system apps from the default list.
+        List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId);
+        if (candidates == null || candidates.isEmpty()) {
+            return null;
+        }
+
+        // Filter out apps without carrier privileges.
+        // Iterate from the end to avoid creating an Iterator object and because we will be removing
+        // elements from the list as we pass through it.
+        for (int i = candidates.size() - 1; i >= 0; i--) {
+            ApplicationInfo ai = candidates.get(i);
+            String packageName = ai.packageName;
+            boolean hasPrivileges =
+                    telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
+                            TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+            if (!hasPrivileges) {
+                candidates.remove(i);
+            }
+        }
+
+        return candidates;
+    }
+
+    /**
+     * Returns the list of "default" carrier app candidates.
+     *
+     * These are the apps subject to the hiding/showing logic in
+     * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager,
+     * TelephonyManager, int)}, as well as the apps which should have default permissions granted,
+     * when a matching SIM is inserted.
+     *
+     * Whether or not the app is actually considered a default app depends on whether the app has
+     * carrier privileges as determined by the SIMs in the device.
+     */
+    public static List<ApplicationInfo> getDefaultCarrierAppCandidates(
+            IPackageManager packageManager, int userId) {
+        String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
+                com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
+        return getDefaultCarrierAppCandidatesHelper(packageManager, userId,
+                systemCarrierAppsDisabledUntilUsed);
+    }
+
+    private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
+            IPackageManager packageManager, int userId,
+            String[] systemCarrierAppsDisabledUntilUsed) {
+        if (systemCarrierAppsDisabledUntilUsed == null
+                || systemCarrierAppsDisabledUntilUsed.length == 0) {
+            return null;
+        }
+        List<ApplicationInfo> apps = null;
+        try {
+            apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
+            for (String packageName : systemCarrierAppsDisabledUntilUsed) {
+                ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
+                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
+                if (ai == null) {
+                    // No app found for packageName
+                    continue;
+                }
+                boolean isSystemPackage = (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+                if (!isSystemPackage) {
+                    continue;
+                }
+                apps.add(ai);
+            }
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not reach PackageManager", e);
         }
+        return apps;
     }
 }
index f4398f0..7970728 100644 (file)
@@ -27,7 +27,9 @@ import android.content.ContentValues;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.IPackagesProvider;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.IRemoteCallback;
@@ -120,6 +122,31 @@ public class SubscriptionInfoUpdater extends Handler {
     }
 
     private void initializeCarrierApps() {
+        // Let the PackageManager query carrier apps as they get certain permissions granted by
+        // default.
+        try {
+            mPackageManager.setCarrierAppPackagesProvider(
+                    new IPackagesProvider.Stub() {
+                        @Override
+                        public String[] getPackages(int userId) {
+                            List<ApplicationInfo> defaultApps =
+                                    CarrierAppUtils.getDefaultCarrierApps(mPackageManager,
+                                            TelephonyManager.getDefault(), userId);
+                            if (defaultApps == null) {
+                                return null;
+                            }
+                            int count = defaultApps.size();
+                            String[] packages = new String[count];
+                            for (int i = 0; i < count; i++) {
+                                packages[i] = defaultApps.get(i).packageName;
+                            }
+                            return packages;
+                        }
+                    });
+        } catch (RemoteException e) {
+            logd("Couldn't contact PackageManager: " + e.getMessage());
+        }
+
         // Initialize carrier apps:
         // -Now (on system startup)
         // -Whenever new carrier privilege rules might change (new SIM is loaded)
index 330fb51..a91bec6 100644 (file)
@@ -80,6 +80,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_DisabledUser()
             throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -96,6 +97,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     /** Configured app has privileges, but was disabled - should do nothing. */
     public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_Disabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -112,6 +114,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     /** Configured app has privileges, and is already enabled - should do nothing. */
     public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_Enabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -128,6 +131,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     /** Configured app has privileges, and is in the default state - should enable. */
     public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_Default() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -139,12 +143,14 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
         Mockito.verify(mPackageManager).setApplicationEnabledSetting(
                 CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, USER_ID,
                 CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).grantDefaultPermissions(USER_ID);
     }
 
     /** Configured app has privileges, and is disabled until used - should enable. */
     public void testDisableCarrierAppsUntilPrivileged_HasPrivileges_DisabledUntilUsed()
             throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -156,11 +162,13 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
         Mockito.verify(mPackageManager).setApplicationEnabledSetting(
                 CARRIER_APP, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, USER_ID,
                 CALLING_PACKAGE);
+        Mockito.verify(mPackageManager).grantDefaultPermissions(USER_ID);
     }
 
     /** Configured app has no privileges, and was disabled by the user - should do nothing. */
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_DisabledUser() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -177,6 +185,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     /** Configured app has no privileges, and was disabled - should do nothing. */
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Disabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -193,6 +202,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     /** Configured app has no privileges, and is explicitly enabled - should do nothing. */
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Enabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -209,6 +219,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     /** Configured app has no privileges, and is in the default state - should disable until use. */
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Default() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
@@ -226,6 +237,7 @@ public class CarrierAppUtilsTest extends InstrumentationTestCase {
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_DisabledUntilUsed()
             throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         appInfo.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,