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