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 /** 293 * Create {@link SmsStorageMonitor} instance. 294 * 295 * @param phone Phone instance 296 * @param flags Android feature flags 297 * 298 * @return The created instance 299 */ 300 public SmsStorageMonitor makeSmsStorageMonitor(Phone phone, @NonNull FeatureFlags flags) { 301 return new SmsStorageMonitor(phone, flags); 302 } 303 304 public SmsUsageMonitor makeSmsUsageMonitor(Context context, FeatureFlags flags) { 305 return new SmsUsageMonitor(context, flags); 306 } 307 308 public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci, 309 @NonNull FeatureFlags featureFlags) { 310 return new ServiceStateTracker(phone, ci, featureFlags); 311 } 312 313 /** 314 * Create a new EmergencyNumberTracker. 315 */ 316 public EmergencyNumberTracker makeEmergencyNumberTracker(Phone phone, CommandsInterface ci, 317 @NonNull FeatureFlags featureFlags) { 318 return new EmergencyNumberTracker(phone, ci, featureFlags); 319 } 320 321 private static final boolean USE_NEW_NITZ_STATE_MACHINE = true; 322 323 /** 324 * Returns a new {@link NitzStateMachine} instance. 325 */ 326 public NitzStateMachine makeNitzStateMachine(GsmCdmaPhone phone) { 327 return NitzStateMachineImpl.createInstance(phone); 328 } 329 330 public SimActivationTracker makeSimActivationTracker(Phone phone) { 331 return new SimActivationTracker(phone); 332 } 333 334 public CarrierSignalAgent makeCarrierSignalAgent(Phone phone) { 335 return new CarrierSignalAgent(phone); 336 } 337 338 public CarrierActionAgent makeCarrierActionAgent(Phone phone) { 339 return new CarrierActionAgent(phone); 340 } 341 342 /** 343 * Create {@link CarrierResolver} instance 344 * 345 * @param phone The phone instance 346 * @param flags Android feature flags 347 * 348 * @return The created instance 349 */ 350 public CarrierResolver makeCarrierResolver(Phone phone, FeatureFlags flags) { 351 return new CarrierResolver(phone, flags); 352 } 353 354 public IccPhoneBookInterfaceManager makeIccPhoneBookInterfaceManager(Phone phone) { 355 return new IccPhoneBookInterfaceManager(phone); 356 } 357 358 /** 359 * Returns a new {@link IccSmsInterfaceManager} instance. 360 */ 361 public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone, 362 @NonNull FeatureFlags featureFlags) { 363 return new IccSmsInterfaceManager(phone, featureFlags); 364 } 365 366 /** 367 * Create a new UiccProfile object. 368 */ 369 public UiccProfile makeUiccProfile(Context context, CommandsInterface ci, IccCardStatus ics, 370 int phoneId, UiccCard uiccCard, Object lock, 371 @NonNull FeatureFlags flags) { 372 return new UiccProfile(context, ci, ics, phoneId, uiccCard, lock, flags); 373 } 374 375 public EriManager makeEriManager(Phone phone, int eriFileSource) { 376 return new EriManager(phone, eriFileSource); 377 } 378 379 public WspTypeDecoder makeWspTypeDecoder(byte[] pdu) { 380 return new WspTypeDecoder(pdu); 381 } 382 383 /** 384 * Create a tracker for a single-part SMS. 385 */ 386 public InboundSmsTracker makeInboundSmsTracker(Context context, byte[] pdu, long timestamp, 387 int destPort, boolean is3gpp2, boolean is3gpp2WapPdu, String address, 388 String displayAddr, String messageBody, boolean isClass0, int subId, 389 @InboundSmsHandler.SmsSource int smsSource) { 390 return new InboundSmsTracker(context, pdu, timestamp, destPort, is3gpp2, is3gpp2WapPdu, 391 address, displayAddr, messageBody, isClass0, subId, smsSource); 392 } 393 394 /** 395 * Create a tracker for a multi-part SMS. 396 */ 397 public InboundSmsTracker makeInboundSmsTracker(Context context, byte[] pdu, long timestamp, 398 int destPort, boolean is3gpp2, String address, String displayAddr, int referenceNumber, 399 int sequenceNumber, int messageCount, boolean is3gpp2WapPdu, String messageBody, 400 boolean isClass0, int subId, @InboundSmsHandler.SmsSource int smsSource) { 401 return new InboundSmsTracker(context, pdu, timestamp, destPort, is3gpp2, address, 402 displayAddr, referenceNumber, sequenceNumber, messageCount, is3gpp2WapPdu, 403 messageBody, isClass0, subId, smsSource); 404 } 405 406 /** 407 * Create a tracker from a row of raw table 408 */ 409 public InboundSmsTracker makeInboundSmsTracker(Context context, Cursor cursor, 410 boolean isCurrentFormat3gpp2) { 411 return new InboundSmsTracker(context, cursor, isCurrentFormat3gpp2); 412 } 413 414 /** 415 * Create an ImsPhoneCallTracker. 416 * 417 * @param imsPhone imsphone 418 * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker 419 * @deprecated Use {@link #makeImsPhoneCallTracker(ImsPhone, FeatureFlags)} instead 420 */ 421 public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone) { 422 return makeImsPhoneCallTracker(imsPhone, new FeatureFlagsImpl()); 423 } 424 425 /** 426 * Create a ims phone call tracker. 427 * 428 * @param imsPhone imsphone 429 * @param featureFlags feature flags 430 * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker 431 */ 432 public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone, 433 @NonNull FeatureFlags featureFlags) { 434 return new ImsPhoneCallTracker(imsPhone, ImsManager::getConnector, featureFlags); 435 } 436 437 public ImsExternalCallTracker makeImsExternalCallTracker(ImsPhone imsPhone) { 438 439 return new ImsExternalCallTracker(imsPhone, imsPhone.getContext().getMainExecutor()); 440 } 441 442 /** 443 * Create an ImsNrSaModeHandler. 444 */ 445 public ImsNrSaModeHandler makeImsNrSaModeHandler(ImsPhone imsPhone) { 446 447 return new ImsNrSaModeHandler(imsPhone, imsPhone.getLooper()); 448 } 449 450 /** 451 * Create an AppSmsManager for per-app SMS message. 452 */ 453 public AppSmsManager makeAppSmsManager(Context context) { 454 return new AppSmsManager(context); 455 } 456 457 /** 458 * Create a DeviceStateMonitor. 459 */ 460 public DeviceStateMonitor makeDeviceStateMonitor(Phone phone, 461 @NonNull FeatureFlags featureFlags) { 462 return new DeviceStateMonitor(phone, featureFlags); 463 } 464 465 /** 466 * Make access networks manager 467 * 468 * @param phone The phone instance 469 * @param looper Looper for the handler. 470 * @return The access networks manager 471 * @deprecated {@link #makeAccessNetworksManager(Phone, Looper, FeatureFlags)} instead 472 */ 473 public AccessNetworksManager makeAccessNetworksManager(Phone phone, Looper looper) { 474 return new AccessNetworksManager(phone, looper, new FeatureFlagsImpl()); 475 } 476 477 /** 478 * Make access networks manager 479 * 480 * @param phone The phone instance 481 * @param looper Looper for the handler. 482 * @param featureFlags feature flags. 483 * @return The access networks manager 484 */ 485 public AccessNetworksManager makeAccessNetworksManager(Phone phone, Looper looper, 486 @NonNull FeatureFlags featureFlags) { 487 return new AccessNetworksManager(phone, looper, featureFlags); 488 } 489 490 public CdmaSubscriptionSourceManager 491 getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h, 492 int what, Object obj) { 493 return CdmaSubscriptionSourceManager.getInstance(context, ci, h, what, obj); 494 } 495 496 public LocaleTracker makeLocaleTracker(Phone phone, NitzStateMachine nitzStateMachine, 497 Looper looper, @NonNull FeatureFlags featureFlags) { 498 return new LocaleTracker(phone, nitzStateMachine, looper, featureFlags); 499 } 500 501 public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier, 502 int phoneId, int precisePhoneType, 503 TelephonyComponentFactory telephonyComponentFactory, 504 @NonNull FeatureFlags featureFlags) { 505 return new GsmCdmaPhone(context, ci, notifier, phoneId, precisePhoneType, 506 telephonyComponentFactory, featureFlags); 507 } 508 509 public PhoneSwitcher makePhoneSwitcher(int maxDataAttachModemCount, Context context, 510 Looper looper, @NonNull FeatureFlags featureFlags) { 511 return PhoneSwitcher.make(maxDataAttachModemCount, context, looper, featureFlags); 512 } 513 514 /** 515 * Create a new DisplayInfoController. 516 */ 517 public DisplayInfoController makeDisplayInfoController(Phone phone, FeatureFlags featureFlags) { 518 return new DisplayInfoController(phone, featureFlags); 519 } 520 521 /** 522 * Initialize multi sim settings controller. 523 * 524 * @param c The context. 525 * @return The multi sim settings controller instance. 526 */ 527 public MultiSimSettingController initMultiSimSettingController(Context c, 528 @NonNull FeatureFlags featureFlags) { 529 return MultiSimSettingController.init(c, featureFlags); 530 } 531 532 /** 533 * Create a new SignalStrengthController instance. 534 */ 535 public SignalStrengthController makeSignalStrengthController(GsmCdmaPhone phone) { 536 return new SignalStrengthController(phone); 537 } 538 539 /** 540 * Create a new LinkBandwidthEstimator. 541 */ 542 public LinkBandwidthEstimator makeLinkBandwidthEstimator(Phone phone, Looper looper) { 543 return new LinkBandwidthEstimator(phone, looper, mTelephonyFacade); 544 } 545 546 /** 547 * Create a new data network controller instance. The instance is per-SIM. On multi-sim devices, 548 * there will be multiple {@link DataNetworkController} instances. 549 * 550 * @param phone The phone object 551 * @param looper The looper for event handling 552 * @param featureFlags The feature flag. 553 * @return The data network controller instance 554 */ 555 public DataNetworkController makeDataNetworkController(Phone phone, Looper looper, 556 @NonNull FeatureFlags featureFlags) { 557 return new DataNetworkController(phone, looper, featureFlags); 558 } 559 560 /** 561 * Create data profile manager. 562 * 563 * @param phone The phone instance. 564 * @param dataNetworkController Data network controller instance. 565 * @param dataServiceManager Data service manager instance. 566 * @param looper The looper to be used by the handler. Currently the handler thread is the phone 567 * process's main thread. 568 * @param featureFlags Feature flags controlling which feature is enabled. * 569 * @param callback Callback for passing events back to data network controller. 570 * @return The data profile manager instance. 571 */ 572 public @NonNull DataProfileManager makeDataProfileManager(@NonNull Phone phone, 573 @NonNull DataNetworkController dataNetworkController, 574 @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper, 575 @NonNull FeatureFlags featureFlags, 576 @NonNull DataProfileManager.DataProfileManagerCallback callback) { 577 return new DataProfileManager(phone, dataNetworkController, dataServiceManager, looper, 578 featureFlags, callback); 579 } 580 581 /** 582 * Create data settings manager. 583 * 584 * @param phone The phone instance. 585 * @param dataNetworkController Data network controller instance. 586 * @param looper The looper to be used by the handler. Currently the handler thread is the phone 587 * process's main thread. 588 * @param callback Callback for passing events back to data network controller. 589 * @return The data settings manager instance. 590 */ 591 public @NonNull DataSettingsManager makeDataSettingsManager(@NonNull Phone phone, 592 @NonNull DataNetworkController dataNetworkController, 593 @NonNull FeatureFlags featureFlags, @NonNull Looper looper, 594 @NonNull DataSettingsManager.DataSettingsManagerCallback callback) { 595 return new DataSettingsManager(phone, dataNetworkController, featureFlags, looper, 596 callback); 597 } 598 599 /** Create CellularNetworkSecuritySafetySource. */ 600 public CellularNetworkSecuritySafetySource makeCellularNetworkSecuritySafetySource( 601 Context context) { 602 return CellularNetworkSecuritySafetySource.getInstance(context); 603 } 604 605 /** Create CellularIdentifierDisclosureNotifier. */ 606 public CellularIdentifierDisclosureNotifier makeIdentifierDisclosureNotifier( 607 CellularNetworkSecuritySafetySource safetySource) { 608 return CellularIdentifierDisclosureNotifier.getInstance(safetySource); 609 } 610 611 /** Create NullCipherNotifier. */ 612 public NullCipherNotifier makeNullCipherNotifier( 613 CellularNetworkSecuritySafetySource safetySource) { 614 return NullCipherNotifier.getInstance(safetySource); 615 } 616 } 617