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