1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony; 18 19 import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA; 20 import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE; 21 22 import static java.util.Arrays.copyOf; 23 24 import android.annotation.Nullable; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.SharedPreferences; 29 import android.content.pm.PackageManager; 30 import android.net.LocalServerSocket; 31 import android.os.Build; 32 import android.os.HandlerThread; 33 import android.os.Looper; 34 import android.preference.PreferenceManager; 35 import android.provider.Settings; 36 import android.provider.Settings.SettingNotFoundException; 37 import android.telephony.AnomalyReporter; 38 import android.telephony.RadioAccessFamily; 39 import android.telephony.SubscriptionManager; 40 import android.telephony.TelephonyManager; 41 import android.util.LocalLog; 42 43 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; 44 import com.android.internal.telephony.dataconnection.TelephonyNetworkFactory; 45 import com.android.internal.telephony.euicc.EuiccCardController; 46 import com.android.internal.telephony.euicc.EuiccController; 47 import com.android.internal.telephony.imsphone.ImsPhone; 48 import com.android.internal.telephony.imsphone.ImsPhoneFactory; 49 import com.android.internal.telephony.metrics.MetricsCollector; 50 import com.android.internal.telephony.metrics.TelephonyMetrics; 51 import com.android.internal.telephony.sip.SipPhone; 52 import com.android.internal.telephony.sip.SipPhoneFactory; 53 import com.android.internal.telephony.uicc.UiccController; 54 import com.android.internal.telephony.util.NotificationChannelController; 55 import com.android.internal.util.IndentingPrintWriter; 56 import com.android.telephony.Rlog; 57 58 import java.io.FileDescriptor; 59 import java.io.PrintWriter; 60 import java.util.HashMap; 61 import java.util.Map; 62 63 /** 64 * {@hide} 65 */ 66 public class PhoneFactory { 67 static final String LOG_TAG = "PhoneFactory"; 68 static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000; 69 static final int SOCKET_OPEN_MAX_RETRY = 3; 70 static final boolean DBG = false; 71 72 //***** Class Variables 73 74 // lock sLockProxyPhones protects sPhones, sPhone and sTelephonyNetworkFactories 75 final static Object sLockProxyPhones = new Object(); 76 static private Phone[] sPhones = null; 77 static private Phone sPhone = null; 78 79 static private CommandsInterface[] sCommandsInterfaces = null; 80 81 static private ProxyController sProxyController; 82 static private UiccController sUiccController; 83 private static IntentBroadcaster sIntentBroadcaster; 84 private static @Nullable EuiccController sEuiccController; 85 private static @Nullable EuiccCardController sEuiccCardController; 86 87 static private SubscriptionInfoUpdater sSubInfoRecordUpdater = null; 88 89 @UnsupportedAppUsage 90 static private boolean sMadeDefaults = false; 91 @UnsupportedAppUsage 92 static private PhoneNotifier sPhoneNotifier; 93 @UnsupportedAppUsage 94 static private Context sContext; 95 static private PhoneConfigurationManager sPhoneConfigurationManager; 96 static private PhoneSwitcher sPhoneSwitcher; 97 static private TelephonyNetworkFactory[] sTelephonyNetworkFactories; 98 static private NotificationChannelController sNotificationChannelController; 99 static private CellularNetworkValidator sCellularNetworkValidator; 100 101 static private final HashMap<String, LocalLog>sLocalLogs = new HashMap<String, LocalLog>(); 102 private static MetricsCollector sMetricsCollector; 103 private static RadioInterfaceCapabilityController sRadioHalCapabilities; 104 105 //***** Class Methods 106 makeDefaultPhones(Context context)107 public static void makeDefaultPhones(Context context) { 108 makeDefaultPhone(context); 109 } 110 111 /** 112 * FIXME replace this with some other way of making these 113 * instances 114 */ 115 @UnsupportedAppUsage makeDefaultPhone(Context context)116 public static void makeDefaultPhone(Context context) { 117 synchronized (sLockProxyPhones) { 118 if (!sMadeDefaults) { 119 sContext = context; 120 // create the telephony device controller. 121 TelephonyDevController.create(); 122 123 TelephonyMetrics metrics = TelephonyMetrics.getInstance(); 124 metrics.setContext(context); 125 126 int retryCount = 0; 127 for(;;) { 128 boolean hasException = false; 129 retryCount ++; 130 131 try { 132 // use UNIX domain socket to 133 // prevent subsequent initialization 134 new LocalServerSocket("com.android.internal.telephony"); 135 } catch (java.io.IOException ex) { 136 hasException = true; 137 } 138 139 if ( !hasException ) { 140 break; 141 } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { 142 throw new RuntimeException("PhoneFactory probably already running"); 143 } else { 144 try { 145 Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); 146 } catch (InterruptedException er) { 147 } 148 } 149 } 150 151 // register statsd pullers. 152 sMetricsCollector = new MetricsCollector(context); 153 154 sPhoneNotifier = new DefaultPhoneNotifier(context); 155 156 int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); 157 Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription); 158 159 /* In case of multi SIM mode two instances of Phone, RIL are created, 160 where as in single SIM mode only instance. isMultiSimEnabled() function checks 161 whether it is single SIM or multi SIM mode */ 162 int numPhones = TelephonyManager.getDefault().getActiveModemCount(); 163 164 int[] networkModes = new int[numPhones]; 165 sPhones = new Phone[numPhones]; 166 sCommandsInterfaces = new RIL[numPhones]; 167 sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones]; 168 169 for (int i = 0; i < numPhones; i++) { 170 // reads the system properties and makes commandsinterface 171 // Get preferred network type. 172 networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE; 173 174 Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i])); 175 sCommandsInterfaces[i] = new RIL(context, 176 RadioAccessFamily.getRafFromNetworkType(networkModes[i]), 177 cdmaSubscription, i); 178 } 179 180 if (numPhones > 0) { 181 final RadioConfig radioConfig = RadioConfig.make(context, 182 sCommandsInterfaces[0].getHalVersion()); 183 sRadioHalCapabilities = RadioInterfaceCapabilityController.init(radioConfig, 184 sCommandsInterfaces[0]); 185 } else { 186 // There is no command interface to go off of 187 final RadioConfig radioConfig = RadioConfig.make(context, HalVersion.UNKNOWN); 188 sRadioHalCapabilities = RadioInterfaceCapabilityController.init( 189 radioConfig, null); 190 } 191 192 193 // Instantiate UiccController so that all other classes can just 194 // call getInstance() 195 sUiccController = UiccController.make(context); 196 197 Rlog.i(LOG_TAG, "Creating SubscriptionController"); 198 TelephonyComponentFactory.getInstance().inject(SubscriptionController.class. 199 getName()).initSubscriptionController(context); 200 TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. 201 getName()).initMultiSimSettingController(context, 202 SubscriptionController.getInstance()); 203 204 if (context.getPackageManager().hasSystemFeature( 205 PackageManager.FEATURE_TELEPHONY_EUICC)) { 206 sEuiccController = EuiccController.init(context); 207 sEuiccCardController = EuiccCardController.init(context); 208 } 209 210 for (int i = 0; i < numPhones; i++) { 211 sPhones[i] = createPhone(context, i); 212 } 213 214 // Set the default phone in base class. 215 // FIXME: This is a first best guess at what the defaults will be. It 216 // FIXME: needs to be done in a more controlled manner in the future. 217 if (numPhones > 0) sPhone = sPhones[0]; 218 219 // Ensure that we have a default SMS app. Requesting the app with 220 // updateIfNeeded set to true is enough to configure a default SMS app. 221 ComponentName componentName = 222 SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */); 223 String packageName = "NONE"; 224 if (componentName != null) { 225 packageName = componentName.getPackageName(); 226 } 227 Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName); 228 229 // Set up monitor to watch for changes to SMS packages 230 SmsApplication.initSmsPackageMonitor(context); 231 232 sMadeDefaults = true; 233 234 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); 235 HandlerThread pfhandlerThread = new HandlerThread("PhoneFactoryHandlerThread"); 236 pfhandlerThread.start(); 237 sSubInfoRecordUpdater = TelephonyComponentFactory.getInstance().inject( 238 SubscriptionInfoUpdater.class.getName()). 239 makeSubscriptionInfoUpdater(pfhandlerThread. 240 getLooper(), context, SubscriptionController.getInstance()); 241 242 // Only bring up IMS if the device supports having an IMS stack. 243 if (context.getPackageManager().hasSystemFeature( 244 PackageManager.FEATURE_TELEPHONY_IMS)) { 245 // Start monitoring after defaults have been made. 246 // Default phone must be ready before ImsPhone is created because ImsService 247 // might need it when it is being opened. 248 for (int i = 0; i < numPhones; i++) { 249 sPhones[i].createImsPhone(); 250 } 251 } else { 252 Rlog.i(LOG_TAG, "IMS is not supported on this device, skipping ImsResolver."); 253 } 254 255 sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext); 256 257 sCellularNetworkValidator = CellularNetworkValidator.make(sContext); 258 259 int maxActivePhones = sPhoneConfigurationManager 260 .getNumberOfModemsWithSimultaneousDataConnections(); 261 262 sPhoneSwitcher = TelephonyComponentFactory.getInstance().inject( 263 PhoneSwitcher.class.getName()). 264 makePhoneSwitcher(maxActivePhones, sContext, Looper.myLooper()); 265 266 sProxyController = ProxyController.getInstance(context); 267 268 sIntentBroadcaster = IntentBroadcaster.getInstance(context); 269 270 sNotificationChannelController = new NotificationChannelController(context); 271 272 for (int i = 0; i < numPhones; i++) { 273 sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory( 274 Looper.myLooper(), sPhones[i]); 275 } 276 } 277 } 278 } 279 280 /** 281 * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate 282 * Phone and CommandInterface objects. 283 * @param context 284 * @param activeModemCount 285 */ onMultiSimConfigChanged(Context context, int activeModemCount)286 public static void onMultiSimConfigChanged(Context context, int activeModemCount) { 287 synchronized (sLockProxyPhones) { 288 int prevActiveModemCount = sPhones.length; 289 if (prevActiveModemCount == activeModemCount) return; 290 291 // TODO: clean up sPhones, sCommandsInterfaces and sTelephonyNetworkFactories objects. 292 // Currently we will not clean up the 2nd Phone object, so that it can be re-used if 293 // user switches back. 294 if (prevActiveModemCount > activeModemCount) return; 295 296 sPhones = copyOf(sPhones, activeModemCount); 297 sCommandsInterfaces = copyOf(sCommandsInterfaces, activeModemCount); 298 sTelephonyNetworkFactories = copyOf(sTelephonyNetworkFactories, activeModemCount); 299 300 int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); 301 for (int i = prevActiveModemCount; i < activeModemCount; i++) { 302 sCommandsInterfaces[i] = new RIL(context, RadioAccessFamily.getRafFromNetworkType( 303 RILConstants.PREFERRED_NETWORK_MODE), 304 cdmaSubscription, i); 305 sPhones[i] = createPhone(context, i); 306 if (context.getPackageManager().hasSystemFeature( 307 PackageManager.FEATURE_TELEPHONY_IMS)) { 308 sPhones[i].createImsPhone(); 309 } 310 sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory( 311 Looper.myLooper(), sPhones[i]); 312 } 313 } 314 } 315 createPhone(Context context, int phoneId)316 private static Phone createPhone(Context context, int phoneId) { 317 int phoneType = TelephonyManager.getPhoneType(RILConstants.PREFERRED_NETWORK_MODE); 318 Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " phoneId = " + phoneId); 319 320 // We always use PHONE_TYPE_CDMA_LTE now. 321 if (phoneType == PHONE_TYPE_CDMA) phoneType = PHONE_TYPE_CDMA_LTE; 322 TelephonyComponentFactory injectedComponentFactory = 323 TelephonyComponentFactory.getInstance().inject(GsmCdmaPhone.class.getName()); 324 325 return injectedComponentFactory.makePhone(context, 326 sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId, phoneType, 327 TelephonyComponentFactory.getInstance()); 328 } 329 330 @UnsupportedAppUsage getDefaultPhone()331 public static Phone getDefaultPhone() { 332 synchronized (sLockProxyPhones) { 333 if (!sMadeDefaults) { 334 throw new IllegalStateException("Default phones haven't been made yet!"); 335 } 336 return sPhone; 337 } 338 } 339 340 @UnsupportedAppUsage getPhone(int phoneId)341 public static Phone getPhone(int phoneId) { 342 Phone phone; 343 String dbgInfo = ""; 344 345 synchronized (sLockProxyPhones) { 346 if (!sMadeDefaults) { 347 throw new IllegalStateException("Default phones haven't been made yet!"); 348 // CAF_MSIM FIXME need to introduce default phone id ? 349 } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { 350 if (DBG) { 351 dbgInfo = "phoneId == DEFAULT_PHONE_ID return sPhone"; 352 } 353 phone = sPhone; 354 } else { 355 if (DBG) { 356 dbgInfo = "phoneId != DEFAULT_PHONE_ID return sPhones[phoneId]"; 357 } 358 phone = (phoneId >= 0 && phoneId < sPhones.length) 359 ? sPhones[phoneId] : null; 360 } 361 if (DBG) { 362 Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId + 363 " phone=" + phone); 364 } 365 return phone; 366 } 367 } 368 369 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getPhones()370 public static Phone[] getPhones() { 371 synchronized (sLockProxyPhones) { 372 if (!sMadeDefaults) { 373 throw new IllegalStateException("Default phones haven't been made yet!"); 374 } 375 return sPhones; 376 } 377 } 378 getSubscriptionInfoUpdater()379 public static SubscriptionInfoUpdater getSubscriptionInfoUpdater() { 380 return sSubInfoRecordUpdater; 381 } 382 383 /** 384 * Get the network factory associated with a given phone ID. 385 * @param phoneId the phone id 386 * @return a factory for this phone ID, or null if none. 387 */ getNetworkFactory(int phoneId)388 public static TelephonyNetworkFactory getNetworkFactory(int phoneId) { 389 synchronized (sLockProxyPhones) { 390 if (!sMadeDefaults) { 391 throw new IllegalStateException("Default phones haven't been made yet!"); 392 } 393 final String dbgInfo; 394 if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { 395 dbgInfo = "getNetworkFactory with DEFAULT_PHONE_ID => factory for sPhone"; 396 phoneId = sPhone.getSubId(); 397 } else { 398 dbgInfo = "getNetworkFactory with non-default, return factory for passed id"; 399 } 400 // sTelephonyNetworkFactories is null in tests because in tests makeDefaultPhones() 401 // is not called. 402 final TelephonyNetworkFactory factory = (sTelephonyNetworkFactories != null 403 && (phoneId >= 0 && phoneId < sTelephonyNetworkFactories.length)) 404 ? sTelephonyNetworkFactories[phoneId] : null; 405 if (DBG) { 406 Rlog.d(LOG_TAG, "getNetworkFactory:-" + dbgInfo + " phoneId=" + phoneId 407 + " factory=" + factory); 408 } 409 return factory; 410 } 411 } 412 413 /** 414 * Makes a {@link SipPhone} object. 415 * @param sipUri the local SIP URI the phone runs on 416 * @return the {@code SipPhone} object or null if the SIP URI is not valid 417 */ makeSipPhone(String sipUri)418 public static SipPhone makeSipPhone(String sipUri) { 419 return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier); 420 } 421 422 /** 423 * Returns the preferred network type bitmask that should be set in the modem. 424 * 425 * @param phoneId The phone's id. 426 * @return the preferred network mode bitmask that should be set. 427 */ 428 // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController .. 429 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) calculatePreferredNetworkType(int phoneId)430 public static int calculatePreferredNetworkType(int phoneId) { 431 if (getPhone(phoneId) == null) { 432 Rlog.d(LOG_TAG, "Invalid phoneId return default network mode "); 433 return RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE); 434 } 435 int networkType = (int) getPhone(phoneId).getAllowedNetworkTypes( 436 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER); 437 Rlog.d(LOG_TAG, "calculatePreferredNetworkType: phoneId = " + phoneId + " networkType = " 438 + networkType); 439 return networkType; 440 } 441 442 /* Gets the default subscription */ 443 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getDefaultSubscription()444 public static int getDefaultSubscription() { 445 return SubscriptionController.getInstance().getDefaultSubId(); 446 } 447 448 /* Returns User SMS Prompt property, enabled or not */ isSMSPromptEnabled()449 public static boolean isSMSPromptEnabled() { 450 boolean prompt = false; 451 int value = 0; 452 try { 453 value = Settings.Global.getInt(sContext.getContentResolver(), 454 Settings.Global.MULTI_SIM_SMS_PROMPT); 455 } catch (SettingNotFoundException snfe) { 456 Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values"); 457 } 458 prompt = (value == 0) ? false : true ; 459 Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt); 460 461 return prompt; 462 } 463 464 /** 465 * Makes a {@link ImsPhone} object. 466 * @return the {@code ImsPhone} object or null if the exception occured 467 */ makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone)468 public static Phone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) { 469 return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone); 470 } 471 472 /** 473 * Request a refresh of the embedded subscription list. 474 * 475 * @param cardId the card ID of the eUICC. 476 * @param callback Optional callback to execute after the refresh completes. Must terminate 477 * quickly as it will be called from SubscriptionInfoUpdater's handler thread. 478 */ requestEmbeddedSubscriptionInfoListRefresh( int cardId, @Nullable Runnable callback)479 public static void requestEmbeddedSubscriptionInfoListRefresh( 480 int cardId, @Nullable Runnable callback) { 481 sSubInfoRecordUpdater.requestEmbeddedSubscriptionInfoListRefresh(cardId, callback); 482 } 483 484 /** 485 * Get a the SmsController. 486 */ getSmsController()487 public static SmsController getSmsController() { 488 synchronized (sLockProxyPhones) { 489 if (!sMadeDefaults) { 490 throw new IllegalStateException("Default phones haven't been made yet!"); 491 } 492 return sProxyController.getSmsController(); 493 } 494 } 495 496 /** 497 * Get Command Interfaces. 498 */ getCommandsInterfaces()499 public static CommandsInterface[] getCommandsInterfaces() { 500 synchronized (sLockProxyPhones) { 501 return sCommandsInterfaces; 502 } 503 } 504 505 /** 506 * Adds a local log category. 507 * 508 * Only used within the telephony process. Use localLog to add log entries. 509 * 510 * TODO - is there a better way to do this? Think about design when we have a minute. 511 * 512 * @param key the name of the category - will be the header in the service dump. 513 * @param size the number of lines to maintain in this category 514 */ addLocalLog(String key, int size)515 public static void addLocalLog(String key, int size) { 516 synchronized(sLocalLogs) { 517 if (sLocalLogs.containsKey(key)) { 518 throw new IllegalArgumentException("key " + key + " already present"); 519 } 520 sLocalLogs.put(key, new LocalLog(size)); 521 } 522 } 523 524 /** 525 * Add a line to the named Local Log. 526 * 527 * This will appear in the TelephonyDebugService dump. 528 * 529 * @param key the name of the log category to put this in. Must be created 530 * via addLocalLog. 531 * @param log the string to add to the log. 532 */ localLog(String key, String log)533 public static void localLog(String key, String log) { 534 synchronized(sLocalLogs) { 535 if (sLocalLogs.containsKey(key) == false) { 536 throw new IllegalArgumentException("key " + key + " not found"); 537 } 538 sLocalLogs.get(key).log(log); 539 } 540 } 541 542 /** Returns the MetricsCollector instance. */ getMetricsCollector()543 public static MetricsCollector getMetricsCollector() { 544 return sMetricsCollector; 545 } 546 dump(FileDescriptor fd, PrintWriter printwriter, String[] args)547 public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) { 548 IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, " "); 549 pw.println("PhoneFactory:"); 550 pw.println(" sMadeDefaults=" + sMadeDefaults); 551 552 sPhoneSwitcher.dump(fd, pw, args); 553 pw.println(); 554 555 Phone[] phones = (Phone[])PhoneFactory.getPhones(); 556 for (int i = 0; i < phones.length; i++) { 557 pw.increaseIndent(); 558 Phone phone = phones[i]; 559 560 try { 561 phone.dump(fd, pw, args); 562 } catch (Exception e) { 563 pw.println("Telephony DebugService: Could not get Phone[" + i + "] e=" + e); 564 continue; 565 } 566 567 pw.flush(); 568 pw.println("++++++++++++++++++++++++++++++++"); 569 570 sTelephonyNetworkFactories[i].dump(fd, pw, args); 571 572 pw.flush(); 573 pw.decreaseIndent(); 574 pw.println("++++++++++++++++++++++++++++++++"); 575 } 576 577 pw.println("UiccController:"); 578 pw.increaseIndent(); 579 try { 580 sUiccController.dump(fd, pw, args); 581 } catch (Exception e) { 582 e.printStackTrace(); 583 } 584 pw.flush(); 585 pw.decreaseIndent(); 586 pw.println("++++++++++++++++++++++++++++++++"); 587 588 pw.println("SubscriptionController:"); 589 pw.increaseIndent(); 590 try { 591 SubscriptionController.getInstance().dump(fd, pw, args); 592 } catch (Exception e) { 593 e.printStackTrace(); 594 } 595 pw.flush(); 596 pw.decreaseIndent(); 597 pw.println("++++++++++++++++++++++++++++++++"); 598 599 pw.println("SubInfoRecordUpdater:"); 600 pw.increaseIndent(); 601 try { 602 sSubInfoRecordUpdater.dump(fd, pw, args); 603 } catch (Exception e) { 604 e.printStackTrace(); 605 } 606 pw.flush(); 607 pw.decreaseIndent(); 608 pw.println("++++++++++++++++++++++++++++++++"); 609 610 pw.println("LocalLogs:"); 611 pw.increaseIndent(); 612 synchronized (sLocalLogs) { 613 for (String key : sLocalLogs.keySet()) { 614 pw.println(key); 615 pw.increaseIndent(); 616 sLocalLogs.get(key).dump(fd, pw, args); 617 pw.decreaseIndent(); 618 } 619 pw.flush(); 620 } 621 pw.decreaseIndent(); 622 pw.println("++++++++++++++++++++++++++++++++"); 623 624 pw.println("SharedPreferences:"); 625 pw.increaseIndent(); 626 try { 627 if (sContext != null) { 628 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(sContext); 629 Map spValues = sp.getAll(); 630 for (Object key : spValues.keySet()) { 631 pw.println(key + " : " + spValues.get(key)); 632 } 633 } 634 } catch (Exception e) { 635 e.printStackTrace(); 636 } 637 pw.decreaseIndent(); 638 pw.println("++++++++++++++++++++++++++++++++"); 639 pw.println("DebugEvents:"); 640 pw.increaseIndent(); 641 try { 642 AnomalyReporter.dump(fd, pw, args); 643 } catch (Exception e) { 644 e.printStackTrace(); 645 } 646 647 pw.flush(); 648 pw.decreaseIndent(); 649 } 650 } 651