• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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