Home | History | Annotate | Download | only in dataconnection
      1 /*
      2  * Copyright (C) 2014 MediaTek Inc.
      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.dataconnection;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.os.Handler;
     24 import android.os.Message;
     25 import android.os.AsyncResult;
     26 import android.os.SystemProperties;
     27 import android.telephony.ServiceState;
     28 import android.telephony.TelephonyManager;
     29 import android.telephony.SubscriptionManager;
     30 
     31 import com.android.internal.telephony.IccCardConstants;
     32 import com.android.internal.telephony.Phone;
     33 import com.android.internal.telephony.PhoneConstants;
     34 import com.android.internal.telephony.PhoneBase;
     35 import com.android.internal.telephony.PhoneProxy;
     36 import com.android.internal.telephony.TelephonyIntents;
     37 import com.android.internal.util.AsyncChannel;
     38 import com.android.internal.telephony.PhoneFactory;
     39 import com.android.internal.telephony.TelephonyProperties;
     40 import com.android.internal.telephony.DefaultPhoneNotifier;
     41 import com.android.internal.telephony.SubscriptionController;
     42 
     43 import android.util.Log;
     44 import java.util.HashSet;
     45 import java.util.Iterator;
     46 import android.os.Registrant;
     47 import android.os.RegistrantList;
     48 import android.telephony.Rlog;
     49 
     50 public class DctController extends Handler {
     51     private static final String LOG_TAG = "DctController";
     52     private static final boolean DBG = true;
     53 
     54     private static final int EVENT_PHONE1_DETACH = 1;
     55     private static final int EVENT_PHONE2_DETACH = 2;
     56     private static final int EVENT_PHONE3_DETACH = 3;
     57     private static final int EVENT_PHONE4_DETACH = 4;
     58     private static final int EVENT_PHONE1_RADIO_OFF = 5;
     59     private static final int EVENT_PHONE2_RADIO_OFF = 6;
     60     private static final int EVENT_PHONE3_RADIO_OFF = 7;
     61     private static final int EVENT_PHONE4_RADIO_OFF = 8;
     62 
     63     private static final int PHONE_NONE = -1;
     64 
     65     private static DctController sDctController;
     66 
     67     private static final int EVENT_ALL_DATA_DISCONNECTED = 1;
     68     private static final int EVENT_SET_DATA_ALLOW_DONE = 2;
     69 
     70     private RegistrantList mNotifyDataSwitchInfo = new RegistrantList();
     71     private SubscriptionController mSubController = SubscriptionController.getInstance();
     72 
     73     private Phone mActivePhone;
     74     private int mPhoneNum;
     75     private boolean[] mServicePowerOffFlag;
     76     private PhoneProxy[] mPhones;
     77     private DcSwitchState[] mDcSwitchState;
     78     private DcSwitchAsyncChannel[] mDcSwitchAsyncChannel;
     79     private Handler[] mDcSwitchStateHandler;
     80 
     81     private HashSet<String> mApnTypes = new HashSet<String>();
     82 
     83     private BroadcastReceiver mDataStateReceiver;
     84     private Context mContext;
     85 
     86     private int mCurrentDataPhone = PHONE_NONE;
     87     private int mRequestedDataPhone = PHONE_NONE;
     88 
     89     private Handler mRspHander = new Handler() {
     90         public void handleMessage(Message msg){
     91             AsyncResult ar;
     92             switch(msg.what) {
     93                 case EVENT_PHONE1_DETACH:
     94                 case EVENT_PHONE2_DETACH:
     95                 case EVENT_PHONE3_DETACH:
     96                 case EVENT_PHONE4_DETACH:
     97                     logd("EVENT_PHONE" + msg.what +
     98                             "_DETACH: mRequestedDataPhone=" + mRequestedDataPhone);
     99                     mCurrentDataPhone = PHONE_NONE;
    100                     if (mRequestedDataPhone != PHONE_NONE) {
    101                         mCurrentDataPhone = mRequestedDataPhone;
    102                         mRequestedDataPhone = PHONE_NONE;
    103 
    104                         Iterator<String> itrType = mApnTypes.iterator();
    105                         while (itrType.hasNext()) {
    106                             mDcSwitchAsyncChannel[mCurrentDataPhone].connectSync(itrType.next());
    107                         }
    108                         mApnTypes.clear();
    109                     }
    110                 break;
    111 
    112                 case EVENT_PHONE1_RADIO_OFF:
    113                 case EVENT_PHONE2_RADIO_OFF:
    114                 case EVENT_PHONE3_RADIO_OFF:
    115                 case EVENT_PHONE4_RADIO_OFF:
    116                     logd("EVENT_PHONE" + (msg.what - EVENT_PHONE1_RADIO_OFF + 1) + "_RADIO_OFF.");
    117                     mServicePowerOffFlag[msg.what - EVENT_PHONE1_RADIO_OFF] = true;
    118                 break;
    119 
    120                 default:
    121                 break;
    122             }
    123         }
    124     };
    125 
    126     private DefaultPhoneNotifier.IDataStateChangedCallback mDataStateChangedCallback =
    127             new DefaultPhoneNotifier.IDataStateChangedCallback() {
    128         public void onDataStateChanged(long subId, String state, String reason,
    129                 String apnName, String apnType, boolean unavailable) {
    130             logd("[DataStateChanged]:" + "state=" + state + ",reason=" + reason
    131                       + ",apnName=" + apnName + ",apnType=" + apnType + ",from subId=" + subId);
    132             int phoneId = SubscriptionManager.getPhoneId(subId);
    133             mDcSwitchState[phoneId].notifyDataConnection(phoneId, state, reason,
    134                     apnName, apnType, unavailable);
    135         }
    136     };
    137 
    138     private class DataStateReceiver extends BroadcastReceiver {
    139         public void onReceive(Context context, Intent intent) {
    140             synchronized(this) {
    141                 if (intent.getAction().equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
    142                     ServiceState ss = ServiceState.newFromBundle(intent.getExtras());
    143 
    144                     long subId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY, PhoneConstants.SUB1);
    145                     int phoneId = SubscriptionManager.getPhoneId(subId);
    146                     logd("DataStateReceiver: phoneId= " + phoneId);
    147 
    148                     // for the case of network out of service when bootup (ignore dummy values too)
    149                     if (!SubscriptionManager.isValidSubId(subId) || (subId < 0)) {
    150                         // FIXME: Maybe add SM.isRealSubId(subId)??
    151                         logd("DataStateReceiver: ignore invalid subId=" + subId);
    152                         return;
    153                     }
    154                     if (!SubscriptionManager.isValidPhoneId(phoneId)) {
    155                         logd("DataStateReceiver: ignore invalid phoneId=" + phoneId);
    156                         return;
    157                     }
    158 
    159                     boolean prevPowerOff = mServicePowerOffFlag[phoneId];
    160                     if (ss != null) {
    161                         int state = ss.getState();
    162                         switch (state) {
    163                             case ServiceState.STATE_POWER_OFF:
    164                                 mServicePowerOffFlag[phoneId] = true;
    165                                 logd("DataStateReceiver: STATE_POWER_OFF Intent from phoneId="
    166                                         + phoneId);
    167                                 break;
    168                             case ServiceState.STATE_IN_SERVICE:
    169                                 mServicePowerOffFlag[phoneId] = false;
    170                                 logd("DataStateReceiver: STATE_IN_SERVICE Intent from phoneId="
    171                                         + phoneId);
    172                                 break;
    173                             case ServiceState.STATE_OUT_OF_SERVICE:
    174                                 logd("DataStateReceiver: STATE_OUT_OF_SERVICE Intent from phoneId="
    175                                         + phoneId);
    176                                 if (mServicePowerOffFlag[phoneId]) {
    177                                     mServicePowerOffFlag[phoneId] = false;
    178                                 }
    179                                 break;
    180                             case ServiceState.STATE_EMERGENCY_ONLY:
    181                                 logd("DataStateReceiver: STATE_EMERGENCY_ONLY Intent from phoneId="
    182                                         + phoneId);
    183                                 break;
    184                             default:
    185                                 logd("DataStateReceiver: SERVICE_STATE_CHANGED invalid state");
    186                                 break;
    187                         }
    188 
    189                         if (prevPowerOff && mServicePowerOffFlag[phoneId] == false &&
    190                                 mCurrentDataPhone == PHONE_NONE &&
    191                                 phoneId == getDataConnectionFromSetting()) {
    192                             logd("DataStateReceiver: Current Phone is none and default phoneId="
    193                                     + phoneId + ", then enableApnType()");
    194                             enableApnType(subId, PhoneConstants.APN_TYPE_DEFAULT);
    195                         }
    196                     }
    197                 }
    198             }
    199         }
    200     }
    201 
    202     public DefaultPhoneNotifier.IDataStateChangedCallback getDataStateChangedCallback() {
    203         return mDataStateChangedCallback;
    204     }
    205 
    206     public static DctController getInstance() {
    207        if (sDctController == null) {
    208         throw new RuntimeException(
    209             "DCTrackerController.getInstance can't be called before makeDCTController()");
    210         }
    211        return sDctController;
    212     }
    213 
    214     public static DctController makeDctController(PhoneProxy[] phones) {
    215         if (sDctController == null) {
    216             sDctController = new DctController(phones);
    217         }
    218         return sDctController;
    219     }
    220 
    221     private DctController(PhoneProxy[] phones) {
    222         if (phones == null || phones.length == 0) {
    223             if (phones == null) {
    224                 loge("DctController(phones): UNEXPECTED phones=null, ignore");
    225             } else {
    226                 loge("DctController(phones): UNEXPECTED phones.length=0, ignore");
    227             }
    228             return;
    229         }
    230         mPhoneNum = phones.length;
    231         mServicePowerOffFlag = new boolean[mPhoneNum];
    232         mPhones = phones;
    233 
    234         mDcSwitchState = new DcSwitchState[mPhoneNum];
    235         mDcSwitchAsyncChannel = new DcSwitchAsyncChannel[mPhoneNum];
    236         mDcSwitchStateHandler = new Handler[mPhoneNum];
    237 
    238         mActivePhone = mPhones[0];
    239 
    240         for (int i = 0; i < mPhoneNum; ++i) {
    241             int phoneId = i;
    242             mServicePowerOffFlag[i] = true;
    243             mDcSwitchState[i] = new DcSwitchState(mPhones[i], "DcSwitchState-" + phoneId, phoneId);
    244             mDcSwitchState[i].start();
    245             mDcSwitchAsyncChannel[i] = new DcSwitchAsyncChannel(mDcSwitchState[i], phoneId);
    246             mDcSwitchStateHandler[i] = new Handler();
    247 
    248             int status = mDcSwitchAsyncChannel[i].fullyConnectSync(mPhones[i].getContext(),
    249                 mDcSwitchStateHandler[i], mDcSwitchState[i].getHandler());
    250 
    251             if (status == AsyncChannel.STATUS_SUCCESSFUL) {
    252                 logd("DctController(phones): Connect success: " + i);
    253             } else {
    254                 loge("DctController(phones): Could not connect to " + i);
    255             }
    256 
    257             mDcSwitchState[i].registerForIdle(mRspHander, EVENT_PHONE1_DETACH + i, null);
    258 
    259             // Register for radio state change
    260             PhoneBase phoneBase = (PhoneBase)((PhoneProxy)mPhones[i]).getActivePhone();
    261             phoneBase.mCi.registerForOffOrNotAvailable(mRspHander, EVENT_PHONE1_RADIO_OFF + i, null);
    262         }
    263 
    264         mContext = mActivePhone.getContext();
    265 
    266         IntentFilter filter = new IntentFilter();
    267         filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
    268         filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
    269 
    270         mDataStateReceiver = new DataStateReceiver();
    271         Intent intent = mContext.registerReceiver(mDataStateReceiver, filter);
    272     }
    273 
    274     private IccCardConstants.State getIccCardState(int phoneId) {
    275         return mPhones[phoneId].getIccCard().getState();
    276     }
    277 
    278     /**
    279      * Enable PDP interface by apn type and phone id
    280      *
    281      * @param type enable pdp interface by apn type, such as PhoneConstants.APN_TYPE_MMS, etc.
    282      * @param subId Indicate which sub to query
    283      * @return PhoneConstants.APN_REQUEST_STARTED: action is already started
    284      * PhoneConstants.APN_ALREADY_ACTIVE: interface has already active
    285      * PhoneConstants.APN_TYPE_NOT_AVAILABLE: invalid APN type
    286      * PhoneConstants.APN_REQUEST_FAILED: request failed
    287      * PhoneConstants.APN_REQUEST_FAILED_DUE_TO_RADIO_OFF: readio turn off
    288      * @see #disableApnType()
    289      */
    290     public synchronized int enableApnType(long subId, String type) {
    291         int phoneId = SubscriptionManager.getPhoneId(subId);
    292 
    293         if (phoneId == PHONE_NONE || !isValidphoneId(phoneId)) {
    294             logw("enableApnType(): with PHONE_NONE or Invalid PHONE ID");
    295             return PhoneConstants.APN_REQUEST_FAILED;
    296         }
    297 
    298         logd("enableApnType():type=" + type + ",phoneId=" + phoneId +
    299                 ",powerOff=" + mServicePowerOffFlag[phoneId]);
    300 
    301         if (!PhoneConstants.APN_TYPE_DEFAULT.equals(type)) {
    302             for (int peerphoneId =0; peerphoneId < mPhoneNum; peerphoneId++) {
    303                 // check peer Phone has non default APN activated as receiving non default APN request.
    304                 if (phoneId == peerphoneId) {
    305                     continue;
    306                 }
    307 
    308                 String[] activeApnTypes = mPhones[peerphoneId].getActiveApnTypes();
    309                 if (activeApnTypes != null && activeApnTypes.length != 0) {
    310                     for (int i=0; i<activeApnTypes.length; i++) {
    311                         if (!PhoneConstants.APN_TYPE_DEFAULT.equals(activeApnTypes[i]) &&
    312                                 mPhones[peerphoneId].getDataConnectionState(activeApnTypes[i]) !=
    313                                 PhoneConstants.DataState.DISCONNECTED) {
    314                             logd("enableApnType:Peer Phone still have non-default active APN type:"+
    315                                     "activeApnTypes[" + i + "]=" + activeApnTypes[i]);
    316                             return PhoneConstants.APN_REQUEST_FAILED;
    317                         }
    318                     }
    319                 }
    320             }
    321         }
    322 
    323         logd("enableApnType(): CurrentDataPhone=" +
    324                     mCurrentDataPhone + ", RequestedDataPhone=" + mRequestedDataPhone);
    325 
    326         if (phoneId == mCurrentDataPhone &&
    327                !mDcSwitchAsyncChannel[mCurrentDataPhone].isIdleOrDeactingSync()) {
    328            mRequestedDataPhone = PHONE_NONE;
    329            logd("enableApnType(): mRequestedDataPhone equals request PHONE ID.");
    330            return mDcSwitchAsyncChannel[phoneId].connectSync(type);
    331         } else {
    332             // Only can switch data when mCurrentDataPhone is PHONE_NONE,
    333             // it is set to PHONE_NONE only as receiving EVENT_PHONEX_DETACH
    334             if (mCurrentDataPhone == PHONE_NONE) {
    335                 mCurrentDataPhone = phoneId;
    336                 mRequestedDataPhone = PHONE_NONE;
    337                 logd("enableApnType(): current PHONE is NONE or IDLE, mCurrentDataPhone=" +
    338                         mCurrentDataPhone);
    339                 return mDcSwitchAsyncChannel[phoneId].connectSync(type);
    340             } else {
    341                 logd("enableApnType(): current PHONE:" + mCurrentDataPhone + " is active.");
    342                 if (phoneId != mRequestedDataPhone) {
    343                     mApnTypes.clear();
    344                 }
    345                 mApnTypes.add(type);
    346                 mRequestedDataPhone = phoneId;
    347                 mDcSwitchState[mCurrentDataPhone].cleanupAllConnection();
    348             }
    349         }
    350         return PhoneConstants.APN_REQUEST_STARTED;
    351     }
    352 
    353     /**
    354      * disable PDP interface by apn type and sub id
    355      *
    356      * @param type enable pdp interface by apn type, such as PhoneConstants.APN_TYPE_MMS, etc.
    357      * @param subId Indicate which sub to query
    358      * @return PhoneConstants.APN_REQUEST_STARTED: action is already started
    359      * PhoneConstants.APN_ALREADY_ACTIVE: interface has already active
    360      * PhoneConstants.APN_TYPE_NOT_AVAILABLE: invalid APN type
    361      * PhoneConstants.APN_REQUEST_FAILED: request failed
    362      * PhoneConstants.APN_REQUEST_FAILED_DUE_TO_RADIO_OFF: readio turn off
    363      * @see #enableApnTypeGemini()
    364      */
    365     public synchronized int disableApnType(long subId, String type) {
    366 
    367         int phoneId = SubscriptionManager.getPhoneId(subId);
    368 
    369         if (phoneId == PHONE_NONE || !isValidphoneId(phoneId)) {
    370             logw("disableApnType(): with PHONE_NONE or Invalid PHONE ID");
    371             return PhoneConstants.APN_REQUEST_FAILED;
    372         }
    373         logd("disableApnType():type=" + type + ",phoneId=" + phoneId +
    374                 ",powerOff=" + mServicePowerOffFlag[phoneId]);
    375         return mDcSwitchAsyncChannel[phoneId].disconnectSync(type);
    376     }
    377 
    378     public boolean isDataConnectivityPossible(String type, int phoneId) {
    379         if (phoneId == PHONE_NONE || !isValidphoneId(phoneId)) {
    380             logw("isDataConnectivityPossible(): with PHONE_NONE or Invalid PHONE ID");
    381             return false;
    382         } else {
    383             return mPhones[phoneId].isDataConnectivityPossible(type);
    384         }
    385     }
    386 
    387     public boolean isIdleOrDeacting(int phoneId) {
    388         if (mDcSwitchAsyncChannel[phoneId].isIdleOrDeactingSync()) {
    389             return true;
    390         } else {
    391             return false;
    392         }
    393     }
    394 
    395     private boolean isValidphoneId(int phoneId) {
    396         return phoneId >= 0 && phoneId <= mPhoneNum;
    397     }
    398 
    399     private boolean isValidApnType(String apnType) {
    400          if (apnType.equals(PhoneConstants.APN_TYPE_DEFAULT)
    401              || apnType.equals(PhoneConstants.APN_TYPE_MMS)
    402              || apnType.equals(PhoneConstants.APN_TYPE_SUPL)
    403              || apnType.equals(PhoneConstants.APN_TYPE_DUN)
    404              || apnType.equals(PhoneConstants.APN_TYPE_HIPRI)
    405              || apnType.equals(PhoneConstants.APN_TYPE_FOTA)
    406              || apnType.equals(PhoneConstants.APN_TYPE_IMS)
    407              || apnType.equals(PhoneConstants.APN_TYPE_CBS))
    408         {
    409             return true;
    410         } else {
    411             return false;
    412         }
    413     }
    414 
    415     private int getDataConnectionFromSetting(){
    416         long [] subId = SubscriptionManager.getSubId(PhoneConstants.SIM_ID_1);
    417         int phoneId = SubscriptionManager.getPhoneId(subId[0]);
    418         return phoneId;
    419     }
    420 
    421     private static void logv(String s) {
    422         Log.v(LOG_TAG, "[DctController] " + s);
    423     }
    424 
    425     private static void logd(String s) {
    426         Log.d(LOG_TAG, "[DctController] " + s);
    427     }
    428 
    429     private static void logw(String s) {
    430         Log.w(LOG_TAG, "[DctController] " + s);
    431     }
    432 
    433     private static void loge(String s) {
    434         Log.e(LOG_TAG, "[DctController] " + s);
    435     }
    436 
    437 
    438     public void setDataSubId(long subId) {
    439         //FIXME This should rework
    440         //FIXME Need to have a StateMachine logic to handle this api considering various clients
    441         Rlog.d(LOG_TAG, "setDataAllowed subId :" + subId);
    442         int phoneId = mSubController.getPhoneId(subId);
    443         int prefPhoneId = mSubController.getPhoneId(mSubController.getDefaultDataSubId());
    444         Phone phone = mPhones[prefPhoneId].getActivePhone();
    445         DcTrackerBase dcTracker =((PhoneBase)phone).mDcTracker;
    446         dcTracker.setDataAllowed(false, null);
    447         mPhones[prefPhoneId].registerForAllDataDisconnected(
    448                 this, EVENT_ALL_DATA_DISCONNECTED, new Integer(phoneId));
    449 
    450     }
    451 
    452     public void registerForDataSwitchInfo(Handler h, int what, Object obj) {
    453         //FIXME This should rework
    454         Registrant r = new Registrant (h, what, obj);
    455         synchronized (mNotifyDataSwitchInfo) {
    456             mNotifyDataSwitchInfo.add(r);
    457         }
    458     }
    459 
    460     @Override
    461     public void handleMessage (Message msg) {
    462         //FIXME This should rework
    463             AsyncResult ar = (AsyncResult)msg.obj;
    464             Rlog.d(LOG_TAG, "handleMessage msg=" + msg);
    465 
    466             switch (msg.what) {
    467                 case EVENT_ALL_DATA_DISCONNECTED:
    468                     Integer phoneId = (Integer)ar.userObj;
    469                     int prefPhoneId = mSubController.getPhoneId(
    470                             mSubController.getDefaultDataSubId());
    471                     Rlog.d(LOG_TAG, "EVENT_ALL_DATA_DISCONNECTED phoneId :" + phoneId);
    472                     mPhones[prefPhoneId].unregisterForAllDataDisconnected(this);
    473                     Message alllowedDataDone = Message.obtain(this, EVENT_SET_DATA_ALLOW_DONE,
    474                             new Integer(phoneId));
    475                     Phone phone = mPhones[phoneId].getActivePhone();
    476                     DcTrackerBase dcTracker =((PhoneBase)phone).mDcTracker;
    477                     dcTracker.setDataAllowed(true, alllowedDataDone);
    478                     break;
    479 
    480                 case EVENT_SET_DATA_ALLOW_DONE:
    481                     phoneId = (Integer)ar.userObj;
    482                     long[] subId = mSubController.getSubId(phoneId);
    483                     Rlog.d(LOG_TAG, "EVENT_SET_DATA_ALLOWED_DONE  phoneId :" + subId[0]);
    484                     mNotifyDataSwitchInfo.notifyRegistrants(new AsyncResult(null, subId[0], null));
    485                     mPhones[phoneId].updateDataConnectionTracker();
    486                     break;
    487             }
    488     }
    489 }
    490