1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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 15 */ 16 17package com.android.internal.telephony; 18 19import android.annotation.Nullable; 20import android.content.pm.ApplicationInfo; 21import android.content.pm.IPackageManager; 22import android.content.pm.PackageManager; 23import android.content.res.Resources; 24import android.os.RemoteException; 25import android.telephony.TelephonyManager; 26import android.util.Slog; 27 28import com.android.internal.annotations.VisibleForTesting; 29 30import java.util.ArrayList; 31import java.util.List; 32 33/** 34 * Utilities for handling carrier applications. 35 * @hide 36 */ 37public final class CarrierAppUtils { 38 private static final String TAG = "CarrierAppUtils"; 39 40 private static final boolean DEBUG = false; // STOPSHIP if true 41 42 private CarrierAppUtils() {} 43 44 /** 45 * Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted. 46 * 47 * Evaluates the list of applications in config_disabledUntilUsedPreinstalledCarrierApps. We 48 * want to disable each such application which is present on the system image until the user 49 * inserts a SIM which causes that application to gain carrier privilege (indicating a "match"), 50 * without interfering with the user if they opt to enable/disable the app explicitly. 51 * 52 * So, for each such app, we either disable until used IFF the app is not carrier privileged AND 53 * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if 54 * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED. 55 * 56 * When enabling a carrier app we also grant it default permissions. 57 * 58 * This method is idempotent and is safe to be called at any time; it should be called once at 59 * system startup prior to any application running, as well as any time the set of carrier 60 * privileged apps may have changed. 61 */ 62 public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, 63 IPackageManager packageManager, TelephonyManager telephonyManager, int userId) { 64 if (DEBUG) { 65 Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); 66 } 67 String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray( 68 com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps); 69 disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager, userId, 70 systemCarrierAppsDisabledUntilUsed); 71 } 72 73 /** 74 * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager, 75 * int)}, but assumes that no carrier apps have carrier privileges. 76 * 77 * This prevents a potential race condition on first boot - since the app's default state is 78 * enabled, we will initially disable it when the telephony stack is first initialized as it has 79 * not yet read the carrier privilege rules. However, since telephony is initialized later on 80 * late in boot, the app being disabled may have already been started in response to certain 81 * broadcasts. The app will continue to run (briefly) after being disabled, before the Package 82 * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. 83 */ 84 public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, 85 IPackageManager packageManager, int userId) { 86 if (DEBUG) { 87 Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); 88 } 89 String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray( 90 com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps); 91 disableCarrierAppsUntilPrivileged(callingPackage, packageManager, 92 null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed); 93 } 94 95 // Must be public b/c framework unit tests can't access package-private methods. 96 @VisibleForTesting 97 public static void disableCarrierAppsUntilPrivileged(String callingPackage, 98 IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, int userId, 99 String[] systemCarrierAppsDisabledUntilUsed) { 100 List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager, 101 userId, systemCarrierAppsDisabledUntilUsed); 102 if (candidates == null || candidates.isEmpty()) { 103 return; 104 } 105 106 List<String> enabledCarrierPackages = new ArrayList<>(); 107 108 try { 109 for (ApplicationInfo ai : candidates) { 110 String packageName = ai.packageName; 111 boolean hasPrivileges = telephonyManager != null && 112 telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) == 113 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 114 115 // Only update enabled state for the app on /system. Once it has been updated we 116 // shouldn't touch it. 117 if (!ai.isUpdatedSystemApp()) { 118 if (hasPrivileges 119 && (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 120 || ai.enabledSetting == 121 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 122 Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user " 123 + userId); 124 packageManager.setApplicationEnabledSetting(packageName, 125 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 126 PackageManager.DONT_KILL_APP, userId, callingPackage); 127 } else if (!hasPrivileges 128 && ai.enabledSetting == 129 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 130 Slog.i(TAG, "Update state(" + packageName 131 + "): DISABLED_UNTIL_USED for user " + userId); 132 packageManager.setApplicationEnabledSetting(packageName, 133 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0, 134 userId, callingPackage); 135 } 136 } 137 138 // Always re-grant default permissions to carrier apps w/ privileges. 139 if (hasPrivileges) { 140 enabledCarrierPackages.add(ai.packageName); 141 } 142 } 143 144 if (!enabledCarrierPackages.isEmpty()) { 145 // Since we enabled at least one app, ensure we grant default permissions to those 146 // apps. 147 String[] packageNames = new String[enabledCarrierPackages.size()]; 148 enabledCarrierPackages.toArray(packageNames); 149 packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId); 150 } 151 } catch (RemoteException e) { 152 Slog.w(TAG, "Could not reach PackageManager", e); 153 } 154 } 155 156 /** 157 * Returns the list of "default" carrier apps. 158 * 159 * This is the subset of apps returned by 160 * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier 161 * privileges per the SIM(s) inserted in the device. 162 */ 163 public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager, 164 TelephonyManager telephonyManager, int userId) { 165 // Get all system apps from the default list. 166 List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId); 167 if (candidates == null || candidates.isEmpty()) { 168 return null; 169 } 170 171 // Filter out apps without carrier privileges. 172 // Iterate from the end to avoid creating an Iterator object and because we will be removing 173 // elements from the list as we pass through it. 174 for (int i = candidates.size() - 1; i >= 0; i--) { 175 ApplicationInfo ai = candidates.get(i); 176 String packageName = ai.packageName; 177 boolean hasPrivileges = 178 telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) == 179 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 180 if (!hasPrivileges) { 181 candidates.remove(i); 182 } 183 } 184 185 return candidates; 186 } 187 188 /** 189 * Returns the list of "default" carrier app candidates. 190 * 191 * These are the apps subject to the hiding/showing logic in 192 * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager, 193 * TelephonyManager, int)}, as well as the apps which should have default permissions granted, 194 * when a matching SIM is inserted. 195 * 196 * Whether or not the app is actually considered a default app depends on whether the app has 197 * carrier privileges as determined by the SIMs in the device. 198 */ 199 public static List<ApplicationInfo> getDefaultCarrierAppCandidates( 200 IPackageManager packageManager, int userId) { 201 String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray( 202 com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps); 203 return getDefaultCarrierAppCandidatesHelper(packageManager, userId, 204 systemCarrierAppsDisabledUntilUsed); 205 } 206 207 private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper( 208 IPackageManager packageManager, int userId, 209 String[] systemCarrierAppsDisabledUntilUsed) { 210 if (systemCarrierAppsDisabledUntilUsed == null 211 || systemCarrierAppsDisabledUntilUsed.length == 0) { 212 return null; 213 } 214 List<ApplicationInfo> apps = null; 215 try { 216 apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.length); 217 for (String packageName : systemCarrierAppsDisabledUntilUsed) { 218 ApplicationInfo ai = packageManager.getApplicationInfo(packageName, 219 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId); 220 if (ai == null) { 221 // No app found for packageName 222 continue; 223 } 224 if (!ai.isSystemApp()) { 225 continue; 226 } 227 apps.add(ai); 228 } 229 } catch (RemoteException e) { 230 Slog.w(TAG, "Could not reach PackageManager", e); 231 } 232 return apps; 233 } 234} 235