• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.ons;
18 
19 import android.app.Service;
20 import android.compat.Compatibility;
21 import android.compat.annotation.ChangeId;
22 import android.compat.annotation.EnabledAfter;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.SharedPreferences;
28 import android.content.pm.PackageManager;
29 import android.os.Binder;
30 import android.os.Build;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.os.TelephonyServiceManager.ServiceRegisterer;
37 import android.telephony.AvailableNetworkInfo;
38 import android.telephony.CarrierConfigManager;
39 import android.telephony.SubscriptionInfo;
40 import android.telephony.SubscriptionManager;
41 import android.telephony.TelephonyFrameworkInitializer;
42 import android.telephony.TelephonyManager;
43 
44 import com.android.internal.annotations.VisibleForTesting;
45 import com.android.internal.telephony.IOns;
46 import com.android.internal.telephony.ISetOpportunisticDataCallback;
47 import com.android.internal.telephony.IUpdateAvailableNetworksCallback;
48 import com.android.internal.telephony.TelephonyIntents;
49 import com.android.internal.telephony.TelephonyPermissions;
50 import com.android.telephony.Rlog;
51 
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.List;
55 
56 /**
57  * OpportunisticNetworkService implements ions.
58  * It scans network and matches the results with opportunistic subscriptions.
59  * Use the same to provide user opportunistic data in areas with corresponding networks
60  */
61 public class OpportunisticNetworkService extends Service {
62     @VisibleForTesting protected Context mContext;
63     private TelephonyManager mTelephonyManager;
64     @VisibleForTesting protected SubscriptionManager mSubscriptionManager;
65     private ONSProfileActivator mONSProfileActivator;
66     private ONSStats mONSStats;
67     private Handler mHandler = null;
68 
69     private final Object mLock = new Object();
70     @VisibleForTesting protected boolean mIsEnabled;
71     @VisibleForTesting protected ONSProfileSelector mProfileSelector;
72     private SharedPreferences mSharedPref;
73     @VisibleForTesting protected HashMap<String, ONSConfigInput> mONSConfigInputHashMap;
74 
75     private static final String TAG = "ONS";
76     private static final String PREF_NAME = TAG;
77     private static final String PREF_ENABLED = "isEnabled";
78     private static final String CARRIER_APP_CONFIG_NAME = "carrierApp";
79     private static final String SYSTEM_APP_CONFIG_NAME = "systemApp";
80     private static final boolean DBG = true;
81     /* message to indicate sim state update */
82     private static final int MSG_SIM_STATE_CHANGE = 1;
83 
84     /**
85      * To expand the error codes for {@link TelephonyManager#updateAvailableNetworks} and
86      * {@link TelephonyManager#setPreferredOpportunisticDataSubscription}.
87      */
88     @ChangeId
89     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
90     static final long CALLBACK_ON_MORE_ERROR_CODE_CHANGE = 130595455L;
91 
92     /**
93      * Profile selection callback. Will be called once Profile selector decides on
94      * the opportunistic data profile.
95      */
96     private ONSProfileSelector.ONSProfileSelectionCallback  mProfileSelectionCallback =
97             new ONSProfileSelector.ONSProfileSelectionCallback() {
98 
99                 @Override
100                 public void onProfileSelectionDone() {
101                     logDebug("profile selection done");
102                 }
103             };
104 
105     /** Broadcast receiver to get SIM card state changed event */
106     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
107         @Override
108         public void onReceive(Context context, Intent intent) {
109             mHandler.sendEmptyMessage(MSG_SIM_STATE_CHANGE);
110         }
111     };
112 
createMsgHandler()113     private void createMsgHandler() {
114         mHandler = new Handler(Looper.myLooper()) {
115             @Override
116             public void handleMessage(Message msg) {
117                 switch (msg.what) {
118                     case MSG_SIM_STATE_CHANGE:
119                         synchronized (mLock) {
120                             handleSimStateChange();
121                         }
122                         break;
123                     default:
124                         log("invalid message");
125                         break;
126                 }
127             }
128         };
129     }
130 
startWorkerThreadAndInit()131     private void startWorkerThreadAndInit() {
132         Thread thread = new Thread() {
133             @Override
134             public void run() {
135                 super.run();
136                 Looper.prepare();
137                 Looper looper = Looper.myLooper();
138                 initialize(getBaseContext());
139                 synchronized (this) {
140                     this.notifyAll();
141                 }
142                 looper.loop();
143             }
144         };
145 
146         thread.start();
147         synchronized (thread) {
148             try {
149                 thread.wait();
150             } catch (Exception e) {
151                 log(e.getLocalizedMessage());
152             }
153         }
154     }
155 
enforceModifyPhoneStatePermission(Context context)156     private static boolean enforceModifyPhoneStatePermission(Context context) {
157         if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
158                 == PackageManager.PERMISSION_GRANTED) {
159             return true;
160         }
161 
162         return false;
163     }
164 
165     @VisibleForTesting
handleSimStateChange()166     protected void handleSimStateChange() {
167         logDebug("SIM state changed");
168 
169         ONSConfigInput carrierAppConfigInput = mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME);
170         if (carrierAppConfigInput == null) {
171             return;
172         }
173         List<SubscriptionInfo> subscriptionInfos =
174             mSubscriptionManager.getActiveSubscriptionInfoList(false);
175         if (subscriptionInfos == null) {
176           return;
177         }
178 
179         logDebug("handleSimStateChange: subscriptionInfos - " + subscriptionInfos);
180         for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
181             if (subscriptionInfo.getSubscriptionId() == carrierAppConfigInput.getPrimarySub()) {
182                 return;
183             }
184         }
185 
186         logDebug("Carrier subscription is not available, removing entry");
187         mONSConfigInputHashMap.put(CARRIER_APP_CONFIG_NAME, null);
188         if (!mIsEnabled) {
189             return;
190         }
191         if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null) {
192             mProfileSelector.startProfileSelection(
193                     mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME).getAvailableNetworkInfos(),
194                     mONSConfigInputHashMap.get(
195                             SYSTEM_APP_CONFIG_NAME).getAvailableNetworkCallback());
196         }
197     }
198 
hasOpportunisticSubPrivilege(String callingPackage, int subId)199     private boolean hasOpportunisticSubPrivilege(String callingPackage, int subId) {
200         return mTelephonyManager.hasCarrierPrivileges(subId)
201                 || mSubscriptionManager.canManageSubscription(
202                 mProfileSelector.getOpprotunisticSubInfo(subId), callingPackage);
203     }
204 
205     private final IOns.Stub mBinder = new IOns.Stub() {
206         /**
207          * Enable or disable Opportunistic Network service.
208          *
209          * This method should be called to enable or disable
210          * OpportunisticNetwork service on the device.
211          *
212          * <p>
213          * Requires Permission:
214          *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
215          * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
216          *
217          * @param enable enable(True) or disable(False)
218          * @param callingPackage caller's package name
219          * @return returns true if successfully set.
220          */
221         @Override
222         public boolean setEnable(boolean enable, String callingPackage) {
223             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
224                     mContext, mSubscriptionManager.getDefaultSubscriptionId(), "setEnable");
225             log("setEnable: " + enable);
226 
227             final long identity = Binder.clearCallingIdentity();
228             try {
229                 enableOpportunisticNetwork(enable);
230             } finally {
231                 Binder.restoreCallingIdentity(identity);
232             }
233 
234             return true;
235         }
236 
237         /**
238          * is Opportunistic Network service enabled
239          *
240          * This method should be called to determine if the Opportunistic Network service
241          * is enabled
242          *
243          * <p>
244          * Requires Permission:
245          *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
246          * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
247          *
248          * @param callingPackage caller's package name
249          */
250         @Override
251         public boolean isEnabled(String callingPackage) {
252             TelephonyPermissions
253                     .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
254                             mContext, mSubscriptionManager.getDefaultSubscriptionId(), "isEnabled");
255             return mIsEnabled;
256         }
257 
258         /**
259          * Set preferred opportunistic data.
260          *
261          * <p>Requires that the calling app has carrier privileges on both primary and
262          * secondary subscriptions (see
263          * {@link #hasCarrierPrivileges}), or has permission
264          * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
265          * @param subId which opportunistic subscription
266          * {@link SubscriptionManager#getOpportunisticSubscriptions} is preferred for cellular data.
267          * Pass {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} to unset the preference
268          * @param needValidation whether validation is needed before switch happens.
269          * @param callback callback upon request completion.
270          * @param callingPackage caller's package name
271          *
272          */
273         public void setPreferredDataSubscriptionId(int subId, boolean needValidation,
274                 ISetOpportunisticDataCallback callbackStub, String callingPackage) {
275             logDebug("setPreferredDataSubscriptionId subId:" + subId
276                     + " callingPackage:" + callingPackage);
277             if (!enforceModifyPhoneStatePermission(mContext)) {
278                 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
279                         mSubscriptionManager.getDefaultSubscriptionId(), "setPreferredDataSubscriptionId");
280                 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
281                     TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, subId,
282                             "setPreferredDataSubscriptionId");
283                 }
284             } else {
285                 if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) != null) {
286                     sendSetOpptCallbackHelper(callbackStub,
287                         TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED);
288                     return;
289                 }
290             }
291 
292 
293             final long identity = Binder.clearCallingIdentity();
294             try {
295                 mProfileSelector.selectProfileForData(subId, needValidation, callbackStub);
296             } finally {
297                 Binder.restoreCallingIdentity(identity);
298             }
299         }
300 
301         /**
302          * Get preferred default data sub Id
303          *
304          * <p>Requires that the calling app has carrier privileges
305          * (see {@link #hasCarrierPrivileges}),or has either
306          * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or.
307          * {@link android.Manifest.permission#READ_PHONE_STATE} permission.
308          * @return subId preferred opportunistic subscription id or
309          * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} if there are no preferred
310          * subscription id
311          *
312          */
313         @Override
314         public int getPreferredDataSubscriptionId(String callingPackage,
315                 String callingFeatureId) {
316             if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(
317                     mContext,
318                     Binder.getCallingPid(),
319                     Binder.getCallingUid(),
320                     callingPackage,
321                     callingFeatureId,
322                     "getPreferredDataSubscriptionId")) {
323                 throw new SecurityException(
324                         "getPreferredDataSubscriptionId requires READ_PHONE_STATE,"
325                         + " READ_PRIVILEGED_PHONE_STATE, or carrier privileges on"
326                         + " any active subscription.");
327             }
328 
329             final long identity = Binder.clearCallingIdentity();
330             try {
331                 return mProfileSelector.getPreferredDataSubscriptionId();
332             } finally {
333                 Binder.restoreCallingIdentity(identity);
334             }
335         }
336 
337         /**
338          * Update availability of a list of networks in the current location.
339          *
340          * This api should be called if the caller is aware of the availability of a network
341          * at the current location. This information will be used by OpportunisticNetwork service
342          * to decide to attach to the network. If an empty list is passed,
343          * it is assumed that no network is available.
344          *  @param availableNetworks is a list of available network information.
345          *  @param callback callback upon request completion.
346          *  @param callingPackage caller's package name
347          * <p>
348          * <p>Requires that the calling app has carrier privileges on both primary and
349          * secondary subscriptions (see
350          * {@link #hasCarrierPrivileges}), or has permission
351          * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
352          *
353          */
354         public void updateAvailableNetworks(List<AvailableNetworkInfo> availableNetworks,
355                 IUpdateAvailableNetworksCallback callbackStub, String callingPackage) {
356             logDebug("updateAvailableNetworks: " + availableNetworks);
357             /* check if system app */
358             if (enforceModifyPhoneStatePermission(mContext)) {
359                 handleSystemAppAvailableNetworks(
360                         (ArrayList<AvailableNetworkInfo>) availableNetworks, callbackStub);
361             } else {
362                 /* check if the app has primary carrier permission */
363                 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
364                         mSubscriptionManager.getDefaultSubscriptionId(), "updateAvailableNetworks");
365                 handleCarrierAppAvailableNetworks(
366                         (ArrayList<AvailableNetworkInfo>) availableNetworks, callbackStub,
367                         callingPackage);
368             }
369         }
370     };
371 
372     @Override
onBind(Intent intent)373     public IBinder onBind(Intent intent) {
374         return mBinder;
375     }
376 
377     @Override
onCreate()378     public void onCreate() {
379         startWorkerThreadAndInit();
380 
381         /* register the service */
382         ServiceRegisterer opportunisticNetworkServiceRegisterer = TelephonyFrameworkInitializer
383                 .getTelephonyServiceManager()
384                 .getOpportunisticNetworkServiceRegisterer();
385         if (opportunisticNetworkServiceRegisterer.get() == null) {
386             opportunisticNetworkServiceRegisterer.register(mBinder);
387         }
388     }
389 
390     @Override
onStartCommand(Intent intent, int flags, int startId)391     public int onStartCommand(Intent intent, int flags, int startId) {
392         mHandler.post(new Runnable() {
393 
394             private Intent mIntent = null;
395             Runnable setIntent(Intent intent) {
396                 mIntent = intent;
397                 return this;
398             }
399 
400             @Override
401             public void run() {
402                 if (mIntent == null) {
403                     return;
404                 }
405 
406                 String action = mIntent.getAction();
407                 if (action == null) {
408                     return;
409                 }
410 
411                 switch (action) {
412                     case ONSProfileSelector.ACTION_SUB_SWITCH: {
413                         if (mProfileSelector != null) {
414                             mProfileSelector.onSubSwitchComplete(mIntent);
415                         }
416                     }
417                     break;
418 
419                     case ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD: {
420                         mONSProfileActivator.getONSProfileDownloader().onCallbackIntentReceived(
421                                 mIntent.getParcelableExtra(Intent.EXTRA_INTENT),
422                                 mIntent.getIntExtra(ONSProfileResultReceiver.EXTRA_RESULT_CODE, 0)
423                         );
424                     }
425                     break;
426 
427                     case ONSProfileConfigurator.ACTION_ONS_ESIM_CONFIG: {
428                         mONSProfileActivator.getONSProfileConfigurator().onCallbackIntentReceived(
429                                 mIntent.getParcelableExtra(Intent.EXTRA_INTENT),
430                                 mIntent.getIntExtra(ONSProfileResultReceiver.EXTRA_RESULT_CODE, 0)
431                         );
432                     }
433                     break;
434 
435                     case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
436                         mONSProfileActivator.handleCarrierConfigChange();
437                         break;
438                 }
439             }
440         }.setIntent(intent));
441 
442         return START_STICKY;
443     }
444 
445     @Override
onDestroy()446     public void onDestroy() {
447         super.onDestroy();
448         log("Destroyed Successfully...");
449         mHandler.getLooper().quitSafely();
450     }
451 
452     /**
453      * initialize ONS and register as service.
454      * Read persistent state to update enable state
455      * Start sub components if already enabled.
456      * @param context context instance
457      */
458     @VisibleForTesting
initialize(Context context)459     protected void initialize(Context context) {
460         mContext = context;
461         createMsgHandler();
462         mTelephonyManager = TelephonyManager.from(mContext);
463         mProfileSelector = new ONSProfileSelector(mContext, mProfileSelectionCallback);
464         mSharedPref = mContext.createDeviceProtectedStorageContext().getSharedPreferences(
465                 PREF_NAME, Context.MODE_PRIVATE);
466         mSubscriptionManager = (SubscriptionManager) mContext.getSystemService(
467                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
468         mONSConfigInputHashMap = new HashMap<String, ONSConfigInput>();
469         mONSStats = new ONSStats(mContext, mSubscriptionManager);
470         mContext.registerReceiver(mBroadcastReceiver,
471             new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
472         enableOpportunisticNetwork(getPersistentEnableState());
473         mONSProfileActivator = new ONSProfileActivator(mContext, mONSStats);
474     }
475 
handleCarrierAppAvailableNetworks( ArrayList<AvailableNetworkInfo> availableNetworks, IUpdateAvailableNetworksCallback callbackStub, String callingPackage)476     private void handleCarrierAppAvailableNetworks(
477             ArrayList<AvailableNetworkInfo> availableNetworks,
478             IUpdateAvailableNetworksCallback callbackStub, String callingPackage) {
479         if ((availableNetworks != null) && (availableNetworks.size() > 0)) {
480             /* carrier apps should report only subscription */
481             if (availableNetworks.size() > 1) {
482                 log("Carrier app should not pass more than one subscription");
483                 if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
484                     sendUpdateNetworksCallbackHelper(callbackStub,
485                             TelephonyManager
486                                     .UPDATE_AVAILABLE_NETWORKS_MULTIPLE_NETWORKS_NOT_SUPPORTED);
487                 } else {
488                     sendUpdateNetworksCallbackHelper(callbackStub,
489                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
490                 }
491                 return;
492             }
493 
494             if (!mProfileSelector.hasOpprotunisticSub(availableNetworks)) {
495                 log("No opportunistic subscriptions received");
496                 if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
497                     sendUpdateNetworksCallbackHelper(callbackStub,
498                             TelephonyManager
499                                     .UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
500                 } else {
501                     sendUpdateNetworksCallbackHelper(callbackStub,
502                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
503                 }
504                 return;
505             }
506 
507             for (AvailableNetworkInfo availableNetworkInfo : availableNetworks) {
508                 final long identity = Binder.clearCallingIdentity();
509                 boolean isActiveSubId = false;
510                 try {
511                     isActiveSubId =
512                             mSubscriptionManager.isActiveSubId(availableNetworkInfo.getSubId());
513                 } finally {
514                     Binder.restoreCallingIdentity(identity);
515                 }
516                 if (isActiveSubId) {
517                     TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
518                         availableNetworkInfo.getSubId(), "updateAvailableNetworks");
519                 } else {
520                     /* check if the app has opportunistic carrier permission */
521                     if (!hasOpportunisticSubPrivilege(callingPackage,
522                         availableNetworkInfo.getSubId())) {
523                         log("No carrier privilege for opportunistic subscription");
524                         sendUpdateNetworksCallbackHelper(callbackStub,
525                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_CARRIER_PRIVILEGE);
526                         return;
527                     }
528                 }
529             }
530 
531             final long identity = Binder.clearCallingIdentity();
532             try {
533                 ONSConfigInput onsConfigInput = new ONSConfigInput(availableNetworks, callbackStub);
534                 SubscriptionInfo subscriptionInfo = mSubscriptionManager.getDefaultVoiceSubscriptionInfo();
535                 if (subscriptionInfo != null) {
536                     onsConfigInput.setPrimarySub(subscriptionInfo.getSubscriptionId());
537                     onsConfigInput.setPreferredDataSub(availableNetworks.get(0).getSubId());
538                     mONSConfigInputHashMap.put(CARRIER_APP_CONFIG_NAME, onsConfigInput);
539                 }
540                 /* standalone opportunistic subscription should be handled in priority. */
541                 if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null) {
542                     if (mProfileSelector.containStandaloneOppSubs(mONSConfigInputHashMap.get(
543                             SYSTEM_APP_CONFIG_NAME).getAvailableNetworkInfos())) {
544                         log("standalone opportunistic subscription is using.");
545                         return;
546                     }
547                 }
548 
549                 if (mIsEnabled) {
550                     /*  if carrier is reporting availability, then it takes higher priority. */
551                     mProfileSelector.startProfileSelection(availableNetworks, callbackStub);
552                 } else {
553                     if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
554                         sendUpdateNetworksCallbackHelper(callbackStub,
555                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED);
556                     } else {
557                         sendUpdateNetworksCallbackHelper(callbackStub,
558                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_ABORTED);
559                     }
560                 }
561             } finally {
562                 Binder.restoreCallingIdentity(identity);
563             }
564         } else {
565             final long identity = Binder.clearCallingIdentity();
566             try {
567                 mONSConfigInputHashMap.put(CARRIER_APP_CONFIG_NAME, null);
568                 if (!mIsEnabled) {
569                     sendUpdateNetworksCallbackHelper(callbackStub,
570                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
571                     return;
572                 }
573                 /* if carrier is reporting unavailability, then decide whether to start
574                    system app request or not. */
575                 if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null) {
576                     sendUpdateNetworksCallbackHelper(callbackStub,
577                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
578                     mProfileSelector.startProfileSelection(
579                             mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME)
580                                     .getAvailableNetworkInfos(),
581                             mONSConfigInputHashMap.get(
582                                     SYSTEM_APP_CONFIG_NAME).getAvailableNetworkCallback());
583                 } else {
584                     mProfileSelector.stopProfileSelection(callbackStub);
585                 }
586             } finally {
587                 Binder.restoreCallingIdentity(identity);
588             }
589         }
590     }
591 
sendUpdateNetworksCallbackHelper(IUpdateAvailableNetworksCallback callback, int result)592     private void sendUpdateNetworksCallbackHelper(IUpdateAvailableNetworksCallback callback, int result) {
593         if (callback == null) return;
594         try {
595             callback.onComplete(result);
596         } catch (RemoteException exception) {
597             log("RemoteException " + exception);
598         }
599     }
600 
sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result)601     private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) {
602         if (callback == null) return;
603         try {
604             callback.onComplete(result);
605         } catch (RemoteException exception) {
606             log("RemoteException " + exception);
607         }
608     }
609 
getPersistentEnableState()610     private boolean getPersistentEnableState() {
611         return mSharedPref.getBoolean(PREF_ENABLED, true);
612     }
613 
handleSystemAppAvailableNetworks( ArrayList<AvailableNetworkInfo> availableNetworks, IUpdateAvailableNetworksCallback callbackStub)614     private void handleSystemAppAvailableNetworks(
615             ArrayList<AvailableNetworkInfo> availableNetworks,
616             IUpdateAvailableNetworksCallback callbackStub) {
617         final long identity = Binder.clearCallingIdentity();
618         try {
619             if ((availableNetworks != null) && (availableNetworks.size() > 0)) {
620                 /* all subscriptions should be opportunistic subscriptions */
621                 if (!mProfileSelector.hasOpprotunisticSub(availableNetworks)) {
622                     log("No opportunistic subscriptions received");
623                     if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
624                         sendUpdateNetworksCallbackHelper(callbackStub,
625                                 TelephonyManager
626                                         .UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
627                     } else {
628                         sendUpdateNetworksCallbackHelper(callbackStub,
629                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
630                     }
631                     return;
632                 }
633                 mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME,
634                         new ONSConfigInput(availableNetworks, callbackStub));
635                 /* reporting availability. proceed if carrier app has not requested any, but
636                    standalone opportunistic subscription should be handled in priority. */
637                 if (mIsEnabled) {
638                     if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null
639                             || mProfileSelector.containStandaloneOppSubs(availableNetworks)) {
640                         mProfileSelector.startProfileSelection(availableNetworks, callbackStub);
641                     }
642                 } else {
643                     if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
644                         sendUpdateNetworksCallbackHelper(callbackStub,
645                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED);
646                     } else {
647                         sendUpdateNetworksCallbackHelper(callbackStub,
648                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_ABORTED);
649                     }
650                 }
651             } else {
652                 if (!mIsEnabled) {
653                     mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME, null);
654                     sendUpdateNetworksCallbackHelper(callbackStub,
655                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
656                     return;
657                 }
658                 /* if system is reporting unavailability, then decide whether to start
659                    carrier app request or not. */
660                 mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME, null);
661                 if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null) {
662                     mProfileSelector.stopProfileSelection(callbackStub);
663                 } else {
664                     sendUpdateNetworksCallbackHelper(callbackStub,
665                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
666                     log("Try to start carrier app request");
667                     mProfileSelector.startProfileSelection(
668                             mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
669                                     .getAvailableNetworkInfos(),
670                             mONSConfigInputHashMap.get(
671                                     CARRIER_APP_CONFIG_NAME).getAvailableNetworkCallback());
672                 }
673             }
674         } finally {
675             Binder.restoreCallingIdentity(identity);
676         }
677     }
678 
updateEnableState(boolean enable)679     private void updateEnableState(boolean enable) {
680         mIsEnabled = enable;
681         mSharedPref.edit().putBoolean(PREF_ENABLED, mIsEnabled).apply();
682     }
683 
684     /**
685      * update the enable state
686      * start profile selection if enabled.
687      * @param enable enable(true) or disable(false)
688      */
enableOpportunisticNetwork(boolean enable)689     private void enableOpportunisticNetwork(boolean enable) {
690         synchronized (mLock) {
691             if (mIsEnabled != enable) {
692                 updateEnableState(enable);
693                 if (!mIsEnabled) {
694                     mProfileSelector.stopProfileSelection(null);
695                 } else {
696                     if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) != null &&
697                         mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
698                             .getAvailableNetworkInfos() != null) {
699                         mProfileSelector.startProfileSelection(
700                             mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
701                                 .getAvailableNetworkInfos(),
702                             mONSConfigInputHashMap.get(
703                                 CARRIER_APP_CONFIG_NAME).getAvailableNetworkCallback());
704                     } else if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null &&
705                         mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME)
706                             .getAvailableNetworkInfos() != null) {
707                         mProfileSelector.startProfileSelection(
708                             mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME)
709                                 .getAvailableNetworkInfos(),
710                             mONSConfigInputHashMap.get(
711                                 SYSTEM_APP_CONFIG_NAME).getAvailableNetworkCallback());
712                     }
713                 }
714             }
715         }
716         logDebug("service is enable state " + mIsEnabled);
717     }
718 
log(String msg)719     private void log(String msg) {
720         Rlog.d(TAG, msg);
721     }
722 
logDebug(String msg)723     private void logDebug(String msg) {
724         if (DBG) Rlog.d(TAG, msg);
725     }
726 }
727