1 /* 2 * Copyright 2020 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.google.android.iwlan; 18 19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 21 22 import android.content.Context; 23 import android.content.Intent; 24 import android.net.ConnectivityManager; 25 import android.net.LinkProperties; 26 import android.net.Network; 27 import android.net.NetworkCapabilities; 28 import android.net.NetworkSpecifier; 29 import android.net.TelephonyNetworkSpecifier; 30 import android.net.TransportInfo; 31 import android.net.vcn.VcnTransportInfo; 32 import android.net.vcn.VcnUtils; 33 import android.os.Handler; 34 import android.os.HandlerExecutor; 35 import android.os.HandlerThread; 36 import android.os.IBinder; 37 import android.os.Looper; 38 import android.os.Message; 39 import android.support.annotation.NonNull; 40 import android.telephony.AccessNetworkConstants; 41 import android.telephony.NetworkRegistrationInfo; 42 import android.telephony.NetworkService; 43 import android.telephony.NetworkServiceCallback; 44 import android.telephony.SubscriptionManager; 45 import android.telephony.TelephonyManager; 46 import android.util.Log; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 50 import java.util.ArrayList; 51 import java.util.List; 52 import java.util.Map; 53 import java.util.Objects; 54 import java.util.concurrent.ConcurrentHashMap; 55 56 public class IwlanNetworkService extends NetworkService { 57 private static final String TAG = IwlanNetworkService.class.getSimpleName(); 58 private static Context mContext; 59 private IwlanNetworkMonitorCallback mNetworkMonitorCallback; 60 private IwlanOnSubscriptionsChangedListener mSubsChangeListener; 61 private Handler mIwlanNetworkServiceHandler; 62 private HandlerThread mIwlanNetworkServiceHandlerThread; 63 private static boolean sNetworkConnected; 64 private static final Map<Integer, IwlanNetworkServiceProvider> sIwlanNetworkServiceProviders = 65 new ConcurrentHashMap<>(); 66 private static final int INVALID_SUB_ID = -1; 67 68 // The current subscription with the active internet PDN. Need not be the default data sub. 69 // If internet is over WiFi, this value will be INVALID_SUB_ID. 70 private static int mConnectedDataSub = INVALID_SUB_ID; 71 72 private static final int EVENT_BASE = IwlanEventListener.NETWORK_SERVICE_INTERNAL_EVENT_BASE; 73 private static final int EVENT_NETWORK_REGISTRATION_INFO_REQUEST = EVENT_BASE; 74 private static final int EVENT_CREATE_NETWORK_SERVICE_PROVIDER = EVENT_BASE + 1; 75 private static final int EVENT_REMOVE_NETWORK_SERVICE_PROVIDER = EVENT_BASE + 2; 76 77 @VisibleForTesting 78 enum Transport { 79 UNSPECIFIED_NETWORK, 80 MOBILE, 81 WIFI 82 } 83 84 private static Transport sDefaultDataTransport = Transport.UNSPECIFIED_NETWORK; 85 86 // This callback runs in the same thread as IwlanNetworkServiceHandler 87 static final class IwlanNetworkMonitorCallback extends ConnectivityManager.NetworkCallback { 88 /** Called when the framework connects and has declared a new network ready for use. */ 89 @Override onAvailable(Network network)90 public void onAvailable(Network network) { 91 Log.d(TAG, "onAvailable: " + network); 92 } 93 94 /** 95 * Called when the network is about to be lost, typically because there are no outstanding 96 * requests left for it. This may be paired with a {@link 97 * ConnectivityManager.NetworkCallback#onAvailable} call with the new replacement network 98 * for graceful handover. This method is not guaranteed to be called before {@link 99 * ConnectivityManager.NetworkCallback#onLost} is called, for example in case a network is 100 * suddenly disconnected. 101 */ 102 @Override onLosing(Network network, int maxMsToLive)103 public void onLosing(Network network, int maxMsToLive) { 104 Log.d(TAG, "onLosing: maxMsToLive: " + maxMsToLive + " network: " + network); 105 } 106 107 /** 108 * Called when a network disconnects or otherwise no longer satisfies this request or 109 * callback. 110 */ 111 @Override onLost(Network network)112 public void onLost(Network network) { 113 Log.d(TAG, "onLost: " + network); 114 IwlanNetworkService.setConnectedDataSub(INVALID_SUB_ID); 115 IwlanNetworkService.setNetworkConnected(false, Transport.UNSPECIFIED_NETWORK); 116 } 117 118 /** Called when the network corresponding to this request changes {@link LinkProperties}. */ 119 @Override onLinkPropertiesChanged(Network network, LinkProperties linkProperties)120 public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { 121 Log.d(TAG, "onLinkPropertiesChanged: " + linkProperties); 122 } 123 124 /** Called when access to the specified network is blocked or unblocked. */ 125 @Override onBlockedStatusChanged(Network network, boolean blocked)126 public void onBlockedStatusChanged(Network network, boolean blocked) { 127 // TODO: check if we need to handle this 128 Log.d(TAG, "onBlockedStatusChanged: " + " BLOCKED:" + blocked); 129 } 130 131 @Override onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities)132 public void onCapabilitiesChanged( 133 Network network, NetworkCapabilities networkCapabilities) { 134 // onCapabilitiesChanged is guaranteed to be called immediately after onAvailable per 135 // API 136 Log.d(TAG, "onCapabilitiesChanged: " + network); 137 if (networkCapabilities != null) { 138 if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { 139 IwlanNetworkService.setConnectedDataSub( 140 getConnectedDataSub( 141 mContext.getSystemService(ConnectivityManager.class), 142 networkCapabilities)); 143 IwlanNetworkService.setNetworkConnected( 144 true, IwlanNetworkService.Transport.MOBILE); 145 } else if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) { 146 IwlanNetworkService.setConnectedDataSub(INVALID_SUB_ID); 147 IwlanNetworkService.setNetworkConnected( 148 true, IwlanNetworkService.Transport.WIFI); 149 } else { 150 Log.w(TAG, "Network does not have cellular or wifi capability"); 151 } 152 } 153 } 154 } 155 156 static final class IwlanOnSubscriptionsChangedListener 157 extends SubscriptionManager.OnSubscriptionsChangedListener { 158 /** 159 * Callback invoked when there is any change to any SubscriptionInfo. Typically, this method 160 * invokes {@link SubscriptionManager#getActiveSubscriptionInfoList} 161 */ 162 @Override onSubscriptionsChanged()163 public void onSubscriptionsChanged() { 164 for (IwlanNetworkServiceProvider np : sIwlanNetworkServiceProviders.values()) { 165 np.subscriptionChanged(); 166 } 167 } 168 } 169 170 @VisibleForTesting 171 class IwlanNetworkServiceProvider extends NetworkServiceProvider { 172 private final IwlanNetworkService mIwlanNetworkService; 173 private final String SUB_TAG; 174 private boolean mIsSubActive = false; 175 176 /** 177 * Constructor 178 * 179 * @param slotIndex SIM slot id the data service provider associated with. 180 */ IwlanNetworkServiceProvider(int slotIndex, IwlanNetworkService iwlanNetworkService)181 public IwlanNetworkServiceProvider(int slotIndex, IwlanNetworkService iwlanNetworkService) { 182 super(slotIndex); 183 SUB_TAG = TAG + "[" + slotIndex + "]"; 184 mIwlanNetworkService = iwlanNetworkService; 185 186 // Register IwlanEventListener 187 List<Integer> events = new ArrayList<Integer>(); 188 events.add(IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT); 189 events.add(IwlanEventListener.CROSS_SIM_CALLING_DISABLE_EVENT); 190 IwlanEventListener.getInstance(mContext, slotIndex) 191 .addEventListener(events, getIwlanNetworkServiceHandler()); 192 } 193 194 @Override requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback)195 public void requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback) { 196 getIwlanNetworkServiceHandler() 197 .obtainMessage( 198 EVENT_NETWORK_REGISTRATION_INFO_REQUEST, 199 new NetworkRegistrationInfoRequestData(domain, callback, this)) 200 .sendToTarget(); 201 } 202 203 /** 204 * Called when the instance of network service is destroyed (e.g. got unbind or binder died) 205 * or when the network service provider is removed. The extended class should implement this 206 * method to perform cleanup works. 207 */ 208 @Override close()209 public void close() { 210 mIwlanNetworkService.removeNetworkServiceProvider(this); 211 IwlanEventListener.getInstance(mContext, getSlotIndex()) 212 .removeEventListener(getIwlanNetworkServiceHandler()); 213 } 214 215 @VisibleForTesting subscriptionChanged()216 void subscriptionChanged() { 217 boolean subActive = 218 getSubscriptionManager() 219 .getActiveSubscriptionInfoForSimSlotIndex(getSlotIndex()) 220 != null; 221 if (subActive == mIsSubActive) { 222 return; 223 } 224 mIsSubActive = subActive; 225 if (subActive) { 226 Log.d(SUB_TAG, "sub changed from not_ready --> ready"); 227 } else { 228 Log.d(SUB_TAG, "sub changed from ready --> not_ready"); 229 } 230 231 notifyNetworkRegistrationInfoChanged(); 232 } 233 } 234 235 private final class IwlanNetworkServiceHandler extends Handler { 236 private final String TAG = IwlanNetworkServiceHandler.class.getSimpleName(); 237 238 @Override handleMessage(Message msg)239 public void handleMessage(Message msg) { 240 Log.d(TAG, "msg.what = " + eventToString(msg.what)); 241 242 IwlanNetworkServiceProvider iwlanNetworkServiceProvider; 243 int slotId; 244 245 switch (msg.what) { 246 case IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT: 247 case IwlanEventListener.CROSS_SIM_CALLING_DISABLE_EVENT: 248 iwlanNetworkServiceProvider = getNetworkServiceProvider(msg.arg1); 249 iwlanNetworkServiceProvider.notifyNetworkRegistrationInfoChanged(); 250 break; 251 252 case EVENT_NETWORK_REGISTRATION_INFO_REQUEST: 253 NetworkRegistrationInfoRequestData networkRegistrationInfoRequestData = 254 (NetworkRegistrationInfoRequestData) msg.obj; 255 int domain = networkRegistrationInfoRequestData.mDomain; 256 NetworkServiceCallback callback = networkRegistrationInfoRequestData.mCallback; 257 iwlanNetworkServiceProvider = 258 networkRegistrationInfoRequestData.mIwlanNetworkServiceProvider; 259 260 if (callback == null) { 261 Log.d(TAG, "Error: callback is null. returning"); 262 return; 263 } 264 if (domain != NetworkRegistrationInfo.DOMAIN_PS) { 265 callback.onRequestNetworkRegistrationInfoComplete( 266 NetworkServiceCallback.RESULT_ERROR_UNSUPPORTED, null); 267 return; 268 } 269 270 NetworkRegistrationInfo.Builder nriBuilder = 271 new NetworkRegistrationInfo.Builder(); 272 nriBuilder 273 .setAvailableServices( 274 List.of(NetworkRegistrationInfo.SERVICE_TYPE_DATA)) 275 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) 276 .setEmergencyOnly(!iwlanNetworkServiceProvider.mIsSubActive) 277 .setDomain(NetworkRegistrationInfo.DOMAIN_PS); 278 279 slotId = iwlanNetworkServiceProvider.getSlotIndex(); 280 if (!IwlanNetworkService.isNetworkConnected( 281 isActiveDataOnOtherSub(slotId), 282 IwlanHelper.isCrossSimCallingEnabled(mContext, slotId))) { 283 nriBuilder 284 .setRegistrationState( 285 NetworkRegistrationInfo 286 .REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) 287 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN); 288 Log.d( 289 TAG + "[" + slotId + "]", 290 ": reg state" + " REGISTRATION_STATE_NOT_REGISTERED_SEARCHING"); 291 } else { 292 nriBuilder 293 .setRegistrationState( 294 NetworkRegistrationInfo.REGISTRATION_STATE_HOME) 295 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN); 296 Log.d(TAG + "[" + slotId + "]", ": reg state REGISTRATION_STATE_HOME"); 297 } 298 299 callback.onRequestNetworkRegistrationInfoComplete( 300 NetworkServiceCallback.RESULT_SUCCESS, nriBuilder.build()); 301 break; 302 303 case EVENT_CREATE_NETWORK_SERVICE_PROVIDER: 304 iwlanNetworkServiceProvider = (IwlanNetworkServiceProvider) msg.obj; 305 306 if (sIwlanNetworkServiceProviders.isEmpty()) { 307 initCallback(); 308 } 309 310 addIwlanNetworkServiceProvider(iwlanNetworkServiceProvider); 311 break; 312 313 case EVENT_REMOVE_NETWORK_SERVICE_PROVIDER: 314 iwlanNetworkServiceProvider = (IwlanNetworkServiceProvider) msg.obj; 315 slotId = iwlanNetworkServiceProvider.getSlotIndex(); 316 IwlanNetworkServiceProvider nsp = sIwlanNetworkServiceProviders.remove(slotId); 317 if (nsp == null) { 318 Log.w( 319 TAG + "[" + slotId + "]", 320 "No NetworkServiceProvider exists for slot!"); 321 return; 322 } 323 if (sIwlanNetworkServiceProviders.isEmpty()) { 324 deinitCallback(); 325 } 326 break; 327 328 default: 329 throw new IllegalStateException("Unexpected value: " + msg.what); 330 } 331 } 332 IwlanNetworkServiceHandler(Looper looper)333 IwlanNetworkServiceHandler(Looper looper) { 334 super(looper); 335 } 336 } 337 338 private static final class NetworkRegistrationInfoRequestData { 339 final int mDomain; 340 final NetworkServiceCallback mCallback; 341 final IwlanNetworkServiceProvider mIwlanNetworkServiceProvider; 342 NetworkRegistrationInfoRequestData( int domain, NetworkServiceCallback callback, IwlanNetworkServiceProvider nsp)343 private NetworkRegistrationInfoRequestData( 344 int domain, NetworkServiceCallback callback, IwlanNetworkServiceProvider nsp) { 345 mDomain = domain; 346 mCallback = callback; 347 mIwlanNetworkServiceProvider = nsp; 348 } 349 } 350 351 /** 352 * Create the instance of {@link NetworkServiceProvider}. Network service provider must override 353 * this method to facilitate the creation of {@link NetworkServiceProvider} instances. The 354 * system will call this method after binding the network service for each active SIM slot id. 355 * 356 * @param slotIndex SIM slot id the network service associated with. 357 * @return Network service object. Null if failed to create the provider (e.g. invalid slot 358 * index) 359 */ 360 @Override onCreateNetworkServiceProvider(int slotIndex)361 public NetworkServiceProvider onCreateNetworkServiceProvider(int slotIndex) { 362 Log.d(TAG, "onCreateNetworkServiceProvider: slotidx:" + slotIndex); 363 364 // TODO: validity check slot index 365 366 IwlanNetworkServiceProvider np = new IwlanNetworkServiceProvider(slotIndex, this); 367 getIwlanNetworkServiceHandler() 368 .obtainMessage(EVENT_CREATE_NETWORK_SERVICE_PROVIDER, np) 369 .sendToTarget(); 370 return np; 371 } 372 setConnectedDataSub(int subId)373 static void setConnectedDataSub(int subId) { 374 mConnectedDataSub = subId; 375 } 376 getConnectedDataSub( ConnectivityManager connectivityManager, NetworkCapabilities networkCapabilities)377 static int getConnectedDataSub( 378 ConnectivityManager connectivityManager, NetworkCapabilities networkCapabilities) { 379 int connectedDataSub = INVALID_SUB_ID; 380 NetworkSpecifier specifier = networkCapabilities.getNetworkSpecifier(); 381 TransportInfo transportInfo = networkCapabilities.getTransportInfo(); 382 383 if (specifier instanceof TelephonyNetworkSpecifier telephonyNetworkSpecifier) { 384 connectedDataSub = telephonyNetworkSpecifier.getSubscriptionId(); 385 } else if (transportInfo instanceof VcnTransportInfo vcnTransportInfo) { 386 connectedDataSub = 387 VcnUtils.getSubIdFromVcnCaps(connectivityManager, networkCapabilities); 388 } 389 return connectedDataSub; 390 } 391 isActiveDataOnOtherSub(int slotId)392 static boolean isActiveDataOnOtherSub(int slotId) { 393 int subId = IwlanHelper.getSubId(mContext, slotId); 394 return mConnectedDataSub != INVALID_SUB_ID && subId != mConnectedDataSub; 395 } 396 isNetworkConnected(boolean isActiveDataOnOtherSub, boolean isCstEnabled)397 public static boolean isNetworkConnected(boolean isActiveDataOnOtherSub, boolean isCstEnabled) { 398 if (isActiveDataOnOtherSub && isCstEnabled) { 399 // For cross-SIM IWLAN (Transport.MOBILE), an active data PDN must be maintained on the 400 // other subscription. 401 if (sNetworkConnected && (sDefaultDataTransport != Transport.MOBILE)) { 402 Log.e(TAG, "Internet is on other slot, but default transport is not MOBILE!"); 403 } 404 return sNetworkConnected; 405 } else { 406 // For all other cases, only wifi transport can be used. 407 return ((sDefaultDataTransport == Transport.WIFI) && sNetworkConnected); 408 } 409 } 410 setNetworkConnected(boolean connected, Transport transport)411 public static void setNetworkConnected(boolean connected, Transport transport) { 412 if (connected == sNetworkConnected && transport == sDefaultDataTransport) { 413 return; 414 } 415 if (connected && (transport == IwlanNetworkService.Transport.UNSPECIFIED_NETWORK)) { 416 return; 417 } 418 sNetworkConnected = connected; 419 sDefaultDataTransport = transport; 420 421 for (IwlanNetworkServiceProvider np : sIwlanNetworkServiceProviders.values()) { 422 np.notifyNetworkRegistrationInfoChanged(); 423 } 424 } 425 addIwlanNetworkServiceProvider(IwlanNetworkServiceProvider np)426 void addIwlanNetworkServiceProvider(IwlanNetworkServiceProvider np) { 427 int slotIndex = np.getSlotIndex(); 428 if (sIwlanNetworkServiceProviders.containsKey(slotIndex)) { 429 throw new IllegalStateException( 430 "NetworkServiceProvider already exists for slot " + slotIndex); 431 } 432 sIwlanNetworkServiceProviders.put(slotIndex, np); 433 } 434 removeNetworkServiceProvider(IwlanNetworkServiceProvider np)435 public void removeNetworkServiceProvider(IwlanNetworkServiceProvider np) { 436 getIwlanNetworkServiceHandler() 437 .obtainMessage(EVENT_REMOVE_NETWORK_SERVICE_PROVIDER, np) 438 .sendToTarget(); 439 } 440 initCallback()441 void initCallback() { 442 // register for default network callback 443 mNetworkMonitorCallback = new IwlanNetworkMonitorCallback(); 444 getConnectivityManager() 445 .registerSystemDefaultNetworkCallback( 446 mNetworkMonitorCallback, getIwlanNetworkServiceHandler()); 447 Log.d(TAG, "Registered with Connectivity Service"); 448 449 /* register with subscription manager */ 450 mSubsChangeListener = new IwlanOnSubscriptionsChangedListener(); 451 getSubscriptionManager() 452 .addOnSubscriptionsChangedListener( 453 new HandlerExecutor(getIwlanNetworkServiceHandler()), mSubsChangeListener); 454 Log.d(TAG, "Registered with Subscription Service"); 455 } 456 deinitCallback()457 void deinitCallback() { 458 // deinit network related stuff 459 getConnectivityManager().unregisterNetworkCallback(mNetworkMonitorCallback); 460 mNetworkMonitorCallback = null; 461 462 // deinit subscription manager related stuff 463 getSubscriptionManager().removeOnSubscriptionsChangedListener(mSubsChangeListener); 464 mSubsChangeListener = null; 465 if (mIwlanNetworkServiceHandlerThread != null) { 466 mIwlanNetworkServiceHandlerThread.quit(); 467 mIwlanNetworkServiceHandlerThread = null; 468 } 469 mIwlanNetworkServiceHandler = null; 470 } 471 472 @VisibleForTesting setAppContext(Context appContext)473 void setAppContext(Context appContext) { 474 mContext = appContext; 475 } 476 477 @VisibleForTesting getNetworkServiceProvider(int slotIndex)478 IwlanNetworkServiceProvider getNetworkServiceProvider(int slotIndex) { 479 return sIwlanNetworkServiceProviders.get(slotIndex); 480 } 481 482 @VisibleForTesting getNetworkMonitorCallback()483 IwlanNetworkMonitorCallback getNetworkMonitorCallback() { 484 return mNetworkMonitorCallback; 485 } 486 487 @VisibleForTesting 488 @NonNull getIwlanNetworkServiceHandler()489 Handler getIwlanNetworkServiceHandler() { 490 if (mIwlanNetworkServiceHandler == null) { 491 mIwlanNetworkServiceHandler = new IwlanNetworkServiceHandler(getLooper()); 492 } 493 return mIwlanNetworkServiceHandler; 494 } 495 496 @VisibleForTesting getLooper()497 Looper getLooper() { 498 mIwlanNetworkServiceHandlerThread = new HandlerThread("IwlanNetworkServiceThread"); 499 mIwlanNetworkServiceHandlerThread.start(); 500 return mIwlanNetworkServiceHandlerThread.getLooper(); 501 } 502 eventToString(int event)503 private static String eventToString(int event) { 504 return switch (event) { 505 case IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT -> 506 "CROSS_SIM_CALLING_ENABLE_EVENT"; 507 case IwlanEventListener.CROSS_SIM_CALLING_DISABLE_EVENT -> 508 "CROSS_SIM_CALLING_DISABLE_EVENT"; 509 case EVENT_NETWORK_REGISTRATION_INFO_REQUEST -> 510 "EVENT_NETWORK_REGISTRATION_INFO_REQUEST"; 511 case EVENT_CREATE_NETWORK_SERVICE_PROVIDER -> "EVENT_CREATE_NETWORK_SERVICE_PROVIDER"; 512 case EVENT_REMOVE_NETWORK_SERVICE_PROVIDER -> "EVENT_REMOVE_NETWORK_SERVICE_PROVIDER"; 513 default -> "Unknown(" + event + ")"; 514 }; 515 } 516 517 @Override onCreate()518 public void onCreate() { 519 mContext = getApplicationContext(); 520 } 521 522 @Override onBind(Intent intent)523 public IBinder onBind(Intent intent) { 524 Log.d(TAG, "IwlanNetworkService onBind"); 525 return super.onBind(intent); 526 } 527 528 @NonNull getConnectivityManager()529 ConnectivityManager getConnectivityManager() { 530 return Objects.requireNonNull(mContext.getSystemService(ConnectivityManager.class)); 531 } 532 533 @NonNull getSubscriptionManager()534 SubscriptionManager getSubscriptionManager() { 535 return Objects.requireNonNull(mContext.getSystemService(SubscriptionManager.class)); 536 } 537 } 538