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