• 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.data.CellularNetworkValidator;
45 import com.android.internal.telephony.data.PhoneSwitcher;
46 import com.android.internal.telephony.data.TelephonyNetworkFactory;
47 import com.android.internal.telephony.euicc.EuiccCardController;
48 import com.android.internal.telephony.euicc.EuiccController;
49 import com.android.internal.telephony.imsphone.ImsPhone;
50 import com.android.internal.telephony.imsphone.ImsPhoneFactory;
51 import com.android.internal.telephony.metrics.MetricsCollector;
52 import com.android.internal.telephony.metrics.TelephonyMetrics;
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      * Returns the preferred network type bitmask that should be set in the modem.
415      *
416      * @param phoneId The phone's id.
417      * @return the preferred network mode bitmask that should be set.
418      */
419     // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController ..
420     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
calculatePreferredNetworkType(int phoneId)421     public static int calculatePreferredNetworkType(int phoneId) {
422         if (getPhone(phoneId) == null) {
423             Rlog.d(LOG_TAG, "Invalid phoneId return default network mode ");
424             return RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE);
425         }
426         int networkType = (int) getPhone(phoneId).getAllowedNetworkTypes(
427                 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
428         Rlog.d(LOG_TAG, "calculatePreferredNetworkType: phoneId = " + phoneId + " networkType = "
429                 + networkType);
430         return networkType;
431     }
432 
433     /* Gets the default subscription */
434     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getDefaultSubscription()435     public static int getDefaultSubscription() {
436         return SubscriptionController.getInstance().getDefaultSubId();
437     }
438 
439     /* Returns User SMS Prompt property,  enabled or not */
isSMSPromptEnabled()440     public static boolean isSMSPromptEnabled() {
441         boolean prompt = false;
442         int value = 0;
443         try {
444             value = Settings.Global.getInt(sContext.getContentResolver(),
445                     Settings.Global.MULTI_SIM_SMS_PROMPT);
446         } catch (SettingNotFoundException snfe) {
447             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values");
448         }
449         prompt = (value == 0) ? false : true ;
450         Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt);
451 
452        return prompt;
453     }
454 
455     /**
456      * Makes a {@link ImsPhone} object.
457      * @return the {@code ImsPhone} object or null if the exception occured
458      */
makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone)459     public static Phone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) {
460         return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone);
461     }
462 
463     /**
464      * Request a refresh of the embedded subscription list.
465      *
466      * @param cardId the card ID of the eUICC.
467      * @param callback Optional callback to execute after the refresh completes. Must terminate
468      *     quickly as it will be called from SubscriptionInfoUpdater's handler thread.
469      */
requestEmbeddedSubscriptionInfoListRefresh( int cardId, @Nullable Runnable callback)470     public static void requestEmbeddedSubscriptionInfoListRefresh(
471             int cardId, @Nullable Runnable callback) {
472         sSubInfoRecordUpdater.requestEmbeddedSubscriptionInfoListRefresh(cardId, callback);
473     }
474 
475     /**
476      * Get a the SmsController.
477      */
getSmsController()478     public static SmsController getSmsController() {
479         synchronized (sLockProxyPhones) {
480             if (!sMadeDefaults) {
481                 throw new IllegalStateException("Default phones haven't been made yet!");
482             }
483             return sProxyController.getSmsController();
484         }
485     }
486 
487     /**
488      * Get Command Interfaces.
489      */
getCommandsInterfaces()490     public static CommandsInterface[] getCommandsInterfaces() {
491         synchronized (sLockProxyPhones) {
492             return sCommandsInterfaces;
493         }
494     }
495 
496     /**
497      * Adds a local log category.
498      *
499      * Only used within the telephony process.  Use localLog to add log entries.
500      *
501      * TODO - is there a better way to do this?  Think about design when we have a minute.
502      *
503      * @param key the name of the category - will be the header in the service dump.
504      * @param size the number of lines to maintain in this category
505      */
addLocalLog(String key, int size)506     public static void addLocalLog(String key, int size) {
507         synchronized(sLocalLogs) {
508             if (sLocalLogs.containsKey(key)) {
509                 throw new IllegalArgumentException("key " + key + " already present");
510             }
511             sLocalLogs.put(key, new LocalLog(size));
512         }
513     }
514 
515     /**
516      * Add a line to the named Local Log.
517      *
518      * This will appear in the TelephonyDebugService dump.
519      *
520      * @param key the name of the log category to put this in.  Must be created
521      *            via addLocalLog.
522      * @param log the string to add to the log.
523      */
localLog(String key, String log)524     public static void localLog(String key, String log) {
525         synchronized(sLocalLogs) {
526             if (sLocalLogs.containsKey(key) == false) {
527                 throw new IllegalArgumentException("key " + key + " not found");
528             }
529             sLocalLogs.get(key).log(log);
530         }
531     }
532 
533     /** Returns the MetricsCollector instance. */
getMetricsCollector()534     public static MetricsCollector getMetricsCollector() {
535         return sMetricsCollector;
536     }
537 
dump(FileDescriptor fd, PrintWriter printwriter, String[] args)538     public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) {
539         IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, "  ");
540         pw.println("PhoneFactory:");
541         pw.println(" sMadeDefaults=" + sMadeDefaults);
542 
543         sPhoneSwitcher.dump(fd, pw, args);
544         pw.println();
545 
546         Phone[] phones = (Phone[])PhoneFactory.getPhones();
547         for (int i = 0; i < phones.length; i++) {
548             pw.increaseIndent();
549             Phone phone = phones[i];
550 
551             try {
552                 phone.dump(fd, pw, args);
553             } catch (Exception e) {
554                 pw.println("Telephony DebugService: Could not get Phone[" + i + "] e=" + e);
555                 continue;
556             }
557 
558             pw.flush();
559             pw.println("++++++++++++++++++++++++++++++++");
560 
561             sTelephonyNetworkFactories[i].dump(fd, pw, args);
562 
563             pw.flush();
564             pw.decreaseIndent();
565             pw.println("++++++++++++++++++++++++++++++++");
566         }
567 
568         pw.println("UiccController:");
569         pw.increaseIndent();
570         try {
571             sUiccController.dump(fd, pw, args);
572         } catch (Exception e) {
573             e.printStackTrace();
574         }
575         pw.flush();
576         pw.decreaseIndent();
577         pw.println("++++++++++++++++++++++++++++++++");
578 
579         pw.println("SubscriptionController:");
580         pw.increaseIndent();
581         try {
582             SubscriptionController.getInstance().dump(fd, pw, args);
583         } catch (Exception e) {
584             e.printStackTrace();
585         }
586         pw.flush();
587         pw.decreaseIndent();
588         pw.println("++++++++++++++++++++++++++++++++");
589 
590         pw.println("SubInfoRecordUpdater:");
591         pw.increaseIndent();
592         try {
593             sSubInfoRecordUpdater.dump(fd, pw, args);
594         } catch (Exception e) {
595             e.printStackTrace();
596         }
597         pw.flush();
598         pw.decreaseIndent();
599         pw.println("++++++++++++++++++++++++++++++++");
600 
601         pw.println("LocalLogs:");
602         pw.increaseIndent();
603         synchronized (sLocalLogs) {
604             for (String key : sLocalLogs.keySet()) {
605                 pw.println(key);
606                 pw.increaseIndent();
607                 sLocalLogs.get(key).dump(fd, pw, args);
608                 pw.decreaseIndent();
609             }
610             pw.flush();
611         }
612         pw.decreaseIndent();
613         pw.println("++++++++++++++++++++++++++++++++");
614 
615         pw.println("SharedPreferences:");
616         pw.increaseIndent();
617         try {
618             if (sContext != null) {
619                 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(sContext);
620                 Map spValues = sp.getAll();
621                 for (Object key : spValues.keySet()) {
622                     pw.println(key + " : " + spValues.get(key));
623                 }
624             }
625         } catch (Exception e) {
626             e.printStackTrace();
627         }
628         pw.decreaseIndent();
629         pw.println("++++++++++++++++++++++++++++++++");
630         pw.println("DebugEvents:");
631         pw.increaseIndent();
632         try {
633             AnomalyReporter.dump(fd, pw, args);
634         } catch (Exception e) {
635             e.printStackTrace();
636         }
637 
638         pw.flush();
639         pw.decreaseIndent();
640     }
641 }
642