Home | History | Annotate | Download | only in dataconnection
      1 /*
      2  * Copyright 2018 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.dataconnection;
     18 
     19 import android.hardware.radio.V1_0.SetupDataCallResult;
     20 import android.net.LinkAddress;
     21 import android.net.LinkProperties;
     22 import android.net.NetworkUtils;
     23 import android.os.AsyncResult;
     24 import android.os.Handler;
     25 import android.os.HandlerThread;
     26 import android.os.Looper;
     27 import android.os.Message;
     28 import android.telephony.Rlog;
     29 import android.telephony.SubscriptionManager;
     30 import android.telephony.data.DataCallResponse;
     31 import android.telephony.data.DataProfile;
     32 import android.telephony.data.DataService;
     33 import android.telephony.data.DataServiceCallback;
     34 import android.text.TextUtils;
     35 
     36 import com.android.internal.annotations.VisibleForTesting;
     37 import com.android.internal.telephony.Phone;
     38 import com.android.internal.telephony.PhoneFactory;
     39 
     40 import java.net.Inet4Address;
     41 import java.net.InetAddress;
     42 import java.util.ArrayList;
     43 import java.util.Arrays;
     44 import java.util.HashMap;
     45 import java.util.List;
     46 import java.util.Map;
     47 
     48 /**
     49  * This class represents cellular data service which handles telephony data requests and response
     50  * from the cellular modem.
     51  */
     52 public class CellularDataService extends DataService {
     53     private static final String TAG = CellularDataService.class.getSimpleName();
     54 
     55     private static final boolean DBG = false;
     56 
     57     private static final int SETUP_DATA_CALL_COMPLETE               = 1;
     58     private static final int DEACTIVATE_DATA_ALL_COMPLETE           = 2;
     59     private static final int SET_INITIAL_ATTACH_APN_COMPLETE        = 3;
     60     private static final int SET_DATA_PROFILE_COMPLETE              = 4;
     61     private static final int GET_DATA_CALL_LIST_COMPLETE            = 5;
     62     private static final int DATA_CALL_LIST_CHANGED                 = 6;
     63 
     64     private class CellularDataServiceProvider extends DataService.DataServiceProvider {
     65 
     66         private final Map<Message, DataServiceCallback> mCallbackMap = new HashMap<>();
     67 
     68         private final Looper mLooper;
     69 
     70         private final Handler mHandler;
     71 
     72         private final Phone mPhone;
     73 
     74         private CellularDataServiceProvider(int slotId) {
     75             super(slotId);
     76 
     77             mPhone = PhoneFactory.getPhone(getSlotId());
     78 
     79             HandlerThread thread = new HandlerThread(CellularDataService.class.getSimpleName());
     80             thread.start();
     81             mLooper = thread.getLooper();
     82             mHandler = new Handler(mLooper) {
     83                 @Override
     84                 public void handleMessage(Message message) {
     85                     DataServiceCallback callback = mCallbackMap.remove(message);
     86 
     87                     AsyncResult ar = (AsyncResult) message.obj;
     88                     switch (message.what) {
     89                         case SETUP_DATA_CALL_COMPLETE:
     90                             SetupDataCallResult result = (SetupDataCallResult) ar.result;
     91                             callback.onSetupDataCallComplete(ar.exception != null
     92                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
     93                                     : DataServiceCallback.RESULT_SUCCESS,
     94                                     convertDataCallResult(result));
     95                             break;
     96                         case DEACTIVATE_DATA_ALL_COMPLETE:
     97                             callback.onDeactivateDataCallComplete(ar.exception != null
     98                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
     99                                     : DataServiceCallback.RESULT_SUCCESS);
    100                             break;
    101                         case SET_INITIAL_ATTACH_APN_COMPLETE:
    102                             callback.onSetInitialAttachApnComplete(ar.exception != null
    103                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
    104                                     : DataServiceCallback.RESULT_SUCCESS);
    105                             break;
    106                         case SET_DATA_PROFILE_COMPLETE:
    107                             callback.onSetDataProfileComplete(ar.exception != null
    108                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
    109                                     : DataServiceCallback.RESULT_SUCCESS);
    110                             break;
    111                         case GET_DATA_CALL_LIST_COMPLETE:
    112                             callback.onGetDataCallListComplete(
    113                                     ar.exception != null
    114                                             ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
    115                                             : DataServiceCallback.RESULT_SUCCESS,
    116                                     ar.exception != null
    117                                             ? null
    118                                             : getDataCallList((List<SetupDataCallResult>) ar.result)
    119                                     );
    120                             break;
    121                         case DATA_CALL_LIST_CHANGED:
    122                             notifyDataCallListChanged(getDataCallList(
    123                                     (List<SetupDataCallResult>) ar.result));
    124                             break;
    125                         default:
    126                             loge("Unexpected event: " + message.what);
    127                             return;
    128                     }
    129                 }
    130             };
    131 
    132             if (DBG) log("Register for data call list changed.");
    133             mPhone.mCi.registerForDataCallListChanged(mHandler, DATA_CALL_LIST_CHANGED, null);
    134         }
    135 
    136         private List<DataCallResponse> getDataCallList(List<SetupDataCallResult> dcList) {
    137             List<DataCallResponse> dcResponseList = new ArrayList<>();
    138             for (SetupDataCallResult dcResult : dcList) {
    139                 dcResponseList.add(convertDataCallResult(dcResult));
    140             }
    141             return dcResponseList;
    142         }
    143 
    144         @Override
    145         public void setupDataCall(int radioTechnology, DataProfile dataProfile, boolean isRoaming,
    146                                   boolean allowRoaming, int reason, LinkProperties linkProperties,
    147                                   DataServiceCallback callback) {
    148             if (DBG) log("setupDataCall " + getSlotId());
    149 
    150             Message message = null;
    151             // Only obtain the message when the caller wants a callback. If the caller doesn't care
    152             // the request completed or results, then no need to pass the message down.
    153             if (callback != null) {
    154                 message = Message.obtain(mHandler, SETUP_DATA_CALL_COMPLETE);
    155                 mCallbackMap.put(message, callback);
    156             }
    157 
    158             mPhone.mCi.setupDataCall(radioTechnology, dataProfile, isRoaming, allowRoaming, reason,
    159                     linkProperties, message);
    160         }
    161 
    162         @Override
    163         public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) {
    164             if (DBG) log("deactivateDataCall " + getSlotId());
    165 
    166             Message message = null;
    167             // Only obtain the message when the caller wants a callback. If the caller doesn't care
    168             // the request completed or results, then no need to pass the message down.
    169             if (callback != null) {
    170                 message = Message.obtain(mHandler, DEACTIVATE_DATA_ALL_COMPLETE);
    171                 mCallbackMap.put(message, callback);
    172             }
    173 
    174             mPhone.mCi.deactivateDataCall(cid, reason, message);
    175         }
    176 
    177         @Override
    178         public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
    179                                         DataServiceCallback callback) {
    180             if (DBG) log("setInitialAttachApn " + getSlotId());
    181 
    182             Message message = null;
    183             // Only obtain the message when the caller wants a callback. If the caller doesn't care
    184             // the request completed or results, then no need to pass the message down.
    185             if (callback != null) {
    186                 message = Message.obtain(mHandler, SET_INITIAL_ATTACH_APN_COMPLETE);
    187                 mCallbackMap.put(message, callback);
    188             }
    189 
    190             mPhone.mCi.setInitialAttachApn(dataProfile, isRoaming, message);
    191         }
    192 
    193         @Override
    194         public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
    195                                    DataServiceCallback callback) {
    196             if (DBG) log("setDataProfile " + getSlotId());
    197 
    198             Message message = null;
    199             // Only obtain the message when the caller wants a callback. If the caller doesn't care
    200             // the request completed or results, then no need to pass the message down.
    201             if (callback != null) {
    202                 message = Message.obtain(mHandler, SET_DATA_PROFILE_COMPLETE);
    203                 mCallbackMap.put(message, callback);
    204             }
    205 
    206             mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), isRoaming, message);
    207         }
    208 
    209         @Override
    210         public void getDataCallList(DataServiceCallback callback) {
    211             if (DBG) log("getDataCallList " + getSlotId());
    212 
    213             Message message = null;
    214             // Only obtain the message when the caller wants a callback. If the caller doesn't care
    215             // the request completed or results, then no need to pass the message down.
    216             if (callback != null) {
    217                 message = Message.obtain(mHandler, GET_DATA_CALL_LIST_COMPLETE);
    218                 mCallbackMap.put(message, callback);
    219             }
    220             mPhone.mCi.getDataCallList(message);
    221         }
    222     }
    223 
    224     @Override
    225     public DataServiceProvider createDataServiceProvider(int slotId) {
    226         log("Cellular data service created for slot " + slotId);
    227         if (!SubscriptionManager.isValidSlotIndex(slotId)) {
    228             loge("Tried to cellular data service with invalid slotId " + slotId);
    229             return null;
    230         }
    231         return new CellularDataServiceProvider(slotId);
    232     }
    233 
    234     /**
    235      * Convert SetupDataCallResult defined in types.hal into DataCallResponse
    236      * @param dcResult setup data call result
    237      * @return converted DataCallResponse object
    238      */
    239     @VisibleForTesting
    240     public DataCallResponse convertDataCallResult(SetupDataCallResult dcResult) {
    241         if (dcResult == null) return null;
    242 
    243         // Process address
    244         String[] addresses = null;
    245         if (!TextUtils.isEmpty(dcResult.addresses)) {
    246             addresses = dcResult.addresses.split("\\s+");
    247         }
    248 
    249         List<LinkAddress> laList = new ArrayList<>();
    250         if (addresses != null) {
    251             for (String address : addresses) {
    252                 address = address.trim();
    253                 if (address.isEmpty()) continue;
    254 
    255                 try {
    256                     LinkAddress la;
    257                     // Check if the address contains prefix length. If yes, LinkAddress
    258                     // can parse that.
    259                     if (address.split("/").length == 2) {
    260                         la = new LinkAddress(address);
    261                     } else {
    262                         InetAddress ia = NetworkUtils.numericToInetAddress(address);
    263                         la = new LinkAddress(ia, (ia instanceof Inet4Address) ? 32 : 128);
    264                     }
    265 
    266                     laList.add(la);
    267                 } catch (IllegalArgumentException e) {
    268                     loge("Unknown address: " + address + ", exception = " + e);
    269                 }
    270             }
    271         }
    272 
    273         // Process dns
    274         String[] dnses = null;
    275         if (!TextUtils.isEmpty(dcResult.dnses)) {
    276             dnses = dcResult.dnses.split("\\s+");
    277         }
    278 
    279         List<InetAddress> dnsList = new ArrayList<>();
    280         if (dnses != null) {
    281             for (String dns : dnses) {
    282                 dns = dns.trim();
    283                 InetAddress ia;
    284                 try {
    285                     ia = NetworkUtils.numericToInetAddress(dns);
    286                     dnsList.add(ia);
    287                 } catch (IllegalArgumentException e) {
    288                     loge("Unknown dns: " + dns + ", exception = " + e);
    289                 }
    290             }
    291         }
    292 
    293         // Process gateway
    294         String[] gateways = null;
    295         if (!TextUtils.isEmpty(dcResult.gateways)) {
    296             gateways = dcResult.gateways.split("\\s+");
    297         }
    298 
    299         List<InetAddress> gatewayList = new ArrayList<>();
    300         if (gateways != null) {
    301             for (String gateway : gateways) {
    302                 gateway = gateway.trim();
    303                 InetAddress ia;
    304                 try {
    305                     ia = NetworkUtils.numericToInetAddress(gateway);
    306                     gatewayList.add(ia);
    307                 } catch (IllegalArgumentException e) {
    308                     loge("Unknown gateway: " + gateway + ", exception = " + e);
    309                 }
    310             }
    311         }
    312 
    313         return new DataCallResponse(dcResult.status,
    314                 dcResult.suggestedRetryTime,
    315                 dcResult.cid,
    316                 dcResult.active,
    317                 dcResult.type,
    318                 dcResult.ifname,
    319                 laList,
    320                 dnsList,
    321                 gatewayList,
    322                 new ArrayList<>(Arrays.asList(dcResult.pcscf.trim().split("\\s+"))),
    323                 dcResult.mtu
    324         );
    325     }
    326 
    327     private void log(String s) {
    328         Rlog.d(TAG, s);
    329     }
    330 
    331     private void loge(String s) {
    332         Rlog.e(TAG, s);
    333     }
    334 }
    335