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