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