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