1 /* 2 * Copyright (C) 2020 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 17 package com.android.internal.telephony; 18 19 import android.annotation.Nullable; 20 import android.annotation.UserIdInt; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.pm.ApplicationInfo; 24 import android.content.pm.PackageManager; 25 import android.os.Build; 26 import android.os.CarrierAssociatedAppEntry; 27 import android.os.SystemConfigManager; 28 import android.os.UserHandle; 29 import android.permission.LegacyPermissionManager; 30 import android.provider.Settings; 31 import android.telephony.TelephonyManager; 32 import android.util.ArrayMap; 33 import android.util.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.telephony.util.TelephonyUtils; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Map; 41 import java.util.Set; 42 43 /** 44 * Utilities for handling carrier applications. 45 * @hide 46 */ 47 public final class CarrierAppUtils { 48 private static final String TAG = "CarrierAppUtils"; 49 50 private static final boolean DEBUG = false; // STOPSHIP if true 51 CarrierAppUtils()52 private CarrierAppUtils() {} 53 54 /** 55 * Handle preinstalled carrier apps which should be disabled until a matching SIM is inserted. 56 * 57 * Evaluates the list of applications in 58 * {@link SystemConfigManager#getDisabledUntilUsedPreinstalledCarrierApps()}. We want to disable 59 * each such application which is present on the system image until the user inserts a SIM 60 * which causes that application to gain carrier privilege (indicating a "match"), without 61 * interfering with the user if they opt to enable/disable the app explicitly. 62 * 63 * So, for each such app, we either disable until used IFF the app is not carrier privileged AND 64 * in the default state (e.g. not explicitly DISABLED/DISABLED_BY_USER/ENABLED), or we enable if 65 * the app is carrier privileged and in either the default state or DISABLED_UNTIL_USED. 66 * 67 * In addition, there is a list of carrier-associated applications in 68 * {@link SystemConfigManager#getDisabledUntilUsedPreinstalledCarrierAssociatedApps}. Each app 69 * in this list is associated with a carrier app. When the given carrier app is enabled/disabled 70 * per the above, the associated applications are enabled/disabled to match. 71 * 72 * When enabling a carrier app we also grant it default permissions. 73 * 74 * This method is idempotent and is safe to be called at any time; it should be called once at 75 * system startup prior to any application running, as well as any time the set of carrier 76 * privileged apps may have changed. 77 */ disableCarrierAppsUntilPrivileged(String callingPackage, TelephonyManager telephonyManager, @UserIdInt int userId, Context context)78 public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, 79 TelephonyManager telephonyManager, @UserIdInt int userId, Context context) { 80 if (DEBUG) { 81 Log.d(TAG, "disableCarrierAppsUntilPrivileged"); 82 } 83 SystemConfigManager config = context.getSystemService(SystemConfigManager.class); 84 Set<String> systemCarrierAppsDisabledUntilUsed = 85 config.getDisabledUntilUsedPreinstalledCarrierApps(); 86 Map<String, List<CarrierAssociatedAppEntry>> systemCarrierAssociatedAppsDisabledUntilUsed = 87 config.getDisabledUntilUsedPreinstalledCarrierAssociatedAppEntries(); 88 ContentResolver contentResolver = getContentResolverForUser(context, userId); 89 disableCarrierAppsUntilPrivileged(callingPackage, telephonyManager, contentResolver, 90 userId, systemCarrierAppsDisabledUntilUsed, 91 systemCarrierAssociatedAppsDisabledUntilUsed, context); 92 } 93 94 /** 95 * Like {@link #disableCarrierAppsUntilPrivileged(String, TelephonyManager, int, Context)}, 96 * but assumes that no carrier apps have carrier privileges. 97 * 98 * This prevents a potential race condition on first boot - since the app's default state is 99 * enabled, we will initially disable it when the telephony stack is first initialized as it has 100 * not yet read the carrier privilege rules. However, since telephony is initialized later on 101 * late in boot, the app being disabled may have already been started in response to certain 102 * broadcasts. The app will continue to run (briefly) after being disabled, before the Package 103 * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. 104 */ disableCarrierAppsUntilPrivileged(String callingPackage, @UserIdInt int userId, Context context)105 public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, 106 @UserIdInt int userId, Context context) { 107 if (DEBUG) { 108 Log.d(TAG, "disableCarrierAppsUntilPrivileged"); 109 } 110 SystemConfigManager config = context.getSystemService(SystemConfigManager.class); 111 Set<String> systemCarrierAppsDisabledUntilUsed = 112 config.getDisabledUntilUsedPreinstalledCarrierApps(); 113 114 Map<String, List<CarrierAssociatedAppEntry>> systemCarrierAssociatedAppsDisabledUntilUsed = 115 config.getDisabledUntilUsedPreinstalledCarrierAssociatedAppEntries(); 116 ContentResolver contentResolver = getContentResolverForUser(context, userId); 117 disableCarrierAppsUntilPrivileged(callingPackage, null /* telephonyManager */, 118 contentResolver, userId, systemCarrierAppsDisabledUntilUsed, 119 systemCarrierAssociatedAppsDisabledUntilUsed, context); 120 } 121 getContentResolverForUser(Context context, @UserIdInt int userId)122 private static ContentResolver getContentResolverForUser(Context context, 123 @UserIdInt int userId) { 124 Context userContext = context.createContextAsUser(UserHandle.of(userId), 0); 125 return userContext.getContentResolver(); 126 } 127 isUpdatedSystemApp(ApplicationInfo ai)128 private static boolean isUpdatedSystemApp(ApplicationInfo ai) { 129 return (ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; 130 } 131 132 /** 133 * Disable carrier apps until they are privileged 134 * Must be public b/c framework unit tests can't access package-private methods. 135 */ 136 // Must be public b/c framework unit tests can't access package-private methods. 137 @VisibleForTesting disableCarrierAppsUntilPrivileged(String callingPackage, @Nullable TelephonyManager telephonyManager, ContentResolver contentResolver, int userId, Set<String> systemCarrierAppsDisabledUntilUsed, Map<String, List<CarrierAssociatedAppEntry>> systemCarrierAssociatedAppsDisabledUntilUsed, Context context)138 public static void disableCarrierAppsUntilPrivileged(String callingPackage, 139 @Nullable TelephonyManager telephonyManager, ContentResolver contentResolver, 140 int userId, Set<String> systemCarrierAppsDisabledUntilUsed, 141 Map<String, List<CarrierAssociatedAppEntry>> 142 systemCarrierAssociatedAppsDisabledUntilUsed, Context context) { 143 PackageManager packageManager = context.getPackageManager(); 144 LegacyPermissionManager permissionManager = (LegacyPermissionManager) 145 context.getSystemService(Context.LEGACY_PERMISSION_SERVICE); 146 List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper( 147 userId, systemCarrierAppsDisabledUntilUsed, context); 148 if (candidates == null || candidates.isEmpty()) { 149 return; 150 } 151 152 Map<String, List<AssociatedAppInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper( 153 userId, systemCarrierAssociatedAppsDisabledUntilUsed, context); 154 155 List<String> enabledCarrierPackages = new ArrayList<>(); 156 int carrierAppsHandledSdk = 157 Settings.Secure.getIntForUser(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 158 0, contentResolver.getUserId()); 159 if (DEBUG) { 160 Log.i(TAG, "Last execution SDK: " + carrierAppsHandledSdk); 161 } 162 boolean hasRunEver = carrierAppsHandledSdk != 0; // SDKs < R used to just set 1 here 163 boolean hasRunForSdk = carrierAppsHandledSdk == Build.VERSION.SDK_INT; 164 165 try { 166 for (ApplicationInfo ai : candidates) { 167 String packageName = ai.packageName; 168 boolean hasPrivileges = telephonyManager != null 169 && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) 170 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 171 172 // add hiddenUntilInstalled flag for carrier apps and associated apps 173 packageManager.setSystemAppState( 174 packageName, PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN); 175 List<AssociatedAppInfo> associatedAppList = associatedApps.get(packageName); 176 if (associatedAppList != null) { 177 for (AssociatedAppInfo associatedApp : associatedAppList) { 178 packageManager.setSystemAppState(associatedApp.appInfo.packageName, 179 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN); 180 } 181 } 182 183 int enabledSetting = context.createContextAsUser(UserHandle.of(userId), 0) 184 .getPackageManager().getApplicationEnabledSetting(packageName); 185 if (hasPrivileges) { 186 // Only update enabled state for the app on /system. Once it has been 187 // updated we shouldn't touch it. 188 if (!isUpdatedSystemApp(ai) && enabledSetting 189 == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 190 || enabledSetting 191 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED 192 || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { 193 Log.i(TAG, "Update state (" + packageName + "): ENABLED for user " 194 + userId); 195 context.createContextAsUser(UserHandle.of(userId), 0) 196 .getPackageManager() 197 .setSystemAppState( 198 packageName, PackageManager.SYSTEM_APP_STATE_INSTALLED); 199 context.createPackageContextAsUser(callingPackage, 0, UserHandle.of(userId)) 200 .getPackageManager() 201 .setApplicationEnabledSetting( 202 packageName, 203 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 204 PackageManager.DONT_KILL_APP); 205 } 206 207 // Also enable any associated apps for this carrier app. 208 if (associatedAppList != null) { 209 for (AssociatedAppInfo associatedApp : associatedAppList) { 210 int associatedAppEnabledSetting = context 211 .createContextAsUser(UserHandle.of(userId), 0) 212 .getPackageManager() 213 .getApplicationEnabledSetting( 214 associatedApp.appInfo.packageName); 215 boolean associatedAppInstalled = (associatedApp.appInfo.flags 216 & ApplicationInfo.FLAG_INSTALLED) != 0; 217 if (DEBUG) { 218 Log.i(TAG, "(hasPrivileges) associated app " 219 + associatedApp.appInfo.packageName + ", enabled = " 220 + associatedAppEnabledSetting + ", installed = " 221 + associatedAppInstalled); 222 } 223 if (associatedAppEnabledSetting 224 == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 225 || associatedAppEnabledSetting 226 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED 227 || !associatedAppInstalled) { 228 Log.i(TAG, "Update associated state (" 229 + associatedApp.appInfo.packageName + "): ENABLED for user " 230 + userId); 231 context.createContextAsUser(UserHandle.of(userId), 0) 232 .getPackageManager() 233 .setSystemAppState(associatedApp.appInfo.packageName, 234 PackageManager.SYSTEM_APP_STATE_INSTALLED); 235 context.createPackageContextAsUser( 236 callingPackage, 0, UserHandle.of(userId)) 237 .getPackageManager() 238 .setApplicationEnabledSetting( 239 associatedApp.appInfo.packageName, 240 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 241 PackageManager.DONT_KILL_APP); 242 } 243 } 244 } 245 246 // Always re-grant default permissions to carrier apps w/ privileges. 247 enabledCarrierPackages.add(ai.packageName); 248 } else { // No carrier privileges 249 // Only update enabled state for the app on /system. Once it has been 250 // updated we shouldn't touch it. 251 if (!isUpdatedSystemApp(ai) && enabledSetting 252 == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 253 && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { 254 Log.i(TAG, "Update state (" + packageName 255 + "): DISABLED_UNTIL_USED for user " + userId); 256 context.createContextAsUser(UserHandle.of(userId), 0) 257 .getPackageManager() 258 .setSystemAppState( 259 packageName, PackageManager.SYSTEM_APP_STATE_UNINSTALLED); 260 } 261 262 // Associated apps are more brittle, because we can't rely on the distinction 263 // between "default" and "enabled". To account for this, we have two cases: 264 // 1. We've never run before, so we're fine to disable all associated apps. 265 // 2. We've run before, but not on this SDK version, so we will only operate on 266 // apps with addedInSdk in the range (lastHandledSdk, currentSdk]. 267 // Otherwise, don't touch the associated apps. 268 if (associatedAppList != null) { 269 for (AssociatedAppInfo associatedApp : associatedAppList) { 270 boolean allowDisable = !hasRunEver || (!hasRunForSdk 271 && associatedApp.addedInSdk 272 != CarrierAssociatedAppEntry.SDK_UNSPECIFIED 273 && associatedApp.addedInSdk > carrierAppsHandledSdk 274 && associatedApp.addedInSdk <= Build.VERSION.SDK_INT); 275 int associatedAppEnabledSetting = context 276 .createContextAsUser(UserHandle.of(userId), 0) 277 .getPackageManager() 278 .getApplicationEnabledSetting( 279 associatedApp.appInfo.packageName); 280 boolean associatedAppInstalled = (associatedApp.appInfo.flags 281 & ApplicationInfo.FLAG_INSTALLED) != 0; 282 if (DEBUG) { 283 Log.i(TAG, "(!hasPrivileges) associated app " 284 + associatedApp.appInfo.packageName + ", allowDisable = " 285 + allowDisable + ", addedInSdk = " 286 + associatedApp.addedInSdk + ", enabled = " 287 + associatedAppEnabledSetting + ", installed = " 288 + associatedAppInstalled); 289 } 290 if (allowDisable 291 && associatedAppEnabledSetting 292 == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 293 && associatedAppInstalled) { 294 Log.i(TAG, 295 "Update associated state (" 296 + associatedApp.appInfo.packageName 297 + "): DISABLED_UNTIL_USED for user " + userId); 298 context.createContextAsUser(UserHandle.of(userId), 0) 299 .getPackageManager() 300 .setSystemAppState(associatedApp.appInfo.packageName, 301 PackageManager.SYSTEM_APP_STATE_UNINSTALLED); 302 } 303 } 304 } 305 } 306 } 307 308 // Mark the execution so we do not disable apps again on this SDK version. 309 if (!hasRunEver || !hasRunForSdk) { 310 Settings.Secure.putIntForUser(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 311 Build.VERSION.SDK_INT, contentResolver.getUserId()); 312 } 313 314 if (!enabledCarrierPackages.isEmpty()) { 315 // Since we enabled at least one app, ensure we grant default permissions to those 316 // apps. 317 String[] packageNames = new String[enabledCarrierPackages.size()]; 318 enabledCarrierPackages.toArray(packageNames); 319 permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, 320 UserHandle.of(userId), TelephonyUtils.DIRECT_EXECUTOR, isSuccess -> { }); 321 } 322 } catch (PackageManager.NameNotFoundException e) { 323 Log.w(TAG, "Could not reach PackageManager", e); 324 } 325 } 326 327 /** 328 * Returns the list of "default" carrier apps. 329 * 330 * This is the subset of apps returned by 331 * {@link #getDefaultCarrierAppCandidates(int, Context)} which currently have carrier 332 * privileges per the SIM(s) inserted in the device. 333 */ getDefaultCarrierApps( TelephonyManager telephonyManager, int userId, Context context)334 public static List<ApplicationInfo> getDefaultCarrierApps( 335 TelephonyManager telephonyManager, int userId, Context context) { 336 // Get all system apps from the default list. 337 List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(userId, context); 338 if (candidates == null || candidates.isEmpty()) { 339 return null; 340 } 341 342 // Filter out apps without carrier privileges. 343 // Iterate from the end to avoid creating an Iterator object and because we will be removing 344 // elements from the list as we pass through it. 345 for (int i = candidates.size() - 1; i >= 0; i--) { 346 ApplicationInfo ai = candidates.get(i); 347 String packageName = ai.packageName; 348 boolean hasPrivileges = 349 telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) 350 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 351 if (!hasPrivileges) { 352 candidates.remove(i); 353 } 354 } 355 356 return candidates; 357 } 358 359 /** 360 * Returns the list of "default" carrier app candidates. 361 * 362 * These are the apps subject to the hiding/showing logic in 363 * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, TelephonyManager, int, 364 * Context)}, as well as the apps which should have default 365 * permissions granted, when a matching SIM is inserted. 366 * 367 * Whether or not the app is actually considered a default app depends on whether the app has 368 * carrier privileges as determined by the SIMs in the device. 369 */ getDefaultCarrierAppCandidates( int userId, Context context)370 public static List<ApplicationInfo> getDefaultCarrierAppCandidates( 371 int userId, Context context) { 372 Set<String> systemCarrierAppsDisabledUntilUsed = 373 context.getSystemService(SystemConfigManager.class) 374 .getDisabledUntilUsedPreinstalledCarrierApps(); 375 return getDefaultCarrierAppCandidatesHelper(userId, systemCarrierAppsDisabledUntilUsed, 376 context); 377 } 378 getDefaultCarrierAppCandidatesHelper( int userId, Set<String> systemCarrierAppsDisabledUntilUsed, Context context)379 private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper( 380 int userId, Set<String> systemCarrierAppsDisabledUntilUsed, Context context) { 381 if (systemCarrierAppsDisabledUntilUsed == null 382 || systemCarrierAppsDisabledUntilUsed.isEmpty()) { 383 return null; 384 } 385 386 List<ApplicationInfo> apps = new ArrayList<>(systemCarrierAppsDisabledUntilUsed.size()); 387 for (String packageName : systemCarrierAppsDisabledUntilUsed) { 388 ApplicationInfo ai = 389 getApplicationInfoIfSystemApp(userId, packageName, context); 390 if (ai != null) { 391 apps.add(ai); 392 } 393 } 394 return apps; 395 } 396 getDefaultCarrierAssociatedAppsHelper( int userId, Map<String, List<CarrierAssociatedAppEntry>> systemCarrierAssociatedAppsDisabledUntilUsed, Context context)397 private static Map<String, List<AssociatedAppInfo>> getDefaultCarrierAssociatedAppsHelper( 398 int userId, Map<String, List<CarrierAssociatedAppEntry>> 399 systemCarrierAssociatedAppsDisabledUntilUsed, Context context) { 400 int size = systemCarrierAssociatedAppsDisabledUntilUsed.size(); 401 Map<String, List<AssociatedAppInfo>> associatedApps = new ArrayMap<>(size); 402 for (Map.Entry<String, List<CarrierAssociatedAppEntry>> entry 403 : systemCarrierAssociatedAppsDisabledUntilUsed.entrySet()) { 404 String carrierAppPackage = entry.getKey(); 405 List<CarrierAssociatedAppEntry> associatedAppPackages = entry.getValue(); 406 for (int j = 0; j < associatedAppPackages.size(); j++) { 407 CarrierAssociatedAppEntry associatedApp = associatedAppPackages.get(j); 408 ApplicationInfo ai = 409 getApplicationInfoIfSystemApp(userId, associatedApp.packageName, context); 410 // Only update enabled state for the app on /system. Once it has been updated we 411 // shouldn't touch it. 412 if (ai != null && !isUpdatedSystemApp(ai)) { 413 List<AssociatedAppInfo> appList = associatedApps.get(carrierAppPackage); 414 if (appList == null) { 415 appList = new ArrayList<>(); 416 associatedApps.put(carrierAppPackage, appList); 417 } 418 appList.add(new AssociatedAppInfo(ai, associatedApp.addedInSdk)); 419 } 420 } 421 } 422 return associatedApps; 423 } 424 425 @Nullable getApplicationInfoIfSystemApp( int userId, String packageName, Context context)426 private static ApplicationInfo getApplicationInfoIfSystemApp( 427 int userId, String packageName, Context context) { 428 try { 429 ApplicationInfo ai = context.createContextAsUser(UserHandle.of(userId), 0) 430 .getPackageManager() 431 .getApplicationInfo(packageName, 432 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS 433 | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS 434 | PackageManager.MATCH_SYSTEM_ONLY); 435 if (ai != null) { 436 return ai; 437 } 438 } catch (PackageManager.NameNotFoundException e) { 439 Log.w(TAG, "Could not reach PackageManager", e); 440 } 441 return null; 442 } 443 444 private static final class AssociatedAppInfo { 445 public final ApplicationInfo appInfo; 446 // Might be CarrierAssociatedAppEntry.SDK_UNSPECIFIED. 447 public final int addedInSdk; 448 AssociatedAppInfo(ApplicationInfo appInfo, int addedInSdk)449 AssociatedAppInfo(ApplicationInfo appInfo, int addedInSdk) { 450 this.appInfo = appInfo; 451 this.addedInSdk = addedInSdk; 452 } 453 } 454 } 455