diff options
| author | 2016-04-11 17:58:17 +0000 | |
|---|---|---|
| committer | 2016-04-11 17:58:18 +0000 | |
| commit | b53874e71459af4461d12fa626a39d02d98cf2b3 (patch) | |
| tree | 387a1154e93cbbfe5c13190524dff2e5ee49f341 | |
| parent | 76961ccc52c5cb9d73336782be2d74c23600c5a3 (diff) | |
| parent | e68b127525c23e8e0cbe1e9dee75534d99e2833d (diff) | |
Merge changes from topic 'carrier-app-race' into nyc-dev
* changes:
Disable preinstalled carrier apps earlier in boot.
Move CarrierAppUtils into frameworks/base/telephony.
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 14 | ||||
| -rw-r--r-- | telephony/java/com/android/internal/telephony/CarrierAppUtils.java | 234 |
2 files changed, 246 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4c03a33991fa..3b07fe185b4f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -229,6 +229,7 @@ import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.os.InstallerConnection.InstallerException; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; +import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; @@ -2051,6 +2052,10 @@ 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; } @@ -17057,8 +17062,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } PackageSetting pkgSetting; final int uid = Binder.getCallingUid(); - final int permission = mContext.checkCallingOrSelfPermission( - android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); + final int permission; + if (uid == Process.SYSTEM_UID) { + permission = PackageManager.PERMISSION_GRANTED; + } else { + permission = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); + } enforceCrossUserPermission(uid, userId, false /* requireFullPermission */, true /* checkShell */, "set enabled"); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java new file mode 100644 index 000000000000..ca7354f66a1b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.telephony; + +import android.annotation.Nullable; +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.telephony.TelephonyManager; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utilities for handling carrier applications. + * @hide + */ +public final class CarrierAppUtils { + private static final String TAG = "CarrierAppUtils"; + + private static final boolean DEBUG = false; // STOPSHIP if true + + private CarrierAppUtils() {} + + /** + * Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted. + * + * Evaluates the list of applications in config_disabledUntilUsedPreinstalledCarrierApps. We + * want to disable each such application which is present on the system image until the user + * inserts a SIM which causes that application to gain carrier privilege (indicating a "match"), + * without interfering with the user if they opt to enable/disable the app explicitly. + * + * So, for each such app, we either disable until used IFF the app is not carrier privileged AND + * 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. + */ + public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, + IPackageManager packageManager, TelephonyManager telephonyManager, int userId) { + if (DEBUG) { + Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); + } + String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray( + com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps); + disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId, + systemCarrierAppsDisabledUntilUsed); + } + + /** + * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager, + * 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 + * not yet read the carrier privilege rules. However, since telephony is initialized later on + * late in boot, the app being disabled may have already been started in response to certain + * broadcasts. The app will continue to run (briefly) after being disabled, before the Package + * 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) { + if (DEBUG) { + Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); + } + String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray( + com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps); + disableCarrierAppsUntilPrivileged(callingPackage, packageManager, + null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed); + } + + // 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) { + List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager, + userId, systemCarrierAppsDisabledUntilUsed); + if (candidates == null || candidates.isEmpty()) { + return; + } + + List<String> enabledCarrierPackages = new ArrayList<>(); + + try { + for (ApplicationInfo ai : candidates) { + String packageName = ai.packageName; + boolean hasPrivileges = telephonyManager != null && + 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 + || ai.enabledSetting == + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { + Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user " + + userId); + packageManager.setApplicationEnabledSetting(packageName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP, userId, callingPackage); + } else if (!hasPrivileges + && 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); + } + } + + // Always re-grant default permissions to carrier apps w/ privileges. + if (hasPrivileges) { + enabledCarrierPackages.add(ai.packageName); + } + } + + if (!enabledCarrierPackages.isEmpty()) { + // Since we enabled at least one app, ensure we grant default permissions to those + // apps. + String[] packageNames = new String[enabledCarrierPackages.size()]; + enabledCarrierPackages.toArray(packageNames); + packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, 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; + } + if (!ai.isSystemApp()) { + continue; + } + apps.add(ai); + } + } catch (RemoteException e) { + Slog.w(TAG, "Could not reach PackageManager", e); + } + return apps; + } +} |