Home | History | Annotate | Download | only in telephony
      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 
     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      */
    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 
    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 
    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 
    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 
    310     public static SubscriptionInfoUpdater getSubscriptionInfoUpdater() {
    311         return sSubInfoRecordUpdater;
    312     }
    313 
    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      */
    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 ..
    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 */
    357     public static int getDefaultSubscription() {
    358         return SubscriptionController.getInstance().getDefaultSubId();
    359     }
    360 
    361     /* Returns User SMS Prompt property,  enabled or not */
    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      */
    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      */
    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      */
    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      */
    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 
    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