• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.ServiceConnection;
25 import android.content.pm.PackageManager;
26 import android.os.AsyncResult;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Message;
30 import android.os.PersistableBundle;
31 import android.os.RegistrantList;
32 import android.os.RemoteException;
33 import android.os.UserHandle;
34 import android.telephony.AccessNetworkConstants;
35 import android.telephony.AccessNetworkConstants.TransportType;
36 import android.telephony.CarrierConfigManager;
37 import android.telephony.INetworkService;
38 import android.telephony.INetworkServiceCallback;
39 import android.telephony.NetworkRegistrationInfo;
40 import android.telephony.NetworkService;
41 import android.telephony.SubscriptionManager;
42 import android.text.TextUtils;
43 
44 import com.android.telephony.Rlog;
45 
46 import java.util.Hashtable;
47 import java.util.Map;
48 
49 /**
50  * Class that serves as the layer between NetworkService and ServiceStateTracker. It helps binding,
51  * sending request and registering for state change to NetworkService.
52  */
53 public class NetworkRegistrationManager extends Handler {
54     private final String mTag;
55 
56     private static final int EVENT_BIND_NETWORK_SERVICE = 1;
57 
58     private final int mTransportType;
59 
60     private final Phone mPhone;
61 
62     private final CarrierConfigManager mCarrierConfigManager;
63 
64     // Registrants who listens registration state change callback from this class.
65     private final RegistrantList mRegStateChangeRegistrants = new RegistrantList();
66 
67     private INetworkService mINetworkService;
68 
69     private RegManagerDeathRecipient mDeathRecipient;
70 
71     private String mTargetBindingPackageName;
72 
73     private NetworkServiceConnection mServiceConnection;
74 
75     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
76         @Override
77         public void onReceive(Context context, Intent intent) {
78             final String action = intent.getAction();
79             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)
80                     && mPhone.getPhoneId() == intent.getIntExtra(
81                     CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) {
82                 // We should wait for carrier config changed event because the target binding
83                 // package name can come from the carrier config. Note that we still get this event
84                 // even when SIM is absent.
85                 logd("Carrier config changed. Try to bind network service.");
86                 sendEmptyMessage(EVENT_BIND_NETWORK_SERVICE);
87             }
88         }
89     };
90 
NetworkRegistrationManager(@ransportType int transportType, Phone phone)91     public NetworkRegistrationManager(@TransportType int transportType, Phone phone) {
92         mTransportType = transportType;
93         mPhone = phone;
94 
95         String tagSuffix = "-" + ((transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
96                 ? "C" : "I") + "-" + mPhone.getPhoneId();
97         mTag = "NRM" + tagSuffix;
98 
99         mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
100                 Context.CARRIER_CONFIG_SERVICE);
101 
102         IntentFilter intentFilter = new IntentFilter();
103         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
104         try {
105             Context contextAsUser = phone.getContext().createPackageContextAsUser(
106                 phone.getContext().getPackageName(), 0, UserHandle.ALL);
107             contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter,
108                 null /* broadcastPermission */, null);
109         } catch (PackageManager.NameNotFoundException e) {
110             loge("Package name not found: " + e.getMessage());
111         }
112         PhoneConfigurationManager.registerForMultiSimConfigChange(
113                 this, EVENT_BIND_NETWORK_SERVICE, null);
114 
115         sendEmptyMessage(EVENT_BIND_NETWORK_SERVICE);
116     }
117 
118     /**
119      * Handle message events
120      *
121      * @param msg The message to handle
122      */
123     @Override
handleMessage(Message msg)124     public void handleMessage(Message msg) {
125         switch (msg.what) {
126             case EVENT_BIND_NETWORK_SERVICE:
127                 rebindService();
128                 break;
129             default:
130                 loge("Unhandled event " + msg.what);
131         }
132     }
133 
isServiceConnected()134     public boolean isServiceConnected() {
135         return (mINetworkService != null) && (mINetworkService.asBinder().isBinderAlive());
136     }
137 
unregisterForNetworkRegistrationInfoChanged(Handler h)138     public void unregisterForNetworkRegistrationInfoChanged(Handler h) {
139         mRegStateChangeRegistrants.remove(h);
140     }
141 
registerForNetworkRegistrationInfoChanged(Handler h, int what, Object obj)142     public void registerForNetworkRegistrationInfoChanged(Handler h, int what, Object obj) {
143         logd("registerForNetworkRegistrationInfoChanged");
144         mRegStateChangeRegistrants.addUnique(h, what, obj);
145     }
146 
147     private final Map<NetworkRegStateCallback, Message> mCallbackTable = new Hashtable();
148 
requestNetworkRegistrationInfo(@etworkRegistrationInfo.Domain int domain, Message onCompleteMessage)149     public void requestNetworkRegistrationInfo(@NetworkRegistrationInfo.Domain int domain,
150                                                Message onCompleteMessage) {
151         if (onCompleteMessage == null) return;
152 
153         if (!isServiceConnected()) {
154             loge("service not connected. Domain = "
155                     + ((domain == NetworkRegistrationInfo.DOMAIN_CS) ? "CS" : "PS"));
156             onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj, null,
157                     new IllegalStateException("Service not connected."));
158             onCompleteMessage.sendToTarget();
159             return;
160         }
161 
162         NetworkRegStateCallback callback = new NetworkRegStateCallback();
163         try {
164             mCallbackTable.put(callback, onCompleteMessage);
165             mINetworkService.requestNetworkRegistrationInfo(mPhone.getPhoneId(), domain, callback);
166         } catch (RemoteException e) {
167             loge("requestNetworkRegistrationInfo RemoteException " + e);
168             mCallbackTable.remove(callback);
169             onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj, null, e);
170             onCompleteMessage.sendToTarget();
171         }
172     }
173 
174     private class RegManagerDeathRecipient implements IBinder.DeathRecipient {
175 
176         private final ComponentName mComponentName;
177 
RegManagerDeathRecipient(ComponentName name)178         RegManagerDeathRecipient(ComponentName name) {
179             mComponentName = name;
180         }
181 
182         @Override
binderDied()183         public void binderDied() {
184             // TODO: try to restart the service.
185             logd("Network service " + mComponentName + " for transport type "
186                     + AccessNetworkConstants.transportTypeToString(mTransportType) + " died.");
187         }
188     }
189 
190     private class NetworkServiceConnection implements ServiceConnection {
191         @Override
onServiceConnected(ComponentName name, IBinder service)192         public void onServiceConnected(ComponentName name, IBinder service) {
193             logd("service " + name + " for transport "
194                     + AccessNetworkConstants.transportTypeToString(mTransportType)
195                     + " is now connected.");
196             mINetworkService = INetworkService.Stub.asInterface(service);
197             mDeathRecipient = new RegManagerDeathRecipient(name);
198             try {
199                 service.linkToDeath(mDeathRecipient, 0);
200                 mINetworkService.createNetworkServiceProvider(mPhone.getPhoneId());
201                 mINetworkService.registerForNetworkRegistrationInfoChanged(mPhone.getPhoneId(),
202                         new NetworkRegStateCallback());
203             } catch (RemoteException exception) {
204                 // Remote exception means that the binder already died.
205                 logd("RemoteException " + exception);
206             }
207         }
208 
209         @Override
onServiceDisconnected(ComponentName name)210         public void onServiceDisconnected(ComponentName name) {
211             logd("service " + name + " for transport "
212                     + AccessNetworkConstants.transportTypeToString(mTransportType)
213                     + " is now disconnected.");
214             mTargetBindingPackageName = null;
215         }
216     }
217 
218     private class NetworkRegStateCallback extends INetworkServiceCallback.Stub {
219         @Override
onRequestNetworkRegistrationInfoComplete( int result, NetworkRegistrationInfo info)220         public void onRequestNetworkRegistrationInfoComplete(
221                 int result, NetworkRegistrationInfo info) {
222             logd("onRequestNetworkRegistrationInfoComplete result: "
223                     + result + ", info: " + info);
224             Message onCompleteMessage = mCallbackTable.remove(this);
225             if (onCompleteMessage != null) {
226                 onCompleteMessage.arg1 = result;
227                 onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj,
228                         new NetworkRegistrationInfo(info), null);
229                 onCompleteMessage.sendToTarget();
230             } else {
231                 loge("onCompleteMessage is null");
232             }
233         }
234 
235         @Override
onNetworkStateChanged()236         public void onNetworkStateChanged() {
237             logd("onNetworkStateChanged");
238             mRegStateChangeRegistrants.notifyRegistrants();
239         }
240     }
241 
unbindService()242     private void unbindService() {
243         if (mINetworkService != null && mINetworkService.asBinder().isBinderAlive()) {
244             logd("unbinding service");
245             // Remove the network availability updater and then unbind the service.
246             try {
247                 mINetworkService.removeNetworkServiceProvider(mPhone.getPhoneId());
248             } catch (RemoteException e) {
249                 loge("Cannot remove data service provider. " + e);
250             }
251         }
252 
253         if (mServiceConnection != null) {
254             mPhone.getContext().unbindService(mServiceConnection);
255         }
256         mINetworkService = null;
257         mServiceConnection = null;
258         mTargetBindingPackageName = null;
259     }
260 
bindService(String packageName)261     private void bindService(String packageName) {
262         if (mPhone == null || !SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())) {
263             loge("can't bindService with invalid phone or phoneId.");
264             return;
265         }
266 
267         if (TextUtils.isEmpty(packageName)) {
268             loge("Can't find the binding package");
269             return;
270         }
271 
272         Intent intent = null;
273         String className = getClassName();
274         if (TextUtils.isEmpty(className)) {
275             intent = new Intent(NetworkService.SERVICE_INTERFACE);
276             intent.setPackage(packageName);
277         } else {
278             ComponentName cm = new ComponentName(packageName, className);
279             intent = new Intent(NetworkService.SERVICE_INTERFACE).setComponent(cm);
280         }
281 
282         try {
283             // We bind this as a foreground service because it is operating directly on the SIM,
284             // and we do not want it subjected to power-savings restrictions while doing so.
285             logd("Trying to bind " + getPackageName() + " for transport "
286                     + AccessNetworkConstants.transportTypeToString(mTransportType));
287             mServiceConnection = new NetworkServiceConnection();
288             if (!mPhone.getContext().bindService(intent, mServiceConnection,
289                     Context.BIND_AUTO_CREATE)) {
290                 loge("Cannot bind to the data service.");
291                 return;
292             }
293             mTargetBindingPackageName = packageName;
294         } catch (SecurityException e) {
295             loge("bindService failed " + e);
296         }
297     }
298 
rebindService()299     private void rebindService() {
300         String packageName = getPackageName();
301         // Do nothing if no need to rebind.
302         if (SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())
303                 && TextUtils.equals(packageName, mTargetBindingPackageName)) {
304             logd("Service " + packageName + " already bound or being bound.");
305             return;
306         }
307 
308         unbindService();
309         bindService(packageName);
310     }
311 
getPackageName()312     private String getPackageName() {
313         String packageName;
314         int resourceId;
315         String carrierConfig;
316 
317         switch (mTransportType) {
318             case AccessNetworkConstants.TRANSPORT_TYPE_WWAN:
319                 resourceId = com.android.internal.R.string.config_wwan_network_service_package;
320                 carrierConfig = CarrierConfigManager
321                         .KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING;
322                 break;
323             case AccessNetworkConstants.TRANSPORT_TYPE_WLAN:
324                 resourceId = com.android.internal.R.string.config_wlan_network_service_package;
325                 carrierConfig = CarrierConfigManager
326                         .KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING;
327                 break;
328             default:
329                 throw new IllegalStateException("Transport type not WWAN or WLAN. type="
330                         + mTransportType);
331         }
332 
333         // Read package name from resource overlay
334         packageName = mPhone.getContext().getResources().getString(resourceId);
335 
336         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());
337 
338         if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) {
339             // If carrier config overrides it, use the one from carrier config
340             packageName = b.getString(carrierConfig, packageName);
341         }
342 
343         return packageName;
344     }
345 
getClassName()346     private String getClassName() {
347         String className;
348         int resourceId;
349         String carrierConfig;
350 
351         switch (mTransportType) {
352             case AccessNetworkConstants.TRANSPORT_TYPE_WWAN:
353                 resourceId = com.android.internal.R.string.config_wwan_network_service_class;
354                 carrierConfig = CarrierConfigManager
355                         .KEY_CARRIER_NETWORK_SERVICE_WWAN_CLASS_OVERRIDE_STRING;
356                 break;
357             case AccessNetworkConstants.TRANSPORT_TYPE_WLAN:
358                 resourceId = com.android.internal.R.string.config_wlan_network_service_class;
359                 carrierConfig = CarrierConfigManager
360                         .KEY_CARRIER_NETWORK_SERVICE_WLAN_CLASS_OVERRIDE_STRING;
361                 break;
362             default:
363                 throw new IllegalStateException("Transport type not WWAN or WLAN. type="
364                         + mTransportType);
365         }
366 
367         // Read class name from resource overlay
368         className = mPhone.getContext().getResources().getString(resourceId);
369 
370         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());
371 
372         if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) {
373             // If carrier config overrides it, use the one from carrier config
374             className = b.getString(carrierConfig, className);
375         }
376 
377         return className;
378     }
logd(String msg)379     private void logd(String msg) {
380         Rlog.d(mTag, msg);
381     }
382 
loge(String msg)383     private void loge(String msg) {
384         Rlog.e(mTag, msg);
385     }
386 }
387