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