• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.Handler;
29 import android.os.HandlerThread;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.telephony.AccessNetworkConstants;
34 import android.telephony.NetworkRegistrationInfo;
35 import android.telephony.NetworkService;
36 import android.telephony.NetworkServiceCallback;
37 import android.telephony.SubscriptionManager;
38 import android.telephony.TelephonyManager;
39 import android.util.Log;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.List;
46 
47 public class IwlanNetworkService extends NetworkService {
48     private static final String TAG = IwlanNetworkService.class.getSimpleName();
49     private Context mContext;
50     private IwlanNetworkMonitorCallback mNetworkMonitorCallback;
51     private IwlanOnSubscriptionsChangedListener mSubsChangeListener;
52     private HandlerThread mNetworkCallbackHandlerThread;
53     private static boolean sNetworkConnected;
54     private static List<IwlanNetworkServiceProvider> sIwlanNetworkServiceProviderList =
55             new ArrayList<IwlanNetworkServiceProvider>();
56 
57     @VisibleForTesting
58     enum Transport {
59         UNSPECIFIED_NETWORK,
60         MOBILE,
61         WIFI;
62     }
63 
64     private static Transport sDefaultDataTransport = Transport.UNSPECIFIED_NETWORK;
65 
66     final class IwlanNetworkMonitorCallback extends ConnectivityManager.NetworkCallback {
67         /** Called when the framework connects and has declared a new network ready for use. */
68         @Override
onAvailable(Network network)69         public void onAvailable(Network network) {
70             Log.d(TAG, "onAvailable: " + network);
71         }
72 
73         /**
74          * Called when the network is about to be lost, typically because there are no outstanding
75          * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call
76          * with the new replacement network for graceful handover. This method is not guaranteed to
77          * be called before {@link NetworkCallback#onLost} is called, for example in case a network
78          * is suddenly disconnected.
79          */
80         @Override
onLosing(Network network, int maxMsToLive)81         public void onLosing(Network network, int maxMsToLive) {
82             Log.d(TAG, "onLosing: maxMsToLive: " + maxMsToLive + " network: " + network);
83         }
84 
85         /**
86          * Called when a network disconnects or otherwise no longer satisfies this request or
87          * callback.
88          */
89         @Override
onLost(Network network)90         public void onLost(Network network) {
91             Log.d(TAG, "onLost: " + network);
92             IwlanNetworkService.setNetworkConnected(false, Transport.UNSPECIFIED_NETWORK);
93         }
94 
95         /** Called when the network corresponding to this request changes {@link LinkProperties}. */
96         @Override
onLinkPropertiesChanged(Network network, LinkProperties linkProperties)97         public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
98             Log.d(TAG, "onLinkPropertiesChanged: " + linkProperties);
99         }
100 
101         /** Called when access to the specified network is blocked or unblocked. */
102         @Override
onBlockedStatusChanged(Network network, boolean blocked)103         public void onBlockedStatusChanged(Network network, boolean blocked) {
104             // TODO: check if we need to handle this
105             Log.d(TAG, "onBlockedStatusChanged: " + " BLOCKED:" + blocked);
106         }
107 
108         @Override
onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities)109         public void onCapabilitiesChanged(
110                 Network network, NetworkCapabilities networkCapabilities) {
111             // onCapabilitiesChanged is guaranteed to be called immediately after onAvailable per
112             // API
113             Log.d(TAG, "onCapabilitiesChanged: " + network);
114             if (networkCapabilities != null) {
115                 if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
116                     IwlanNetworkService.setNetworkConnected(
117                             true, IwlanNetworkService.Transport.MOBILE);
118                 } else if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) {
119                     IwlanNetworkService.setNetworkConnected(
120                             true, IwlanNetworkService.Transport.WIFI);
121                 } else {
122                     Log.w(TAG, "Network does not have cellular or wifi capability");
123                 }
124             }
125         }
126     }
127 
128     final class IwlanOnSubscriptionsChangedListener
129             extends SubscriptionManager.OnSubscriptionsChangedListener {
130         /**
131          * Callback invoked when there is any change to any SubscriptionInfo. Typically this method
132          * invokes {@link SubscriptionManager#getActiveSubscriptionInfoList}
133          */
134         @Override
onSubscriptionsChanged()135         public void onSubscriptionsChanged() {
136             for (IwlanNetworkServiceProvider np : sIwlanNetworkServiceProviderList) {
137                 np.subscriptionChanged();
138             }
139         }
140     }
141 
142     @VisibleForTesting
143     class IwlanNetworkServiceProvider extends NetworkServiceProvider {
144         private final IwlanNetworkService mIwlanNetworkService;
145         private final String SUB_TAG;
146         private boolean mIsSubActive = false;
147         private HandlerThread mHandlerThread;
148         private Handler mHandler;
149 
150         private final class NSPHandler extends Handler {
151             private final String TAG =
152                     IwlanNetworkService.class.getSimpleName()
153                             + NSPHandler.class.getSimpleName()
154                             + "["
155                             + getSlotIndex()
156                             + "]";
157 
158             @Override
handleMessage(Message msg)159             public void handleMessage(Message msg) {
160                 Log.d(TAG, "msg.what = " + msg.what);
161                 switch (msg.what) {
162                     case IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT:
163                         Log.d(TAG, "CROSS_SIM_CALLING_ENABLE_EVENT");
164                         notifyNetworkRegistrationInfoChanged();
165                         break;
166                     case IwlanEventListener.CROSS_SIM_CALLING_DISABLE_EVENT:
167                         Log.d(TAG, "CROSS_SIM_CALLING_DISABLE_EVENT");
168                         notifyNetworkRegistrationInfoChanged();
169                         break;
170                     default:
171                         Log.d(TAG, "Unknown message received!");
172                         break;
173                 }
174             }
175 
NSPHandler(Looper looper)176             NSPHandler(Looper looper) {
177                 super(looper);
178             }
179         }
180 
getLooper()181         Looper getLooper() {
182             mHandlerThread = new HandlerThread("NSPHandlerThread");
183             mHandlerThread.start();
184             return mHandlerThread.getLooper();
185         }
186 
187         /**
188          * Constructor
189          *
190          * @param slotIndex SIM slot id the data service provider associated with.
191          */
IwlanNetworkServiceProvider(int slotIndex, IwlanNetworkService iwlanNetworkService)192         public IwlanNetworkServiceProvider(int slotIndex, IwlanNetworkService iwlanNetworkService) {
193             super(slotIndex);
194             SUB_TAG = TAG + "[" + slotIndex + "]";
195             mIwlanNetworkService = iwlanNetworkService;
196 
197             // Register IwlanEventListener
198             initHandler();
199             List<Integer> events = new ArrayList<Integer>();
200             events.add(IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT);
201             events.add(IwlanEventListener.CROSS_SIM_CALLING_DISABLE_EVENT);
202             IwlanEventListener.getInstance(mContext, slotIndex).addEventListener(events, mHandler);
203         }
204 
initHandler()205         void initHandler() {
206             mHandler = new NSPHandler(getLooper());
207         }
208 
209         @Override
requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback)210         public void requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback) {
211             if (callback == null) {
212                 Log.d(SUB_TAG, "Error: callback is null. returning");
213                 return;
214             }
215             if (domain != NetworkRegistrationInfo.DOMAIN_PS) {
216                 callback.onRequestNetworkRegistrationInfoComplete(
217                         NetworkServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
218                 return;
219             }
220 
221             NetworkRegistrationInfo.Builder nriBuilder = new NetworkRegistrationInfo.Builder();
222             nriBuilder
223                     .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
224                     .setAvailableServices(Arrays.asList(NetworkRegistrationInfo.SERVICE_TYPE_DATA))
225                     .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
226                     .setEmergencyOnly(!mIsSubActive)
227                     .setDomain(NetworkRegistrationInfo.DOMAIN_PS);
228 
229             if (!IwlanNetworkService.isNetworkConnected(
230                     IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()),
231                     IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex()))) {
232                 nriBuilder.setRegistrationState(
233                         NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING);
234                 Log.d(SUB_TAG, "reg state REGISTRATION_STATE_NOT_REGISTERED_SEARCHING");
235             } else {
236                 nriBuilder.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
237                 Log.d(SUB_TAG, "reg state REGISTRATION_STATE_HOME");
238             }
239 
240             callback.onRequestNetworkRegistrationInfoComplete(
241                     NetworkServiceCallback.RESULT_SUCCESS, nriBuilder.build());
242         }
243 
244         /**
245          * Called when the instance of network service is destroyed (e.g. got unbind or binder died)
246          * or when the network service provider is removed. The extended class should implement this
247          * method to perform cleanup works.
248          */
249         @Override
close()250         public void close() {
251             mIwlanNetworkService.removeNetworkServiceProvider(this);
252             IwlanEventListener.getInstance(mContext, getSlotIndex()).removeEventListener(mHandler);
253             mHandlerThread.quit();
254         }
255 
256         @VisibleForTesting
subscriptionChanged()257         void subscriptionChanged() {
258             boolean subActive = false;
259             SubscriptionManager sm = SubscriptionManager.from(mContext);
260             if (sm.getActiveSubscriptionInfoForSimSlotIndex(getSlotIndex()) != null) {
261                 subActive = true;
262             }
263             if (subActive == mIsSubActive) {
264                 return;
265             }
266             mIsSubActive = subActive;
267             if (subActive) {
268                 Log.d(SUB_TAG, "sub changed from not_ready --> ready");
269             } else {
270                 Log.d(SUB_TAG, "sub changed from ready --> not_ready");
271             }
272 
273             notifyNetworkRegistrationInfoChanged();
274         }
275     }
276 
277     /**
278      * Create the instance of {@link NetworkServiceProvider}. Network service provider must override
279      * this method to facilitate the creation of {@link NetworkServiceProvider} instances. The
280      * system will call this method after binding the network service for each active SIM slot id.
281      *
282      * @param slotIndex SIM slot id the network service associated with.
283      * @return Network service object. Null if failed to create the provider (e.g. invalid slot
284      *     index)
285      */
286     @Override
onCreateNetworkServiceProvider(int slotIndex)287     public NetworkServiceProvider onCreateNetworkServiceProvider(int slotIndex) {
288         Log.d(TAG, "onCreateNetworkServiceProvider: slotidx:" + slotIndex);
289 
290         // TODO: validity check slot index
291 
292         if (sIwlanNetworkServiceProviderList.isEmpty()) {
293             // first invocation
294             mNetworkCallbackHandlerThread =
295                     new HandlerThread(IwlanNetworkService.class.getSimpleName());
296             mNetworkCallbackHandlerThread.start();
297             Looper looper = mNetworkCallbackHandlerThread.getLooper();
298             Handler handler = new Handler(looper);
299 
300             // register for default network callback
301             ConnectivityManager connectivityManager =
302                     mContext.getSystemService(ConnectivityManager.class);
303             mNetworkMonitorCallback = new IwlanNetworkMonitorCallback();
304             connectivityManager.registerDefaultNetworkCallback(mNetworkMonitorCallback, handler);
305             Log.d(TAG, "Registered with Connectivity Service");
306 
307             /* register with subscription manager */
308             SubscriptionManager subscriptionManager =
309                     mContext.getSystemService(SubscriptionManager.class);
310             mSubsChangeListener = new IwlanOnSubscriptionsChangedListener();
311             subscriptionManager.addOnSubscriptionsChangedListener(mSubsChangeListener);
312             Log.d(TAG, "Registered with Subscription Service");
313         }
314 
315         IwlanNetworkServiceProvider np = new IwlanNetworkServiceProvider(slotIndex, this);
316         sIwlanNetworkServiceProviderList.add(np);
317         return np;
318     }
319 
isNetworkConnected(boolean isDds, boolean isCstEnabled)320     public static boolean isNetworkConnected(boolean isDds, boolean isCstEnabled) {
321         if (!isDds && isCstEnabled) {
322             // Only Non-DDS sub with CST enabled, can use any transport.
323             return sNetworkConnected;
324         } else {
325             // For all other cases, only wifi transport can be used.
326             return ((sDefaultDataTransport == Transport.WIFI) && sNetworkConnected);
327         }
328     }
329 
setNetworkConnected(boolean connected, Transport transport)330     public static void setNetworkConnected(boolean connected, Transport transport) {
331         if (connected == sNetworkConnected && transport == sDefaultDataTransport) {
332             return;
333         }
334         if (connected && (transport == IwlanNetworkService.Transport.UNSPECIFIED_NETWORK)) {
335             return;
336         }
337         sNetworkConnected = connected;
338         sDefaultDataTransport = transport;
339 
340         for (IwlanNetworkServiceProvider np : sIwlanNetworkServiceProviderList) {
341             np.notifyNetworkRegistrationInfoChanged();
342         }
343     }
344 
removeNetworkServiceProvider(IwlanNetworkServiceProvider np)345     public void removeNetworkServiceProvider(IwlanNetworkServiceProvider np) {
346         sIwlanNetworkServiceProviderList.remove(np);
347         if (sIwlanNetworkServiceProviderList.isEmpty()) {
348             // deinit network related stuff
349             ConnectivityManager connectivityManager =
350                     mContext.getSystemService(ConnectivityManager.class);
351             connectivityManager.unregisterNetworkCallback(mNetworkMonitorCallback);
352             mNetworkCallbackHandlerThread.quit(); // no need to quitSafely
353             mNetworkCallbackHandlerThread = null;
354             mNetworkMonitorCallback = null;
355 
356             // deinit subscription manager related stuff
357             SubscriptionManager subscriptionManager =
358                     mContext.getSystemService(SubscriptionManager.class);
359             subscriptionManager.removeOnSubscriptionsChangedListener(mSubsChangeListener);
360             mSubsChangeListener = null;
361         }
362     }
363 
getContext()364     Context getContext() {
365         return getApplicationContext();
366     }
367 
368     @VisibleForTesting
setAppContext(Context appContext)369     void setAppContext(Context appContext) {
370         mContext = appContext;
371     }
372 
373     @VisibleForTesting
getNetworkServiceProvider(int slotIndex)374     IwlanNetworkServiceProvider getNetworkServiceProvider(int slotIndex) {
375         for (IwlanNetworkServiceProvider np : sIwlanNetworkServiceProviderList) {
376             if (np.getSlotIndex() == slotIndex) {
377                 return np;
378             }
379         }
380         return null;
381     }
382 
383     @Override
onCreate()384     public void onCreate() {
385         mContext = getApplicationContext();
386     }
387 
388     @Override
onBind(Intent intent)389     public IBinder onBind(Intent intent) {
390         Log.d(TAG, "IwlanNetworkService onBind");
391         return super.onBind(intent);
392     }
393 }
394