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("NetworkService(" + mComponentName +  " transport type "
186                     + 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                 mDeathRecipient.binderDied();
206                 logd("RemoteException " + exception);
207             }
208         }
209 
210         @Override
onServiceDisconnected(ComponentName name)211         public void onServiceDisconnected(ComponentName name) {
212             logd("service " + name + " for transport "
213                     + AccessNetworkConstants.transportTypeToString(mTransportType)
214                     + " is now disconnected.");
215             mTargetBindingPackageName = null;
216         }
217     }
218 
219     private class NetworkRegStateCallback extends INetworkServiceCallback.Stub {
220         @Override
onRequestNetworkRegistrationInfoComplete( int result, NetworkRegistrationInfo info)221         public void onRequestNetworkRegistrationInfoComplete(
222                 int result, NetworkRegistrationInfo info) {
223             logd("onRequestNetworkRegistrationInfoComplete result: "
224                     + result + ", info: " + info);
225             Message onCompleteMessage = mCallbackTable.remove(this);
226             if (onCompleteMessage != null) {
227                 onCompleteMessage.arg1 = result;
228                 onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj,
229                         new NetworkRegistrationInfo(info), null);
230                 onCompleteMessage.sendToTarget();
231             } else {
232                 loge("onCompleteMessage is null");
233             }
234         }
235 
236         @Override
onNetworkStateChanged()237         public void onNetworkStateChanged() {
238             logd("onNetworkStateChanged");
239             mRegStateChangeRegistrants.notifyRegistrants();
240         }
241     }
242 
unbindService()243     private void unbindService() {
244         if (mINetworkService != null && mINetworkService.asBinder().isBinderAlive()) {
245             logd("unbinding service");
246             // Remove the network availability updater and then unbind the service.
247             try {
248                 mINetworkService.removeNetworkServiceProvider(mPhone.getPhoneId());
249             } catch (RemoteException e) {
250                 loge("Cannot remove data service provider. " + e);
251             }
252         }
253 
254         if (mServiceConnection != null) {
255             mPhone.getContext().unbindService(mServiceConnection);
256         }
257         mINetworkService = null;
258         mServiceConnection = null;
259         mTargetBindingPackageName = null;
260     }
261 
bindService(String packageName)262     private void bindService(String packageName) {
263         if (mPhone == null || !SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())) {
264             loge("can't bindService with invalid phone or phoneId.");
265             return;
266         }
267 
268         if (TextUtils.isEmpty(packageName)) {
269             loge("Can't find the binding package");
270             return;
271         }
272 
273         Intent intent = null;
274         String className = getClassName();
275         if (TextUtils.isEmpty(className)) {
276             intent = new Intent(NetworkService.SERVICE_INTERFACE);
277             intent.setPackage(packageName);
278         } else {
279             ComponentName cm = new ComponentName(packageName, className);
280             intent = new Intent(NetworkService.SERVICE_INTERFACE).setComponent(cm);
281         }
282 
283         try {
284             // We bind this as a foreground service because it is operating directly on the SIM,
285             // and we do not want it subjected to power-savings restrictions while doing so.
286             logd("Trying to bind " + getPackageName() + " for transport "
287                     + AccessNetworkConstants.transportTypeToString(mTransportType));
288             mServiceConnection = new NetworkServiceConnection();
289             if (!mPhone.getContext().bindService(intent, mServiceConnection,
290                     Context.BIND_AUTO_CREATE)) {
291                 loge("Cannot bind to the data service.");
292                 return;
293             }
294             mTargetBindingPackageName = packageName;
295         } catch (SecurityException e) {
296             loge("bindService failed " + e);
297         }
298     }
299 
rebindService()300     private void rebindService() {
301         String packageName = getPackageName();
302         // Do nothing if no need to rebind.
303         if (SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())
304                 && TextUtils.equals(packageName, mTargetBindingPackageName)) {
305             logd("Service " + packageName + " already bound or being bound.");
306             return;
307         }
308 
309         unbindService();
310         bindService(packageName);
311     }
312 
getPackageName()313     private String getPackageName() {
314         String packageName;
315         int resourceId;
316         String carrierConfig;
317 
318         switch (mTransportType) {
319             case AccessNetworkConstants.TRANSPORT_TYPE_WWAN:
320                 resourceId = com.android.internal.R.string.config_wwan_network_service_package;
321                 carrierConfig = CarrierConfigManager
322                         .KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING;
323                 break;
324             case AccessNetworkConstants.TRANSPORT_TYPE_WLAN:
325                 resourceId = com.android.internal.R.string.config_wlan_network_service_package;
326                 carrierConfig = CarrierConfigManager
327                         .KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING;
328                 break;
329             default:
330                 throw new IllegalStateException("Transport type not WWAN or WLAN. type="
331                         + mTransportType);
332         }
333 
334         // Read package name from resource overlay
335         packageName = mPhone.getContext().getResources().getString(resourceId);
336 
337         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());
338 
339         if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) {
340             // If carrier config overrides it, use the one from carrier config
341             packageName = b.getString(carrierConfig, packageName);
342         }
343 
344         return packageName;
345     }
346 
getClassName()347     private String getClassName() {
348         String className;
349         int resourceId;
350         String carrierConfig;
351 
352         switch (mTransportType) {
353             case AccessNetworkConstants.TRANSPORT_TYPE_WWAN:
354                 resourceId = com.android.internal.R.string.config_wwan_network_service_class;
355                 carrierConfig = CarrierConfigManager
356                         .KEY_CARRIER_NETWORK_SERVICE_WWAN_CLASS_OVERRIDE_STRING;
357                 break;
358             case AccessNetworkConstants.TRANSPORT_TYPE_WLAN:
359                 resourceId = com.android.internal.R.string.config_wlan_network_service_class;
360                 carrierConfig = CarrierConfigManager
361                         .KEY_CARRIER_NETWORK_SERVICE_WLAN_CLASS_OVERRIDE_STRING;
362                 break;
363             default:
364                 throw new IllegalStateException("Transport type not WWAN or WLAN. type="
365                         + mTransportType);
366         }
367 
368         // Read class name from resource overlay
369         className = mPhone.getContext().getResources().getString(resourceId);
370 
371         PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());
372 
373         if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) {
374             // If carrier config overrides it, use the one from carrier config
375             className = b.getString(carrierConfig, className);
376         }
377 
378         return className;
379     }
logd(String msg)380     private void logd(String msg) {
381         Rlog.d(mTag, msg);
382     }
383 
loge(String msg)384     private void loge(String msg) {
385         Rlog.e(mTag, msg);
386     }
387 }
388