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