2 * Copyright (C) 2015 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 package com.android.internal.telephony;
19 import android.annotation.Nullable;
20 import android.content.ContentResolver;
21 import android.content.pm.ApplicationInfo;
22 import android.content.pm.IPackageManager;
23 import android.content.pm.PackageManager;
24 import android.content.res.Resources;
25 import android.os.RemoteException;
26 import android.provider.Settings;
27 import android.telephony.TelephonyManager;
28 import android.util.ArrayMap;
29 import android.util.ArraySet;
30 import android.util.Slog;
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.server.SystemConfig;
35 import java.util.ArrayList;
36 import java.util.List;
40 * Utilities for handling carrier applications.
43 public final class CarrierAppUtils {
44 private static final String TAG = "CarrierAppUtils";
46 private static final boolean DEBUG = false; // STOPSHIP if true
48 private CarrierAppUtils() {}
51 * Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted.
53 * Evaluates the list of applications in
54 * {@link SystemConfig#getDisabledUntilUsedPreinstalledCarrierApps()}. We want to disable each
55 * such application which is present on the system image until the user inserts a SIM which
56 * causes that application to gain carrier privilege (indicating a "match"), without interfering
57 * with the user if they opt to enable/disable the app explicitly.
59 * So, for each such app, we either disable until used IFF the app is not carrier privileged AND
60 * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if
61 * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED.
63 * In addition, there is a list of carrier-associated applications in
64 * {@link SystemConfig#getDisabledUntilUsedPreinstalledCarrierAssociatedApps}. Each app in this
65 * list is associated with a carrier app. When the given carrier app is enabled/disabled per the
66 * above, the associated applications are enabled/disabled to match.
68 * When enabling a carrier app we also grant it default permissions.
70 * This method is idempotent and is safe to be called at any time; it should be called once at
71 * system startup prior to any application running, as well as any time the set of carrier
72 * privileged apps may have changed.
74 public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
75 IPackageManager packageManager, TelephonyManager telephonyManager,
76 ContentResolver contentResolver, int userId) {
78 Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
80 SystemConfig config = SystemConfig.getInstance();
81 ArraySet<String> systemCarrierAppsDisabledUntilUsed =
82 config.getDisabledUntilUsedPreinstalledCarrierApps();
83 ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
84 config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
85 disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
86 contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
87 systemCarrierAssociatedAppsDisabledUntilUsed);
91 * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager,
92 * ContentResolver, int)}, but assumes that no carrier apps have carrier privileges.
94 * This prevents a potential race condition on first boot - since the app's default state is
95 * enabled, we will initially disable it when the telephony stack is first initialized as it has
96 * not yet read the carrier privilege rules. However, since telephony is initialized later on
97 * late in boot, the app being disabled may have already been started in response to certain
98 * broadcasts. The app will continue to run (briefly) after being disabled, before the Package
99 * Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
101 public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
102 IPackageManager packageManager, ContentResolver contentResolver, int userId) {
104 Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
106 SystemConfig config = SystemConfig.getInstance();
107 ArraySet<String> systemCarrierAppsDisabledUntilUsed =
108 config.getDisabledUntilUsedPreinstalledCarrierApps();
111 ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
112 config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
113 disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
114 null /* telephonyManager */, contentResolver, userId,
115 systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed);
118 // Must be public b/c framework unit tests can't access package-private methods.
120 public static void disableCarrierAppsUntilPrivileged(String callingPackage,
121 IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
122 ContentResolver contentResolver, int userId,
123 ArraySet<String> systemCarrierAppsDisabledUntilUsed,
124 ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
125 List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
126 userId, systemCarrierAppsDisabledUntilUsed);
127 if (candidates == null || candidates.isEmpty()) {
131 Map<String, List<ApplicationInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper(
134 systemCarrierAssociatedAppsDisabledUntilUsed);
136 List<String> enabledCarrierPackages = new ArrayList<>();
138 boolean hasRunOnce = Settings.Secure.getIntForUser(
139 contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, userId) == 1;
142 for (ApplicationInfo ai : candidates) {
143 String packageName = ai.packageName;
144 boolean hasPrivileges = telephonyManager != null &&
145 telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
146 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
149 // Only update enabled state for the app on /system. Once it has been
150 // updated we shouldn't touch it.
151 if (!ai.isUpdatedSystemApp()
152 && (ai.enabledSetting ==
153 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
154 || ai.enabledSetting ==
155 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
156 Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
158 packageManager.setApplicationEnabledSetting(
160 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
161 PackageManager.DONT_KILL_APP,
166 // Also enable any associated apps for this carrier app.
167 List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
168 if (associatedAppList != null) {
169 for (ApplicationInfo associatedApp : associatedAppList) {
170 if (associatedApp.enabledSetting ==
171 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
172 || associatedApp.enabledSetting ==
173 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
174 Slog.i(TAG, "Update associated state(" + associatedApp.packageName
175 + "): ENABLED for user " + userId);
176 packageManager.setApplicationEnabledSetting(
177 associatedApp.packageName,
178 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
179 PackageManager.DONT_KILL_APP,
186 // Always re-grant default permissions to carrier apps w/ privileges.
187 enabledCarrierPackages.add(ai.packageName);
188 } else { // No carrier privileges
189 // Only update enabled state for the app on /system. Once it has been
190 // updated we shouldn't touch it.
191 if (!ai.isUpdatedSystemApp()
192 && ai.enabledSetting ==
193 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
194 Slog.i(TAG, "Update state(" + packageName
195 + "): DISABLED_UNTIL_USED for user " + userId);
196 packageManager.setApplicationEnabledSetting(
198 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
204 // Also disable any associated apps for this carrier app if this is the first
205 // run. We avoid doing this a second time because it is brittle to rely on the
206 // distinction between "default" and "enabled".
208 List<ApplicationInfo> associatedAppList = associatedApps.get(packageName);
209 if (associatedAppList != null) {
210 for (ApplicationInfo associatedApp : associatedAppList) {
211 if (associatedApp.enabledSetting
212 == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
214 "Update associated state(" + associatedApp.packageName
215 + "): DISABLED_UNTIL_USED for user " + userId);
216 packageManager.setApplicationEnabledSetting(
217 associatedApp.packageName,
219 .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
230 // Mark the execution so we do not disable apps again.
232 Settings.Secure.putIntForUser(
233 contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, userId);
236 if (!enabledCarrierPackages.isEmpty()) {
237 // Since we enabled at least one app, ensure we grant default permissions to those
239 String[] packageNames = new String[enabledCarrierPackages.size()];
240 enabledCarrierPackages.toArray(packageNames);
241 packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
243 } catch (RemoteException e) {
244 Slog.w(TAG, "Could not reach PackageManager", e);
249 * Returns the list of "default" carrier apps.
251 * This is the subset of apps returned by
252 * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier
253 * privileges per the SIM(s) inserted in the device.
255 public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager,
256 TelephonyManager telephonyManager, int userId) {
257 // Get all system apps from the default list.
258 List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId);
259 if (candidates == null || candidates.isEmpty()) {
263 // Filter out apps without carrier privileges.
264 // Iterate from the end to avoid creating an Iterator object and because we will be removing
265 // elements from the list as we pass through it.
266 for (int i = candidates.size() - 1; i >= 0; i--) {
267 ApplicationInfo ai = candidates.get(i);
268 String packageName = ai.packageName;
269 boolean hasPrivileges =
270 telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
271 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
272 if (!hasPrivileges) {
273 candidates.remove(i);
281 * Returns the list of "default" carrier app candidates.
283 * These are the apps subject to the hiding/showing logic in
284 * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager,
285 * TelephonyManager, ContentResolver, int)}, as well as the apps which should have default
286 * permissions granted, when a matching SIM is inserted.
288 * Whether or not the app is actually considered a default app depends on whether the app has
289 * carrier privileges as determined by the SIMs in the device.
291 public static List<ApplicationInfo> getDefaultCarrierAppCandidates(
292 IPackageManager packageManager, int userId) {
293 ArraySet<String> systemCarrierAppsDisabledUntilUsed =
294 SystemConfig.getInstance().getDisabledUntilUsedPreinstalledCarrierApps();
295 return getDefaultCarrierAppCandidatesHelper(packageManager, userId,
296 systemCarrierAppsDisabledUntilUsed);
299 private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper(
300 IPackageManager packageManager,
302 ArraySet<String> systemCarrierAppsDisabledUntilUsed) {
303 if (systemCarrierAppsDisabledUntilUsed == null) {
307 int size = systemCarrierAppsDisabledUntilUsed.size();
312 List<ApplicationInfo> apps = new ArrayList<>(size);
313 for (int i = 0; i < size; i++) {
314 String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i);
316 getApplicationInfoIfSystemApp(packageManager, userId, packageName);
324 private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper(
325 IPackageManager packageManager,
327 ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
328 int size = systemCarrierAssociatedAppsDisabledUntilUsed.size();
329 Map<String, List<ApplicationInfo>> associatedApps = new ArrayMap<>(size);
330 for (int i = 0; i < size; i++) {
331 String carrierAppPackage = systemCarrierAssociatedAppsDisabledUntilUsed.keyAt(i);
332 List<String> associatedAppPackages =
333 systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i);
334 for (int j = 0; j < associatedAppPackages.size(); j++) {
336 getApplicationInfoIfSystemApp(
337 packageManager, userId, associatedAppPackages.get(j));
338 // Only update enabled state for the app on /system. Once it has been updated we
339 // shouldn't touch it.
340 if (ai != null && !ai.isUpdatedSystemApp()) {
341 List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage);
342 if (appList == null) {
343 appList = new ArrayList<>();
344 associatedApps.put(carrierAppPackage, appList);
350 return associatedApps;
354 private static ApplicationInfo getApplicationInfoIfSystemApp(
355 IPackageManager packageManager,
357 String packageName) {
359 ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
360 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
361 if (ai != null && ai.isSystemApp()) {
364 } catch (RemoteException e) {
365 Slog.w(TAG, "Could not reach PackageManager", e);