1 /*
2  * Copyright (C) 2015 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.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.content.res.XmlResourceParser;
23 import android.database.Cursor;
24 import android.os.Handler;
25 import android.os.Looper;
26 import android.system.ErrnoException;
27 import android.system.Os;
28 import android.system.OsConstants;
29 import android.system.StructStatVfs;
30 import android.text.TextUtils;
31 
32 import com.android.ims.ImsManager;
33 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
34 import com.android.internal.telephony.cdma.EriManager;
35 import com.android.internal.telephony.data.AccessNetworksManager;
36 import com.android.internal.telephony.data.DataNetworkController;
37 import com.android.internal.telephony.data.DataProfileManager;
38 import com.android.internal.telephony.data.DataServiceManager;
39 import com.android.internal.telephony.data.DataSettingsManager;
40 import com.android.internal.telephony.data.LinkBandwidthEstimator;
41 import com.android.internal.telephony.data.PhoneSwitcher;
42 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
43 import com.android.internal.telephony.flags.FeatureFlags;
44 import com.android.internal.telephony.flags.FeatureFlagsImpl;
45 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
46 import com.android.internal.telephony.imsphone.ImsNrSaModeHandler;
47 import com.android.internal.telephony.imsphone.ImsPhone;
48 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
49 import com.android.internal.telephony.nitz.NitzStateMachineImpl;
50 import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier;
51 import com.android.internal.telephony.security.CellularNetworkSecuritySafetySource;
52 import com.android.internal.telephony.security.NullCipherNotifier;
53 import com.android.internal.telephony.uicc.IccCardStatus;
54 import com.android.internal.telephony.uicc.UiccCard;
55 import com.android.internal.telephony.uicc.UiccProfile;
56 import com.android.telephony.Rlog;
57 
58 import dalvik.system.PathClassLoader;
59 
60 import org.xmlpull.v1.XmlPullParser;
61 import org.xmlpull.v1.XmlPullParserException;
62 
63 import java.io.File;
64 import java.io.IOException;
65 import java.util.Arrays;
66 import java.util.HashSet;
67 import java.util.Set;
68 import java.util.function.Consumer;
69 import java.util.stream.Collectors;
70 
71 /**
72  * This class has one-line methods to instantiate objects only. The purpose is to make code
73  * unit-test friendly and use this class as a way to do dependency injection. Instantiating objects
74  * this way makes it easier to mock them in tests.
75  */
76 public class TelephonyComponentFactory {
77 
78     private static final String TAG = TelephonyComponentFactory.class.getSimpleName();
79 
80     private static TelephonyComponentFactory sInstance;
81     private final TelephonyFacade mTelephonyFacade = new TelephonyFacade();
82 
83     private InjectedComponents mInjectedComponents;
84 
85     private static class InjectedComponents {
86         private static final String ATTRIBUTE_JAR = "jar";
87         private static final String ATTRIBUTE_PACKAGE = "package";
88         private static final String TAG_INJECTION = "injection";
89         private static final String TAG_COMPONENTS = "components";
90         private static final String TAG_COMPONENT = "component";
91         private static final String SYSTEM = "/system/";
92         private static final String PRODUCT = "/product/";
93         private static final String SYSTEM_EXT = "/system_ext/";
94 
95         private final Set<String> mComponentNames = new HashSet<>();
96         private TelephonyComponentFactory mInjectedInstance;
97         private String mPackageName;
98         private String mJarPath;
99 
100         /**
101          * @return paths correctly configured to inject.
102          * 1) PackageName and JarPath mustn't be empty.
103          * 2) JarPath is restricted under /system or /product or /system_ext only.
104          * 3) JarPath is on a READ-ONLY partition.
105          */
getValidatedPaths()106         private @Nullable String getValidatedPaths() {
107             if (TextUtils.isEmpty(mPackageName) || TextUtils.isEmpty(mJarPath)) {
108                 return null;
109             }
110             // filter out invalid paths
111             return Arrays.stream(mJarPath.split(File.pathSeparator))
112                     .filter(s -> (s.startsWith(SYSTEM) || s.startsWith(PRODUCT)
113                             || s.startsWith(SYSTEM_EXT)))
114                     .filter(s -> {
115                         try {
116                             // This will also throw an error if the target doesn't exist.
117                             StructStatVfs vfs = Os.statvfs(s);
118                             return (vfs.f_flag & OsConstants.ST_RDONLY) != 0;
119                         } catch (ErrnoException e) {
120                             Rlog.w(TAG, "Injection jar is not protected , path: " + s
121                                     + e.getMessage());
122                             return false;
123                         }
124                     }).distinct()
125                     .collect(Collectors.joining(File.pathSeparator));
126         }
127 
makeInjectedInstance()128         private void makeInjectedInstance() {
129             String validatedPaths = getValidatedPaths();
130             Rlog.d(TAG, "validated paths: " + validatedPaths);
131             if (!TextUtils.isEmpty(validatedPaths)) {
132                 try {
133                     PathClassLoader classLoader = new PathClassLoader(validatedPaths,
134                             ClassLoader.getSystemClassLoader());
135                     Class<?> cls = classLoader.loadClass(mPackageName);
136                     mInjectedInstance = (TelephonyComponentFactory) cls.newInstance();
137                 } catch (ClassNotFoundException e) {
138                     Rlog.e(TAG, "failed: " + e.getMessage());
139                 } catch (IllegalAccessException | InstantiationException e) {
140                     Rlog.e(TAG, "injection failed: " + e.getMessage());
141                 }
142             }
143         }
144 
isComponentInjected(String componentName)145         private boolean isComponentInjected(String componentName) {
146             if (mInjectedInstance == null) {
147                 return false;
148             }
149             return mComponentNames.contains(componentName);
150         }
151 
152         /**
153          * Find the injection tag, set attributes, and then parse the injection.
154          */
parseXml(@onNull XmlPullParser parser)155         private void parseXml(@NonNull XmlPullParser parser) {
156             parseXmlByTag(parser, false, p -> {
157                 setAttributes(p);
158                 parseInjection(p);
159             }, TAG_INJECTION);
160         }
161 
162         /**
163          * Only parse the first injection tag. Find the components tag, then try parse it next.
164          */
parseInjection(@onNull XmlPullParser parser)165         private void parseInjection(@NonNull XmlPullParser parser) {
166             parseXmlByTag(parser, false, p -> parseComponents(p), TAG_COMPONENTS);
167         }
168 
169         /**
170          * Only parse the first components tag. Find the component tags, then try parse them next.
171          */
parseComponents(@onNull XmlPullParser parser)172         private void parseComponents(@NonNull XmlPullParser parser) {
173             parseXmlByTag(parser, true, p -> parseComponent(p), TAG_COMPONENT);
174         }
175 
176         /**
177          * Extract text values from component tags.
178          */
parseComponent(@onNull XmlPullParser parser)179         private void parseComponent(@NonNull XmlPullParser parser) {
180             try {
181                 int outerDepth = parser.getDepth();
182                 int type;
183                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
184                         && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
185                     if (type == XmlPullParser.TEXT) {
186                         mComponentNames.add(parser.getText());
187                     }
188                 }
189             } catch (XmlPullParserException | IOException e) {
190                 Rlog.e(TAG, "Failed to parse the component." , e);
191             }
192         }
193 
194         /**
195          * Iterates the tags, finds the corresponding tag and then applies the consumer.
196          */
parseXmlByTag(@onNull XmlPullParser parser, boolean allowDuplicate, @NonNull Consumer<XmlPullParser> consumer, @NonNull final String tag)197         private void parseXmlByTag(@NonNull XmlPullParser parser, boolean allowDuplicate,
198                 @NonNull Consumer<XmlPullParser> consumer, @NonNull final String tag) {
199             try {
200                 int outerDepth = parser.getDepth();
201                 int type;
202                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
203                         && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
204                     if (type == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
205                         consumer.accept(parser);
206                         if (!allowDuplicate) {
207                             return;
208                         }
209                     }
210                 }
211             } catch (XmlPullParserException | IOException e) {
212                 Rlog.e(TAG, "Failed to parse or find tag: " + tag, e);
213             }
214         }
215 
216         /**
217          * Sets the mPackageName and mJarPath by <injection/> tag.
218          * @param parser
219          * @return
220          */
setAttributes(@onNull XmlPullParser parser)221         private void setAttributes(@NonNull XmlPullParser parser) {
222             for (int i = 0; i < parser.getAttributeCount(); i++) {
223                 String name = parser.getAttributeName(i);
224                 String value = parser.getAttributeValue(i);
225                 if (InjectedComponents.ATTRIBUTE_PACKAGE.equals(name)) {
226                     mPackageName = value;
227                 } else if (InjectedComponents.ATTRIBUTE_JAR.equals(name)) {
228                     mJarPath = value;
229                 }
230             }
231         }
232     }
233 
234     public static TelephonyComponentFactory getInstance() {
235         if (sInstance == null) {
236             sInstance = new TelephonyComponentFactory();
237         }
238         return sInstance;
239     }
240 
241     /**
242      * Inject TelephonyComponentFactory using a xml config file.
243      * @param parser a nullable {@link XmlResourceParser} created with the injection config file.
244      * The config xml should has below formats:
245      * <injection package="package.InjectedTelephonyComponentFactory" jar="path to jar file">
246      *     <components>
247      *         <component>example.package.ComponentAbc</component>
248      *         <component>example.package.ComponentXyz</component>
249      *         <!-- e.g. com.android.internal.telephony.GsmCdmaPhone -->
250      *     </components>
251      * </injection>
252      */
253     public void injectTheComponentFactory(XmlResourceParser parser) {
254         if (mInjectedComponents != null) {
255             Rlog.d(TAG, "Already injected.");
256             return;
257         }
258 
259         if (parser != null) {
260             mInjectedComponents = new InjectedComponents();
261             mInjectedComponents.parseXml(parser);
262             mInjectedComponents.makeInjectedInstance();
263             boolean injectSuccessful = !TextUtils.isEmpty(mInjectedComponents.getValidatedPaths());
264             Rlog.d(TAG, "Total components injected: " + (injectSuccessful
265                     ? mInjectedComponents.mComponentNames.size() : 0));
266         }
267     }
268 
269     /**
270      * Use the injected TelephonyComponentFactory if configured. Otherwise, use the default.
271      * @param componentName Name of the component class uses the injected component factory,
272      * e.g. GsmCdmaPhone.class.getName() for {@link GsmCdmaPhone}
273      * @return injected component factory. If not configured or injected, return the default one.
274      */
275     public TelephonyComponentFactory inject(String componentName) {
276         if (mInjectedComponents != null && mInjectedComponents.isComponentInjected(componentName)) {
277             return mInjectedComponents.mInjectedInstance;
278         }
279         return sInstance;
280     }
281 
282     /**
283      * Create a new GsmCdmaCallTracker
284      * @param phone GsmCdmaPhone
285      * @param featureFlags Telephony feature flag
286      */
287     public GsmCdmaCallTracker makeGsmCdmaCallTracker(GsmCdmaPhone phone,
288             @NonNull FeatureFlags featureFlags) {
289         return new GsmCdmaCallTracker(phone, featureFlags);
290     }
291 
292     public SmsStorageMonitor makeSmsStorageMonitor(Phone phone) {
293         return new SmsStorageMonitor(phone);
294     }
295 
296     public SmsUsageMonitor makeSmsUsageMonitor(Context context) {
297         return new SmsUsageMonitor(context);
298     }
299 
300     public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci,
301             @NonNull FeatureFlags featureFlags) {
302         return new ServiceStateTracker(phone, ci, featureFlags);
303     }
304 
305     /**
306      * Create a new EmergencyNumberTracker.
307      */
308     public EmergencyNumberTracker makeEmergencyNumberTracker(Phone phone, CommandsInterface ci,
309             @NonNull FeatureFlags featureFlags) {
310         return new EmergencyNumberTracker(phone, ci, featureFlags);
311     }
312 
313     private static final boolean USE_NEW_NITZ_STATE_MACHINE = true;
314 
315     /**
316      * Returns a new {@link NitzStateMachine} instance.
317      */
318     public NitzStateMachine makeNitzStateMachine(GsmCdmaPhone phone) {
319         return NitzStateMachineImpl.createInstance(phone);
320     }
321 
322     public SimActivationTracker makeSimActivationTracker(Phone phone) {
323         return new SimActivationTracker(phone);
324     }
325 
326     public CarrierSignalAgent makeCarrierSignalAgent(Phone phone) {
327         return new CarrierSignalAgent(phone);
328     }
329 
330     public CarrierActionAgent makeCarrierActionAgent(Phone phone) {
331         return new CarrierActionAgent(phone);
332     }
333 
334     public CarrierResolver makeCarrierResolver(Phone phone) {
335         return new CarrierResolver(phone);
336     }
337 
338     public IccPhoneBookInterfaceManager makeIccPhoneBookInterfaceManager(Phone phone) {
339         return new IccPhoneBookInterfaceManager(phone);
340     }
341 
342     /**
343      * Returns a new {@link IccSmsInterfaceManager} instance.
344      */
345     public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone,
346             @NonNull FeatureFlags featureFlags) {
347         return new IccSmsInterfaceManager(phone, featureFlags);
348     }
349 
350     /**
351      * Create a new UiccProfile object.
352      */
353     public UiccProfile makeUiccProfile(Context context, CommandsInterface ci, IccCardStatus ics,
354                                        int phoneId, UiccCard uiccCard, Object lock,
355             @NonNull FeatureFlags flags) {
356         return new UiccProfile(context, ci, ics, phoneId, uiccCard, lock, flags);
357     }
358 
359     public EriManager makeEriManager(Phone phone, int eriFileSource) {
360         return new EriManager(phone, eriFileSource);
361     }
362 
363     public WspTypeDecoder makeWspTypeDecoder(byte[] pdu) {
364         return new WspTypeDecoder(pdu);
365     }
366 
367     /**
368      * Create a tracker for a single-part SMS.
369      */
370     public InboundSmsTracker makeInboundSmsTracker(Context context, byte[] pdu, long timestamp,
371             int destPort, boolean is3gpp2, boolean is3gpp2WapPdu, String address,
372             String displayAddr, String messageBody, boolean isClass0, int subId,
373             @InboundSmsHandler.SmsSource int smsSource) {
374         return new InboundSmsTracker(context, pdu, timestamp, destPort, is3gpp2, is3gpp2WapPdu,
375                 address, displayAddr, messageBody, isClass0, subId, smsSource);
376     }
377 
378     /**
379      * Create a tracker for a multi-part SMS.
380      */
381     public InboundSmsTracker makeInboundSmsTracker(Context context, byte[] pdu, long timestamp,
382             int destPort, boolean is3gpp2, String address, String displayAddr, int referenceNumber,
383             int sequenceNumber, int messageCount, boolean is3gpp2WapPdu, String messageBody,
384             boolean isClass0, int subId, @InboundSmsHandler.SmsSource int smsSource) {
385         return new InboundSmsTracker(context, pdu, timestamp, destPort, is3gpp2, address,
386                 displayAddr, referenceNumber, sequenceNumber, messageCount, is3gpp2WapPdu,
387                 messageBody, isClass0, subId, smsSource);
388     }
389 
390     /**
391      * Create a tracker from a row of raw table
392      */
393     public InboundSmsTracker makeInboundSmsTracker(Context context, Cursor cursor,
394             boolean isCurrentFormat3gpp2) {
395         return new InboundSmsTracker(context, cursor, isCurrentFormat3gpp2);
396     }
397 
398     /**
399      * Create an ImsPhoneCallTracker.
400      *
401      * @param imsPhone imsphone
402      * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker
403      * @deprecated Use {@link #makeImsPhoneCallTracker(ImsPhone, FeatureFlags)} instead
404      */
405     public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone) {
406         return makeImsPhoneCallTracker(imsPhone, new FeatureFlagsImpl());
407     }
408 
409     /**
410      * Create a ims phone call tracker.
411      *
412      * @param imsPhone imsphone
413      * @param featureFlags feature flags
414      * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker
415      */
416     public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone,
417                                                        @NonNull FeatureFlags featureFlags) {
418         return new ImsPhoneCallTracker(imsPhone, ImsManager::getConnector, featureFlags);
419     }
420 
421     public ImsExternalCallTracker makeImsExternalCallTracker(ImsPhone imsPhone) {
422 
423         return new ImsExternalCallTracker(imsPhone, imsPhone.getContext().getMainExecutor());
424     }
425 
426     /**
427      * Create an ImsNrSaModeHandler.
428      */
429     public ImsNrSaModeHandler makeImsNrSaModeHandler(ImsPhone imsPhone) {
430 
431         return new ImsNrSaModeHandler(imsPhone, imsPhone.getLooper());
432     }
433 
434     /**
435      * Create an AppSmsManager for per-app SMS message.
436      */
437     public AppSmsManager makeAppSmsManager(Context context) {
438         return new AppSmsManager(context);
439     }
440 
441     /**
442      * Create a DeviceStateMonitor.
443      */
444     public DeviceStateMonitor makeDeviceStateMonitor(Phone phone,
445             @NonNull FeatureFlags featureFlags) {
446         return new DeviceStateMonitor(phone, featureFlags);
447     }
448 
449     /**
450      * Make access networks manager
451      *
452      * @param phone The phone instance
453      * @param looper Looper for the handler.
454      * @return The access networks manager
455      * @deprecated {@link #makeAccessNetworksManager(Phone, Looper, FeatureFlags)} instead
456      */
457     public AccessNetworksManager makeAccessNetworksManager(Phone phone, Looper looper) {
458         return new AccessNetworksManager(phone, looper, new FeatureFlagsImpl());
459     }
460 
461     /**
462      * Make access networks manager
463      *
464      * @param phone The phone instance
465      * @param looper Looper for the handler.
466      * @param featureFlags feature flags.
467      * @return The access networks manager
468      */
469     public AccessNetworksManager makeAccessNetworksManager(Phone phone, Looper looper,
470             @NonNull FeatureFlags featureFlags) {
471         return new AccessNetworksManager(phone, looper, featureFlags);
472     }
473 
474     public CdmaSubscriptionSourceManager
475     getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h,
476                                              int what, Object obj) {
477         return CdmaSubscriptionSourceManager.getInstance(context, ci, h, what, obj);
478     }
479 
480     public LocaleTracker makeLocaleTracker(Phone phone, NitzStateMachine nitzStateMachine,
481                                            Looper looper, @NonNull FeatureFlags featureFlags) {
482         return new LocaleTracker(phone, nitzStateMachine, looper, featureFlags);
483     }
484 
485     public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
486             int phoneId, int precisePhoneType,
487             TelephonyComponentFactory telephonyComponentFactory,
488             @NonNull FeatureFlags featureFlags) {
489         return new GsmCdmaPhone(context, ci, notifier, phoneId, precisePhoneType,
490                 telephonyComponentFactory, featureFlags);
491     }
492 
493     public PhoneSwitcher makePhoneSwitcher(int maxDataAttachModemCount, Context context,
494             Looper looper, @NonNull FeatureFlags featureFlags) {
495         return PhoneSwitcher.make(maxDataAttachModemCount, context, looper, featureFlags);
496     }
497 
498     /**
499      * Create a new DisplayInfoController.
500      */
501     public DisplayInfoController makeDisplayInfoController(Phone phone, FeatureFlags featureFlags) {
502         return new DisplayInfoController(phone, featureFlags);
503     }
504 
505     /**
506      * Initialize multi sim settings controller.
507      *
508      * @param c The context.
509      * @return The multi sim settings controller instance.
510      */
511     public MultiSimSettingController initMultiSimSettingController(Context c,
512             @NonNull FeatureFlags featureFlags) {
513         return MultiSimSettingController.init(c, featureFlags);
514     }
515 
516     /**
517      * Create a new SignalStrengthController instance.
518      */
519     public SignalStrengthController makeSignalStrengthController(GsmCdmaPhone phone) {
520         return new SignalStrengthController(phone);
521     }
522 
523     /**
524      * Create a new LinkBandwidthEstimator.
525      */
526     public LinkBandwidthEstimator makeLinkBandwidthEstimator(Phone phone, Looper looper) {
527         return new LinkBandwidthEstimator(phone, looper, mTelephonyFacade);
528     }
529 
530     /**
531      * Create a new data network controller instance. The instance is per-SIM. On multi-sim devices,
532      * there will be multiple {@link DataNetworkController} instances.
533      *
534      * @param phone The phone object
535      * @param looper The looper for event handling
536      * @param featureFlags The feature flag.
537      * @return The data network controller instance
538      */
539     public DataNetworkController makeDataNetworkController(Phone phone, Looper looper,
540             @NonNull FeatureFlags featureFlags) {
541         return new DataNetworkController(phone, looper, featureFlags);
542     }
543 
544     /**
545      * Create data profile manager.
546      *
547      * @param phone The phone instance.
548      * @param dataNetworkController Data network controller instance.
549      * @param dataServiceManager Data service manager instance.
550      * @param looper The looper to be used by the handler. Currently the handler thread is the phone
551      * process's main thread.
552      * @param featureFlags Feature flags controlling which feature is enabled.     *
553      * @param callback Callback for passing events back to data network controller.
554      * @return The data profile manager instance.
555      */
556     public @NonNull DataProfileManager makeDataProfileManager(@NonNull Phone phone,
557             @NonNull DataNetworkController dataNetworkController,
558             @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper,
559             @NonNull FeatureFlags featureFlags,
560             @NonNull DataProfileManager.DataProfileManagerCallback callback) {
561         return new DataProfileManager(phone, dataNetworkController, dataServiceManager, looper,
562                 featureFlags, callback);
563     }
564 
565     /**
566      * Create data settings manager.
567      *
568      * @param phone The phone instance.
569      * @param dataNetworkController Data network controller instance.
570      * @param looper The looper to be used by the handler. Currently the handler thread is the phone
571      * process's main thread.
572      * @param callback Callback for passing events back to data network controller.
573      * @return The data settings manager instance.
574      */
575     public @NonNull DataSettingsManager makeDataSettingsManager(@NonNull Phone phone,
576             @NonNull DataNetworkController dataNetworkController,
577             @NonNull FeatureFlags featureFlags, @NonNull Looper looper,
578             @NonNull DataSettingsManager.DataSettingsManagerCallback callback) {
579         return new DataSettingsManager(phone, dataNetworkController, featureFlags, looper,
580                 callback);
581     }
582 
583     /** Create CellularNetworkSecuritySafetySource. */
584     public CellularNetworkSecuritySafetySource makeCellularNetworkSecuritySafetySource(
585             Context context) {
586         return CellularNetworkSecuritySafetySource.getInstance(context);
587     }
588 
589     /** Create CellularIdentifierDisclosureNotifier. */
590     public CellularIdentifierDisclosureNotifier makeIdentifierDisclosureNotifier(
591             CellularNetworkSecuritySafetySource safetySource) {
592         return CellularIdentifierDisclosureNotifier.getInstance(safetySource);
593     }
594 
595     /** Create NullCipherNotifier. */
596     public NullCipherNotifier makeNullCipherNotifier(
597             CellularNetworkSecuritySafetySource safetySource) {
598         return NullCipherNotifier.getInstance(safetySource);
599     }
600 }
601