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