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