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