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 static android.text.format.DateUtils.MINUTE_IN_MILLIS; 20 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 21 22 import android.annotation.NonNull; 23 import android.app.AppOpsManager; 24 import android.content.BroadcastReceiver; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.ServiceConnection; 30 import android.content.pm.PackageManager; 31 import android.content.pm.ResolveInfo; 32 import android.net.LinkProperties; 33 import android.os.AsyncResult; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.Message; 37 import android.os.PersistableBundle; 38 import android.os.RegistrantList; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.permission.PermissionManager; 42 import android.telephony.AccessNetworkConstants; 43 import android.telephony.AccessNetworkConstants.TransportType; 44 import android.telephony.AnomalyReporter; 45 import android.telephony.CarrierConfigManager; 46 import android.telephony.SubscriptionManager; 47 import android.telephony.data.DataCallResponse; 48 import android.telephony.data.DataProfile; 49 import android.telephony.data.DataService; 50 import android.telephony.data.DataServiceCallback; 51 import android.telephony.data.IDataService; 52 import android.telephony.data.IDataServiceCallback; 53 import android.text.TextUtils; 54 55 import com.android.internal.telephony.Phone; 56 import com.android.internal.telephony.PhoneConfigurationManager; 57 import com.android.internal.telephony.util.TelephonyUtils; 58 import com.android.telephony.Rlog; 59 60 import java.util.HashSet; 61 import java.util.List; 62 import java.util.Map; 63 import java.util.Set; 64 import java.util.UUID; 65 import java.util.concurrent.ConcurrentHashMap; 66 import java.util.concurrent.CountDownLatch; 67 68 /** 69 * Data service manager manages handling data requests and responses on data services (e.g. 70 * Cellular data service, IWLAN data service). 71 */ 72 public class DataServiceManager extends Handler { 73 private static final boolean DBG = true; 74 75 static final String DATA_CALL_RESPONSE = "data_call_response"; 76 77 private static final int EVENT_BIND_DATA_SERVICE = 1; 78 79 private static final int EVENT_WATCHDOG_TIMEOUT = 2; 80 81 private static final long REQUEST_UNRESPONDED_TIMEOUT = 10 * MINUTE_IN_MILLIS; // 10 mins 82 83 private static final long CHANGE_PERMISSION_TIMEOUT_MS = 15 * SECOND_IN_MILLIS; // 15 secs 84 85 private final Phone mPhone; 86 87 private final String mTag; 88 89 private final CarrierConfigManager mCarrierConfigManager; 90 private final AppOpsManager mAppOps; 91 private final PermissionManager mPermissionManager; 92 93 private final int mTransportType; 94 95 private boolean mBound; 96 97 private IDataService mIDataService; 98 99 private DataServiceManagerDeathRecipient mDeathRecipient; 100 101 private final RegistrantList mServiceBindingChangedRegistrants = new RegistrantList(); 102 103 private final Map<IBinder, Message> mMessageMap = new ConcurrentHashMap<>(); 104 105 private final RegistrantList mDataCallListChangedRegistrants = new RegistrantList(); 106 107 private String mTargetBindingPackageName; 108 109 private CellularDataServiceConnection mServiceConnection; 110 111 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 112 @Override 113 public void onReceive(Context context, Intent intent) { 114 final String action = intent.getAction(); 115 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) 116 && mPhone.getPhoneId() == intent.getIntExtra( 117 CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { 118 // We should wait for carrier config changed event because the target binding 119 // package name can come from the carrier config. Note that we still get this event 120 // even when SIM is absent. 121 if (DBG) log("Carrier config changed. Try to bind data service."); 122 sendEmptyMessage(EVENT_BIND_DATA_SERVICE); 123 } 124 } 125 }; 126 127 private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient { 128 @Override binderDied()129 public void binderDied() { 130 // TODO: try to rebind the service. 131 loge("DataService " + mTargetBindingPackageName + ", transport type " + mTransportType 132 + " died."); 133 } 134 } 135 grantPermissionsToService(String packageName)136 private void grantPermissionsToService(String packageName) { 137 final String[] pkgToGrant = {packageName}; 138 CountDownLatch latch = new CountDownLatch(1); 139 try { 140 mPermissionManager.grantDefaultPermissionsToEnabledTelephonyDataServices( 141 pkgToGrant, UserHandle.of(UserHandle.myUserId()), Runnable::run, 142 isSuccess -> { 143 if (isSuccess) { 144 latch.countDown(); 145 } else { 146 loge("Failed to grant permissions to service."); 147 } 148 }); 149 TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); 150 mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, 151 UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); 152 } catch (RuntimeException e) { 153 loge("Binder to package manager died, permission grant for DataService failed."); 154 throw e; 155 } 156 } 157 158 /** 159 * Loop through all DataServices installed on the system and revoke permissions from any that 160 * are not currently the WWAN or WLAN data service. 161 */ revokePermissionsFromUnusedDataServices()162 private void revokePermissionsFromUnusedDataServices() { 163 // Except the current data services from having their permissions removed. 164 Set<String> dataServices = getAllDataServicePackageNames(); 165 for (int transportType : mPhone.getTransportManager().getAvailableTransports()) { 166 dataServices.remove(getDataServicePackageName(transportType)); 167 } 168 169 CountDownLatch latch = new CountDownLatch(1); 170 try { 171 String[] dataServicesArray = new String[dataServices.size()]; 172 dataServices.toArray(dataServicesArray); 173 mPermissionManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices( 174 dataServicesArray, UserHandle.of(UserHandle.myUserId()), Runnable::run, 175 isSuccess -> { 176 if (isSuccess) { 177 latch.countDown(); 178 } else { 179 loge("Failed to revoke permissions from data services."); 180 } 181 }); 182 TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); 183 for (String pkg : dataServices) { 184 mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, UserHandle.myUserId(), 185 pkg, AppOpsManager.MODE_ERRORED); 186 } 187 } catch (RuntimeException e) { 188 loge("Binder to package manager died; failed to revoke DataService permissions."); 189 throw e; 190 } 191 } 192 193 private final class CellularDataServiceConnection implements ServiceConnection { 194 @Override onServiceConnected(ComponentName name, IBinder service)195 public void onServiceConnected(ComponentName name, IBinder service) { 196 if (DBG) log("onServiceConnected"); 197 mIDataService = IDataService.Stub.asInterface(service); 198 mDeathRecipient = new DataServiceManagerDeathRecipient(); 199 mBound = true; 200 201 try { 202 service.linkToDeath(mDeathRecipient, 0); 203 mIDataService.createDataServiceProvider(mPhone.getPhoneId()); 204 mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(), 205 new CellularDataServiceCallback("dataCallListChanged")); 206 } catch (RemoteException e) { 207 mDeathRecipient.binderDied(); 208 loge("Remote exception. " + e); 209 return; 210 } 211 removeMessages(EVENT_WATCHDOG_TIMEOUT); 212 mServiceBindingChangedRegistrants.notifyResult(true); 213 } 214 @Override onServiceDisconnected(ComponentName name)215 public void onServiceDisconnected(ComponentName name) { 216 if (DBG) log("onServiceDisconnected"); 217 removeMessages(EVENT_WATCHDOG_TIMEOUT); 218 mIDataService = null; 219 mBound = false; 220 mServiceBindingChangedRegistrants.notifyResult(false); 221 mTargetBindingPackageName = null; 222 } 223 } 224 225 private final class CellularDataServiceCallback extends IDataServiceCallback.Stub { 226 227 private final String mTag; 228 CellularDataServiceCallback(String tag)229 CellularDataServiceCallback(String tag) { 230 mTag = tag; 231 } 232 getTag()233 public String getTag() { 234 return mTag; 235 } 236 237 @Override onSetupDataCallComplete(@ataServiceCallback.ResultCode int resultCode, DataCallResponse response)238 public void onSetupDataCallComplete(@DataServiceCallback.ResultCode int resultCode, 239 DataCallResponse response) { 240 if (DBG) { 241 log("onSetupDataCallComplete. resultCode = " + resultCode + ", response = " 242 + response); 243 } 244 removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); 245 Message msg = mMessageMap.remove(asBinder()); 246 if (msg != null) { 247 msg.getData().putParcelable(DATA_CALL_RESPONSE, response); 248 sendCompleteMessage(msg, resultCode); 249 } else { 250 loge("Unable to find the message for setup call response."); 251 } 252 } 253 254 @Override onDeactivateDataCallComplete(@ataServiceCallback.ResultCode int resultCode)255 public void onDeactivateDataCallComplete(@DataServiceCallback.ResultCode int resultCode) { 256 if (DBG) log("onDeactivateDataCallComplete. resultCode = " + resultCode); 257 removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); 258 Message msg = mMessageMap.remove(asBinder()); 259 sendCompleteMessage(msg, resultCode); 260 } 261 262 @Override onSetInitialAttachApnComplete(@ataServiceCallback.ResultCode int resultCode)263 public void onSetInitialAttachApnComplete(@DataServiceCallback.ResultCode int resultCode) { 264 if (DBG) log("onSetInitialAttachApnComplete. resultCode = " + resultCode); 265 Message msg = mMessageMap.remove(asBinder()); 266 sendCompleteMessage(msg, resultCode); 267 } 268 269 @Override onSetDataProfileComplete(@ataServiceCallback.ResultCode int resultCode)270 public void onSetDataProfileComplete(@DataServiceCallback.ResultCode int resultCode) { 271 if (DBG) log("onSetDataProfileComplete. resultCode = " + resultCode); 272 Message msg = mMessageMap.remove(asBinder()); 273 sendCompleteMessage(msg, resultCode); 274 } 275 276 @Override onRequestDataCallListComplete(@ataServiceCallback.ResultCode int resultCode, List<DataCallResponse> dataCallList)277 public void onRequestDataCallListComplete(@DataServiceCallback.ResultCode int resultCode, 278 List<DataCallResponse> dataCallList) { 279 if (DBG) log("onRequestDataCallListComplete. resultCode = " + resultCode); 280 Message msg = mMessageMap.remove(asBinder()); 281 sendCompleteMessage(msg, resultCode); 282 } 283 284 @Override onDataCallListChanged(List<DataCallResponse> dataCallList)285 public void onDataCallListChanged(List<DataCallResponse> dataCallList) { 286 mDataCallListChangedRegistrants.notifyRegistrants( 287 new AsyncResult(null, dataCallList, null)); 288 } 289 } 290 291 /** 292 * Constructor 293 * 294 * @param phone The phone object 295 * @param transportType The transport type 296 * @param tagSuffix Logging tag suffix 297 */ DataServiceManager(Phone phone, @TransportType int transportType, String tagSuffix)298 public DataServiceManager(Phone phone, @TransportType int transportType, String tagSuffix) { 299 mPhone = phone; 300 mTag = "DSM" + tagSuffix; 301 mTransportType = transportType; 302 mBound = false; 303 mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( 304 Context.CARRIER_CONFIG_SERVICE); 305 // NOTE: Do NOT use AppGlobals to retrieve the permission manager; AppGlobals 306 // caches the service instance, but we need to explicitly request a new service 307 // so it can be mocked out for tests 308 mPermissionManager = 309 (PermissionManager) phone.getContext().getSystemService(Context.PERMISSION_SERVICE); 310 mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE); 311 312 IntentFilter intentFilter = new IntentFilter(); 313 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 314 try { 315 Context contextAsUser = phone.getContext().createPackageContextAsUser( 316 phone.getContext().getPackageName(), 0, UserHandle.ALL); 317 contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter, 318 null /* broadcastPermission */, null); 319 } catch (PackageManager.NameNotFoundException e) { 320 loge("Package name not found: " + e.getMessage()); 321 } 322 PhoneConfigurationManager.registerForMultiSimConfigChange( 323 this, EVENT_BIND_DATA_SERVICE, null); 324 325 sendEmptyMessage(EVENT_BIND_DATA_SERVICE); 326 } 327 328 /** 329 * Handle message events 330 * 331 * @param msg The message to handle 332 */ 333 @Override handleMessage(Message msg)334 public void handleMessage(Message msg) { 335 switch (msg.what) { 336 case EVENT_BIND_DATA_SERVICE: 337 rebindDataService(); 338 break; 339 case EVENT_WATCHDOG_TIMEOUT: 340 handleRequestUnresponded((CellularDataServiceCallback) msg.obj); 341 break; 342 default: 343 loge("Unhandled event " + msg.what); 344 } 345 } 346 handleRequestUnresponded(CellularDataServiceCallback callback)347 private void handleRequestUnresponded(CellularDataServiceCallback callback) { 348 String message = "Request " + callback.getTag() + " unresponded on transport " 349 + AccessNetworkConstants.transportTypeToString(mTransportType) + " in " 350 + REQUEST_UNRESPONDED_TIMEOUT / 1000 + " seconds."; 351 log(message); 352 // Using fixed UUID to avoid duplicate bugreport notification 353 AnomalyReporter.reportAnomaly( 354 UUID.fromString("f5d5cbe6-9bd6-4009-b764-42b1b649b1de"), 355 message); 356 } 357 unbindDataService()358 private void unbindDataService() { 359 // Start by cleaning up all packages that *shouldn't* have permissions. 360 revokePermissionsFromUnusedDataServices(); 361 if (mIDataService != null && mIDataService.asBinder().isBinderAlive()) { 362 log("unbinding service"); 363 // Remove the network availability updater and then unbind the service. 364 try { 365 mIDataService.removeDataServiceProvider(mPhone.getPhoneId()); 366 } catch (RemoteException e) { 367 loge("Cannot remove data service provider. " + e); 368 } 369 } 370 371 if (mServiceConnection != null) { 372 mPhone.getContext().unbindService(mServiceConnection); 373 } 374 mIDataService = null; 375 mServiceConnection = null; 376 mTargetBindingPackageName = null; 377 mBound = false; 378 } 379 bindDataService(String packageName)380 private void bindDataService(String packageName) { 381 if (mPhone == null || !SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())) { 382 loge("can't bindDataService with invalid phone or phoneId."); 383 return; 384 } 385 386 if (TextUtils.isEmpty(packageName)) { 387 loge("Can't find the binding package"); 388 return; 389 } 390 391 Intent intent = null; 392 String className = getDataServiceClassName(); 393 if (TextUtils.isEmpty(className)) { 394 intent = new Intent(DataService.SERVICE_INTERFACE); 395 intent.setPackage(packageName); 396 } else { 397 ComponentName cm = new ComponentName(packageName, className); 398 intent = new Intent(DataService.SERVICE_INTERFACE).setComponent(cm); 399 } 400 401 // Then pre-emptively grant the permissions to the package we will bind. 402 grantPermissionsToService(packageName); 403 404 try { 405 mServiceConnection = new CellularDataServiceConnection(); 406 if (!mPhone.getContext().bindService( 407 intent, mServiceConnection, Context.BIND_AUTO_CREATE)) { 408 loge("Cannot bind to the data service."); 409 return; 410 } 411 mTargetBindingPackageName = packageName; 412 } catch (Exception e) { 413 loge("Cannot bind to the data service. Exception: " + e); 414 } 415 } 416 rebindDataService()417 private void rebindDataService() { 418 String packageName = getDataServicePackageName(); 419 // Do nothing if no need to rebind. 420 if (SubscriptionManager.isValidPhoneId(mPhone.getPhoneId()) 421 && TextUtils.equals(packageName, mTargetBindingPackageName)) { 422 if (DBG) log("Service " + packageName + " already bound or being bound."); 423 return; 424 } 425 426 unbindDataService(); 427 bindDataService(packageName); 428 } 429 430 @NonNull getAllDataServicePackageNames()431 private Set<String> getAllDataServicePackageNames() { 432 // Cowardly using the public PackageManager interface here. 433 // Note: This matches only packages that were installed on the system image. If we ever 434 // expand the permissions model to allow CarrierPrivileged packages, then this will need 435 // to be updated. 436 List<ResolveInfo> dataPackages = 437 mPhone.getContext().getPackageManager().queryIntentServices( 438 new Intent(DataService.SERVICE_INTERFACE), 439 PackageManager.MATCH_SYSTEM_ONLY); 440 HashSet<String> packageNames = new HashSet<>(); 441 for (ResolveInfo info : dataPackages) { 442 if (info.serviceInfo == null) continue; 443 packageNames.add(info.serviceInfo.packageName); 444 } 445 return packageNames; 446 } 447 448 /** 449 * Get the data service package name for our current transport type. 450 * 451 * @return package name of the data service package for the the current transportType. 452 */ getDataServicePackageName()453 private String getDataServicePackageName() { 454 return getDataServicePackageName(mTransportType); 455 } 456 457 /** 458 * Get the data service package by transport type. 459 * 460 * When we bind to a DataService package, we need to revoke permissions from stale 461 * packages; we need to exclude data packages for all transport types, so we need to 462 * to be able to query by transport type. 463 * 464 * @param transportType The transport type 465 * @return package name of the data service package for the specified transportType. 466 */ getDataServicePackageName(@ransportType int transportType)467 private String getDataServicePackageName(@TransportType int transportType) { 468 String packageName; 469 int resourceId; 470 String carrierConfig; 471 472 switch (transportType) { 473 case AccessNetworkConstants.TRANSPORT_TYPE_WWAN: 474 resourceId = com.android.internal.R.string.config_wwan_data_service_package; 475 carrierConfig = CarrierConfigManager 476 .KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING; 477 break; 478 case AccessNetworkConstants.TRANSPORT_TYPE_WLAN: 479 resourceId = com.android.internal.R.string.config_wlan_data_service_package; 480 carrierConfig = CarrierConfigManager 481 .KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING; 482 break; 483 default: 484 throw new IllegalStateException("Transport type not WWAN or WLAN. type=" 485 + AccessNetworkConstants.transportTypeToString(mTransportType)); 486 } 487 488 // Read package name from resource overlay 489 packageName = mPhone.getContext().getResources().getString(resourceId); 490 491 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); 492 493 if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { 494 // If carrier config overrides it, use the one from carrier config 495 packageName = b.getString(carrierConfig, packageName); 496 } 497 498 return packageName; 499 } 500 501 /** 502 * Get the data service class name for our current transport type. 503 * 504 * @return class name of the data service package for the the current transportType. 505 */ getDataServiceClassName()506 private String getDataServiceClassName() { 507 return getDataServiceClassName(mTransportType); 508 } 509 510 511 /** 512 * Get the data service class by transport type. 513 * 514 * @param transportType either WWAN or WLAN 515 * @return class name of the data service package for the specified transportType. 516 */ getDataServiceClassName(int transportType)517 private String getDataServiceClassName(int transportType) { 518 String className; 519 int resourceId; 520 String carrierConfig; 521 switch (transportType) { 522 case AccessNetworkConstants.TRANSPORT_TYPE_WWAN: 523 resourceId = com.android.internal.R.string.config_wwan_data_service_class; 524 carrierConfig = CarrierConfigManager 525 .KEY_CARRIER_DATA_SERVICE_WWAN_CLASS_OVERRIDE_STRING; 526 break; 527 case AccessNetworkConstants.TRANSPORT_TYPE_WLAN: 528 resourceId = com.android.internal.R.string.config_wlan_data_service_class; 529 carrierConfig = CarrierConfigManager 530 .KEY_CARRIER_DATA_SERVICE_WLAN_CLASS_OVERRIDE_STRING; 531 break; 532 default: 533 throw new IllegalStateException("Transport type not WWAN or WLAN. type=" 534 + transportType); 535 } 536 537 // Read package name from resource overlay 538 className = mPhone.getContext().getResources().getString(resourceId); 539 540 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); 541 542 if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { 543 // If carrier config overrides it, use the one from carrier config 544 className = b.getString(carrierConfig, className); 545 } 546 547 return className; 548 } 549 sendCompleteMessage(Message msg, int code)550 private void sendCompleteMessage(Message msg, int code) { 551 if (msg != null) { 552 msg.arg1 = code; 553 msg.sendToTarget(); 554 } 555 } 556 557 /** 558 * Setup a data connection. The data service provider must implement this method to support 559 * establishing a packet data connection. When completed or error, the service must invoke 560 * the provided callback to notify the platform. 561 * 562 * @param accessNetworkType Access network type that the data call will be established on. 563 * Must be one of {@link AccessNetworkConstants.AccessNetworkType}. 564 * @param dataProfile Data profile used for data call setup. See {@link DataProfile} 565 * @param isRoaming True if the device is data roaming. 566 * @param allowRoaming True if data roaming is allowed by the user. 567 * @param reason The reason for data setup. Must be {@link DataService#REQUEST_REASON_NORMAL} or 568 * {@link DataService#REQUEST_REASON_HANDOVER}. 569 * @param linkProperties If {@code reason} is {@link DataService#REQUEST_REASON_HANDOVER}, this 570 * is the link properties of the existing data connection, otherwise null. 571 * @param onCompleteMessage The result message for this request. Null if the client does not 572 * care about the result. 573 */ setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, Message onCompleteMessage)574 public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, 575 boolean allowRoaming, int reason, LinkProperties linkProperties, 576 Message onCompleteMessage) { 577 if (DBG) log("setupDataCall"); 578 if (!mBound) { 579 loge("Data service not bound."); 580 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 581 return; 582 } 583 584 CellularDataServiceCallback callback = new CellularDataServiceCallback("setupDataCall"); 585 if (onCompleteMessage != null) { 586 mMessageMap.put(callback.asBinder(), onCompleteMessage); 587 } 588 try { 589 sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback), 590 REQUEST_UNRESPONDED_TIMEOUT); 591 mIDataService.setupDataCall(mPhone.getPhoneId(), accessNetworkType, dataProfile, 592 isRoaming, allowRoaming, reason, linkProperties, callback); 593 } catch (RemoteException e) { 594 loge("Cannot invoke setupDataCall on data service."); 595 mMessageMap.remove(callback.asBinder()); 596 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 597 } 598 } 599 600 /** 601 * Deactivate a data connection. The data service provider must implement this method to 602 * support data connection tear down. When completed or error, the service must invoke the 603 * provided callback to notify the platform. 604 * 605 * @param cid Call id returned in the callback of {@link #setupDataCall(int, DataProfile, 606 * boolean, boolean, int, LinkProperties, Message)} 607 * @param reason The reason for data deactivation. Must be 608 * {@link DataService#REQUEST_REASON_NORMAL}, {@link DataService#REQUEST_REASON_SHUTDOWN} 609 * or {@link DataService#REQUEST_REASON_HANDOVER}. 610 * @param onCompleteMessage The result message for this request. Null if the client does not 611 * care about the result. 612 */ deactivateDataCall(int cid, int reason, Message onCompleteMessage)613 public void deactivateDataCall(int cid, int reason, Message onCompleteMessage) { 614 if (DBG) log("deactivateDataCall"); 615 if (!mBound) { 616 loge("Data service not bound."); 617 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 618 return; 619 } 620 621 CellularDataServiceCallback callback = 622 new CellularDataServiceCallback("deactivateDataCall"); 623 if (onCompleteMessage != null) { 624 mMessageMap.put(callback.asBinder(), onCompleteMessage); 625 } 626 try { 627 sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback), 628 REQUEST_UNRESPONDED_TIMEOUT); 629 mIDataService.deactivateDataCall(mPhone.getPhoneId(), cid, reason, callback); 630 } catch (RemoteException e) { 631 loge("Cannot invoke deactivateDataCall on data service."); 632 mMessageMap.remove(callback.asBinder()); 633 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 634 } 635 } 636 637 /** 638 * Set an APN to initial attach network. 639 * 640 * @param dataProfile Data profile used for data call setup. See {@link DataProfile}. 641 * @param isRoaming True if the device is data roaming. 642 * @param onCompleteMessage The result message for this request. Null if the client does not 643 * care about the result. 644 */ setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message onCompleteMessage)645 public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, 646 Message onCompleteMessage) { 647 if (DBG) log("setInitialAttachApn"); 648 if (!mBound) { 649 loge("Data service not bound."); 650 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 651 return; 652 } 653 654 CellularDataServiceCallback callback = 655 new CellularDataServiceCallback("setInitialAttachApn"); 656 if (onCompleteMessage != null) { 657 mMessageMap.put(callback.asBinder(), onCompleteMessage); 658 } 659 try { 660 mIDataService.setInitialAttachApn(mPhone.getPhoneId(), dataProfile, isRoaming, 661 callback); 662 } catch (RemoteException e) { 663 loge("Cannot invoke setInitialAttachApn on data service."); 664 mMessageMap.remove(callback.asBinder()); 665 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 666 } 667 } 668 669 /** 670 * Send current carrier's data profiles to the data service for data call setup. This is 671 * only for CDMA carrier that can change the profile through OTA. The data service should 672 * always uses the latest data profile sent by the framework. 673 * 674 * @param dps A list of data profiles. 675 * @param isRoaming True if the device is data roaming. 676 * @param onCompleteMessage The result message for this request. Null if the client does not 677 * care about the result. 678 */ setDataProfile(List<DataProfile> dps, boolean isRoaming, Message onCompleteMessage)679 public void setDataProfile(List<DataProfile> dps, boolean isRoaming, 680 Message onCompleteMessage) { 681 if (DBG) log("setDataProfile"); 682 if (!mBound) { 683 loge("Data service not bound."); 684 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 685 return; 686 } 687 688 CellularDataServiceCallback callback = new CellularDataServiceCallback("setDataProfile"); 689 if (onCompleteMessage != null) { 690 mMessageMap.put(callback.asBinder(), onCompleteMessage); 691 } 692 try { 693 mIDataService.setDataProfile(mPhone.getPhoneId(), dps, isRoaming, callback); 694 } catch (RemoteException e) { 695 loge("Cannot invoke setDataProfile on data service."); 696 mMessageMap.remove(callback.asBinder()); 697 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 698 } 699 } 700 701 /** 702 * Get the active data call list. 703 * 704 * @param onCompleteMessage The result message for this request. Null if the client does not 705 * care about the result. 706 */ requestDataCallList(Message onCompleteMessage)707 public void requestDataCallList(Message onCompleteMessage) { 708 if (DBG) log("requestDataCallList"); 709 if (!mBound) { 710 loge("Data service not bound."); 711 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 712 return; 713 } 714 715 CellularDataServiceCallback callback = 716 new CellularDataServiceCallback("requestDataCallList"); 717 if (onCompleteMessage != null) { 718 mMessageMap.put(callback.asBinder(), onCompleteMessage); 719 } 720 try { 721 mIDataService.requestDataCallList(mPhone.getPhoneId(), callback); 722 } catch (RemoteException e) { 723 loge("Cannot invoke requestDataCallList on data service."); 724 if (callback != null) { 725 mMessageMap.remove(callback.asBinder()); 726 } 727 sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); 728 } 729 } 730 731 /** 732 * Register for data call list changed event. 733 * 734 * @param h The target to post the event message to. 735 * @param what The event. 736 */ registerForDataCallListChanged(Handler h, int what)737 public void registerForDataCallListChanged(Handler h, int what) { 738 if (h != null) { 739 mDataCallListChangedRegistrants.addUnique(h, what, null); 740 } 741 } 742 743 /** 744 * Unregister for data call list changed event. 745 * 746 * @param h The handler 747 */ unregisterForDataCallListChanged(Handler h)748 public void unregisterForDataCallListChanged(Handler h) { 749 if (h != null) { 750 mDataCallListChangedRegistrants.remove(h); 751 } 752 } 753 754 /** 755 * Register for data service binding status changed event. 756 * 757 * @param h The target to post the event message to. 758 * @param what The event. 759 * @param obj The user object. 760 */ registerForServiceBindingChanged(Handler h, int what, Object obj)761 public void registerForServiceBindingChanged(Handler h, int what, Object obj) { 762 if (h != null) { 763 mServiceBindingChangedRegistrants.addUnique(h, what, obj); 764 } 765 766 } 767 768 /** 769 * Unregister for data service binding status changed event. 770 * 771 * @param h The handler 772 */ unregisterForServiceBindingChanged(Handler h)773 public void unregisterForServiceBindingChanged(Handler h) { 774 if (h != null) { 775 mServiceBindingChangedRegistrants.remove(h); 776 } 777 } 778 779 /** 780 * Get the transport type. Must be a {@link TransportType}. 781 * 782 * @return 783 */ getTransportType()784 public int getTransportType() { 785 return mTransportType; 786 } 787 log(String s)788 private void log(String s) { 789 Rlog.d(mTag, s); 790 } 791 loge(String s)792 private void loge(String s) { 793 Rlog.e(mTag, s); 794 } 795 } 796