Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright 2017 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 android.telephony.data;
     18 
     19 import android.annotation.CallSuper;
     20 import android.annotation.IntDef;
     21 import android.annotation.NonNull;
     22 import android.annotation.Nullable;
     23 import android.app.Service;
     24 import android.content.Intent;
     25 import android.net.LinkProperties;
     26 import android.os.Handler;
     27 import android.os.HandlerThread;
     28 import android.os.IBinder;
     29 import android.os.Looper;
     30 import android.os.Message;
     31 import android.os.RemoteException;
     32 import android.telephony.AccessNetworkConstants;
     33 import android.telephony.Rlog;
     34 import android.util.SparseArray;
     35 
     36 import com.android.internal.annotations.VisibleForTesting;
     37 
     38 import java.lang.annotation.Retention;
     39 import java.lang.annotation.RetentionPolicy;
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 
     43 /**
     44  * Base class of data service. Services that extend DataService must register the service in
     45  * their AndroidManifest to be detected by the framework. They must be protected by the permission
     46  * "android.permission.BIND_DATA_SERVICE". The data service definition in the manifest must follow
     47  * the following format:
     48  * ...
     49  * <service android:name=".xxxDataService"
     50  *     android:permission="android.permission.BIND_DATA_SERVICE" >
     51  *     <intent-filter>
     52  *         <action android:name="android.telephony.data.DataService" />
     53  *     </intent-filter>
     54  * </service>
     55  * @hide
     56  */
     57 public abstract class DataService extends Service {
     58     private static final String TAG = DataService.class.getSimpleName();
     59 
     60     public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
     61     public static final String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID";
     62 
     63     /** {@hide} */
     64     @IntDef(prefix = "REQUEST_REASON_", value = {
     65             REQUEST_REASON_NORMAL,
     66             REQUEST_REASON_HANDOVER,
     67     })
     68     @Retention(RetentionPolicy.SOURCE)
     69     public @interface SetupDataReason {}
     70 
     71     /** {@hide} */
     72     @IntDef(prefix = "REQUEST_REASON_", value = {
     73             REQUEST_REASON_NORMAL,
     74             REQUEST_REASON_SHUTDOWN,
     75             REQUEST_REASON_HANDOVER,
     76     })
     77     @Retention(RetentionPolicy.SOURCE)
     78     public @interface DeactivateDataReason {}
     79 
     80 
     81     /** The reason of the data request is normal */
     82     public static final int REQUEST_REASON_NORMAL = 1;
     83 
     84     /** The reason of the data request is device shutdown */
     85     public static final int REQUEST_REASON_SHUTDOWN = 2;
     86 
     87     /** The reason of the data request is IWLAN handover */
     88     public static final int REQUEST_REASON_HANDOVER = 3;
     89 
     90     private static final int DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER                 = 1;
     91     private static final int DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER                 = 2;
     92     private static final int DATA_SERVICE_REMOVE_ALL_DATA_SERVICE_PROVIDERS            = 3;
     93     private static final int DATA_SERVICE_REQUEST_SETUP_DATA_CALL                      = 4;
     94     private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL                 = 5;
     95     private static final int DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN               = 6;
     96     private static final int DATA_SERVICE_REQUEST_SET_DATA_PROFILE                     = 7;
     97     private static final int DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST                   = 8;
     98     private static final int DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED      = 9;
     99     private static final int DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED    = 10;
    100     private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED            = 11;
    101 
    102     private final HandlerThread mHandlerThread;
    103 
    104     private final DataServiceHandler mHandler;
    105 
    106     private final SparseArray<DataServiceProvider> mServiceMap = new SparseArray<>();
    107 
    108     /** @hide */
    109     @VisibleForTesting
    110     public final IDataServiceWrapper mBinder = new IDataServiceWrapper();
    111 
    112     /**
    113      * The abstract class of the actual data service implementation. The data service provider
    114      * must extend this class to support data connection. Note that each instance of data service
    115      * provider is associated with one physical SIM slot.
    116      */
    117     public class DataServiceProvider {
    118 
    119         private final int mSlotId;
    120 
    121         private final List<IDataServiceCallback> mDataCallListChangedCallbacks = new ArrayList<>();
    122 
    123         /**
    124          * Constructor
    125          * @param slotId SIM slot id the data service provider associated with.
    126          */
    127         public DataServiceProvider(int slotId) {
    128             mSlotId = slotId;
    129         }
    130 
    131         /**
    132          * @return SIM slot id the data service provider associated with.
    133          */
    134         public final int getSlotId() {
    135             return mSlotId;
    136         }
    137 
    138         /**
    139          * Setup a data connection. The data service provider must implement this method to support
    140          * establishing a packet data connection. When completed or error, the service must invoke
    141          * the provided callback to notify the platform.
    142          *
    143          * @param accessNetworkType Access network type that the data call will be established on.
    144          *        Must be one of {@link AccessNetworkConstants.AccessNetworkType}.
    145          * @param dataProfile Data profile used for data call setup. See {@link DataProfile}
    146          * @param isRoaming True if the device is data roaming.
    147          * @param allowRoaming True if data roaming is allowed by the user.
    148          * @param reason The reason for data setup. Must be {@link #REQUEST_REASON_NORMAL} or
    149          *        {@link #REQUEST_REASON_HANDOVER}.
    150          * @param linkProperties If {@code reason} is {@link #REQUEST_REASON_HANDOVER}, this is the
    151          *        link properties of the existing data connection, otherwise null.
    152          * @param callback The result callback for this request. Null if the client does not care
    153          *        about the result.
    154          */
    155         public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
    156                                   boolean allowRoaming, @SetupDataReason int reason,
    157                                   @Nullable LinkProperties linkProperties,
    158                                   @Nullable DataServiceCallback callback) {
    159             // The default implementation is to return unsupported.
    160             callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
    161         }
    162 
    163         /**
    164          * Deactivate a data connection. The data service provider must implement this method to
    165          * support data connection tear down. When completed or error, the service must invoke the
    166          * provided callback to notify the platform.
    167          *
    168          * @param cid Call id returned in the callback of {@link DataServiceProvider#setupDataCall(
    169          *        int, DataProfile, boolean, boolean, int, LinkProperties, DataServiceCallback)}.
    170          * @param reason The reason for data deactivation. Must be {@link #REQUEST_REASON_NORMAL},
    171          *        {@link #REQUEST_REASON_SHUTDOWN} or {@link #REQUEST_REASON_HANDOVER}.
    172          * @param callback The result callback for this request. Null if the client does not care
    173          *        about the result.
    174          *
    175          */
    176         public void deactivateDataCall(int cid, @DeactivateDataReason int reason,
    177                                        @Nullable DataServiceCallback callback) {
    178             // The default implementation is to return unsupported.
    179             callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
    180         }
    181 
    182         /**
    183          * Set an APN to initial attach network.
    184          *
    185          * @param dataProfile Data profile used for data call setup. See {@link DataProfile}.
    186          * @param isRoaming True if the device is data roaming.
    187          * @param callback The result callback for this request. Null if the client does not care
    188          *        about the result.
    189          */
    190         public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
    191                                         @Nullable DataServiceCallback callback) {
    192             // The default implementation is to return unsupported.
    193             callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
    194         }
    195 
    196         /**
    197          * Send current carrier's data profiles to the data service for data call setup. This is
    198          * only for CDMA carrier that can change the profile through OTA. The data service should
    199          * always uses the latest data profile sent by the framework.
    200          *
    201          * @param dps A list of data profiles.
    202          * @param isRoaming True if the device is data roaming.
    203          * @param callback The result callback for this request. Null if the client does not care
    204          *        about the result.
    205          */
    206         public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
    207                                    @Nullable DataServiceCallback callback) {
    208             // The default implementation is to return unsupported.
    209             callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
    210         }
    211 
    212         /**
    213          * Get the active data call list.
    214          *
    215          * @param callback The result callback for this request.
    216          */
    217         public void getDataCallList(@NonNull DataServiceCallback callback) {
    218             // The default implementation is to return unsupported.
    219             callback.onGetDataCallListComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
    220         }
    221 
    222         private void registerForDataCallListChanged(IDataServiceCallback callback) {
    223             synchronized (mDataCallListChangedCallbacks) {
    224                 mDataCallListChangedCallbacks.add(callback);
    225             }
    226         }
    227 
    228         private void unregisterForDataCallListChanged(IDataServiceCallback callback) {
    229             synchronized (mDataCallListChangedCallbacks) {
    230                 mDataCallListChangedCallbacks.remove(callback);
    231             }
    232         }
    233 
    234         /**
    235          * Notify the system that current data call list changed. Data service must invoke this
    236          * method whenever there is any data call status changed.
    237          *
    238          * @param dataCallList List of the current active data call.
    239          */
    240         public final void notifyDataCallListChanged(List<DataCallResponse> dataCallList) {
    241             synchronized (mDataCallListChangedCallbacks) {
    242                 for (IDataServiceCallback callback : mDataCallListChangedCallbacks) {
    243                     mHandler.obtainMessage(DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED, mSlotId,
    244                             0, new DataCallListChangedIndication(dataCallList, callback))
    245                             .sendToTarget();
    246                 }
    247             }
    248         }
    249 
    250         /**
    251          * Called when the instance of data service is destroyed (e.g. got unbind or binder died).
    252          */
    253         @CallSuper
    254         protected void onDestroy() {
    255             mDataCallListChangedCallbacks.clear();
    256         }
    257     }
    258 
    259     private static final class SetupDataCallRequest {
    260         public final int accessNetworkType;
    261         public final DataProfile dataProfile;
    262         public final boolean isRoaming;
    263         public final boolean allowRoaming;
    264         public final int reason;
    265         public final LinkProperties linkProperties;
    266         public final IDataServiceCallback callback;
    267         SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
    268                              boolean allowRoaming, int reason, LinkProperties linkProperties,
    269                              IDataServiceCallback callback) {
    270             this.accessNetworkType = accessNetworkType;
    271             this.dataProfile = dataProfile;
    272             this.isRoaming = isRoaming;
    273             this.allowRoaming = allowRoaming;
    274             this.linkProperties = linkProperties;
    275             this.reason = reason;
    276             this.callback = callback;
    277         }
    278     }
    279 
    280     private static final class DeactivateDataCallRequest {
    281         public final int cid;
    282         public final int reason;
    283         public final IDataServiceCallback callback;
    284         DeactivateDataCallRequest(int cid, int reason, IDataServiceCallback callback) {
    285             this.cid = cid;
    286             this.reason = reason;
    287             this.callback = callback;
    288         }
    289     }
    290 
    291     private static final class SetInitialAttachApnRequest {
    292         public final DataProfile dataProfile;
    293         public final boolean isRoaming;
    294         public final IDataServiceCallback callback;
    295         SetInitialAttachApnRequest(DataProfile dataProfile, boolean isRoaming,
    296                                    IDataServiceCallback callback) {
    297             this.dataProfile = dataProfile;
    298             this.isRoaming = isRoaming;
    299             this.callback = callback;
    300         }
    301     }
    302 
    303     private static final class SetDataProfileRequest {
    304         public final List<DataProfile> dps;
    305         public final boolean isRoaming;
    306         public final IDataServiceCallback callback;
    307         SetDataProfileRequest(List<DataProfile> dps, boolean isRoaming,
    308                               IDataServiceCallback callback) {
    309             this.dps = dps;
    310             this.isRoaming = isRoaming;
    311             this.callback = callback;
    312         }
    313     }
    314 
    315     private static final class DataCallListChangedIndication {
    316         public final List<DataCallResponse> dataCallList;
    317         public final IDataServiceCallback callback;
    318         DataCallListChangedIndication(List<DataCallResponse> dataCallList,
    319                                       IDataServiceCallback callback) {
    320             this.dataCallList = dataCallList;
    321             this.callback = callback;
    322         }
    323     }
    324 
    325     private class DataServiceHandler extends Handler {
    326 
    327         DataServiceHandler(Looper looper) {
    328             super(looper);
    329         }
    330 
    331         @Override
    332         public void handleMessage(Message message) {
    333             IDataServiceCallback callback;
    334             final int slotId = message.arg1;
    335             DataServiceProvider serviceProvider = mServiceMap.get(slotId);
    336 
    337             switch (message.what) {
    338                 case DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER:
    339                     serviceProvider = createDataServiceProvider(message.arg1);
    340                     if (serviceProvider != null) {
    341                         mServiceMap.put(slotId, serviceProvider);
    342                     }
    343                     break;
    344                 case DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER:
    345                     if (serviceProvider != null) {
    346                         serviceProvider.onDestroy();
    347                         mServiceMap.remove(slotId);
    348                     }
    349                     break;
    350                 case DATA_SERVICE_REMOVE_ALL_DATA_SERVICE_PROVIDERS:
    351                     for (int i = 0; i < mServiceMap.size(); i++) {
    352                         serviceProvider = mServiceMap.get(i);
    353                         if (serviceProvider != null) {
    354                             serviceProvider.onDestroy();
    355                         }
    356                     }
    357                     mServiceMap.clear();
    358                     break;
    359                 case DATA_SERVICE_REQUEST_SETUP_DATA_CALL:
    360                     if (serviceProvider == null) break;
    361                     SetupDataCallRequest setupDataCallRequest = (SetupDataCallRequest) message.obj;
    362                     serviceProvider.setupDataCall(setupDataCallRequest.accessNetworkType,
    363                             setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
    364                             setupDataCallRequest.allowRoaming, setupDataCallRequest.reason,
    365                             setupDataCallRequest.linkProperties,
    366                             (setupDataCallRequest.callback != null)
    367                                     ? new DataServiceCallback(setupDataCallRequest.callback)
    368                                     : null);
    369 
    370                     break;
    371                 case DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL:
    372                     if (serviceProvider == null) break;
    373                     DeactivateDataCallRequest deactivateDataCallRequest =
    374                             (DeactivateDataCallRequest) message.obj;
    375                     serviceProvider.deactivateDataCall(deactivateDataCallRequest.cid,
    376                             deactivateDataCallRequest.reason,
    377                             (deactivateDataCallRequest.callback != null)
    378                                     ? new DataServiceCallback(deactivateDataCallRequest.callback)
    379                                     : null);
    380                     break;
    381                 case DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN:
    382                     if (serviceProvider == null) break;
    383                     SetInitialAttachApnRequest setInitialAttachApnRequest =
    384                             (SetInitialAttachApnRequest) message.obj;
    385                     serviceProvider.setInitialAttachApn(setInitialAttachApnRequest.dataProfile,
    386                             setInitialAttachApnRequest.isRoaming,
    387                             (setInitialAttachApnRequest.callback != null)
    388                                     ? new DataServiceCallback(setInitialAttachApnRequest.callback)
    389                                     : null);
    390                     break;
    391                 case DATA_SERVICE_REQUEST_SET_DATA_PROFILE:
    392                     if (serviceProvider == null) break;
    393                     SetDataProfileRequest setDataProfileRequest =
    394                             (SetDataProfileRequest) message.obj;
    395                     serviceProvider.setDataProfile(setDataProfileRequest.dps,
    396                             setDataProfileRequest.isRoaming,
    397                             (setDataProfileRequest.callback != null)
    398                                     ? new DataServiceCallback(setDataProfileRequest.callback)
    399                                     : null);
    400                     break;
    401                 case DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST:
    402                     if (serviceProvider == null) break;
    403 
    404                     serviceProvider.getDataCallList(new DataServiceCallback(
    405                             (IDataServiceCallback) message.obj));
    406                     break;
    407                 case DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED:
    408                     if (serviceProvider == null) break;
    409                     serviceProvider.registerForDataCallListChanged((IDataServiceCallback) message.obj);
    410                     break;
    411                 case DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED:
    412                     if (serviceProvider == null) break;
    413                     callback = (IDataServiceCallback) message.obj;
    414                     serviceProvider.unregisterForDataCallListChanged(callback);
    415                     break;
    416                 case DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED:
    417                     if (serviceProvider == null) break;
    418                     DataCallListChangedIndication indication =
    419                             (DataCallListChangedIndication) message.obj;
    420                     try {
    421                         indication.callback.onDataCallListChanged(indication.dataCallList);
    422                     } catch (RemoteException e) {
    423                         loge("Failed to call onDataCallListChanged. " + e);
    424                     }
    425                     break;
    426             }
    427         }
    428     }
    429 
    430     /**
    431      * Default constructor.
    432      */
    433     public DataService() {
    434         mHandlerThread = new HandlerThread(TAG);
    435         mHandlerThread.start();
    436 
    437         mHandler = new DataServiceHandler(mHandlerThread.getLooper());
    438         log("Data service created");
    439     }
    440 
    441     /**
    442      * Create the instance of {@link DataServiceProvider}. Data service provider must override
    443      * this method to facilitate the creation of {@link DataServiceProvider} instances. The system
    444      * will call this method after binding the data service for each active SIM slot id.
    445      *
    446      * @param slotId SIM slot id the data service associated with.
    447      * @return Data service object
    448      */
    449     public abstract DataServiceProvider createDataServiceProvider(int slotId);
    450 
    451     /** @hide */
    452     @Override
    453     public IBinder onBind(Intent intent) {
    454         if (intent == null || !DATA_SERVICE_INTERFACE.equals(intent.getAction())) {
    455             loge("Unexpected intent " + intent);
    456             return null;
    457         }
    458         return mBinder;
    459     }
    460 
    461     /** @hide */
    462     @Override
    463     public boolean onUnbind(Intent intent) {
    464         mHandler.obtainMessage(DATA_SERVICE_REMOVE_ALL_DATA_SERVICE_PROVIDERS).sendToTarget();
    465         return false;
    466     }
    467 
    468     /** @hide */
    469     @Override
    470     public void onDestroy() {
    471         mHandlerThread.quit();
    472     }
    473 
    474     /**
    475      * A wrapper around IDataService that forwards calls to implementations of {@link DataService}.
    476      */
    477     private class IDataServiceWrapper extends IDataService.Stub {
    478         @Override
    479         public void createDataServiceProvider(int slotId) {
    480             mHandler.obtainMessage(DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER, slotId, 0)
    481                     .sendToTarget();
    482         }
    483 
    484         @Override
    485         public void removeDataServiceProvider(int slotId) {
    486             mHandler.obtainMessage(DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER, slotId, 0)
    487                     .sendToTarget();
    488         }
    489 
    490         @Override
    491         public void setupDataCall(int slotId, int accessNetworkType, DataProfile dataProfile,
    492                                   boolean isRoaming, boolean allowRoaming, int reason,
    493                                   LinkProperties linkProperties, IDataServiceCallback callback) {
    494             mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotId, 0,
    495                     new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming,
    496                             allowRoaming, reason, linkProperties, callback))
    497                     .sendToTarget();
    498         }
    499 
    500         @Override
    501         public void deactivateDataCall(int slotId, int cid, int reason,
    502                                        IDataServiceCallback callback) {
    503             mHandler.obtainMessage(DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL, slotId, 0,
    504                     new DeactivateDataCallRequest(cid, reason, callback))
    505                     .sendToTarget();
    506         }
    507 
    508         @Override
    509         public void setInitialAttachApn(int slotId, DataProfile dataProfile, boolean isRoaming,
    510                                         IDataServiceCallback callback) {
    511             mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN, slotId, 0,
    512                     new SetInitialAttachApnRequest(dataProfile, isRoaming, callback))
    513                     .sendToTarget();
    514         }
    515 
    516         @Override
    517         public void setDataProfile(int slotId, List<DataProfile> dps, boolean isRoaming,
    518                                    IDataServiceCallback callback) {
    519             mHandler.obtainMessage(DATA_SERVICE_REQUEST_SET_DATA_PROFILE, slotId, 0,
    520                     new SetDataProfileRequest(dps, isRoaming, callback)).sendToTarget();
    521         }
    522 
    523         @Override
    524         public void getDataCallList(int slotId, IDataServiceCallback callback) {
    525             if (callback == null) {
    526                 loge("getDataCallList: callback is null");
    527                 return;
    528             }
    529             mHandler.obtainMessage(DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST, slotId, 0,
    530                     callback).sendToTarget();
    531         }
    532 
    533         @Override
    534         public void registerForDataCallListChanged(int slotId, IDataServiceCallback callback) {
    535             if (callback == null) {
    536                 loge("registerForDataCallListChanged: callback is null");
    537                 return;
    538             }
    539             mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED, slotId,
    540                     0, callback).sendToTarget();
    541         }
    542 
    543         @Override
    544         public void unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback) {
    545             if (callback == null) {
    546                 loge("unregisterForDataCallListChanged: callback is null");
    547                 return;
    548             }
    549             mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED, slotId,
    550                     0, callback).sendToTarget();
    551         }
    552     }
    553 
    554     private void log(String s) {
    555         Rlog.d(TAG, s);
    556     }
    557 
    558     private void loge(String s) {
    559         Rlog.e(TAG, s);
    560     }
    561 }
    562