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