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.service.carrier.CarrierService.ICarrierServiceWrapper.KEY_CONFIG_BUNDLE; 20 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR; 21 22 import android.annotation.NonNull; 23 import android.app.ActivityManager; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.ServiceConnection; 30 import android.content.SharedPreferences; 31 import android.content.pm.PackageInfo; 32 import android.content.pm.PackageManager; 33 import android.os.Binder; 34 import android.os.Build; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.IBinder; 38 import android.os.Message; 39 import android.os.PersistableBundle; 40 import android.os.RemoteException; 41 import android.os.ResultReceiver; 42 import android.os.ServiceManager; 43 import android.os.UserHandle; 44 import android.preference.PreferenceManager; 45 import android.service.carrier.CarrierIdentifier; 46 import android.service.carrier.CarrierService; 47 import android.service.carrier.ICarrierService; 48 import android.telephony.CarrierConfigManager; 49 import android.telephony.SubscriptionManager; 50 import android.telephony.TelephonyManager; 51 import android.util.LocalLog; 52 import android.util.Log; 53 54 import com.android.internal.telephony.ICarrierConfigLoader; 55 import com.android.internal.telephony.IccCardConstants; 56 import com.android.internal.telephony.Phone; 57 import com.android.internal.telephony.PhoneFactory; 58 import com.android.internal.telephony.SubscriptionInfoUpdater; 59 import com.android.internal.telephony.TelephonyPermissions; 60 import com.android.internal.util.FastXmlSerializer; 61 import com.android.internal.util.IndentingPrintWriter; 62 63 import org.xmlpull.v1.XmlPullParser; 64 import org.xmlpull.v1.XmlPullParserException; 65 import org.xmlpull.v1.XmlPullParserFactory; 66 67 import java.io.File; 68 import java.io.FileDescriptor; 69 import java.io.FileInputStream; 70 import java.io.FileNotFoundException; 71 import java.io.FileOutputStream; 72 import java.io.FilenameFilter; 73 import java.io.IOException; 74 import java.io.PrintWriter; 75 import java.util.ArrayList; 76 import java.util.Arrays; 77 import java.util.Collections; 78 import java.util.List; 79 80 /** 81 * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays. 82 */ 83 84 public class CarrierConfigLoader extends ICarrierConfigLoader.Stub { 85 private static final String LOG_TAG = "CarrierConfigLoader"; 86 87 // Package name for platform carrier config app, bundled with system image. 88 private final String mPlatformCarrierConfigPackage; 89 90 /** The singleton instance. */ 91 private static CarrierConfigLoader sInstance; 92 // The context for phone app, passed from PhoneGlobals. 93 private Context mContext; 94 // Carrier configs from default app, indexed by phoneID. 95 private PersistableBundle[] mConfigFromDefaultApp; 96 // Carrier configs from privileged carrier config app, indexed by phoneID. 97 private PersistableBundle[] mConfigFromCarrierApp; 98 // Carrier configs that are provided via the override test API, indexed by phone ID. 99 private PersistableBundle[] mOverrideConfigs; 100 // Service connection for binding to config app. 101 private CarrierServiceConnection[] mServiceConnection; 102 // Whether we have sent config change bcast for each phone id. 103 private boolean[] mHasSentConfigChange; 104 // SubscriptionInfoUpdater 105 private final SubscriptionInfoUpdater mSubscriptionInfoUpdater; 106 107 // Broadcast receiver for Boot intents, register intent filter in construtor. 108 private final BroadcastReceiver mBootReceiver = new ConfigLoaderBroadcastReceiver(); 109 // Broadcast receiver for SIM and pkg intents, register intent filter in constructor. 110 private final BroadcastReceiver mPackageReceiver = new ConfigLoaderBroadcastReceiver(); 111 private final LocalLog mCarrierConfigLoadingLog = new LocalLog(50); 112 113 114 // Message codes; see mHandler below. 115 // Request from SubscriptionInfoUpdater when SIM becomes absent or error. 116 private static final int EVENT_CLEAR_CONFIG = 0; 117 // Has connected to default app. 118 private static final int EVENT_CONNECTED_TO_DEFAULT = 3; 119 // Has connected to carrier app. 120 private static final int EVENT_CONNECTED_TO_CARRIER = 4; 121 // Config has been loaded from default app (or cache). 122 private static final int EVENT_FETCH_DEFAULT_DONE = 5; 123 // Config has been loaded from carrier app (or cache). 124 private static final int EVENT_FETCH_CARRIER_DONE = 6; 125 // Attempt to fetch from default app or read from XML. 126 private static final int EVENT_DO_FETCH_DEFAULT = 7; 127 // Attempt to fetch from carrier app or read from XML. 128 private static final int EVENT_DO_FETCH_CARRIER = 8; 129 // A package has been installed, uninstalled, or updated. 130 private static final int EVENT_PACKAGE_CHANGED = 9; 131 // Bind timed out for the default app. 132 private static final int EVENT_BIND_DEFAULT_TIMEOUT = 10; 133 // Bind timed out for a carrier app. 134 private static final int EVENT_BIND_CARRIER_TIMEOUT = 11; 135 // Check if the system fingerprint has changed. 136 private static final int EVENT_CHECK_SYSTEM_UPDATE = 12; 137 // Rerun carrier config binding after system is unlocked. 138 private static final int EVENT_SYSTEM_UNLOCKED = 13; 139 // Fetching config timed out from the default app. 140 private static final int EVENT_FETCH_DEFAULT_TIMEOUT = 14; 141 // Fetching config timed out from a carrier app. 142 private static final int EVENT_FETCH_CARRIER_TIMEOUT = 15; 143 // SubscriptionInfoUpdater has finished updating the sub for the carrier config. 144 private static final int EVENT_SUBSCRIPTION_INFO_UPDATED = 16; 145 146 private static final int BIND_TIMEOUT_MILLIS = 30000; 147 148 // Tags used for saving and restoring XML documents. 149 private static final String TAG_DOCUMENT = "carrier_config"; 150 private static final String TAG_VERSION = "package_version"; 151 private static final String TAG_BUNDLE = "bundle_data"; 152 153 // SharedPreferences key for last known build fingerprint. 154 private static final String KEY_FINGERPRINT = "build_fingerprint"; 155 156 // Handler to process various events. 157 // 158 // For each phoneId, the event sequence should be: 159 // fetch default, connected to default, fetch default (async), fetch default done, 160 // fetch carrier, connected to carrier, fetch carrier (async), fetch carrier done. 161 // 162 // If there is a saved config file for either the default app or the carrier app, we skip 163 // binding to the app and go straight from fetch to loaded. 164 // 165 // At any time, at most one connection is active. If events are not in this order, previous 166 // connection will be unbound, so only latest event takes effect. 167 // 168 // We broadcast ACTION_CARRIER_CONFIG_CHANGED after: 169 // 1. loading from carrier app (even if read from a file) 170 // 2. loading from default app if there is no carrier app (even if read from a file) 171 // 3. clearing config (e.g. due to sim removal) 172 // 4. encountering bind or IPC error 173 private class ConfigHandler extends Handler { 174 @Override handleMessage(Message msg)175 public void handleMessage(Message msg) { 176 final int phoneId = msg.arg1; 177 logWithLocalLog("mHandler: " + msg.what + " phoneId: " + phoneId); 178 switch (msg.what) { 179 case EVENT_CLEAR_CONFIG: 180 { 181 /* Ignore clear configuration request if device is being shutdown. */ 182 Phone phone = PhoneFactory.getPhone(phoneId); 183 if (phone != null) { 184 if (phone.isShuttingDown()) { 185 break; 186 } 187 } 188 189 mConfigFromDefaultApp[phoneId] = null; 190 mConfigFromCarrierApp[phoneId] = null; 191 mServiceConnection[phoneId] = null; 192 broadcastConfigChangedIntent(phoneId, false); 193 break; 194 } 195 196 case EVENT_SYSTEM_UNLOCKED: 197 { 198 for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) { 199 // When user unlock device, we should only try to send broadcast again if we 200 // have sent it before unlock. This will avoid we try to load carrier config 201 // when SIM is still loading when unlock happens. 202 if (mHasSentConfigChange[i]) { 203 updateConfigForPhoneId(i); 204 } 205 } 206 break; 207 } 208 209 case EVENT_PACKAGE_CHANGED: 210 { 211 final String carrierPackageName = (String) msg.obj; 212 // Only update if there are cached config removed to avoid updating config for 213 // unrelated packages. 214 if (clearCachedConfigForPackage(carrierPackageName)) { 215 int numPhones = TelephonyManager.from(mContext).getPhoneCount(); 216 for (int i = 0; i < numPhones; ++i) { 217 updateConfigForPhoneId(i); 218 } 219 } 220 break; 221 } 222 223 case EVENT_DO_FETCH_DEFAULT: 224 { 225 final PersistableBundle config = 226 restoreConfigFromXml(mPlatformCarrierConfigPackage, phoneId); 227 if (config != null) { 228 log( 229 "Loaded config from XML. package=" 230 + mPlatformCarrierConfigPackage 231 + " phoneId=" 232 + phoneId); 233 mConfigFromDefaultApp[phoneId] = config; 234 Message newMsg = obtainMessage(EVENT_FETCH_DEFAULT_DONE, phoneId, -1); 235 newMsg.getData().putBoolean("loaded_from_xml", true); 236 mHandler.sendMessage(newMsg); 237 } else { 238 // No cached config, so fetch it from the default app. 239 if (bindToConfigPackage( 240 mPlatformCarrierConfigPackage, 241 phoneId, 242 EVENT_CONNECTED_TO_DEFAULT)) { 243 sendMessageDelayed( 244 obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1), 245 BIND_TIMEOUT_MILLIS); 246 } else { 247 // Send broadcast if bind fails. 248 notifySubscriptionInfoUpdater(phoneId); 249 // TODO: We *must* call unbindService even if bindService returns false. 250 // (And possibly if SecurityException was thrown.) 251 loge("binding to default app: " 252 + mPlatformCarrierConfigPackage + " fails"); 253 } 254 } 255 break; 256 } 257 258 case EVENT_CONNECTED_TO_DEFAULT: 259 { 260 removeMessages(EVENT_BIND_DEFAULT_TIMEOUT); 261 final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj; 262 // If new service connection has been created, unbind. 263 if (mServiceConnection[phoneId] != conn || conn.service == null) { 264 mContext.unbindService(conn); 265 break; 266 } 267 final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId); 268 // ResultReceiver callback will execute in this Handler's thread. 269 final ResultReceiver resultReceiver = 270 new ResultReceiver(this) { 271 @Override 272 public void onReceiveResult(int resultCode, Bundle resultData) { 273 mContext.unbindService(conn); 274 // If new service connection has been created, this is stale. 275 if (mServiceConnection[phoneId] != conn) { 276 loge("Received response for stale request."); 277 return; 278 } 279 removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT); 280 if (resultCode == RESULT_ERROR || resultData == null) { 281 // On error, abort config fetching. 282 loge("Failed to get carrier config"); 283 notifySubscriptionInfoUpdater(phoneId); 284 return; 285 } 286 PersistableBundle config = 287 resultData.getParcelable(KEY_CONFIG_BUNDLE); 288 saveConfigToXml( 289 mPlatformCarrierConfigPackage, phoneId, config); 290 mConfigFromDefaultApp[phoneId] = config; 291 sendMessage( 292 obtainMessage( 293 EVENT_FETCH_DEFAULT_DONE, phoneId, -1)); 294 } 295 }; 296 // Now fetch the config asynchronously from the ICarrierService. 297 try { 298 ICarrierService carrierService = 299 ICarrierService.Stub.asInterface(conn.service); 300 carrierService.getCarrierConfig(carrierId, resultReceiver); 301 logWithLocalLog("fetch config for default app: " 302 + mPlatformCarrierConfigPackage 303 + " carrierid: " + carrierId.toString()); 304 } catch (RemoteException e) { 305 loge("Failed to get carrier config from default app: " + 306 mPlatformCarrierConfigPackage + " err: " + e.toString()); 307 mContext.unbindService(conn); 308 break; // So we don't set a timeout. 309 } 310 sendMessageDelayed( 311 obtainMessage(EVENT_FETCH_DEFAULT_TIMEOUT, phoneId, -1), 312 BIND_TIMEOUT_MILLIS); 313 break; 314 } 315 316 case EVENT_BIND_DEFAULT_TIMEOUT: 317 case EVENT_FETCH_DEFAULT_TIMEOUT: 318 { 319 loge("bind/fetch time out from " + mPlatformCarrierConfigPackage); 320 removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT); 321 // If we attempted to bind to the app, but the service connection is null due to 322 // the race condition that clear config event happens before bind/fetch complete 323 // then config was cleared while we were waiting and we should not continue. 324 if (mServiceConnection[phoneId] != null) { 325 // If a ResponseReceiver callback is in the queue when this happens, we will 326 // unbind twice and throw an exception. 327 mContext.unbindService(mServiceConnection[phoneId]); 328 broadcastConfigChangedIntent(phoneId); 329 } 330 notifySubscriptionInfoUpdater(phoneId); 331 break; 332 } 333 334 case EVENT_FETCH_DEFAULT_DONE: 335 { 336 // If we attempted to bind to the app, but the service connection is null, then 337 // config was cleared while we were waiting and we should not continue. 338 if (!msg.getData().getBoolean("loaded_from_xml", false) 339 && mServiceConnection[phoneId] == null) { 340 break; 341 } 342 final String carrierPackageName = getCarrierPackageForPhoneId(phoneId); 343 if (carrierPackageName != null) { 344 log("Found carrier config app: " + carrierPackageName); 345 sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1)); 346 } else { 347 notifySubscriptionInfoUpdater(phoneId); 348 } 349 break; 350 } 351 352 case EVENT_DO_FETCH_CARRIER: 353 { 354 final String carrierPackageName = getCarrierPackageForPhoneId(phoneId); 355 final PersistableBundle config = 356 restoreConfigFromXml(carrierPackageName, phoneId); 357 if (config != null) { 358 log( 359 "Loaded config from XML. package=" 360 + carrierPackageName 361 + " phoneId=" 362 + phoneId); 363 mConfigFromCarrierApp[phoneId] = config; 364 Message newMsg = obtainMessage(EVENT_FETCH_CARRIER_DONE, phoneId, -1); 365 newMsg.getData().putBoolean("loaded_from_xml", true); 366 sendMessage(newMsg); 367 } else { 368 // No cached config, so fetch it from a carrier app. 369 if (carrierPackageName != null 370 && bindToConfigPackage( 371 carrierPackageName, 372 phoneId, 373 EVENT_CONNECTED_TO_CARRIER)) { 374 sendMessageDelayed( 375 obtainMessage(EVENT_BIND_CARRIER_TIMEOUT, phoneId, -1), 376 BIND_TIMEOUT_MILLIS); 377 } else { 378 // Send broadcast if bind fails. 379 broadcastConfigChangedIntent(phoneId); 380 loge("bind to carrier app: " + carrierPackageName + " fails"); 381 notifySubscriptionInfoUpdater(phoneId); 382 } 383 } 384 break; 385 } 386 387 case EVENT_CONNECTED_TO_CARRIER: 388 { 389 removeMessages(EVENT_BIND_CARRIER_TIMEOUT); 390 final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj; 391 // If new service connection has been created, unbind. 392 if (mServiceConnection[phoneId] != conn || conn.service == null) { 393 mContext.unbindService(conn); 394 break; 395 } 396 final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId); 397 // ResultReceiver callback will execute in this Handler's thread. 398 final ResultReceiver resultReceiver = 399 new ResultReceiver(this) { 400 @Override 401 public void onReceiveResult(int resultCode, Bundle resultData) { 402 mContext.unbindService(conn); 403 // If new service connection has been created, this is stale. 404 if (mServiceConnection[phoneId] != conn) { 405 loge("Received response for stale request."); 406 return; 407 } 408 removeMessages(EVENT_FETCH_CARRIER_TIMEOUT); 409 if (resultCode == RESULT_ERROR || resultData == null) { 410 // On error, abort config fetching. 411 loge("Failed to get carrier config from carrier app: " 412 + getCarrierPackageForPhoneId(phoneId)); 413 broadcastConfigChangedIntent(phoneId); 414 notifySubscriptionInfoUpdater(phoneId); 415 return; 416 } 417 PersistableBundle config = 418 resultData.getParcelable(KEY_CONFIG_BUNDLE); 419 saveConfigToXml( 420 getCarrierPackageForPhoneId(phoneId), phoneId, config); 421 mConfigFromCarrierApp[phoneId] = config; 422 sendMessage( 423 obtainMessage( 424 EVENT_FETCH_CARRIER_DONE, phoneId, -1)); 425 } 426 }; 427 // Now fetch the config asynchronously from the ICarrierService. 428 try { 429 ICarrierService carrierService = 430 ICarrierService.Stub.asInterface(conn.service); 431 carrierService.getCarrierConfig(carrierId, resultReceiver); 432 logWithLocalLog("fetch config for carrier app: " 433 + getCarrierPackageForPhoneId(phoneId) 434 + " carrierid: " + carrierId.toString()); 435 } catch (RemoteException e) { 436 loge("Failed to get carrier config: " + e.toString()); 437 mContext.unbindService(conn); 438 break; // So we don't set a timeout. 439 } 440 sendMessageDelayed( 441 obtainMessage(EVENT_FETCH_CARRIER_TIMEOUT, phoneId, -1), 442 BIND_TIMEOUT_MILLIS); 443 break; 444 } 445 446 case EVENT_BIND_CARRIER_TIMEOUT: 447 case EVENT_FETCH_CARRIER_TIMEOUT: 448 { 449 loge("bind/fetch from carrier app timeout"); 450 removeMessages(EVENT_FETCH_CARRIER_TIMEOUT); 451 // If we attempted to bind to the app, but the service connection is null due to 452 // the race condition that clear config event happens before bind/fetch complete 453 // then config was cleared while we were waiting and we should not continue. 454 if (mServiceConnection[phoneId] != null) { 455 // If a ResponseReceiver callback is in the queue when this happens, we will 456 // unbind twice and throw an exception. 457 mContext.unbindService(mServiceConnection[phoneId]); 458 broadcastConfigChangedIntent(phoneId); 459 } 460 notifySubscriptionInfoUpdater(phoneId); 461 break; 462 } 463 case EVENT_FETCH_CARRIER_DONE: 464 { 465 // If we attempted to bind to the app, but the service connection is null, then 466 // config was cleared while we were waiting and we should not continue. 467 if (!msg.getData().getBoolean("loaded_from_xml", false) 468 && mServiceConnection[phoneId] == null) { 469 break; 470 } 471 notifySubscriptionInfoUpdater(phoneId); 472 break; 473 } 474 475 case EVENT_CHECK_SYSTEM_UPDATE: 476 { 477 SharedPreferences sharedPrefs = 478 PreferenceManager.getDefaultSharedPreferences(mContext); 479 final String lastFingerprint = sharedPrefs.getString(KEY_FINGERPRINT, null); 480 if (!Build.FINGERPRINT.equals(lastFingerprint)) { 481 log( 482 "Build fingerprint changed. old: " 483 + lastFingerprint 484 + " new: " 485 + Build.FINGERPRINT); 486 clearCachedConfigForPackage(null); 487 sharedPrefs 488 .edit() 489 .putString(KEY_FINGERPRINT, Build.FINGERPRINT) 490 .apply(); 491 } 492 break; 493 } 494 495 case EVENT_SUBSCRIPTION_INFO_UPDATED: 496 broadcastConfigChangedIntent(phoneId); 497 break; 498 } 499 } 500 } 501 502 private final Handler mHandler; 503 504 /** 505 * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast 506 * receiver for relevant events. 507 */ CarrierConfigLoader(Context context)508 private CarrierConfigLoader(Context context) { 509 mContext = context; 510 mPlatformCarrierConfigPackage = 511 mContext.getString(R.string.platform_carrier_config_package); 512 mHandler = new ConfigHandler(); 513 514 IntentFilter bootFilter = new IntentFilter(); 515 bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 516 context.registerReceiver(mBootReceiver, bootFilter); 517 518 // Register for package updates. Update app or uninstall app update will have all 3 intents, 519 // in the order or removed, added, replaced, all with extra_replace set to true. 520 IntentFilter pkgFilter = new IntentFilter(); 521 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 522 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 523 pkgFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); 524 pkgFilter.addDataScheme("package"); 525 context.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, pkgFilter, null, null); 526 527 int numPhones = TelephonyManager.from(context).getPhoneCount(); 528 mConfigFromDefaultApp = new PersistableBundle[numPhones]; 529 mConfigFromCarrierApp = new PersistableBundle[numPhones]; 530 mOverrideConfigs = new PersistableBundle[numPhones]; 531 mServiceConnection = new CarrierServiceConnection[numPhones]; 532 mHasSentConfigChange = new boolean[numPhones]; 533 // Make this service available through ServiceManager. 534 ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this); 535 log("CarrierConfigLoader has started"); 536 mSubscriptionInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); 537 mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE); 538 } 539 540 /** 541 * Initialize the singleton CarrierConfigLoader instance. 542 * 543 * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}. 544 */ 545 /* package */ init(Context context)546 static CarrierConfigLoader init(Context context) { 547 synchronized (CarrierConfigLoader.class) { 548 if (sInstance == null) { 549 sInstance = new CarrierConfigLoader(context); 550 } else { 551 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); 552 } 553 return sInstance; 554 } 555 } 556 notifySubscriptionInfoUpdater(int phoneId)557 private void notifySubscriptionInfoUpdater(int phoneId) { 558 String configPackagename; 559 PersistableBundle configToSend; 560 int carrierId = getSpecificCarrierIdForPhoneId(phoneId); 561 // Prefer the carrier privileged carrier app, but if there is not one, use the platform 562 // default carrier app. 563 if (mConfigFromCarrierApp[phoneId] != null) { 564 configPackagename = getCarrierPackageForPhoneId(phoneId); 565 configToSend = mConfigFromCarrierApp[phoneId]; 566 } else { 567 configPackagename = mPlatformCarrierConfigPackage; 568 configToSend = mConfigFromDefaultApp[phoneId]; 569 } 570 mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete( 571 phoneId, configPackagename, configToSend, 572 mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1)); 573 } 574 broadcastConfigChangedIntent(int phoneId)575 private void broadcastConfigChangedIntent(int phoneId) { 576 broadcastConfigChangedIntent(phoneId, true); 577 } 578 broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra)579 private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) { 580 Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 581 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | 582 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | 583 Intent.FLAG_RECEIVER_FOREGROUND); 584 // Include subId/carrier id extra only if SIM records are loaded 585 TelephonyManager telephonyManager = TelephonyManager.from(mContext); 586 int simApplicationState = telephonyManager.getSimApplicationState(); 587 if (addSubIdExtra && (simApplicationState != TelephonyManager.SIM_STATE_UNKNOWN 588 && simApplicationState != TelephonyManager.SIM_STATE_NOT_READY)) { 589 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); 590 intent.putExtra(TelephonyManager.EXTRA_SPECIFIC_CARRIER_ID, 591 getSpecificCarrierIdForPhoneId(phoneId)); 592 intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, getCarrierIdForPhoneId(phoneId)); 593 } 594 intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId); 595 log("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId); 596 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); 597 mHasSentConfigChange[phoneId] = true; 598 } 599 600 /** Binds to the default or carrier config app. */ bindToConfigPackage(String pkgName, int phoneId, int eventId)601 private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) { 602 logWithLocalLog("Binding to " + pkgName + " for phone " + phoneId); 603 Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE); 604 carrierService.setPackage(pkgName); 605 mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId); 606 try { 607 return mContext.bindService(carrierService, mServiceConnection[phoneId], 608 Context.BIND_AUTO_CREATE); 609 } catch (SecurityException ex) { 610 return false; 611 } 612 } 613 getCarrierIdentifierForPhoneId(int phoneId)614 private CarrierIdentifier getCarrierIdentifierForPhoneId(int phoneId) { 615 String mcc = ""; 616 String mnc = ""; 617 String imsi = ""; 618 String gid1 = ""; 619 String gid2 = ""; 620 String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId); 621 String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId); 622 int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 623 int specificCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 624 // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC. 625 if (simOperator != null && simOperator.length() >= 3) { 626 mcc = simOperator.substring(0, 3); 627 mnc = simOperator.substring(3); 628 } 629 Phone phone = PhoneFactory.getPhone(phoneId); 630 if (phone != null) { 631 imsi = phone.getSubscriberId(); 632 gid1 = phone.getGroupIdLevel1(); 633 gid2 = phone.getGroupIdLevel2(); 634 carrierId = phone.getCarrierId(); 635 specificCarrierId = phone.getSpecificCarrierId(); 636 } 637 return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2, carrierId, specificCarrierId); 638 } 639 640 /** Returns the package name of a priveleged carrier app, or null if there is none. */ getCarrierPackageForPhoneId(int phoneId)641 private String getCarrierPackageForPhoneId(int phoneId) { 642 List<String> carrierPackageNames = TelephonyManager.from(mContext) 643 .getCarrierPackageNamesForIntentAndPhone( 644 new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId); 645 if (carrierPackageNames != null && carrierPackageNames.size() > 0) { 646 return carrierPackageNames.get(0); 647 } else { 648 return null; 649 } 650 } 651 getIccIdForPhoneId(int phoneId)652 private String getIccIdForPhoneId(int phoneId) { 653 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 654 return null; 655 } 656 Phone phone = PhoneFactory.getPhone(phoneId); 657 if (phone == null) { 658 return null; 659 } 660 return phone.getIccSerialNumber(); 661 } 662 663 /** 664 * Get the sim specific carrier id {@link TelephonyManager#getSimSpecificCarrierId()} 665 */ getSpecificCarrierIdForPhoneId(int phoneId)666 private int getSpecificCarrierIdForPhoneId(int phoneId) { 667 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 668 return TelephonyManager.UNKNOWN_CARRIER_ID; 669 } 670 Phone phone = PhoneFactory.getPhone(phoneId); 671 if (phone == null) { 672 return TelephonyManager.UNKNOWN_CARRIER_ID; 673 } 674 return phone.getSpecificCarrierId(); 675 } 676 677 /** 678 * Get the sim carrier id {@link TelephonyManager#getSimCarrierId() } 679 */ getCarrierIdForPhoneId(int phoneId)680 private int getCarrierIdForPhoneId(int phoneId) { 681 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 682 return TelephonyManager.UNKNOWN_CARRIER_ID; 683 } 684 Phone phone = PhoneFactory.getPhone(phoneId); 685 if (phone == null) { 686 return TelephonyManager.UNKNOWN_CARRIER_ID; 687 } 688 return phone.getCarrierId(); 689 } 690 691 /** 692 * Writes a bundle to an XML file. 693 * 694 * The bundle will be written to a file named after the package name, ICCID and 695 * specific carrier id {@link TelephonyManager#getSimSpecificCarrierId()}. the same carrier 696 * should have a single copy of XML file named after carrier id. However, it's still possible 697 * that platform doesn't recognize the current sim carrier, we will use iccid + carrierid as 698 * the canonical file name. carrierid can also handle the cases SIM OTA resolves to different 699 * carrier while iccid remains the same. 700 * 701 * The file can be restored later with {@link @restoreConfigFromXml}. The XML output will 702 * include the bundle and the current version of the specified package. 703 * 704 * In case of errors or invalid input, no file will be written. 705 * 706 * @param packageName the name of the package from which we fetched this bundle. 707 * @param phoneId the phone ID. 708 * @param config the bundle to be written. Null will be treated as an empty bundle. 709 */ saveConfigToXml(String packageName, int phoneId, PersistableBundle config)710 private void saveConfigToXml(String packageName, int phoneId, PersistableBundle config) { 711 if (SubscriptionManager.getSimStateForSlotIndex(phoneId) 712 != TelephonyManager.SIM_STATE_LOADED) { 713 loge("Skip save config because SIM records are not loaded."); 714 return; 715 } 716 717 final String iccid = getIccIdForPhoneId(phoneId); 718 final int cid = getSpecificCarrierIdForPhoneId(phoneId); 719 if (packageName == null || iccid == null) { 720 loge("Cannot save config with null packageName or iccid."); 721 return; 722 } 723 // b/32668103 Only save to file if config isn't empty. 724 // In case of failure, not caching an empty bundle will 725 // try loading config again on next power on or sim loaded. 726 // Downside is for genuinely empty bundle, will bind and load 727 // on every power on. 728 if (config == null || config.isEmpty()) { 729 return; 730 } 731 732 final String version = getPackageVersion(packageName); 733 if (version == null) { 734 loge("Failed to get package version for: " + packageName); 735 return; 736 } 737 738 logWithLocalLog("save config to xml, packagename: " + packageName + " phoneId: " + phoneId); 739 740 FileOutputStream outFile = null; 741 try { 742 outFile = new FileOutputStream( 743 new File(mContext.getFilesDir(), 744 getFilenameForConfig(packageName, iccid, cid))); 745 FastXmlSerializer out = new FastXmlSerializer(); 746 out.setOutput(outFile, "utf-8"); 747 out.startDocument("utf-8", true); 748 out.startTag(null, TAG_DOCUMENT); 749 out.startTag(null, TAG_VERSION); 750 out.text(version); 751 out.endTag(null, TAG_VERSION); 752 out.startTag(null, TAG_BUNDLE); 753 config.saveToXml(out); 754 out.endTag(null, TAG_BUNDLE); 755 out.endTag(null, TAG_DOCUMENT); 756 out.endDocument(); 757 out.flush(); 758 outFile.close(); 759 } 760 catch (IOException e) { 761 loge(e.toString()); 762 } 763 catch (XmlPullParserException e) { 764 loge(e.toString()); 765 } 766 } 767 768 /** 769 * Reads a bundle from an XML file. 770 * 771 * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved 772 * config bundle for the given package and phone ID. 773 * 774 * In case of errors, or if the saved config is from a different package version than the 775 * current version, then null will be returned. 776 * 777 * @param packageName the name of the package from which we fetched this bundle. 778 * @param phoneId the phone ID. 779 * @return the bundle from the XML file. Returns null if there is no saved config, the saved 780 * version does not match, or reading config fails. 781 */ restoreConfigFromXml(String packageName, int phoneId)782 private PersistableBundle restoreConfigFromXml(String packageName, int phoneId) { 783 final String version = getPackageVersion(packageName); 784 if (version == null) { 785 loge("Failed to get package version for: " + packageName); 786 return null; 787 } 788 if (SubscriptionManager.getSimStateForSlotIndex(phoneId) 789 != TelephonyManager.SIM_STATE_LOADED) { 790 loge("Skip restoring config because SIM records are not yet loaded."); 791 return null; 792 } 793 794 final String iccid = getIccIdForPhoneId(phoneId); 795 final int cid = getSpecificCarrierIdForPhoneId(phoneId); 796 if (packageName == null || iccid == null) { 797 loge("Cannot restore config with null packageName or iccid."); 798 return null; 799 } 800 801 PersistableBundle restoredBundle = null; 802 FileInputStream inFile = null; 803 try { 804 inFile = new FileInputStream( 805 new File(mContext.getFilesDir(), 806 getFilenameForConfig(packageName, iccid, cid))); 807 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 808 parser.setInput(inFile, "utf-8"); 809 810 int event; 811 while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) { 812 813 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) { 814 String savedVersion = parser.nextText(); 815 if (!version.equals(savedVersion)) { 816 loge("Saved version mismatch: " + version + " vs " + savedVersion); 817 break; 818 } 819 } 820 821 if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) { 822 restoredBundle = PersistableBundle.restoreFromXml(parser); 823 } 824 } 825 inFile.close(); 826 } 827 catch (FileNotFoundException e) { 828 loge(e.toString()); 829 } 830 catch (XmlPullParserException e) { 831 loge(e.toString()); 832 } 833 catch (IOException e) { 834 loge(e.toString()); 835 } 836 837 return restoredBundle; 838 } 839 840 /** 841 * Clears cached carrier config. 842 * This deletes all saved XML files associated with the given package name. If packageName is 843 * null, then it deletes all saved XML files. 844 * 845 * @param packageName the name of a carrier package, or null if all cached config should be 846 * cleared. 847 * @return true iff one or more files were deleted. 848 */ clearCachedConfigForPackage(final String packageName)849 private boolean clearCachedConfigForPackage(final String packageName) { 850 File dir = mContext.getFilesDir(); 851 File[] packageFiles = dir.listFiles(new FilenameFilter() { 852 public boolean accept(File dir, String filename) { 853 if (packageName != null) { 854 return filename.startsWith("carrierconfig-" + packageName + "-"); 855 } else { 856 return filename.startsWith("carrierconfig-"); 857 } 858 } 859 }); 860 if (packageFiles == null || packageFiles.length < 1) return false; 861 for (File f : packageFiles) { 862 log("deleting " + f.getName()); 863 f.delete(); 864 } 865 return true; 866 } 867 868 /** Builds a canonical file name for a config file. */ getFilenameForConfig(@onNull String packageName, @NonNull String iccid, int cid)869 private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid, 870 int cid) { 871 // the same carrier should have a single copy of XML file named after carrier id. 872 // However, it's still possible that platform doesn't recognize the current sim carrier, 873 // we will use iccid + carrierid as the canonical file name. carrierid can also handle the 874 // cases SIM OTA resolves to different carrier while iccid remains the same. 875 return "carrierconfig-" + packageName + "-" + iccid + "-" + cid + ".xml"; 876 } 877 878 /** Return the current version code of a package, or null if the name is not found. */ getPackageVersion(String packageName)879 private String getPackageVersion(String packageName) { 880 try { 881 PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0); 882 return Long.toString(info.getLongVersionCode()); 883 } catch (PackageManager.NameNotFoundException e) { 884 return null; 885 } 886 } 887 888 /** 889 * Read up to date config. 890 * 891 * This reads config bundles for the given phoneId. That means getting the latest bundle from 892 * the default app and a privileged carrier app, if present. This will not bind to an app if we 893 * have a saved config file to use instead. 894 */ updateConfigForPhoneId(int phoneId)895 private void updateConfigForPhoneId(int phoneId) { 896 // Clear in-memory cache for carrier app config, so when carrier app gets uninstalled, no 897 // stale config is left. 898 if (mConfigFromCarrierApp[phoneId] != null && 899 getCarrierPackageForPhoneId(phoneId) == null) { 900 mConfigFromCarrierApp[phoneId] = null; 901 } 902 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1)); 903 } 904 905 @Override getConfigForSubId(int subId, String callingPackage)906 public @NonNull PersistableBundle getConfigForSubId(int subId, String callingPackage) { 907 if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( 908 mContext, subId, callingPackage, "getCarrierConfig")) { 909 return new PersistableBundle(); 910 } 911 912 int phoneId = SubscriptionManager.getPhoneId(subId); 913 PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig(); 914 if (SubscriptionManager.isValidPhoneId(phoneId)) { 915 PersistableBundle config = mConfigFromDefaultApp[phoneId]; 916 if (config != null) { 917 retConfig.putAll(config); 918 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); 919 } 920 config = mConfigFromCarrierApp[phoneId]; 921 if (config != null) { 922 retConfig.putAll(config); 923 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); 924 } 925 config = mOverrideConfigs[phoneId]; 926 if (config != null) { 927 retConfig.putAll(config); 928 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); 929 } 930 } 931 return retConfig; 932 } 933 934 @Override overrideConfig(int subscriptionId, PersistableBundle overrides)935 public void overrideConfig(int subscriptionId, PersistableBundle overrides) { 936 mContext.enforceCallingOrSelfPermission( 937 android.Manifest.permission.MODIFY_PHONE_STATE, null); 938 //TODO: Also check for SHELL UID to restrict this method to testing only (b/131326259) 939 int phoneId = SubscriptionManager.getPhoneId(subscriptionId); 940 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 941 log("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId); 942 return; 943 } 944 945 if (overrides == null) { 946 mOverrideConfigs[phoneId] = new PersistableBundle(); 947 } else if (mOverrideConfigs[phoneId] == null) { 948 mOverrideConfigs[phoneId] = overrides; 949 } else { 950 mOverrideConfigs[phoneId].putAll(overrides); 951 } 952 953 notifySubscriptionInfoUpdater(phoneId); 954 } 955 956 @Override notifyConfigChangedForSubId(int subId)957 public void notifyConfigChangedForSubId(int subId) { 958 int phoneId = SubscriptionManager.getPhoneId(subId); 959 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 960 log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId); 961 return; 962 } 963 964 // Requires the calling app to be either a carrier privileged app for this subId or 965 // system privileged app with MODIFY_PHONE_STATE permission. 966 TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext, subId, 967 "Require carrier privileges or MODIFY_PHONE_STATE permission."); 968 969 // This method should block until deleting has completed, so that an error which prevents us 970 // from clearing the cache is passed back to the carrier app. With the files successfully 971 // deleted, this can return and we will eventually bind to the carrier app. 972 String callingPackageName = mContext.getPackageManager().getNameForUid( 973 Binder.getCallingUid()); 974 clearCachedConfigForPackage(callingPackageName); 975 updateConfigForPhoneId(phoneId); 976 } 977 978 @Override updateConfigForPhoneId(int phoneId, String simState)979 public void updateConfigForPhoneId(int phoneId, String simState) { 980 mContext.enforceCallingOrSelfPermission( 981 android.Manifest.permission.MODIFY_PHONE_STATE, null); 982 logWithLocalLog("update config for phoneId: " + phoneId + " simState: " + simState); 983 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 984 return; 985 } 986 // requires Java 7 for switch on string. 987 switch (simState) { 988 case IccCardConstants.INTENT_VALUE_ICC_ABSENT: 989 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: 990 case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: 991 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: 992 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1)); 993 break; 994 case IccCardConstants.INTENT_VALUE_ICC_LOADED: 995 case IccCardConstants.INTENT_VALUE_ICC_LOCKED: 996 updateConfigForPhoneId(phoneId); 997 break; 998 } 999 } 1000 1001 @Override getDefaultCarrierServicePackageName()1002 public String getDefaultCarrierServicePackageName() { 1003 return mPlatformCarrierConfigPackage; 1004 } 1005 1006 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1007 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1008 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1009 != PackageManager.PERMISSION_GRANTED) { 1010 pw.println("Permission Denial: can't dump carrierconfig from from pid=" 1011 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 1012 return; 1013 } 1014 pw.println("CarrierConfigLoader: " + this); 1015 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) { 1016 pw.println("Phone Id = " + i); 1017 // display default values in CarrierConfigManager 1018 printConfig(CarrierConfigManager.getDefaultConfig(), pw, 1019 "Default Values from CarrierConfigManager"); 1020 pw.println(""); 1021 // display ConfigFromDefaultApp 1022 printConfig(mConfigFromDefaultApp[i], pw, "mConfigFromDefaultApp"); 1023 pw.println(""); 1024 // display ConfigFromCarrierApp 1025 printConfig(mConfigFromCarrierApp[i], pw, "mConfigFromCarrierApp"); 1026 pw.println(""); 1027 printConfig(mOverrideConfigs[i], pw, "mOverrideConfigs"); 1028 } 1029 1030 pw.println("CarrierConfigLoadingLog="); 1031 mCarrierConfigLoadingLog.dump(fd, pw, args); 1032 } 1033 printConfig(PersistableBundle configApp, PrintWriter pw, String name)1034 private void printConfig(PersistableBundle configApp, PrintWriter pw, String name) { 1035 IndentingPrintWriter indentPW = new IndentingPrintWriter(pw, " "); 1036 if (configApp == null) { 1037 indentPW.increaseIndent(); 1038 indentPW.println(name + " : null "); 1039 return; 1040 } 1041 indentPW.increaseIndent(); 1042 indentPW.println(name + " : "); 1043 List<String> sortedKeys = new ArrayList<String>(configApp.keySet()); 1044 Collections.sort(sortedKeys); 1045 indentPW.increaseIndent(); 1046 indentPW.increaseIndent(); 1047 for (String key : sortedKeys) { 1048 if (configApp.get(key) != null && configApp.get(key) instanceof Object[]) { 1049 indentPW.println(key + " = " + 1050 Arrays.toString((Object[]) configApp.get(key))); 1051 } else if (configApp.get(key) != null && configApp.get(key) instanceof int[]) { 1052 indentPW.println(key + " = " + Arrays.toString((int[]) configApp.get(key))); 1053 } else { 1054 indentPW.println(key + " = " + configApp.get(key)); 1055 } 1056 } 1057 } 1058 1059 private class CarrierServiceConnection implements ServiceConnection { 1060 int phoneId; 1061 int eventId; 1062 IBinder service; 1063 CarrierServiceConnection(int phoneId, int eventId)1064 public CarrierServiceConnection(int phoneId, int eventId) { 1065 this.phoneId = phoneId; 1066 this.eventId = eventId; 1067 } 1068 1069 @Override onServiceConnected(ComponentName name, IBinder service)1070 public void onServiceConnected(ComponentName name, IBinder service) { 1071 log("Connected to config app: " + name.flattenToString()); 1072 this.service = service; 1073 mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this)); 1074 } 1075 1076 @Override onServiceDisconnected(ComponentName name)1077 public void onServiceDisconnected(ComponentName name) { 1078 this.service = null; 1079 } 1080 } 1081 1082 private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver { 1083 @Override onReceive(Context context, Intent intent)1084 public void onReceive(Context context, Intent intent) { 1085 String action = intent.getAction(); 1086 boolean replace = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 1087 // If replace is true, only care ACTION_PACKAGE_REPLACED. 1088 if (replace && !Intent.ACTION_PACKAGE_REPLACED.equals(action)) 1089 return; 1090 1091 switch (action) { 1092 case Intent.ACTION_BOOT_COMPLETED: 1093 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null)); 1094 break; 1095 1096 case Intent.ACTION_PACKAGE_ADDED: 1097 case Intent.ACTION_PACKAGE_REMOVED: 1098 case Intent.ACTION_PACKAGE_REPLACED: 1099 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 1100 String packageName = mContext.getPackageManager().getNameForUid(uid); 1101 if (packageName != null) { 1102 // We don't have a phoneId for arg1. 1103 mHandler.sendMessage( 1104 mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, packageName)); 1105 } 1106 break; 1107 } 1108 } 1109 } 1110 log(String msg)1111 private void log(String msg) { 1112 Log.d(LOG_TAG, msg); 1113 } 1114 logWithLocalLog(String msg)1115 private void logWithLocalLog(String msg) { 1116 Log.d(LOG_TAG, msg); 1117 mCarrierConfigLoadingLog.log(msg); 1118 } 1119 loge(String msg)1120 private void loge(String msg) { 1121 Log.e(LOG_TAG, msg); 1122 mCarrierConfigLoadingLog.log(msg); 1123 } 1124 } 1125