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