Merge "Add support for carrier "associated" apps." into nyc-mr1-dev

This commit is contained in:
Jeff Davidson
2016-07-27 17:57:38 +00:00
committed by Android (Google) Code Review
4 changed files with 216 additions and 44 deletions

View File

@@ -6229,6 +6229,20 @@ public final class Settings {
*/
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.
*

View File

@@ -42,6 +42,8 @@ import java.io.File;
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 @@ public class SystemConfig {
// 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 @@ public class SystemConfig {
return mBackupTransportWhitelist;
}
public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
}
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -476,6 +487,26 @@ public class SystemConfig {
}
}
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;

View File

@@ -1963,10 +1963,6 @@ public class PackageManagerService extends IPackageManager.Stub {
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 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
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(),

View File

@@ -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 @@ 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.
*
* 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 @@ public final class CarrierAppUtils {
* 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 @@ public final class CarrierAppUtils {
* 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 @@ public final class CarrierAppUtils {
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 @@ public final class CarrierAppUtils {
*
* 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 @@ public final class CarrierAppUtils {
}
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;
}
}