Add support for carrier \"associated\" apps.
am: 24b9d96007
Change-Id: I1de92977f3a0635d88e6517210f6bbb06ab3d0f0
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6d45faa..641153f 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6230,6 +6230,20 @@
public static final int VR_DISPLAY_MODE_OFF = 1;
/**
+ * Whether CarrierAppUtils#disableCarrierAppsUntilPrivileged has been executed at least
+ * once.
+ *
+ * <p>This is used to ensure that we only take one pass which will disable apps that are not
+ * privileged (if any). From then on, we only want to enable apps (when a matching SIM is
+ * inserted), to avoid disabling an app that the user might actively be using.
+ *
+ * <p>Will be set to 1 once executed.
+ *
+ * @hide
+ */
+ public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
+
+ /**
* Whether parent user can access remote contact in managed profile.
*
* @hide
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 886265a..429131b 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -42,6 +42,8 @@
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
/**
* Loads global system configuration info.
@@ -122,6 +124,11 @@
// These are the permitted backup transport service components
final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();
+ // These are the packages of carrier-associated apps which should be disabled until used until
+ // a SIM is inserted which grants carrier privileges to that carrier app.
+ final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
+ new ArrayMap<>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -183,6 +190,10 @@
return mBackupTransportWhitelist;
}
+ public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
+ return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -476,6 +487,26 @@
}
}
XmlUtils.skipCurrentTag(parser);
+ } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
+ && allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
+ if (pkgname == null || carrierPkgname == null) {
+ Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
+ + " without package or carrierAppPackage in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else {
+ List<String> associatedPkgs =
+ mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
+ carrierPkgname);
+ if (associatedPkgs == null) {
+ associatedPkgs = new ArrayList<>();
+ mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
+ carrierPkgname, associatedPkgs);
+ }
+ associatedPkgs.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 54c36e1..a4c90f7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1963,10 +1963,6 @@
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
- // Disable any carrier apps. We do this very early in boot to prevent the apps from being
- // disabled after already being started.
- CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
- UserHandle.USER_SYSTEM);
ServiceManager.addService("package", m);
return m;
}
@@ -17875,6 +17871,11 @@
public void systemReady() {
mSystemReady = true;
+ // Disable any carrier apps. We do this very early in boot to prevent the apps from being
+ // disabled after already being started.
+ CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
+ mContext.getContentResolver(), UserHandle.USER_SYSTEM);
+
// Read the compatibilty setting when the system is ready.
boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
mContext.getContentResolver(),
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index ca7354f..8b81b0d 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -17,18 +17,23 @@
package com.android.internal.telephony;
import android.annotation.Nullable;
+import android.content.ContentResolver;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.RemoteException;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemConfig;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Utilities for handling carrier applications.
@@ -53,6 +58,11 @@
* 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.
*
+ * In addition, there is a list of carrier-associated applications in
+ * {@link SystemConfig#getDisabledUntilUsedPreinstalledCarrierAssociatedApps}. Each app in this
+ * list is associated with a carrier app. When the given carrier app is enabled/disabled per the
+ * above, the associated applications are enabled/disabled to match.
+ *
* 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
@@ -60,19 +70,24 @@
* privileged apps may have changed.
*/
public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
- IPackageManager packageManager, TelephonyManager telephonyManager, int userId) {
+ IPackageManager packageManager, TelephonyManager telephonyManager,
+ ContentResolver contentResolver, int userId) {
if (DEBUG) {
Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
}
+ SystemConfig config = SystemConfig.getInstance();
String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
- disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId,
- systemCarrierAppsDisabledUntilUsed);
+ ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
+ config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+ disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
+ contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
+ systemCarrierAssociatedAppsDisabledUntilUsed);
}
/**
* Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager,
- * int)}, but assumes that no carrier apps have carrier privileges.
+ * ContentResolver, int)}, but assumes that no carrier apps have carrier privileges.
*
* This prevents a potential race condition on first boot - since the app's default state is
* enabled, we will initially disable it when the telephony stack is first initialized as it has
@@ -82,29 +97,43 @@
* Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
*/
public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
- IPackageManager packageManager, int userId) {
+ IPackageManager packageManager, ContentResolver contentResolver, int userId) {
if (DEBUG) {
Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
}
+ SystemConfig config = SystemConfig.getInstance();
String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
+ ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
+ config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
- null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed);
+ null /* telephonyManager */, contentResolver, userId,
+ systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed);
}
// Must be public b/c framework unit tests can't access package-private methods.
@VisibleForTesting
public static void disableCarrierAppsUntilPrivileged(String callingPackage,
- IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, int userId,
- String[] systemCarrierAppsDisabledUntilUsed) {
+ IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
+ ContentResolver contentResolver, int userId,
+ String[] systemCarrierAppsDisabledUntilUsed,
+ ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
userId, systemCarrierAppsDisabledUntilUsed);
if (candidates == null || candidates.isEmpty()) {
return;
}
+ Map<String, List<ApplicationInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper(
+ packageManager,
+ userId,
+ systemCarrierAssociatedAppsDisabledUntilUsed);
+
List<String> enabledCarrierPackages = new ArrayList<>();
+ boolean hasRunOnce = Settings.Secure.getIntForUser(
+ contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, userId) == 1;
+
try {
for (ApplicationInfo ai : candidates) {
String packageName = ai.packageName;
@@ -112,33 +141,92 @@
telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
- // Only update enabled state for the app on /system. Once it has been updated we
- // shouldn't touch it.
- if (!ai.isUpdatedSystemApp()) {
- if (hasPrivileges
- && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ if (hasPrivileges) {
+ // Only update enabled state for the app on /system. Once it has been
+ // updated we shouldn't touch it.
+ if (!ai.isUpdatedSystemApp()
+ && (ai.enabledSetting ==
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
+ userId);
- packageManager.setApplicationEnabledSetting(packageName,
+ packageManager.setApplicationEnabledSetting(
+ packageName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP, userId, callingPackage);
- } else if (!hasPrivileges
+ PackageManager.DONT_KILL_APP,
+ userId,
+ callingPackage);
+ }
+
+ // Also enable any associated apps for this carrier app.
+ List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
+ if (associatedAppList != null) {
+ for (ApplicationInfo associatedApp : associatedAppList) {
+ if (associatedApp.enabledSetting ==
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ || associatedApp.enabledSetting ==
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ Slog.i(TAG, "Update associated state(" + associatedApp.packageName
+ + "): ENABLED for user " + userId);
+ packageManager.setApplicationEnabledSetting(
+ associatedApp.packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP,
+ userId,
+ callingPackage);
+ }
+ }
+ }
+
+ // Always re-grant default permissions to carrier apps w/ privileges.
+ enabledCarrierPackages.add(ai.packageName);
+ } else { // No carrier privileges
+ // Only update enabled state for the app on /system. Once it has been
+ // updated we shouldn't touch it.
+ if (!ai.isUpdatedSystemApp()
&& ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
Slog.i(TAG, "Update state(" + packageName
+ "): DISABLED_UNTIL_USED for user " + userId);
- packageManager.setApplicationEnabledSetting(packageName,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
- userId, callingPackage);
+ packageManager.setApplicationEnabledSetting(
+ packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ 0,
+ userId,
+ callingPackage);
+ }
+
+ // Also disable any associated apps for this carrier app if this is the first
+ // run. We avoid doing this a second time because it is brittle to rely on the
+ // distinction between "default" and "enabled".
+ if (!hasRunOnce) {
+ List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
+ if (associatedAppList != null) {
+ for (ApplicationInfo associatedApp : associatedAppList) {
+ if (associatedApp.enabledSetting
+ == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+ Slog.i(TAG,
+ "Update associated state(" + associatedApp.packageName
+ + "): DISABLED_UNTIL_USED for user " + userId);
+ packageManager.setApplicationEnabledSetting(
+ associatedApp.packageName,
+ PackageManager
+ .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
+ 0,
+ userId,
+ callingPackage);
+ }
+ }
+ }
}
}
+ }
- // Always re-grant default permissions to carrier apps w/ privileges.
- if (hasPrivileges) {
- enabledCarrierPackages.add(ai.packageName);
- }
+ // Mark the execution so we do not disable apps again.
+ if (!hasRunOnce) {
+ Settings.Secure.putIntForUser(
+ contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, userId);
}
if (!enabledCarrierPackages.isEmpty()) {
@@ -190,8 +278,8 @@
*
* 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.
+ * TelephonyManager, ContentResolver, 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.
@@ -205,30 +293,68 @@
}
private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
- IPackageManager packageManager, int userId,
+ 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;
- }
- if (!ai.isSystemApp()) {
- continue;
- }
+ List<ApplicationInfo> apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length);
+ for (int i = 0; i < systemCarrierAppsDisabledUntilUsed.length; i++) {
+ String packageName = systemCarrierAppsDisabledUntilUsed[i];
+ ApplicationInfo ai =
+ getApplicationInfoIfSystemApp(packageManager, userId, packageName);
+ if (ai != null) {
apps.add(ai);
}
+ }
+ return apps;
+ }
+
+ private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper(
+ IPackageManager packageManager,
+ int userId,
+ ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
+ int size = systemCarrierAssociatedAppsDisabledUntilUsed.size();
+ Map<String, List<ApplicationInfo>> associatedApps = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String carrierAppPackage = systemCarrierAssociatedAppsDisabledUntilUsed.keyAt(i);
+ List<String> associatedAppPackages =
+ systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i);
+ for (int j = 0; j < associatedAppPackages.size(); j++) {
+ ApplicationInfo ai =
+ getApplicationInfoIfSystemApp(
+ packageManager, userId, associatedAppPackages.get(j));
+ // Only update enabled state for the app on /system. Once it has been updated we
+ // shouldn't touch it.
+ if (ai != null && !ai.isUpdatedSystemApp()) {
+ List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage);
+ if (appList == null) {
+ appList = new ArrayList<>();
+ associatedApps.put(carrierAppPackage, appList);
+ }
+ appList.add(ai);
+ }
+ }
+ }
+ return associatedApps;
+ }
+
+ @Nullable
+ private static ApplicationInfo getApplicationInfoIfSystemApp(
+ IPackageManager packageManager,
+ int userId,
+ String packageName) {
+ try {
+ ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
+ if (ai != null && ai.isSystemApp()) {
+ return ai;
+ }
} catch (RemoteException e) {
Slog.w(TAG, "Could not reach PackageManager", e);
}
- return apps;
+ return null;
}
}