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