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