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