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