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