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 */ DataServiceProvider(int slotId)127 public DataServiceProvider(int slotId) { 128 mSlotId = slotId; 129 } 130 131 /** 132 * @return SIM slot id the data service provider associated with. 133 */ getSlotId()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 */ setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, @SetupDataReason int reason, @Nullable LinkProperties linkProperties, @Nullable DataServiceCallback callback)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 */ deactivateDataCall(int cid, @DeactivateDataReason int reason, @Nullable DataServiceCallback callback)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 */ setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, @Nullable DataServiceCallback callback)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 */ setDataProfile(List<DataProfile> dps, boolean isRoaming, @Nullable DataServiceCallback callback)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 */ getDataCallList(@onNull DataServiceCallback callback)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 registerForDataCallListChanged(IDataServiceCallback callback)222 private void registerForDataCallListChanged(IDataServiceCallback callback) { 223 synchronized (mDataCallListChangedCallbacks) { 224 mDataCallListChangedCallbacks.add(callback); 225 } 226 } 227 unregisterForDataCallListChanged(IDataServiceCallback callback)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 */ notifyDataCallListChanged(List<DataCallResponse> dataCallList)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 onDestroy()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; SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, 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; DeactivateDataCallRequest(int cid, int reason, 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; SetInitialAttachApnRequest(DataProfile dataProfile, boolean isRoaming, 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; SetDataProfileRequest(List<DataProfile> dps, boolean isRoaming, 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; DataCallListChangedIndication(List<DataCallResponse> dataCallList, 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 DataServiceHandler(Looper looper)327 DataServiceHandler(Looper looper) { 328 super(looper); 329 } 330 331 @Override handleMessage(Message message)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 */ DataService()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 */ createDataServiceProvider(int slotId)449 public abstract DataServiceProvider createDataServiceProvider(int slotId); 450 451 /** @hide */ 452 @Override onBind(Intent intent)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 onUnbind(Intent intent)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 onDestroy()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 createDataServiceProvider(int slotId)479 public void createDataServiceProvider(int slotId) { 480 mHandler.obtainMessage(DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER, slotId, 0) 481 .sendToTarget(); 482 } 483 484 @Override removeDataServiceProvider(int slotId)485 public void removeDataServiceProvider(int slotId) { 486 mHandler.obtainMessage(DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER, slotId, 0) 487 .sendToTarget(); 488 } 489 490 @Override setupDataCall(int slotId, int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, IDataServiceCallback callback)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 deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback)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 setInitialAttachApn(int slotId, DataProfile dataProfile, boolean isRoaming, IDataServiceCallback callback)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 setDataProfile(int slotId, List<DataProfile> dps, boolean isRoaming, IDataServiceCallback callback)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 getDataCallList(int slotId, IDataServiceCallback callback)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 registerForDataCallListChanged(int slotId, IDataServiceCallback callback)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 unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback)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 log(String s)554 private void log(String s) { 555 Rlog.d(TAG, s); 556 } 557 loge(String s)558 private void loge(String s) { 559 Rlog.e(TAG, s); 560 } 561 } 562