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