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