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 17 package com.android.phone; 18 19 import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION; 20 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.KEY_CONFIG_BUNDLE; 21 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR; 22 import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.AppOpsManager; 27 import android.app.compat.CompatChanges; 28 import android.content.BroadcastReceiver; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.ServiceConnection; 34 import android.content.SharedPreferences; 35 import android.content.pm.PackageInfo; 36 import android.content.pm.PackageManager; 37 import android.os.Binder; 38 import android.os.Build; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.HandlerExecutor; 42 import android.os.IBinder; 43 import android.os.Looper; 44 import android.os.Message; 45 import android.os.PermissionEnforcer; 46 import android.os.PersistableBundle; 47 import android.os.Process; 48 import android.os.RemoteException; 49 import android.os.ResultReceiver; 50 import android.os.SystemProperties; 51 import android.os.UserHandle; 52 import android.preference.PreferenceManager; 53 import android.service.carrier.CarrierIdentifier; 54 import android.service.carrier.CarrierService; 55 import android.service.carrier.ICarrierService; 56 import android.telephony.AnomalyReporter; 57 import android.telephony.CarrierConfigManager; 58 import android.telephony.SubscriptionManager; 59 import android.telephony.TelephonyFrameworkInitializer; 60 import android.telephony.TelephonyManager; 61 import android.telephony.TelephonyRegistryManager; 62 import android.text.TextUtils; 63 import android.util.ArraySet; 64 import android.util.LocalLog; 65 import android.util.Log; 66 67 import com.android.internal.annotations.VisibleForTesting; 68 import com.android.internal.telephony.ICarrierConfigLoader; 69 import com.android.internal.telephony.IccCardConstants; 70 import com.android.internal.telephony.Phone; 71 import com.android.internal.telephony.PhoneConfigurationManager; 72 import com.android.internal.telephony.PhoneFactory; 73 import com.android.internal.telephony.TelephonyPermissions; 74 import com.android.internal.telephony.flags.FeatureFlags; 75 import com.android.internal.telephony.subscription.SubscriptionManagerService; 76 import com.android.internal.telephony.util.ArrayUtils; 77 import com.android.internal.telephony.util.TelephonyUtils; 78 import com.android.internal.util.IndentingPrintWriter; 79 80 import java.io.File; 81 import java.io.FileDescriptor; 82 import java.io.FileInputStream; 83 import java.io.FileNotFoundException; 84 import java.io.FileOutputStream; 85 import java.io.FilenameFilter; 86 import java.io.IOException; 87 import java.io.PrintWriter; 88 import java.nio.file.Files; 89 import java.nio.file.Paths; 90 import java.nio.file.attribute.BasicFileAttributes; 91 import java.text.SimpleDateFormat; 92 import java.util.ArrayList; 93 import java.util.Arrays; 94 import java.util.Collections; 95 import java.util.List; 96 import java.util.Locale; 97 import java.util.Objects; 98 import java.util.Set; 99 import java.util.UUID; 100 import java.util.stream.Collectors; 101 import java.util.stream.Stream; 102 103 /** 104 * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays. 105 */ 106 public class CarrierConfigLoader extends ICarrierConfigLoader.Stub { 107 private static final String LOG_TAG = "CarrierConfigLoader"; 108 109 private static final SimpleDateFormat TIME_FORMAT = 110 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); 111 112 // Package name for platform carrier config app, bundled with system image. 113 @NonNull private final String mPlatformCarrierConfigPackage; 114 115 /** The singleton instance. */ 116 @Nullable private static CarrierConfigLoader sInstance; 117 // The context for phone app, passed from PhoneGlobals. 118 @NonNull private Context mContext; 119 120 // All the states below (array indexed by phoneId) are non-null. But the member of the array 121 // is nullable, when e.g. the config for the phone is not loaded yet 122 // Carrier configs from default app, indexed by phoneID. 123 @NonNull private PersistableBundle[] mConfigFromDefaultApp; 124 // Carrier configs from privileged carrier config app, indexed by phoneID. 125 @NonNull private PersistableBundle[] mConfigFromCarrierApp; 126 // Persistent Carrier configs that are provided via the override test API, indexed by phone ID. 127 @NonNull private PersistableBundle[] mPersistentOverrideConfigs; 128 // Carrier configs that are provided via the override test API, indexed by phone ID. 129 @NonNull private PersistableBundle[] mOverrideConfigs; 130 // Carrier configs to override code default when there is no SIM inserted 131 @NonNull private PersistableBundle mNoSimConfig; 132 // Service connection for binding to config app. 133 @NonNull private CarrierServiceConnection[] mServiceConnection; 134 // Service connection for binding to carrier config app for no SIM config. 135 @NonNull private CarrierServiceConnection[] mServiceConnectionForNoSimConfig; 136 // Whether we are bound to a service for each phone 137 @NonNull private boolean[] mServiceBound; 138 // Whether we are bound to a service for no SIM config 139 @NonNull private boolean[] mServiceBoundForNoSimConfig; 140 // Whether we have sent config change broadcast for each phone id. 141 @NonNull private boolean[] mHasSentConfigChange; 142 // Whether the broadcast was sent from EVENT_SYSTEM_UNLOCKED, to track rebroadcasts 143 @NonNull private boolean[] mFromSystemUnlocked; 144 // CarrierService change monitoring 145 @NonNull private CarrierServiceChangeCallback[] mCarrierServiceChangeCallbacks; 146 147 // Broadcast receiver for system events 148 @NonNull 149 private final BroadcastReceiver mSystemBroadcastReceiver = new ConfigLoaderBroadcastReceiver(); 150 @NonNull private final LocalLog mCarrierConfigLoadingLog = new LocalLog(256); 151 // Number of phone instances (active modem count) 152 private int mNumPhones; 153 154 155 // Message codes; see mHandler below. 156 // Request from UiccController when SIM becomes absent or error. 157 private static final int EVENT_CLEAR_CONFIG = 0; 158 // Has connected to default app. 159 private static final int EVENT_CONNECTED_TO_DEFAULT = 3; 160 // Has connected to carrier app. 161 private static final int EVENT_CONNECTED_TO_CARRIER = 4; 162 // Config has been loaded from default app (or cache). 163 private static final int EVENT_FETCH_DEFAULT_DONE = 5; 164 // Config has been loaded from carrier app (or cache). 165 private static final int EVENT_FETCH_CARRIER_DONE = 6; 166 // Attempt to fetch from default app or read from XML. 167 private static final int EVENT_DO_FETCH_DEFAULT = 7; 168 // Attempt to fetch from carrier app or read from XML. 169 private static final int EVENT_DO_FETCH_CARRIER = 8; 170 // A package has been installed, uninstalled, or updated. 171 private static final int EVENT_PACKAGE_CHANGED = 9; 172 // Bind timed out for the default app. 173 private static final int EVENT_BIND_DEFAULT_TIMEOUT = 10; 174 // Bind timed out for a carrier app. 175 private static final int EVENT_BIND_CARRIER_TIMEOUT = 11; 176 // Check if the system fingerprint has changed. 177 private static final int EVENT_CHECK_SYSTEM_UPDATE = 12; 178 // Rerun carrier config binding after system is unlocked. 179 private static final int EVENT_SYSTEM_UNLOCKED = 13; 180 // Fetching config timed out from the default app. 181 private static final int EVENT_FETCH_DEFAULT_TIMEOUT = 14; 182 // Fetching config timed out from a carrier app. 183 private static final int EVENT_FETCH_CARRIER_TIMEOUT = 15; 184 // SubscriptionManagerService has finished updating the sub for the carrier config. 185 private static final int EVENT_SUBSCRIPTION_INFO_UPDATED = 16; 186 // Multi-SIM config changed. 187 private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 17; 188 // Attempt to fetch from default app or read from XML for no SIM case. 189 private static final int EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG = 18; 190 // No SIM config has been loaded from default app (or cache). 191 private static final int EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE = 19; 192 // Has connected to default app for no SIM config. 193 private static final int EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG = 20; 194 // Bind timed out for the default app when trying to fetch no SIM config. 195 private static final int EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT = 21; 196 // Fetching config timed out from the default app for no SIM config. 197 private static final int EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT = 22; 198 // NOTE: any new EVENT_* values must be added to method eventToString(). 199 200 private static final int BIND_TIMEOUT_MILLIS = 30000; 201 202 // Keys used for saving and restoring config bundle from file. 203 private static final String KEY_VERSION = "__carrier_config_package_version__"; 204 205 private static final String OVERRIDE_PACKAGE_ADDITION = "-override"; 206 207 // SharedPreferences key for last known build fingerprint. 208 private static final String KEY_FINGERPRINT = "build_fingerprint"; 209 210 // Argument for #dump that indicates we should also call the default and specified carrier 211 // service's #dump method. In multi-SIM devices, it's possible that carrier A is on SIM 1 and 212 // carrier B is on SIM 2, in which case we should not dump carrier B's service when carrier A 213 // requested the dump. 214 private static final String DUMP_ARG_REQUESTING_PACKAGE = "--requesting-package"; 215 216 // Configs that should always be included when clients calls getConfig[ForSubId] with specified 217 // keys (even configs are not explicitly specified). Those configs have special purpose for the 218 // carrier config APIs to work correctly. 219 private static final String[] CONFIG_SUBSET_METADATA_KEYS = new String[] { 220 CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING, 221 CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL 222 }; 223 224 // UUID to report anomaly when config changed reported with subId that map to invalid phone 225 private static final String UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE = 226 "d81cef11-c2f1-4d76-955d-7f50e8590c48"; 227 228 // Handler to process various events. 229 // 230 // For each phoneId, the event sequence should be: 231 // fetch default, connected to default, fetch default (async), fetch default done, 232 // fetch carrier, connected to carrier, fetch carrier (async), fetch carrier done. 233 // 234 // If there is a saved config file for either the default app or the carrier app, we skip 235 // binding to the app and go straight from fetch to loaded. 236 // 237 // At any time, at most one connection is active. If events are not in this order, previous 238 // connection will be unbound, so only latest event takes effect. 239 // 240 // We broadcast ACTION_CARRIER_CONFIG_CHANGED after: 241 // 1. loading from carrier app (even if read from a file) 242 // 2. loading from default app if there is no carrier app (even if read from a file) 243 // 3. clearing config (e.g. due to sim removal) 244 // 4. encountering bind or IPC error 245 private class ConfigHandler extends Handler { ConfigHandler(@onNull Looper looper)246 ConfigHandler(@NonNull Looper looper) { 247 super(looper); 248 } 249 250 @Override handleMessage(@onNull Message msg)251 public void handleMessage(@NonNull Message msg) { 252 final int phoneId = msg.arg1; 253 logd(eventToString(msg.what) + " phoneId: " + phoneId); 254 if (!SubscriptionManager.isValidPhoneId(phoneId) 255 && msg.what != EVENT_MULTI_SIM_CONFIG_CHANGED) { 256 return; 257 } 258 switch (msg.what) { 259 case EVENT_CLEAR_CONFIG: { 260 clearConfigForPhone(phoneId, true); 261 break; 262 } 263 264 case EVENT_SYSTEM_UNLOCKED: { 265 for (int i = 0; i < mNumPhones; ++i) { 266 // When the user unlocks the device, send the broadcast again (with a 267 // rebroadcast extra) if we have sent it before unlock. This will avoid 268 // trying to load the carrier config when the SIM is still loading when the 269 // unlock happens. 270 if (mHasSentConfigChange[i]) { 271 logdWithLocalLog("System unlocked"); 272 mFromSystemUnlocked[i] = true; 273 updateConfigForPhoneId(i); 274 } 275 } 276 break; 277 } 278 279 case EVENT_PACKAGE_CHANGED: { 280 final String carrierPackageName = (String) msg.obj; 281 // Always clear up the cache and re-load config from scratch since the carrier 282 // service change is reliable and specific to the phoneId now. 283 clearCachedConfigForPackage(carrierPackageName); 284 logdWithLocalLog("Package changed: " + carrierPackageName 285 + ", phone=" + phoneId); 286 updateConfigForPhoneId(phoneId); 287 break; 288 } 289 290 case EVENT_DO_FETCH_DEFAULT: { 291 // Clear in-memory cache for carrier app config, so when carrier app gets 292 // uninstalled, no stale config is left. 293 if (mConfigFromCarrierApp[phoneId] != null 294 && getCarrierPackageForPhoneId(phoneId) == null) { 295 mConfigFromCarrierApp[phoneId] = null; 296 } 297 // Restore persistent override values. 298 PersistableBundle config = restoreConfigFromXml( 299 mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId); 300 if (config != null) { 301 mPersistentOverrideConfigs[phoneId] = config; 302 } 303 304 config = restoreConfigFromXml(mPlatformCarrierConfigPackage, "", phoneId); 305 if (config != null) { 306 mConfigFromDefaultApp[phoneId] = config; 307 Message newMsg = obtainMessage(EVENT_FETCH_DEFAULT_DONE, phoneId, -1); 308 newMsg.getData().putBoolean("loaded_from_xml", true); 309 mHandler.sendMessage(newMsg); 310 } else { 311 // No cached config, so fetch it from the default app. 312 if (bindToConfigPackage( 313 mPlatformCarrierConfigPackage, 314 phoneId, 315 EVENT_CONNECTED_TO_DEFAULT)) { 316 sendMessageDelayed( 317 obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1 /*arg2*/, 318 getMessageToken(phoneId)), 319 BIND_TIMEOUT_MILLIS); 320 } else { 321 // Put a stub bundle in place so that the rest of the logic continues 322 // smoothly. 323 mConfigFromDefaultApp[phoneId] = new PersistableBundle(); 324 // Send broadcast if bind fails. 325 updateSubscriptionDatabase(phoneId); 326 // TODO: We *must* call unbindService even if bindService returns false. 327 // (And possibly if SecurityException was thrown.) 328 loge("binding to default app: " 329 + mPlatformCarrierConfigPackage + " fails"); 330 } 331 } 332 break; 333 } 334 335 case EVENT_CONNECTED_TO_DEFAULT: { 336 removeMessages(EVENT_BIND_DEFAULT_TIMEOUT, getMessageToken(phoneId)); 337 final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj; 338 // If new service connection has been created, unbind. 339 if (mServiceConnection[phoneId] != conn || conn.service == null) { 340 unbindIfBound(mContext, conn, phoneId); 341 break; 342 } 343 final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId); 344 // ResultReceiver callback will execute in this Handler's thread. 345 final ResultReceiver resultReceiver = 346 new ResultReceiver(this) { 347 @Override 348 public void onReceiveResult(int resultCode, Bundle resultData) { 349 unbindIfBound(mContext, conn, phoneId); 350 removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT, 351 getMessageToken(phoneId)); 352 // If new service connection has been created, this is stale. 353 if (mServiceConnection[phoneId] != conn) { 354 loge("Received response for stale request."); 355 return; 356 } 357 if (resultCode == RESULT_ERROR || resultData == null) { 358 // On error, abort config fetching. 359 loge("Failed to get carrier config"); 360 updateSubscriptionDatabase(phoneId); 361 return; 362 } 363 PersistableBundle config = 364 resultData.getParcelable(KEY_CONFIG_BUNDLE); 365 saveConfigToXml(mPlatformCarrierConfigPackage, "", phoneId, 366 carrierId, config); 367 mConfigFromDefaultApp[phoneId] = config; 368 sendMessage( 369 obtainMessage( 370 EVENT_FETCH_DEFAULT_DONE, phoneId, -1)); 371 } 372 }; 373 // Now fetch the config asynchronously from the ICarrierService. 374 try { 375 ICarrierService carrierService = 376 ICarrierService.Stub.asInterface(conn.service); 377 carrierService.getCarrierConfig(phoneId, carrierId, resultReceiver); 378 logdWithLocalLog("Fetch config for default app: " 379 + mPlatformCarrierConfigPackage 380 + ", carrierId=" + carrierId.getSpecificCarrierId()); 381 } catch (RemoteException e) { 382 loge("Failed to get carrier config from default app: " + 383 mPlatformCarrierConfigPackage + " err: " + e); 384 unbindIfBound(mContext, conn, phoneId); 385 break; // So we don't set a timeout. 386 } 387 sendMessageDelayed( 388 obtainMessage(EVENT_FETCH_DEFAULT_TIMEOUT, phoneId, -1 /*arg2*/, 389 getMessageToken(phoneId)), 390 BIND_TIMEOUT_MILLIS); 391 break; 392 } 393 394 case EVENT_BIND_DEFAULT_TIMEOUT: 395 case EVENT_FETCH_DEFAULT_TIMEOUT: { 396 loge("Bind/fetch time out from " + mPlatformCarrierConfigPackage); 397 removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT, getMessageToken(phoneId)); 398 // If we attempted to bind to the app, but the service connection is null due to 399 // the race condition that clear config event happens before bind/fetch complete 400 // then config was cleared while we were waiting and we should not continue. 401 if (mServiceConnection[phoneId] != null) { 402 // If a ResponseReceiver callback is in the queue when this happens, we will 403 // unbind twice and throw an exception. 404 unbindIfBound(mContext, mServiceConnection[phoneId], phoneId); 405 broadcastConfigChangedIntent(phoneId); 406 } 407 // Put a stub bundle in place so that the rest of the logic continues smoothly. 408 mConfigFromDefaultApp[phoneId] = new PersistableBundle(); 409 updateSubscriptionDatabase(phoneId); 410 break; 411 } 412 413 case EVENT_FETCH_DEFAULT_DONE: { 414 // If we attempted to bind to the app, but the service connection is null, then 415 // config was cleared while we were waiting and we should not continue. 416 if (!msg.getData().getBoolean("loaded_from_xml", false) 417 && mServiceConnection[phoneId] == null) { 418 break; 419 } 420 final String carrierPackageName = getCarrierPackageForPhoneId(phoneId); 421 if (carrierPackageName != null) { 422 logd("Found carrier config app: " + carrierPackageName); 423 sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1)); 424 } else { 425 updateSubscriptionDatabase(phoneId); 426 } 427 break; 428 } 429 430 case EVENT_DO_FETCH_CARRIER: { 431 final String carrierPackageName = getCarrierPackageForPhoneId(phoneId); 432 final PersistableBundle config = 433 restoreConfigFromXml(carrierPackageName, "", phoneId); 434 if (config != null) { 435 mConfigFromCarrierApp[phoneId] = config; 436 Message newMsg = obtainMessage(EVENT_FETCH_CARRIER_DONE, phoneId, -1); 437 newMsg.getData().putBoolean("loaded_from_xml", true); 438 sendMessage(newMsg); 439 } else { 440 // No cached config, so fetch it from a carrier app. 441 if (carrierPackageName != null && bindToConfigPackage(carrierPackageName, 442 phoneId, EVENT_CONNECTED_TO_CARRIER)) { 443 sendMessageDelayed( 444 obtainMessage(EVENT_BIND_CARRIER_TIMEOUT, phoneId, -1 /*arg2*/, 445 getMessageToken(phoneId)), 446 BIND_TIMEOUT_MILLIS); 447 } else { 448 // Put a stub bundle in place so that the rest of the logic continues 449 // smoothly. 450 mConfigFromCarrierApp[phoneId] = new PersistableBundle(); 451 // Send broadcast if bind fails. 452 broadcastConfigChangedIntent(phoneId); 453 loge("Bind to carrier app: " + carrierPackageName + " fails"); 454 updateSubscriptionDatabase(phoneId); 455 } 456 } 457 break; 458 } 459 460 case EVENT_CONNECTED_TO_CARRIER: { 461 removeMessages(EVENT_BIND_CARRIER_TIMEOUT, getMessageToken(phoneId)); 462 final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj; 463 // If new service connection has been created, unbind. 464 if (mServiceConnection[phoneId] != conn || conn.service == null) { 465 unbindIfBound(mContext, conn, phoneId); 466 break; 467 } 468 final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId); 469 // ResultReceiver callback will execute in this Handler's thread. 470 final ResultReceiver resultReceiver = 471 new ResultReceiver(this) { 472 @Override 473 public void onReceiveResult(int resultCode, Bundle resultData) { 474 unbindIfBound(mContext, conn, phoneId); 475 removeMessages(EVENT_FETCH_CARRIER_TIMEOUT, 476 getMessageToken(phoneId)); 477 // If new service connection has been created, this is stale. 478 if (mServiceConnection[phoneId] != conn) { 479 loge("Received response for stale request."); 480 return; 481 } 482 if (resultCode == RESULT_ERROR || resultData == null) { 483 // On error, abort config fetching. 484 loge("Failed to get carrier config from carrier app: " 485 + getCarrierPackageForPhoneId(phoneId)); 486 broadcastConfigChangedIntent(phoneId); 487 updateSubscriptionDatabase(phoneId); 488 return; 489 } 490 PersistableBundle config = 491 resultData.getParcelable(KEY_CONFIG_BUNDLE); 492 saveConfigToXml(getCarrierPackageForPhoneId(phoneId), "", 493 phoneId, carrierId, config); 494 if (config != null) { 495 mConfigFromCarrierApp[phoneId] = config; 496 } else { 497 logdWithLocalLog("Config from carrier app is null " 498 + "for phoneId " + phoneId); 499 // Put a stub bundle in place so that the rest of the logic 500 // continues smoothly. 501 mConfigFromCarrierApp[phoneId] = new PersistableBundle(); 502 } 503 sendMessage( 504 obtainMessage( 505 EVENT_FETCH_CARRIER_DONE, phoneId, -1)); 506 } 507 }; 508 // Now fetch the config asynchronously from the ICarrierService. 509 try { 510 ICarrierService carrierService = 511 ICarrierService.Stub.asInterface(conn.service); 512 carrierService.getCarrierConfig(phoneId, carrierId, resultReceiver); 513 logdWithLocalLog("Fetch config for carrier app: " 514 + getCarrierPackageForPhoneId(phoneId) 515 + ", carrierId=" + carrierId.getSpecificCarrierId()); 516 } catch (RemoteException e) { 517 loge("Failed to get carrier config: " + e); 518 unbindIfBound(mContext, conn, phoneId); 519 break; // So we don't set a timeout. 520 } 521 sendMessageDelayed( 522 obtainMessage(EVENT_FETCH_CARRIER_TIMEOUT, phoneId, -1 /*arg2*/, 523 getMessageToken(phoneId)), 524 BIND_TIMEOUT_MILLIS); 525 break; 526 } 527 528 case EVENT_BIND_CARRIER_TIMEOUT: 529 case EVENT_FETCH_CARRIER_TIMEOUT: { 530 loge("Bind/fetch from carrier app timeout, package=" 531 + getCarrierPackageForPhoneId(phoneId)); 532 removeMessages(EVENT_FETCH_CARRIER_TIMEOUT, getMessageToken(phoneId)); 533 // If we attempted to bind to the app, but the service connection is null due to 534 // the race condition that clear config event happens before bind/fetch complete 535 // then config was cleared while we were waiting and we should not continue. 536 if (mServiceConnection[phoneId] != null) { 537 // If a ResponseReceiver callback is in the queue when this happens, we will 538 // unbind twice and throw an exception. 539 unbindIfBound(mContext, mServiceConnection[phoneId], phoneId); 540 broadcastConfigChangedIntent(phoneId); 541 } 542 // Put a stub bundle in place so that the rest of the logic continues smoothly. 543 mConfigFromCarrierApp[phoneId] = new PersistableBundle(); 544 updateSubscriptionDatabase(phoneId); 545 break; 546 } 547 case EVENT_FETCH_CARRIER_DONE: { 548 // If we attempted to bind to the app, but the service connection is null, then 549 // config was cleared while we were waiting and we should not continue. 550 if (!msg.getData().getBoolean("loaded_from_xml", false) 551 && mServiceConnection[phoneId] == null) { 552 break; 553 } 554 updateSubscriptionDatabase(phoneId); 555 break; 556 } 557 558 case EVENT_CHECK_SYSTEM_UPDATE: { 559 SharedPreferences sharedPrefs = 560 PreferenceManager.getDefaultSharedPreferences(mContext); 561 final String lastFingerprint = sharedPrefs.getString(KEY_FINGERPRINT, null); 562 if (!Build.FINGERPRINT.equals(lastFingerprint)) { 563 logd( 564 "Build fingerprint changed. old: " 565 + lastFingerprint 566 + " new: " 567 + Build.FINGERPRINT); 568 clearCachedConfigForPackage(null); 569 sharedPrefs 570 .edit() 571 .putString(KEY_FINGERPRINT, Build.FINGERPRINT) 572 .apply(); 573 } 574 break; 575 } 576 577 case EVENT_SUBSCRIPTION_INFO_UPDATED: 578 broadcastConfigChangedIntent(phoneId); 579 break; 580 case EVENT_MULTI_SIM_CONFIG_CHANGED: 581 onMultiSimConfigChanged(); 582 break; 583 584 case EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG: { 585 PersistableBundle config = 586 restoreNoSimConfigFromXml(mPlatformCarrierConfigPackage); 587 588 if (config != null) { 589 mNoSimConfig = config; 590 sendMessage( 591 obtainMessage( 592 EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE, 593 phoneId, -1)); 594 } else { 595 // No cached config, so fetch it from the default app. 596 if (bindToConfigPackage( 597 mPlatformCarrierConfigPackage, 598 phoneId, 599 EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG)) { 600 sendMessageDelayed( 601 obtainMessage( 602 EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT, 603 phoneId, -1), BIND_TIMEOUT_MILLIS); 604 } else { 605 broadcastConfigChangedIntent(phoneId, false); 606 // TODO: We *must* call unbindService even if bindService returns false. 607 // (And possibly if SecurityException was thrown.) 608 loge("binding to default app to fetch no SIM config: " 609 + mPlatformCarrierConfigPackage + " fails"); 610 } 611 } 612 break; 613 } 614 615 case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE: { 616 broadcastConfigChangedIntent(phoneId, false); 617 break; 618 } 619 620 case EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT: 621 case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT: { 622 loge("Bind/fetch time out for no SIM config from " 623 + mPlatformCarrierConfigPackage); 624 removeMessages(EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT); 625 // If we attempted to bind to the app, but the service connection is null due to 626 // the race condition that clear config event happens before bind/fetch complete 627 // then config was cleared while we were waiting and we should not continue. 628 if (mServiceConnectionForNoSimConfig[phoneId] != null) { 629 // If a ResponseReceiver callback is in the queue when this happens, we will 630 // unbind twice and throw an exception. 631 unbindIfBoundForNoSimConfig(mContext, 632 mServiceConnectionForNoSimConfig[phoneId], phoneId); 633 } 634 broadcastConfigChangedIntent(phoneId, false); 635 break; 636 } 637 638 case EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG: { 639 removeMessages(EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT); 640 final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj; 641 // If new service connection has been created, unbind. 642 if (mServiceConnectionForNoSimConfig[phoneId] != conn || conn.service == null) { 643 unbindIfBoundForNoSimConfig(mContext, conn, phoneId); 644 break; 645 } 646 647 // ResultReceiver callback will execute in this Handler's thread. 648 final ResultReceiver resultReceiver = 649 new ResultReceiver(this) { 650 @Override 651 public void onReceiveResult(int resultCode, Bundle resultData) { 652 unbindIfBoundForNoSimConfig(mContext, conn, phoneId); 653 // If new service connection has been created, this is stale. 654 if (mServiceConnectionForNoSimConfig[phoneId] != conn) { 655 loge("Received response for stale request."); 656 return; 657 } 658 removeMessages(EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT); 659 if (resultCode == RESULT_ERROR || resultData == null) { 660 // On error, abort config fetching. 661 loge("Failed to get no SIM carrier config"); 662 return; 663 } 664 PersistableBundle config = 665 resultData.getParcelable(KEY_CONFIG_BUNDLE); 666 saveNoSimConfigToXml(mPlatformCarrierConfigPackage, config); 667 mNoSimConfig = config; 668 sendMessage( 669 obtainMessage( 670 EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE, 671 phoneId, -1)); 672 } 673 }; 674 // Now fetch the config asynchronously from the ICarrierService. 675 try { 676 ICarrierService carrierService = 677 ICarrierService.Stub.asInterface(conn.service); 678 carrierService.getCarrierConfig(phoneId, null, resultReceiver); 679 logdWithLocalLog("Fetch no sim config from default app: " 680 + mPlatformCarrierConfigPackage); 681 } catch (RemoteException e) { 682 loge("Failed to get no sim carrier config from default app: " + 683 mPlatformCarrierConfigPackage + " err: " + e); 684 unbindIfBoundForNoSimConfig(mContext, conn, phoneId); 685 break; // So we don't set a timeout. 686 } 687 sendMessageDelayed( 688 obtainMessage( 689 EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT, 690 phoneId, -1), BIND_TIMEOUT_MILLIS); 691 break; 692 } 693 } 694 } 695 } 696 697 @NonNull private final Handler mHandler; 698 699 @NonNull private final FeatureFlags mFeatureFlags; 700 701 @NonNull private final PackageManager mPackageManager; 702 private final int mVendorApiLevel; 703 704 /** 705 * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast 706 * receiver for relevant events. 707 */ 708 @VisibleForTesting CarrierConfigLoader(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags)709 /* package */ CarrierConfigLoader(@NonNull Context context, @NonNull Looper looper, 710 @NonNull FeatureFlags featureFlags) { 711 super(PermissionEnforcer.fromContext(context)); 712 mContext = context; 713 mPlatformCarrierConfigPackage = 714 mContext.getString(R.string.platform_carrier_config_package); 715 mHandler = new ConfigHandler(looper); 716 717 IntentFilter systemEventsFilter = new IntentFilter(); 718 systemEventsFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 719 context.registerReceiver(mSystemBroadcastReceiver, systemEventsFilter); 720 721 mNumPhones = TelephonyManager.from(context).getActiveModemCount(); 722 mConfigFromDefaultApp = new PersistableBundle[mNumPhones]; 723 mConfigFromCarrierApp = new PersistableBundle[mNumPhones]; 724 mPersistentOverrideConfigs = new PersistableBundle[mNumPhones]; 725 mOverrideConfigs = new PersistableBundle[mNumPhones]; 726 mNoSimConfig = new PersistableBundle(); 727 mServiceConnection = new CarrierServiceConnection[mNumPhones]; 728 mServiceBound = new boolean[mNumPhones]; 729 mHasSentConfigChange = new boolean[mNumPhones]; 730 mFromSystemUnlocked = new boolean[mNumPhones]; 731 mServiceConnectionForNoSimConfig = new CarrierServiceConnection[mNumPhones]; 732 mServiceBoundForNoSimConfig = new boolean[mNumPhones]; 733 mCarrierServiceChangeCallbacks = new CarrierServiceChangeCallback[mNumPhones]; 734 for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { 735 mCarrierServiceChangeCallbacks[phoneId] = new CarrierServiceChangeCallback(phoneId); 736 TelephonyManager.from(context).registerCarrierPrivilegesCallback(phoneId, 737 new HandlerExecutor(mHandler), mCarrierServiceChangeCallbacks[phoneId]); 738 } 739 mFeatureFlags = featureFlags; 740 mPackageManager = context.getPackageManager(); 741 mVendorApiLevel = SystemProperties.getInt( 742 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); 743 logd("CarrierConfigLoader has started"); 744 745 PhoneConfigurationManager.registerForMultiSimConfigChange( 746 mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); 747 748 mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE); 749 } 750 751 /** 752 * Initialize the singleton CarrierConfigLoader instance. 753 * 754 * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}. 755 */ 756 @NonNull init(@onNull Context context, @NonNull FeatureFlags featureFlags)757 /* package */ static CarrierConfigLoader init(@NonNull Context context, 758 @NonNull FeatureFlags featureFlags) { 759 synchronized (CarrierConfigLoader.class) { 760 if (sInstance == null) { 761 sInstance = new CarrierConfigLoader(context, Looper.myLooper(), featureFlags); 762 // Make this service available through ServiceManager. 763 TelephonyFrameworkInitializer.getTelephonyServiceManager() 764 .getCarrierConfigServiceRegisterer().register(sInstance); 765 } else { 766 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); 767 } 768 return sInstance; 769 } 770 } 771 772 @VisibleForTesting clearConfigForPhone(int phoneId, boolean fetchNoSimConfig)773 /* package */ void clearConfigForPhone(int phoneId, boolean fetchNoSimConfig) { 774 /* Ignore clear configuration request if device is being shutdown. */ 775 Phone phone = PhoneFactory.getPhone(phoneId); 776 if (phone != null) { 777 if (phone.isShuttingDown()) { 778 return; 779 } 780 } 781 782 if (mConfigFromDefaultApp.length <= phoneId) { 783 Log.wtf(LOG_TAG, "Invalid phone id " + phoneId); 784 return; 785 } 786 787 mConfigFromDefaultApp[phoneId] = null; 788 mConfigFromCarrierApp[phoneId] = null; 789 mServiceConnection[phoneId] = null; 790 mHasSentConfigChange[phoneId] = false; 791 792 if (fetchNoSimConfig) { 793 // To fetch no SIM config 794 mHandler.sendMessage( 795 mHandler.obtainMessage( 796 EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG, phoneId, -1)); 797 } 798 } 799 updateSubscriptionDatabase(int phoneId)800 private void updateSubscriptionDatabase(int phoneId) { 801 logd("updateSubscriptionDatabase: phoneId=" + phoneId); 802 String configPackageName; 803 PersistableBundle configToSend; 804 int carrierId = getSpecificCarrierIdForPhoneId(phoneId); 805 // Prefer the carrier privileged carrier app, but if there is not one, use the platform 806 // default carrier app. 807 if (mConfigFromCarrierApp[phoneId] != null) { 808 configPackageName = getCarrierPackageForPhoneId(phoneId); 809 configToSend = mConfigFromCarrierApp[phoneId]; 810 } else { 811 configPackageName = mPlatformCarrierConfigPackage; 812 configToSend = mConfigFromDefaultApp[phoneId]; 813 } 814 815 if (configToSend == null) { 816 configToSend = new PersistableBundle(); 817 } 818 819 // mOverrideConfigs is for testing. And it will override current configs. 820 PersistableBundle config = mOverrideConfigs[phoneId]; 821 if (config != null) { 822 configToSend = new PersistableBundle(configToSend); 823 configToSend.putAll(config); 824 } 825 826 SubscriptionManagerService.getInstance().updateSubscriptionByCarrierConfig( 827 phoneId, configPackageName, configToSend, 828 () -> mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1) 829 .sendToTarget()); 830 } 831 broadcastConfigChangedIntent(int phoneId)832 private void broadcastConfigChangedIntent(int phoneId) { 833 broadcastConfigChangedIntent(phoneId, true); 834 } 835 broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra)836 private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) { 837 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 838 int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 839 int specificCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 840 841 Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 842 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | 843 Intent.FLAG_RECEIVER_FOREGROUND); 844 if (addSubIdExtra) { 845 int simApplicationState = getSimApplicationStateForPhone(phoneId); 846 // Include subId/carrier id extra only if SIM records are loaded 847 if (simApplicationState != TelephonyManager.SIM_STATE_UNKNOWN 848 && simApplicationState != TelephonyManager.SIM_STATE_NOT_READY) { 849 subId = SubscriptionManager.getSubscriptionId(phoneId); 850 carrierId = getCarrierIdForPhoneId(phoneId); 851 specificCarrierId = getSpecificCarrierIdForPhoneId(phoneId); 852 intent.putExtra(TelephonyManager.EXTRA_SPECIFIC_CARRIER_ID, specificCarrierId); 853 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); 854 intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, carrierId); 855 } 856 } 857 intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId); 858 intent.putExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, 859 mFromSystemUnlocked[phoneId]); 860 861 TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class); 862 // Unlike broadcast, we wouldn't notify registrants on carrier config change when device is 863 // unlocked. Only real carrier config change will send the notification to registrants. 864 if (trm != null && !mFromSystemUnlocked[phoneId]) { 865 trm.notifyCarrierConfigChanged(phoneId, subId, carrierId, specificCarrierId); 866 } 867 868 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 869 870 if (SubscriptionManager.isValidSubscriptionId(subId)) { 871 logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId + ", subId=" + subId); 872 } else { 873 logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId); 874 } 875 mHasSentConfigChange[phoneId] = true; 876 mFromSystemUnlocked[phoneId] = false; 877 } 878 getSimApplicationStateForPhone(int phoneId)879 private int getSimApplicationStateForPhone(int phoneId) { 880 int simApplicationState = TelephonyManager.SIM_STATE_UNKNOWN; 881 int subId = SubscriptionManager.getSubscriptionId(phoneId); 882 if (SubscriptionManager.isValidSubscriptionId(subId)) { 883 TelephonyManager telMgr = TelephonyManager.from(mContext) 884 .createForSubscriptionId(subId); 885 simApplicationState = telMgr.getSimApplicationState(); 886 } 887 return simApplicationState; 888 } 889 890 /** Binds to the default or carrier config app. */ bindToConfigPackage(@onNull String pkgName, int phoneId, int eventId)891 private boolean bindToConfigPackage(@NonNull String pkgName, int phoneId, int eventId) { 892 logdWithLocalLog("Binding to " + pkgName + " for phone " + phoneId); 893 Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE); 894 carrierService.setPackage(pkgName); 895 CarrierServiceConnection serviceConnection = new CarrierServiceConnection( 896 phoneId, pkgName, eventId); 897 if (eventId == EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG) { 898 mServiceConnectionForNoSimConfig[phoneId] = serviceConnection; 899 } else { 900 mServiceConnection[phoneId] = serviceConnection; 901 } 902 try { 903 if (mContext.bindService(carrierService, serviceConnection, 904 Context.BIND_AUTO_CREATE)) { 905 if (eventId == EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG) { 906 mServiceBoundForNoSimConfig[phoneId] = true; 907 } else { 908 mServiceBound[phoneId] = true; 909 } 910 return true; 911 } else { 912 return false; 913 } 914 } catch (SecurityException ex) { 915 return false; 916 } 917 } 918 919 @VisibleForTesting 920 @NonNull getCarrierIdentifierForPhoneId(int phoneId)921 /* package */ CarrierIdentifier getCarrierIdentifierForPhoneId(int phoneId) { 922 String mcc = ""; 923 String mnc = ""; 924 String imsi = ""; 925 String gid1 = ""; 926 String gid2 = ""; 927 String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId); 928 String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId); 929 int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 930 int specificCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 931 // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC. 932 if (simOperator != null && simOperator.length() >= 3) { 933 mcc = simOperator.substring(0, 3); 934 mnc = simOperator.substring(3); 935 } 936 Phone phone = PhoneFactory.getPhone(phoneId); 937 if (phone != null) { 938 imsi = phone.getSubscriberId(); 939 gid1 = phone.getGroupIdLevel1(); 940 gid2 = phone.getGroupIdLevel2(); 941 carrierId = phone.getCarrierId(); 942 specificCarrierId = phone.getSpecificCarrierId(); 943 } 944 return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2, carrierId, specificCarrierId); 945 } 946 947 /** Returns the package name of a privileged carrier app, or null if there is none. */ 948 @Nullable getCarrierPackageForPhoneId(int phoneId)949 private String getCarrierPackageForPhoneId(int phoneId) { 950 final long token = Binder.clearCallingIdentity(); 951 try { 952 return TelephonyManager.from(mContext) 953 .getCarrierServicePackageNameForLogicalSlot(phoneId); 954 } finally { 955 Binder.restoreCallingIdentity(token); 956 } 957 } 958 959 @Nullable getIccIdForPhoneId(int phoneId)960 private String getIccIdForPhoneId(int phoneId) { 961 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 962 return null; 963 } 964 Phone phone = PhoneFactory.getPhone(phoneId); 965 if (phone == null) { 966 return null; 967 } 968 return phone.getIccSerialNumber(); 969 } 970 971 /** 972 * Get the sim specific carrier id {@link TelephonyManager#getSimSpecificCarrierId()} 973 */ getSpecificCarrierIdForPhoneId(int phoneId)974 private int getSpecificCarrierIdForPhoneId(int phoneId) { 975 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 976 return TelephonyManager.UNKNOWN_CARRIER_ID; 977 } 978 Phone phone = PhoneFactory.getPhone(phoneId); 979 if (phone == null) { 980 return TelephonyManager.UNKNOWN_CARRIER_ID; 981 } 982 return phone.getSpecificCarrierId(); 983 } 984 985 /** 986 * Get the sim carrier id {@link TelephonyManager#getSimCarrierId() } 987 */ getCarrierIdForPhoneId(int phoneId)988 private int getCarrierIdForPhoneId(int phoneId) { 989 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 990 return TelephonyManager.UNKNOWN_CARRIER_ID; 991 } 992 Phone phone = PhoneFactory.getPhone(phoneId); 993 if (phone == null) { 994 return TelephonyManager.UNKNOWN_CARRIER_ID; 995 } 996 return phone.getCarrierId(); 997 } 998 999 /** 1000 * Writes a bundle to an XML file. 1001 * 1002 * The bundle will be written to a file named after the package name, ICCID and 1003 * specific carrier id {@link TelephonyManager#getSimSpecificCarrierId()}. the same carrier 1004 * should have a single copy of XML file named after carrier id. However, it's still possible 1005 * that platform doesn't recognize the current sim carrier, we will use iccid + carrierid as 1006 * the canonical file name. carrierid can also handle the cases SIM OTA resolves to different 1007 * carrier while iccid remains the same. 1008 * 1009 * The file can be restored later with {@link @restoreConfigFromXml}. The XML output will 1010 * include the bundle and the current version of the specified package. 1011 * 1012 * In case of errors or invalid input, no file will be written. 1013 * 1014 * @param packageName the name of the package from which we fetched this bundle. 1015 * @param extraString An extra string to be used in the XML file name. 1016 * @param phoneId the phone ID. 1017 * @param carrierId contains all carrier-identifying information. 1018 * @param config the bundle to be written. Null will be treated as an empty bundle. 1019 * @param isNoSimConfig whether this is invoked for noSimConfig or not. 1020 */ saveConfigToXml(@ullable String packageName, @NonNull String extraString, int phoneId, @Nullable CarrierIdentifier carrierId, @NonNull PersistableBundle config, boolean isNoSimConfig)1021 private void saveConfigToXml(@Nullable String packageName, @NonNull String extraString, 1022 int phoneId, @Nullable CarrierIdentifier carrierId, @NonNull PersistableBundle config, 1023 boolean isNoSimConfig) { 1024 if (packageName == null) { 1025 loge("Cannot save config with null packageName. phoneId=" + phoneId); 1026 return; 1027 } 1028 1029 String fileName; 1030 if (isNoSimConfig) { 1031 fileName = getFilenameForNoSimConfig(packageName); 1032 } else { 1033 if (TelephonyManager.getSimStateForSlotIndex(phoneId) 1034 != TelephonyManager.SIM_STATE_LOADED) { 1035 loge("Skip saving config because SIM records are not loaded. phoneId=" + phoneId); 1036 return; 1037 } 1038 1039 final String iccid = getIccIdForPhoneId(phoneId); 1040 final int cid = carrierId != null ? carrierId.getSpecificCarrierId() 1041 : TelephonyManager.UNKNOWN_CARRIER_ID; 1042 if (iccid == null) { 1043 loge("Cannot save config with null iccid. phoneId=" + phoneId); 1044 return; 1045 } 1046 fileName = getFilenameForConfig(packageName, extraString, iccid, cid); 1047 } 1048 1049 // b/32668103 Only save to file if config isn't empty. 1050 // In case of failure, not caching an empty bundle will 1051 // try loading config again on next power on or sim loaded. 1052 // Downside is for genuinely empty bundle, will bind and load 1053 // on every power on. 1054 if (config == null || config.isEmpty()) { 1055 return; 1056 } 1057 1058 final String version = getPackageVersion(packageName); 1059 if (version == null) { 1060 loge("Failed to get package version for: " + packageName + ", phoneId=" + phoneId); 1061 return; 1062 } 1063 1064 logdWithLocalLog("Save carrier config to cache. phoneId=" + phoneId 1065 + ", xml=" + getFilePathForLogging(fileName) + ", version=" + version); 1066 1067 FileOutputStream outFile = null; 1068 try { 1069 outFile = new FileOutputStream(new File(mContext.getFilesDir(), fileName)); 1070 config.putString(KEY_VERSION, version); 1071 config.writeToStream(outFile); 1072 outFile.flush(); 1073 outFile.close(); 1074 } catch (IOException e) { 1075 loge(e.toString()); 1076 } 1077 } 1078 1079 @VisibleForTesting saveConfigToXml(@ullable String packageName, @NonNull String extraString, int phoneId, @NonNull CarrierIdentifier carrierId, @NonNull PersistableBundle config)1080 /* package */ void saveConfigToXml(@Nullable String packageName, @NonNull String extraString, 1081 int phoneId, @NonNull CarrierIdentifier carrierId, @NonNull PersistableBundle config) { 1082 saveConfigToXml(packageName, extraString, phoneId, carrierId, config, false); 1083 } 1084 1085 @VisibleForTesting saveNoSimConfigToXml(@ullable String packageName, @NonNull PersistableBundle config)1086 /* package */ void saveNoSimConfigToXml(@Nullable String packageName, 1087 @NonNull PersistableBundle config) { 1088 saveConfigToXml(packageName, "", -1, null, config, true); 1089 } 1090 1091 /** 1092 * Reads a bundle from an XML file. 1093 * 1094 * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved 1095 * config bundle for the given package and phone ID. 1096 * 1097 * In case of errors, or if the saved config is from a different package version than the 1098 * current version, then null will be returned. 1099 * 1100 * @param packageName the name of the package from which we fetched this bundle. 1101 * @param extraString An extra string to be used in the XML file name. 1102 * @param phoneId the phone ID. 1103 * @param isNoSimConfig whether this is invoked for noSimConfig or not. 1104 * @return the bundle from the XML file. Returns null if there is no saved config, the saved 1105 * version does not match, or reading config fails. 1106 */ 1107 @Nullable restoreConfigFromXml(@ullable String packageName, @NonNull String extraString, int phoneId, boolean isNoSimConfig)1108 private PersistableBundle restoreConfigFromXml(@Nullable String packageName, 1109 @NonNull String extraString, int phoneId, boolean isNoSimConfig) { 1110 if (packageName == null) { 1111 loge("Cannot restore config with null packageName"); 1112 } 1113 final String version = getPackageVersion(packageName); 1114 if (version == null) { 1115 loge("Failed to get package version for: " + packageName); 1116 return null; 1117 } 1118 1119 String fileName; 1120 String iccid = null; 1121 if (isNoSimConfig) { 1122 fileName = getFilenameForNoSimConfig(packageName); 1123 } else { 1124 if (TelephonyManager.getSimStateForSlotIndex(phoneId) 1125 != TelephonyManager.SIM_STATE_LOADED) { 1126 loge("Skip restore config because SIM records are not loaded. phoneId=" + phoneId); 1127 return null; 1128 } 1129 1130 iccid = getIccIdForPhoneId(phoneId); 1131 final int cid = getSpecificCarrierIdForPhoneId(phoneId); 1132 if (iccid == null) { 1133 loge("Cannot restore config with null iccid. phoneId=" + phoneId); 1134 return null; 1135 } 1136 fileName = getFilenameForConfig(packageName, extraString, iccid, cid); 1137 } 1138 1139 PersistableBundle restoredBundle = null; 1140 File file = new File(mContext.getFilesDir(), fileName); 1141 String filePath = file.getPath(); 1142 String savedVersion = null; 1143 try (FileInputStream inFile = new FileInputStream(file)) { 1144 1145 restoredBundle = PersistableBundle.readFromStream(inFile); 1146 savedVersion = restoredBundle.getString(KEY_VERSION); 1147 restoredBundle.remove(KEY_VERSION); 1148 1149 if (!version.equals(savedVersion)) { 1150 loge("Saved version mismatch: " + version + " vs " + savedVersion 1151 + ", phoneId=" + phoneId); 1152 restoredBundle = null; 1153 } 1154 } catch (FileNotFoundException e) { 1155 // Missing file is normal occurrence that might occur with a new sim or when restoring 1156 // an override file during boot and should not be treated as an error. 1157 if (isNoSimConfig) { 1158 logd("File not found: " + file.getPath() + ", phoneId=" + phoneId); 1159 } else { 1160 logd("File not found : " + getFilePathForLogging(filePath, iccid) 1161 + ", phoneId=" + phoneId); 1162 } 1163 } catch (IOException e) { 1164 loge(e.toString()); 1165 } 1166 1167 if (restoredBundle != null) { 1168 logdWithLocalLog("Restored carrier config from cache. phoneId=" + phoneId + ", xml=" 1169 + getFilePathForLogging(fileName) + ", version=" + savedVersion 1170 + ", modified time=" + getFileTime(filePath)); 1171 } 1172 return restoredBundle; 1173 } 1174 1175 /** 1176 * This method will mask most part of iccid in the filepath for logging on userbuild 1177 */ 1178 @NonNull getFilePathForLogging(@ullable String filePath, @Nullable String iccid)1179 private String getFilePathForLogging(@Nullable String filePath, @Nullable String iccid) { 1180 // If loggable then return with actual file path 1181 if (TelephonyUtils.IS_DEBUGGABLE) { 1182 return filePath; 1183 } 1184 String path = filePath; 1185 int length = (iccid != null) ? iccid.length() : 0; 1186 if (length > 5 && filePath != null) { 1187 path = filePath.replace(iccid.substring(5), "***************"); 1188 } 1189 return path; 1190 } 1191 1192 @Nullable restoreConfigFromXml(@ullable String packageName, @NonNull String extraString, int phoneId)1193 private PersistableBundle restoreConfigFromXml(@Nullable String packageName, 1194 @NonNull String extraString, int phoneId) { 1195 return restoreConfigFromXml(packageName, extraString, phoneId, false); 1196 } 1197 1198 @Nullable restoreNoSimConfigFromXml(@ullable String packageName)1199 private PersistableBundle restoreNoSimConfigFromXml(@Nullable String packageName) { 1200 return restoreConfigFromXml(packageName, "", -1, true); 1201 } 1202 1203 /** 1204 * Clears cached carrier config. 1205 * This deletes all saved XML files associated with the given package name. If packageName is 1206 * null, then it deletes all saved XML files. 1207 * 1208 * @param packageName the name of a carrier package, or null if all cached config should be 1209 * cleared. 1210 * @return true iff one or more files were deleted. 1211 */ clearCachedConfigForPackage(@ullable final String packageName)1212 private boolean clearCachedConfigForPackage(@Nullable final String packageName) { 1213 File dir = mContext.getFilesDir(); 1214 File[] packageFiles = dir.listFiles(new FilenameFilter() { 1215 public boolean accept(File dir, String filename) { 1216 if (packageName != null) { 1217 return filename.startsWith("carrierconfig-" + packageName + "-"); 1218 } else { 1219 return filename.startsWith("carrierconfig-"); 1220 } 1221 } 1222 }); 1223 if (packageFiles == null || packageFiles.length < 1) return false; 1224 for (File f : packageFiles) { 1225 logdWithLocalLog("Deleting " + getFilePathForLogging(f.getName())); 1226 f.delete(); 1227 } 1228 return true; 1229 } 1230 getFilePathForLogging(String filePath)1231 private String getFilePathForLogging(String filePath) { 1232 if (!TextUtils.isEmpty(filePath)) { 1233 String[] fileTokens = filePath.split("-"); 1234 if (fileTokens != null && fileTokens.length > 2) { 1235 String iccid = fileTokens[fileTokens.length -2]; 1236 return getFilePathForLogging(filePath, iccid); 1237 } 1238 return filePath; 1239 } 1240 return filePath; 1241 } 1242 1243 /** Builds a canonical file name for a config file. */ 1244 @NonNull getFilenameForConfig( @onNull String packageName, @NonNull String extraString, @NonNull String iccid, int cid)1245 private static String getFilenameForConfig( 1246 @NonNull String packageName, @NonNull String extraString, 1247 @NonNull String iccid, int cid) { 1248 // the same carrier should have a single copy of XML file named after carrier id. 1249 // However, it's still possible that platform doesn't recognize the current sim carrier, 1250 // we will use iccid + carrierid as the canonical file name. carrierid can also handle the 1251 // cases SIM OTA resolves to different carrier while iccid remains the same. 1252 return "carrierconfig-" + packageName + extraString + "-" + iccid + "-" + cid + ".xml"; 1253 } 1254 1255 /** Builds a canonical file name for no SIM config file. */ 1256 @NonNull getFilenameForNoSimConfig(@onNull String packageName)1257 private String getFilenameForNoSimConfig(@NonNull String packageName) { 1258 return "carrierconfig-" + packageName + "-" + "nosim" + ".xml"; 1259 } 1260 1261 /** Return the current version code of a package, or null if the name is not found. */ 1262 @Nullable getPackageVersion(@onNull String packageName)1263 private String getPackageVersion(@NonNull String packageName) { 1264 try { 1265 PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0); 1266 return Long.toString(info.getLongVersionCode()); 1267 } catch (PackageManager.NameNotFoundException e) { 1268 return null; 1269 } 1270 } 1271 1272 /** 1273 * Read up to date config. 1274 * 1275 * This reads config bundles for the given phoneId. That means getting the latest bundle from 1276 * the default app and a privileged carrier app, if present. This will not bind to an app if we 1277 * have a saved config file to use instead. 1278 */ updateConfigForPhoneId(int phoneId)1279 private void updateConfigForPhoneId(int phoneId) { 1280 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1)); 1281 } 1282 onMultiSimConfigChanged()1283 private void onMultiSimConfigChanged() { 1284 int oldNumPhones = mNumPhones; 1285 mNumPhones = TelephonyManager.from(mContext).getActiveModemCount(); 1286 if (mNumPhones == oldNumPhones) { 1287 return; 1288 } 1289 logdWithLocalLog("mNumPhones change from " + oldNumPhones + " to " + mNumPhones); 1290 1291 // If DS -> SS switch, release the resources BEFORE truncating the arrays to avoid leaking 1292 for (int phoneId = mNumPhones; phoneId < oldNumPhones; phoneId++) { 1293 if (mServiceConnection[phoneId] != null) { 1294 unbindIfBound(mContext, mServiceConnection[phoneId], phoneId); 1295 } 1296 if (mServiceConnectionForNoSimConfig[phoneId] != null) { 1297 unbindIfBoundForNoSimConfig(mContext, mServiceConnectionForNoSimConfig[phoneId], 1298 phoneId); 1299 } 1300 } 1301 1302 // The phone to slot mapping may change, unregister here and re-register callbacks later 1303 for (int phoneId = 0; phoneId < oldNumPhones; phoneId++) { 1304 if (mCarrierServiceChangeCallbacks[phoneId] != null) { 1305 TelephonyManager.from(mContext).unregisterCarrierPrivilegesCallback( 1306 mCarrierServiceChangeCallbacks[phoneId]); 1307 } 1308 } 1309 1310 // Copy the original arrays, truncate or padding with zeros (if necessary) to new length 1311 mConfigFromDefaultApp = Arrays.copyOf(mConfigFromDefaultApp, mNumPhones); 1312 mConfigFromCarrierApp = Arrays.copyOf(mConfigFromCarrierApp, mNumPhones); 1313 mPersistentOverrideConfigs = Arrays.copyOf(mPersistentOverrideConfigs, mNumPhones); 1314 mOverrideConfigs = Arrays.copyOf(mOverrideConfigs, mNumPhones); 1315 mServiceConnection = Arrays.copyOf(mServiceConnection, mNumPhones); 1316 mServiceConnectionForNoSimConfig = 1317 Arrays.copyOf(mServiceConnectionForNoSimConfig, mNumPhones); 1318 mServiceBound = Arrays.copyOf(mServiceBound, mNumPhones); 1319 mServiceBoundForNoSimConfig = Arrays.copyOf(mServiceBoundForNoSimConfig, mNumPhones); 1320 mHasSentConfigChange = Arrays.copyOf(mHasSentConfigChange, mNumPhones); 1321 mFromSystemUnlocked = Arrays.copyOf(mFromSystemUnlocked, mNumPhones); 1322 mCarrierServiceChangeCallbacks = Arrays.copyOf(mCarrierServiceChangeCallbacks, mNumPhones); 1323 1324 // Load the config for all the phones and re-register callback AFTER padding the arrays. 1325 for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { 1326 updateConfigForPhoneId(phoneId); 1327 mCarrierServiceChangeCallbacks[phoneId] = new CarrierServiceChangeCallback(phoneId); 1328 TelephonyManager.from(mContext).registerCarrierPrivilegesCallback(phoneId, 1329 new HandlerExecutor(mHandler), mCarrierServiceChangeCallbacks[phoneId]); 1330 } 1331 } 1332 1333 @Override 1334 @NonNull getConfigForSubId(int subscriptionId, @NonNull String callingPackage)1335 public PersistableBundle getConfigForSubId(int subscriptionId, @NonNull String callingPackage) { 1336 return getConfigForSubIdWithFeature(subscriptionId, callingPackage, null); 1337 } 1338 1339 @Override 1340 @NonNull getConfigForSubIdWithFeature(int subscriptionId, @NonNull String callingPackage, @Nullable String callingFeatureId)1341 public PersistableBundle getConfigForSubIdWithFeature(int subscriptionId, 1342 @NonNull String callingPackage, @Nullable String callingFeatureId) { 1343 if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subscriptionId, 1344 callingPackage, callingFeatureId, "getCarrierConfig")) { 1345 return new PersistableBundle(); 1346 } 1347 1348 enforceTelephonyFeatureWithException(callingPackage, "getConfigForSubIdWithFeature"); 1349 1350 int phoneId = SubscriptionManager.getPhoneId(subscriptionId); 1351 PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig(); 1352 if (SubscriptionManager.isValidPhoneId(phoneId)) { 1353 PersistableBundle config = mConfigFromDefaultApp[phoneId]; 1354 if (config != null) { 1355 retConfig.putAll(config); 1356 } 1357 config = mConfigFromCarrierApp[phoneId]; 1358 if (config != null) { 1359 retConfig.putAll(config); 1360 } 1361 config = mPersistentOverrideConfigs[phoneId]; 1362 if (config != null) { 1363 retConfig.putAll(config); 1364 } 1365 config = mOverrideConfigs[phoneId]; 1366 if (config != null) { 1367 retConfig.putAll(config); 1368 } 1369 // Ignore the theoretical case of the default app not being present since that won't 1370 // work in CarrierConfigLoader today. 1371 final boolean allConfigsApplied = 1372 (mConfigFromCarrierApp[phoneId] != null 1373 || getCarrierPackageForPhoneId(phoneId) == null) 1374 && mConfigFromDefaultApp[phoneId] != null; 1375 retConfig.putBoolean( 1376 CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, allConfigsApplied); 1377 } else { 1378 if (mNoSimConfig != null) { 1379 retConfig.putAll(mNoSimConfig); 1380 } 1381 } 1382 return retConfig; 1383 } 1384 1385 @Override 1386 @NonNull getConfigSubsetForSubIdWithFeature(int subscriptionId, @NonNull String callingPackage, @Nullable String callingFeatureId, @NonNull String[] keys)1387 public PersistableBundle getConfigSubsetForSubIdWithFeature(int subscriptionId, 1388 @NonNull String callingPackage, @Nullable String callingFeatureId, 1389 @NonNull String[] keys) { 1390 Objects.requireNonNull(callingPackage, "Calling package must be non-null"); 1391 Objects.requireNonNull(keys, "Config keys must be non-null"); 1392 enforceCallerIsSystemOrRequestingPackage(callingPackage); 1393 1394 enforceTelephonyFeatureWithException(callingPackage, 1395 "getConfigSubsetForSubIdWithFeature"); 1396 1397 // Permission check is performed inside and an empty bundle will return on failure. 1398 // No SecurityException thrown here since most clients expect to retrieve the overridden 1399 // value if present or use default one if not 1400 PersistableBundle allConfigs = getConfigForSubIdWithFeature(subscriptionId, callingPackage, 1401 callingFeatureId); 1402 if (allConfigs.isEmpty()) { 1403 return allConfigs; 1404 } 1405 for (String key : keys) { 1406 Objects.requireNonNull(key, "Config key must be non-null"); 1407 } 1408 1409 PersistableBundle configSubset = new PersistableBundle( 1410 keys.length + CONFIG_SUBSET_METADATA_KEYS.length); 1411 for (String carrierConfigKey : keys) { 1412 Object value = allConfigs.get(carrierConfigKey); 1413 if (value == null) { 1414 // Filter out keys without values. 1415 // In history, many AOSP or OEMs/carriers private configs didn't provide default 1416 // values. We have to continue supporting them for now. See b/261776046 for details. 1417 continue; 1418 } 1419 // Config value itself could be PersistableBundle which requires different API to put 1420 if (value instanceof PersistableBundle) { 1421 configSubset.putPersistableBundle(carrierConfigKey, (PersistableBundle) value); 1422 } else { 1423 configSubset.putObject(carrierConfigKey, value); 1424 } 1425 } 1426 1427 // Configs in CONFIG_SUBSET_ALWAYS_INCLUDED_KEYS should always be included 1428 for (String generalKey : CONFIG_SUBSET_METADATA_KEYS) { 1429 configSubset.putObject(generalKey, allConfigs.get(generalKey)); 1430 } 1431 1432 return configSubset; 1433 } 1434 1435 @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_PHONE_STATE) 1436 @Override overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides, boolean persistent)1437 public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides, 1438 boolean persistent) { 1439 overrideConfig_enforcePermission(); 1440 int phoneId = SubscriptionManager.getPhoneId(subscriptionId); 1441 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 1442 logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId); 1443 throw new IllegalArgumentException( 1444 "Invalid phoneId " + phoneId + " for subId " + subscriptionId); 1445 } 1446 1447 enforceTelephonyFeatureWithException(getCurrentPackageName(), "overrideConfig"); 1448 1449 // Post to run on handler thread on which all states should be confined. 1450 mHandler.post(() -> { 1451 overrideConfig(mOverrideConfigs, phoneId, overrides); 1452 1453 if (persistent) { 1454 overrideConfig(mPersistentOverrideConfigs, phoneId, overrides); 1455 1456 if (overrides != null) { 1457 final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId); 1458 saveConfigToXml(mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, 1459 phoneId, 1460 carrierId, mPersistentOverrideConfigs[phoneId]); 1461 } else { 1462 final String iccid = getIccIdForPhoneId(phoneId); 1463 final int cid = getSpecificCarrierIdForPhoneId(phoneId); 1464 String fileName = getFilenameForConfig(mPlatformCarrierConfigPackage, 1465 OVERRIDE_PACKAGE_ADDITION, iccid, cid); 1466 File fileToDelete = new File(mContext.getFilesDir(), fileName); 1467 fileToDelete.delete(); 1468 } 1469 } 1470 logdWithLocalLog("overrideConfig: subId=" + subscriptionId + ", persistent=" 1471 + persistent + ", overrides=" + overrides); 1472 updateSubscriptionDatabase(phoneId); 1473 }); 1474 } 1475 overrideConfig(@onNull PersistableBundle[] currentOverrides, int phoneId, @Nullable PersistableBundle overrides)1476 private void overrideConfig(@NonNull PersistableBundle[] currentOverrides, int phoneId, 1477 @Nullable PersistableBundle overrides) { 1478 if (overrides == null) { 1479 currentOverrides[phoneId] = new PersistableBundle(); 1480 } else if (currentOverrides[phoneId] == null) { 1481 currentOverrides[phoneId] = overrides; 1482 } else { 1483 currentOverrides[phoneId].putAll(overrides); 1484 } 1485 } 1486 1487 @Override notifyConfigChangedForSubId(int subscriptionId)1488 public void notifyConfigChangedForSubId(int subscriptionId) { 1489 // Requires the calling app to be either a carrier privileged app for this subId or 1490 // system privileged app with MODIFY_PHONE_STATE permission. 1491 TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext, 1492 subscriptionId, "Require carrier privileges or MODIFY_PHONE_STATE permission."); 1493 1494 int phoneId = SubscriptionManager.getPhoneId(subscriptionId); 1495 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 1496 final String msg = 1497 "Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId; 1498 if (mFeatureFlags.addAnomalyWhenNotifyConfigChangedWithInvalidPhone()) { 1499 AnomalyReporter.reportAnomaly( 1500 UUID.fromString(UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE), msg); 1501 } 1502 logd(msg); 1503 throw new IllegalArgumentException(msg); 1504 } 1505 1506 enforceTelephonyFeatureWithException(getCurrentPackageName(), 1507 "notifyConfigChangedForSubId"); 1508 1509 logdWithLocalLog("Notified carrier config changed. phoneId=" + phoneId 1510 + ", subId=" + subscriptionId); 1511 1512 // This method should block until deleting has completed, so that an error which prevents us 1513 // from clearing the cache is passed back to the carrier app. With the files successfully 1514 // deleted, this can return and we will eventually bind to the carrier app. 1515 String callingPackageName = mContext.getPackageManager().getNameForUid( 1516 Binder.getCallingUid()); 1517 clearCachedConfigForPackage(callingPackageName); 1518 updateConfigForPhoneId(phoneId); 1519 } 1520 1521 @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_PHONE_STATE) 1522 @Override updateConfigForPhoneId(int phoneId, @NonNull String simState)1523 public void updateConfigForPhoneId(int phoneId, @NonNull String simState) { 1524 updateConfigForPhoneId_enforcePermission(); 1525 logdWithLocalLog("Update config for phoneId=" + phoneId + " simState=" + simState); 1526 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 1527 throw new IllegalArgumentException("Invalid phoneId: " + phoneId); 1528 } 1529 1530 enforceTelephonyFeatureWithException(getCurrentPackageName(), "updateConfigForPhoneId"); 1531 1532 // requires Java 7 for switch on string. 1533 switch (simState) { 1534 case IccCardConstants.INTENT_VALUE_ICC_ABSENT: 1535 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: 1536 case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: 1537 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: 1538 case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: 1539 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1)); 1540 break; 1541 case IccCardConstants.INTENT_VALUE_ICC_LOADED: 1542 case IccCardConstants.INTENT_VALUE_ICC_LOCKED: 1543 updateConfigForPhoneId(phoneId); 1544 break; 1545 } 1546 } 1547 1548 @android.annotation.EnforcePermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) 1549 @Override 1550 @NonNull getDefaultCarrierServicePackageName()1551 public String getDefaultCarrierServicePackageName() { 1552 getDefaultCarrierServicePackageName_enforcePermission(); 1553 1554 enforceTelephonyFeatureWithException(getCurrentPackageName(), 1555 "getDefaultCarrierServicePackageName"); 1556 1557 return mPlatformCarrierConfigPackage; 1558 } 1559 1560 @VisibleForTesting 1561 @NonNull getHandler()1562 /* package */ Handler getHandler() { 1563 return mHandler; 1564 } 1565 1566 @VisibleForTesting 1567 @Nullable getConfigFromDefaultApp(int phoneId)1568 /* package */ PersistableBundle getConfigFromDefaultApp(int phoneId) { 1569 return mConfigFromDefaultApp[phoneId]; 1570 } 1571 1572 @VisibleForTesting 1573 @Nullable getConfigFromCarrierApp(int phoneId)1574 /* package */ PersistableBundle getConfigFromCarrierApp(int phoneId) { 1575 return mConfigFromCarrierApp[phoneId]; 1576 } 1577 1578 @VisibleForTesting 1579 @NonNull getNoSimConfig()1580 /* package */ PersistableBundle getNoSimConfig() { 1581 return mNoSimConfig; 1582 } 1583 1584 @VisibleForTesting 1585 @Nullable getOverrideConfig(int phoneId)1586 /* package */ PersistableBundle getOverrideConfig(int phoneId) { 1587 return mOverrideConfigs[phoneId]; 1588 } 1589 1590 // TODO(b/185129900): always call unbindService after bind, no matter if it succeeded unbindIfBound(@onNull Context context, @NonNull CarrierServiceConnection conn, int phoneId)1591 private void unbindIfBound(@NonNull Context context, @NonNull CarrierServiceConnection conn, 1592 int phoneId) { 1593 if (mServiceBound[phoneId]) { 1594 mServiceBound[phoneId] = false; 1595 context.unbindService(conn); 1596 } 1597 } 1598 unbindIfBoundForNoSimConfig(@onNull Context context, @NonNull CarrierServiceConnection conn, int phoneId)1599 private void unbindIfBoundForNoSimConfig(@NonNull Context context, 1600 @NonNull CarrierServiceConnection conn, int phoneId) { 1601 if (mServiceBoundForNoSimConfig[phoneId]) { 1602 mServiceBoundForNoSimConfig[phoneId] = false; 1603 context.unbindService(conn); 1604 } 1605 } 1606 1607 /** 1608 * Returns a boxed Integer object for phoneId, services as message token to distinguish messages 1609 * with same code when calling {@link Handler#removeMessages(int, Object)}. 1610 */ 1611 @NonNull getMessageToken(int phoneId)1612 private Integer getMessageToken(int phoneId) { 1613 if (phoneId < -128 || phoneId > 127) { 1614 throw new IllegalArgumentException("phoneId should be in range [-128, 127], inclusive"); 1615 } 1616 // Integer#valueOf guarantees the integers within [-128, 127] are cached and thus memory 1617 // comparison (==) returns true for the same integer. 1618 return Integer.valueOf(phoneId); 1619 } 1620 1621 /** 1622 * Get the file time in readable format. 1623 * 1624 * @param filePath The full file path. 1625 * 1626 * @return The time in string format. 1627 */ 1628 @Nullable getFileTime(@onNull String filePath)1629 private String getFileTime(@NonNull String filePath) { 1630 String formattedModifiedTime = null; 1631 try { 1632 // Convert the modified time to a readable format 1633 formattedModifiedTime = TIME_FORMAT.format(Files.readAttributes(Paths.get(filePath), 1634 BasicFileAttributes.class).lastModifiedTime().toMillis()); 1635 } catch (Exception e) { 1636 e.printStackTrace(); 1637 } 1638 1639 return formattedModifiedTime; 1640 } 1641 1642 /** 1643 * If {@code args} contains {@link #DUMP_ARG_REQUESTING_PACKAGE} and a following package name, 1644 * we'll also call {@link IBinder#dump} on the default carrier service (if bound) and the 1645 * specified carrier service (if bound). Typically, this is done for connectivity bug reports 1646 * where we don't call {@code dumpsys activity service all-non-platform} because that contains 1647 * too much info, but we still want to let carrier apps include their diagnostics. 1648 */ 1649 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args)1650 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { 1651 IndentingPrintWriter indentPW = new IndentingPrintWriter(pw, " "); 1652 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1653 != PackageManager.PERMISSION_GRANTED) { 1654 indentPW.println("Permission Denial: can't dump carrierconfig from from pid=" 1655 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 1656 return; 1657 } 1658 String requestingPackage = null; 1659 int requestingPackageIndex = ArrayUtils.indexOf(args, DUMP_ARG_REQUESTING_PACKAGE); 1660 if (requestingPackageIndex >= 0 && requestingPackageIndex < args.length - 1 1661 && !TextUtils.isEmpty(args[requestingPackageIndex + 1])) { 1662 requestingPackage = args[requestingPackageIndex + 1]; 1663 // Throws a SecurityException if the caller is impersonating another app in an effort to 1664 // dump extra info (which may contain PII the caller doesn't have a right to). 1665 enforceCallerIsSystemOrRequestingPackage(requestingPackage); 1666 } 1667 1668 indentPW.println("CarrierConfigLoader: " + this); 1669 for (int i = 0; i < mNumPhones; i++) { 1670 indentPW.println("Phone Id = " + i); 1671 // display default values in CarrierConfigManager 1672 printConfig(CarrierConfigManager.getDefaultConfig(), indentPW, 1673 "Default Values from CarrierConfigManager"); 1674 // display ConfigFromDefaultApp 1675 printConfig(mConfigFromDefaultApp[i], indentPW, "mConfigFromDefaultApp"); 1676 // display ConfigFromCarrierApp 1677 printConfig(mConfigFromCarrierApp[i], indentPW, "mConfigFromCarrierApp"); 1678 printConfig(mPersistentOverrideConfigs[i], indentPW, "mPersistentOverrideConfigs"); 1679 printConfig(mOverrideConfigs[i], indentPW, "mOverrideConfigs"); 1680 } 1681 1682 printConfig(mNoSimConfig, indentPW, "mNoSimConfig"); 1683 indentPW.println("mNumPhones=" + mNumPhones); 1684 indentPW.println("mPlatformCarrierConfigPackage=" + mPlatformCarrierConfigPackage); 1685 indentPW.println("mServiceConnection=[" + Stream.of(mServiceConnection) 1686 .map(c -> c != null ? c.pkgName : null) 1687 .collect(Collectors.joining(", ")) + "]"); 1688 indentPW.println("mServiceBoundForNoSimConfig=" 1689 + Arrays.toString(mServiceBoundForNoSimConfig)); 1690 indentPW.println("mHasSentConfigChange=" + Arrays.toString(mHasSentConfigChange)); 1691 indentPW.println("mFromSystemUnlocked=" + Arrays.toString(mFromSystemUnlocked)); 1692 indentPW.println(); 1693 indentPW.println("CarrierConfigLoader local log="); 1694 indentPW.increaseIndent(); 1695 mCarrierConfigLoadingLog.dump(fd, indentPW, args); 1696 indentPW.decreaseIndent(); 1697 1698 if (requestingPackage != null) { 1699 logd("Including default and requesting package " + requestingPackage 1700 + " carrier services in dump"); 1701 indentPW.println(""); 1702 indentPW.println("Connected services"); 1703 dumpCarrierServiceIfBound(fd, indentPW, "Default config package", 1704 mPlatformCarrierConfigPackage, false /* considerCarrierPrivileges */); 1705 dumpCarrierServiceIfBound(fd, indentPW, "Requesting package", requestingPackage, 1706 true /* considerCarrierPrivileges */); 1707 } 1708 1709 indentPW.println(); 1710 indentPW.println("Cached config files:"); 1711 indentPW.increaseIndent(); 1712 for (File f : mContext.getFilesDir().listFiles((FilenameFilter) (d, filename) 1713 -> filename.startsWith("carrierconfig-"))) { 1714 indentPW.println(getFilePathForLogging(f.getName()) + ", modified time=" 1715 + getFileTime(f.getAbsolutePath())); 1716 } 1717 indentPW.decreaseIndent(); 1718 } 1719 printConfig(@onNull PersistableBundle configApp, @NonNull IndentingPrintWriter indentPW, @NonNull String name)1720 private void printConfig(@NonNull PersistableBundle configApp, 1721 @NonNull IndentingPrintWriter indentPW, @NonNull String name) { 1722 indentPW.increaseIndent(); 1723 if (configApp == null) { 1724 indentPW.println(name + " : null "); 1725 indentPW.decreaseIndent(); 1726 indentPW.println(""); 1727 return; 1728 } 1729 indentPW.println(name + " : "); 1730 List<String> sortedKeys = new ArrayList<String>(configApp.keySet()); 1731 Collections.sort(sortedKeys); 1732 indentPW.increaseIndent(); 1733 indentPW.increaseIndent(); 1734 for (String key : sortedKeys) { 1735 if (configApp.get(key) != null && configApp.get(key) instanceof Object[]) { 1736 indentPW.println(key + " = " + 1737 Arrays.toString((Object[]) configApp.get(key))); 1738 } else if (configApp.get(key) != null && configApp.get(key) instanceof int[]) { 1739 indentPW.println(key + " = " + Arrays.toString((int[]) configApp.get(key))); 1740 } else { 1741 indentPW.println(key + " = " + configApp.get(key)); 1742 } 1743 } 1744 indentPW.decreaseIndent(); 1745 indentPW.decreaseIndent(); 1746 indentPW.decreaseIndent(); 1747 indentPW.println(""); 1748 } 1749 1750 /** 1751 * Passes without problem when one of these conditions is true: 1752 * - The caller is a privileged UID (e.g. for dumpstate.cpp generating a bug report, where the 1753 * system knows the true caller plumbed in through the {@link android.os.BugreportManager} API). 1754 * - The caller's UID matches the supplied package. 1755 * 1756 * @throws SecurityException if none of the above conditions are met. 1757 */ enforceCallerIsSystemOrRequestingPackage(@onNull String requestingPackage)1758 private void enforceCallerIsSystemOrRequestingPackage(@NonNull String requestingPackage) 1759 throws SecurityException { 1760 final int callingUid = Binder.getCallingUid(); 1761 if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID 1762 || callingUid == Process.SHELL_UID || callingUid == Process.PHONE_UID) { 1763 // Bug reports (dumpstate.cpp) run as SHELL, and let some other privileged UIDs through 1764 // as well. 1765 return; 1766 } 1767 // An app is trying to dump extra detail, block it if they aren't who they claim to be. 1768 AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); 1769 if (appOps == null) { 1770 throw new SecurityException("No AppOps"); 1771 } 1772 // Will throw a SecurityException if the UID and package don't match. 1773 appOps.checkPackage(callingUid, requestingPackage); 1774 } 1775 1776 /** 1777 * Searches for one or more appropriate {@link CarrierService} instances to dump based on the 1778 * current connections. 1779 * 1780 * @param targetPkgName the target package name to dump carrier services for 1781 * @param considerCarrierPrivileges if true, allow a carrier service to be dumped if it shares 1782 * carrier privileges with {@code targetPkgName}; 1783 * otherwise, only dump a carrier service if it is {@code 1784 * targetPkgName} 1785 */ dumpCarrierServiceIfBound(@onNull FileDescriptor fd, @NonNull IndentingPrintWriter indentPW, @NonNull String prefix, @NonNull String targetPkgName, boolean considerCarrierPrivileges)1786 private void dumpCarrierServiceIfBound(@NonNull FileDescriptor fd, 1787 @NonNull IndentingPrintWriter indentPW, @NonNull String prefix, 1788 @NonNull String targetPkgName, boolean considerCarrierPrivileges) { 1789 // Null package is possible if it's early in the boot process, there was a recent crash, we 1790 // loaded the config from XML most recently, or a SIM slot is empty. Carrier apps with 1791 // long-lived bindings should typically get dumped here regardless. Even if an app is being 1792 // used for multiple phoneIds, we assume that it's smart enough to handle that on its own, 1793 // and that in most cases we'd just be dumping duplicate information and bloating a report. 1794 indentPW.increaseIndent(); 1795 indentPW.println(prefix + " : " + targetPkgName); 1796 Set<String> dumpedPkgNames = new ArraySet<>(mServiceConnection.length); 1797 for (CarrierServiceConnection connection : mServiceConnection) { 1798 if (connection == null || !SubscriptionManager.isValidPhoneId(connection.phoneId) 1799 || TextUtils.isEmpty(connection.pkgName)) { 1800 continue; 1801 } 1802 final String servicePkgName = connection.pkgName; 1803 // Note: we intentionally ignore system components here because we should NOT match the 1804 // shell caller that's typically used for bug reports via non-BugreportManager triggers. 1805 final boolean exactPackageMatch = TextUtils.equals(targetPkgName, servicePkgName); 1806 final boolean carrierPrivilegesMatch = 1807 considerCarrierPrivileges && hasCarrierPrivileges(targetPkgName, 1808 connection.phoneId); 1809 if (!exactPackageMatch && !carrierPrivilegesMatch) continue; 1810 // Make sure this service is actually alive before trying to dump it. We don't pay 1811 // attention to mServiceBound[connection.phoneId] because typically carrier apps will 1812 // request long-lived bindings, and even if we unbind the app, it may still be alive due 1813 // to CarrierServiceBindHelper. Pull it out as a reference so even if it gets set to 1814 // null within the ServiceConnection during unbinding we can avoid an NPE. 1815 final IBinder service = connection.service; 1816 if (service == null || !service.isBinderAlive() || !service.pingBinder()) continue; 1817 // We've got a live service. Last check is just to make sure we don't dump a package 1818 // multiple times. 1819 if (!dumpedPkgNames.add(servicePkgName)) continue; 1820 if (!exactPackageMatch) { 1821 logd(targetPkgName + " has carrier privileges on phoneId " + connection.phoneId 1822 + ", service provided by " + servicePkgName); 1823 indentPW.increaseIndent(); 1824 indentPW.println("Proxy : " + servicePkgName); 1825 indentPW.decreaseIndent(); 1826 } 1827 // Flush before we let the app output anything to ensure correct ordering of output. 1828 // Internally, Binder#dump calls flush on its printer after finishing so we don't 1829 // need to do anything after. 1830 indentPW.flush(); 1831 try { 1832 logd("Dumping " + servicePkgName); 1833 // We don't need to give the carrier service any args. 1834 connection.service.dump(fd, null /* args */); 1835 logd("Done with " + servicePkgName); 1836 } catch (RemoteException e) { 1837 logd("RemoteException from " + servicePkgName, e); 1838 indentPW.increaseIndent(); 1839 indentPW.println("RemoteException"); 1840 indentPW.increaseIndent(); 1841 e.printStackTrace(indentPW); 1842 indentPW.decreaseIndent(); 1843 indentPW.decreaseIndent(); 1844 // We won't retry this package again because now it's in dumpedPkgNames. 1845 } 1846 indentPW.println(""); 1847 } 1848 if (dumpedPkgNames.isEmpty()) { 1849 indentPW.increaseIndent(); 1850 indentPW.println("Not bound"); 1851 indentPW.decreaseIndent(); 1852 indentPW.println(""); 1853 } 1854 indentPW.decreaseIndent(); 1855 } 1856 hasCarrierPrivileges(@onNull String pkgName, int phoneId)1857 private boolean hasCarrierPrivileges(@NonNull String pkgName, int phoneId) { 1858 int subId = SubscriptionManager.getSubscriptionId(phoneId); 1859 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 1860 return false; 1861 } 1862 return TelephonyManager.from(mContext).createForSubscriptionId(subId) 1863 .checkCarrierPrivilegesForPackage(pkgName) 1864 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 1865 } 1866 1867 /** 1868 * Get the current calling package name. 1869 * @return the current calling package name 1870 */ 1871 @Nullable getCurrentPackageName()1872 private String getCurrentPackageName() { 1873 if (mPackageManager == null) return null; 1874 String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid()); 1875 return (callingUids == null) ? null : callingUids[0]; 1876 } 1877 1878 /** 1879 * Make sure the device has required telephony feature 1880 * 1881 * @throws UnsupportedOperationException if the device does not have required telephony feature 1882 */ enforceTelephonyFeatureWithException(@ullable String callingPackage, @NonNull String methodName)1883 private void enforceTelephonyFeatureWithException(@Nullable String callingPackage, 1884 @NonNull String methodName) { 1885 if (callingPackage == null || mPackageManager == null) { 1886 return; 1887 } 1888 1889 if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis() 1890 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage, 1891 Binder.getCallingUserHandle()) 1892 || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) { 1893 // Skip to check associated telephony feature, 1894 // if compatibility change is not enabled for the current process or 1895 // the SDK version of vendor partition is less than Android V. 1896 return; 1897 } 1898 1899 if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) { 1900 throw new UnsupportedOperationException( 1901 methodName + " is unsupported without " + FEATURE_TELEPHONY_SUBSCRIPTION); 1902 } 1903 } 1904 1905 private class CarrierServiceConnection implements ServiceConnection { 1906 final int phoneId; 1907 @NonNull final String pkgName; 1908 final int eventId; 1909 IBinder service; 1910 CarrierServiceConnection(int phoneId, @NonNull String pkgName, int eventId)1911 CarrierServiceConnection(int phoneId, @NonNull String pkgName, int eventId) { 1912 this.phoneId = phoneId; 1913 this.pkgName = pkgName; 1914 this.eventId = eventId; 1915 } 1916 1917 @Override onServiceConnected(@onNull ComponentName name, @NonNull IBinder service)1918 public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) { 1919 logd("Connected to config app: " + name.flattenToShortString()); 1920 this.service = service; 1921 mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this)); 1922 } 1923 1924 @Override onServiceDisconnected(@onNull ComponentName name)1925 public void onServiceDisconnected(@NonNull ComponentName name) { 1926 logd("Disconnected from config app: " + name.flattenToShortString()); 1927 this.service = null; 1928 } 1929 1930 @Override onBindingDied(@onNull ComponentName name)1931 public void onBindingDied(@NonNull ComponentName name) { 1932 logd("Binding died from config app: " + name.flattenToShortString()); 1933 this.service = null; 1934 } 1935 1936 @Override onNullBinding(@onNull ComponentName name)1937 public void onNullBinding(@NonNull ComponentName name) { 1938 logd("Null binding from config app: " + name.flattenToShortString()); 1939 this.service = null; 1940 } 1941 } 1942 1943 private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver { 1944 @Override onReceive(@onNull Context context, @NonNull Intent intent)1945 public void onReceive(@NonNull Context context, @NonNull Intent intent) { 1946 switch (intent.getAction()) { 1947 case Intent.ACTION_BOOT_COMPLETED: 1948 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null)); 1949 break; 1950 } 1951 } 1952 } 1953 1954 private class CarrierServiceChangeCallback implements 1955 TelephonyManager.CarrierPrivilegesCallback { 1956 final int mPhoneId; 1957 // CarrierPrivilegesCallback will be triggered upon registration. Filter the first callback 1958 // here since we really care of the *change* of carrier service instead of the content 1959 private boolean mHasSentServiceChangeCallback; 1960 CarrierServiceChangeCallback(int phoneId)1961 CarrierServiceChangeCallback(int phoneId) { 1962 this.mPhoneId = phoneId; 1963 this.mHasSentServiceChangeCallback = false; 1964 } 1965 1966 @Override onCarrierPrivilegesChanged( @ndroidx.annotation.NonNull Set<String> privilegedPackageNames, @androidx.annotation.NonNull Set<Integer> privilegedUids)1967 public void onCarrierPrivilegesChanged( 1968 @androidx.annotation.NonNull Set<String> privilegedPackageNames, 1969 @androidx.annotation.NonNull Set<Integer> privilegedUids) { 1970 // Ignored, not interested here 1971 } 1972 1973 @Override onCarrierServiceChanged( @ndroidx.annotation.Nullable String carrierServicePackageName, int carrierServiceUid)1974 public void onCarrierServiceChanged( 1975 @androidx.annotation.Nullable String carrierServicePackageName, 1976 int carrierServiceUid) { 1977 // Ignore the first callback which is triggered upon registration 1978 if (!mHasSentServiceChangeCallback) { 1979 mHasSentServiceChangeCallback = true; 1980 return; 1981 } 1982 mHandler.sendMessage( 1983 mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, mPhoneId, -1, 1984 carrierServicePackageName)); 1985 } 1986 } 1987 1988 // Get readable string for the message code supported in this class. 1989 @NonNull eventToString(int code)1990 private static String eventToString(int code) { 1991 switch (code) { 1992 case EVENT_CLEAR_CONFIG: 1993 return "EVENT_CLEAR_CONFIG"; 1994 case EVENT_CONNECTED_TO_DEFAULT: 1995 return "EVENT_CONNECTED_TO_DEFAULT"; 1996 case EVENT_CONNECTED_TO_CARRIER: 1997 return "EVENT_CONNECTED_TO_CARRIER"; 1998 case EVENT_FETCH_DEFAULT_DONE: 1999 return "EVENT_FETCH_DEFAULT_DONE"; 2000 case EVENT_FETCH_CARRIER_DONE: 2001 return "EVENT_FETCH_CARRIER_DONE"; 2002 case EVENT_DO_FETCH_DEFAULT: 2003 return "EVENT_DO_FETCH_DEFAULT"; 2004 case EVENT_DO_FETCH_CARRIER: 2005 return "EVENT_DO_FETCH_CARRIER"; 2006 case EVENT_PACKAGE_CHANGED: 2007 return "EVENT_PACKAGE_CHANGED"; 2008 case EVENT_BIND_DEFAULT_TIMEOUT: 2009 return "EVENT_BIND_DEFAULT_TIMEOUT"; 2010 case EVENT_BIND_CARRIER_TIMEOUT: 2011 return "EVENT_BIND_CARRIER_TIMEOUT"; 2012 case EVENT_CHECK_SYSTEM_UPDATE: 2013 return "EVENT_CHECK_SYSTEM_UPDATE"; 2014 case EVENT_SYSTEM_UNLOCKED: 2015 return "EVENT_SYSTEM_UNLOCKED"; 2016 case EVENT_FETCH_DEFAULT_TIMEOUT: 2017 return "EVENT_FETCH_DEFAULT_TIMEOUT"; 2018 case EVENT_FETCH_CARRIER_TIMEOUT: 2019 return "EVENT_FETCH_CARRIER_TIMEOUT"; 2020 case EVENT_SUBSCRIPTION_INFO_UPDATED: 2021 return "EVENT_SUBSCRIPTION_INFO_UPDATED"; 2022 case EVENT_MULTI_SIM_CONFIG_CHANGED: 2023 return "EVENT_MULTI_SIM_CONFIG_CHANGED"; 2024 case EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG: 2025 return "EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG"; 2026 case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE: 2027 return "EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE"; 2028 case EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG: 2029 return "EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG"; 2030 case EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT: 2031 return "EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT"; 2032 case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT: 2033 return "EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT"; 2034 default: 2035 return "UNKNOWN(" + code + ")"; 2036 } 2037 } 2038 logd(@onNull String msg)2039 private void logd(@NonNull String msg) { 2040 Log.d(LOG_TAG, msg); 2041 } 2042 logd(@onNull String msg, Throwable tr)2043 private void logd(@NonNull String msg, Throwable tr) { 2044 Log.d(LOG_TAG, msg, tr); 2045 } 2046 logdWithLocalLog(@onNull String msg)2047 private void logdWithLocalLog(@NonNull String msg) { 2048 Log.d(LOG_TAG, msg); 2049 mCarrierConfigLoadingLog.log(msg); 2050 } 2051 loge(@onNull String msg)2052 private void loge(@NonNull String msg) { 2053 Log.e(LOG_TAG, msg); 2054 mCarrierConfigLoadingLog.log(msg); 2055 } 2056 } 2057