• 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             TelephonyPermissions
317                     .checkCallingOrSelfReadPhoneState(mContext,
318                             mSubscriptionManager.getDefaultSubscriptionId(),
319                             callingPackage, callingFeatureId, "getPreferredDataSubscriptionId");
320             final long identity = Binder.clearCallingIdentity();
321             try {
322                 return mProfileSelector.getPreferredDataSubscriptionId();
323             } finally {
324                 Binder.restoreCallingIdentity(identity);
325             }
326         }
327 
328         /**
329          * Update availability of a list of networks in the current location.
330          *
331          * This api should be called if the caller is aware of the availability of a network
332          * at the current location. This information will be used by OpportunisticNetwork service
333          * to decide to attach to the network. If an empty list is passed,
334          * it is assumed that no network is available.
335          *  @param availableNetworks is a list of available network information.
336          *  @param callback callback upon request completion.
337          *  @param callingPackage caller's package name
338          * <p>
339          * <p>Requires that the calling app has carrier privileges on both primary and
340          * secondary subscriptions (see
341          * {@link #hasCarrierPrivileges}), or has permission
342          * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
343          *
344          */
345         public void updateAvailableNetworks(List<AvailableNetworkInfo> availableNetworks,
346                 IUpdateAvailableNetworksCallback callbackStub, String callingPackage) {
347             logDebug("updateAvailableNetworks: " + availableNetworks);
348             /* check if system app */
349             if (enforceModifyPhoneStatePermission(mContext)) {
350                 handleSystemAppAvailableNetworks(
351                         (ArrayList<AvailableNetworkInfo>) availableNetworks, callbackStub);
352             } else {
353                 /* check if the app has primary carrier permission */
354                 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
355                         mSubscriptionManager.getDefaultSubscriptionId(), "updateAvailableNetworks");
356                 handleCarrierAppAvailableNetworks(
357                         (ArrayList<AvailableNetworkInfo>) availableNetworks, callbackStub,
358                         callingPackage);
359             }
360         }
361     };
362 
363     @Override
onBind(Intent intent)364     public IBinder onBind(Intent intent) {
365         return mBinder;
366     }
367 
368     @Override
onCreate()369     public void onCreate() {
370         startWorkerThreadAndInit();
371 
372         /* register the service */
373         ServiceRegisterer opportunisticNetworkServiceRegisterer = TelephonyFrameworkInitializer
374                 .getTelephonyServiceManager()
375                 .getOpportunisticNetworkServiceRegisterer();
376         if (opportunisticNetworkServiceRegisterer.get() == null) {
377             opportunisticNetworkServiceRegisterer.register(mBinder);
378         }
379     }
380 
381     @Override
onStartCommand(Intent intent, int flags, int startId)382     public int onStartCommand(Intent intent, int flags, int startId) {
383         mHandler.post(new Runnable() {
384 
385             private Intent mIntent = null;
386             Runnable setIntent(Intent intent) {
387                 mIntent = intent;
388                 return this;
389             }
390 
391             @Override
392             public void run() {
393                 if (mIntent == null) {
394                     return;
395                 }
396 
397                 String action = mIntent.getAction();
398                 if (action == null) {
399                     return;
400                 }
401 
402                 switch (action) {
403                     case ONSProfileSelector.ACTION_SUB_SWITCH: {
404                         if (mProfileSelector != null) {
405                             mProfileSelector.onSubSwitchComplete(mIntent);
406                         }
407                     }
408                     break;
409 
410                     case ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD: {
411                         mONSProfileActivator.getONSProfileDownloader().onCallbackIntentReceived(
412                                 mIntent.getParcelableExtra(Intent.EXTRA_INTENT),
413                                 mIntent.getIntExtra(ONSProfileResultReceiver.EXTRA_RESULT_CODE, 0)
414                         );
415                     }
416                     break;
417 
418                     case ONSProfileConfigurator.ACTION_ONS_ESIM_CONFIG: {
419                         mONSProfileActivator.getONSProfileConfigurator().onCallbackIntentReceived(
420                                 mIntent.getParcelableExtra(Intent.EXTRA_INTENT),
421                                 mIntent.getIntExtra(ONSProfileResultReceiver.EXTRA_RESULT_CODE, 0)
422                         );
423                     }
424                     break;
425 
426                     case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
427                         mONSProfileActivator.handleCarrierConfigChange();
428                         break;
429                 }
430             }
431         }.setIntent(intent));
432 
433         return START_STICKY;
434     }
435 
436     @Override
onDestroy()437     public void onDestroy() {
438         super.onDestroy();
439         log("Destroyed Successfully...");
440         mHandler.getLooper().quitSafely();
441     }
442 
443     /**
444      * initialize ONS and register as service.
445      * Read persistent state to update enable state
446      * Start sub components if already enabled.
447      * @param context context instance
448      */
449     @VisibleForTesting
initialize(Context context)450     protected void initialize(Context context) {
451         mContext = context;
452         createMsgHandler();
453         mTelephonyManager = TelephonyManager.from(mContext);
454         mProfileSelector = new ONSProfileSelector(mContext, mProfileSelectionCallback);
455         mSharedPref = mContext.createDeviceProtectedStorageContext().getSharedPreferences(
456                 PREF_NAME, Context.MODE_PRIVATE);
457         mSubscriptionManager = (SubscriptionManager) mContext.getSystemService(
458                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
459         mONSConfigInputHashMap = new HashMap<String, ONSConfigInput>();
460         mONSStats = new ONSStats(mContext, mSubscriptionManager);
461         mContext.registerReceiver(mBroadcastReceiver,
462             new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
463         enableOpportunisticNetwork(getPersistentEnableState());
464         mONSProfileActivator = new ONSProfileActivator(mContext, mONSStats);
465     }
466 
handleCarrierAppAvailableNetworks( ArrayList<AvailableNetworkInfo> availableNetworks, IUpdateAvailableNetworksCallback callbackStub, String callingPackage)467     private void handleCarrierAppAvailableNetworks(
468             ArrayList<AvailableNetworkInfo> availableNetworks,
469             IUpdateAvailableNetworksCallback callbackStub, String callingPackage) {
470         if ((availableNetworks != null) && (availableNetworks.size() > 0)) {
471             /* carrier apps should report only subscription */
472             if (availableNetworks.size() > 1) {
473                 log("Carrier app should not pass more than one subscription");
474                 if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
475                     sendUpdateNetworksCallbackHelper(callbackStub,
476                             TelephonyManager
477                                     .UPDATE_AVAILABLE_NETWORKS_MULTIPLE_NETWORKS_NOT_SUPPORTED);
478                 } else {
479                     sendUpdateNetworksCallbackHelper(callbackStub,
480                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
481                 }
482                 return;
483             }
484 
485             if (!mProfileSelector.hasOpprotunisticSub(availableNetworks)) {
486                 log("No opportunistic subscriptions received");
487                 if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
488                     sendUpdateNetworksCallbackHelper(callbackStub,
489                             TelephonyManager
490                                     .UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
491                 } else {
492                     sendUpdateNetworksCallbackHelper(callbackStub,
493                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
494                 }
495                 return;
496             }
497 
498             for (AvailableNetworkInfo availableNetworkInfo : availableNetworks) {
499                 final long identity = Binder.clearCallingIdentity();
500                 boolean isActiveSubId = false;
501                 try {
502                     isActiveSubId =
503                             mSubscriptionManager.isActiveSubId(availableNetworkInfo.getSubId());
504                 } finally {
505                     Binder.restoreCallingIdentity(identity);
506                 }
507                 if (isActiveSubId) {
508                     TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
509                         availableNetworkInfo.getSubId(), "updateAvailableNetworks");
510                 } else {
511                     /* check if the app has opportunistic carrier permission */
512                     if (!hasOpportunisticSubPrivilege(callingPackage,
513                         availableNetworkInfo.getSubId())) {
514                         log("No carrier privilege for opportunistic subscription");
515                         sendUpdateNetworksCallbackHelper(callbackStub,
516                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_CARRIER_PRIVILEGE);
517                         return;
518                     }
519                 }
520             }
521 
522             final long identity = Binder.clearCallingIdentity();
523             try {
524                 ONSConfigInput onsConfigInput = new ONSConfigInput(availableNetworks, callbackStub);
525                 SubscriptionInfo subscriptionInfo = mSubscriptionManager.getDefaultVoiceSubscriptionInfo();
526                 if (subscriptionInfo != null) {
527                     onsConfigInput.setPrimarySub(subscriptionInfo.getSubscriptionId());
528                     onsConfigInput.setPreferredDataSub(availableNetworks.get(0).getSubId());
529                     mONSConfigInputHashMap.put(CARRIER_APP_CONFIG_NAME, onsConfigInput);
530                 }
531                 /* standalone opportunistic subscription should be handled in priority. */
532                 if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null) {
533                     if (mProfileSelector.containStandaloneOppSubs(mONSConfigInputHashMap.get(
534                             SYSTEM_APP_CONFIG_NAME).getAvailableNetworkInfos())) {
535                         log("standalone opportunistic subscription is using.");
536                         return;
537                     }
538                 }
539 
540                 if (mIsEnabled) {
541                     /*  if carrier is reporting availability, then it takes higher priority. */
542                     mProfileSelector.startProfileSelection(availableNetworks, callbackStub);
543                 } else {
544                     if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
545                         sendUpdateNetworksCallbackHelper(callbackStub,
546                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED);
547                     } else {
548                         sendUpdateNetworksCallbackHelper(callbackStub,
549                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_ABORTED);
550                     }
551                 }
552             } finally {
553                 Binder.restoreCallingIdentity(identity);
554             }
555         } else {
556             final long identity = Binder.clearCallingIdentity();
557             try {
558                 mONSConfigInputHashMap.put(CARRIER_APP_CONFIG_NAME, null);
559                 if (!mIsEnabled) {
560                     sendUpdateNetworksCallbackHelper(callbackStub,
561                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
562                     return;
563                 }
564                 /* if carrier is reporting unavailability, then decide whether to start
565                    system app request or not. */
566                 if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null) {
567                     sendUpdateNetworksCallbackHelper(callbackStub,
568                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
569                     mProfileSelector.startProfileSelection(
570                             mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME)
571                                     .getAvailableNetworkInfos(),
572                             mONSConfigInputHashMap.get(
573                                     SYSTEM_APP_CONFIG_NAME).getAvailableNetworkCallback());
574                 } else {
575                     mProfileSelector.stopProfileSelection(callbackStub);
576                 }
577             } finally {
578                 Binder.restoreCallingIdentity(identity);
579             }
580         }
581     }
582 
sendUpdateNetworksCallbackHelper(IUpdateAvailableNetworksCallback callback, int result)583     private void sendUpdateNetworksCallbackHelper(IUpdateAvailableNetworksCallback callback, int result) {
584         if (callback == null) return;
585         try {
586             callback.onComplete(result);
587         } catch (RemoteException exception) {
588             log("RemoteException " + exception);
589         }
590     }
591 
sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result)592     private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback 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 
getPersistentEnableState()601     private boolean getPersistentEnableState() {
602         return mSharedPref.getBoolean(PREF_ENABLED, true);
603     }
604 
handleSystemAppAvailableNetworks( ArrayList<AvailableNetworkInfo> availableNetworks, IUpdateAvailableNetworksCallback callbackStub)605     private void handleSystemAppAvailableNetworks(
606             ArrayList<AvailableNetworkInfo> availableNetworks,
607             IUpdateAvailableNetworksCallback callbackStub) {
608         final long identity = Binder.clearCallingIdentity();
609         try {
610             if ((availableNetworks != null) && (availableNetworks.size() > 0)) {
611                 /* all subscriptions should be opportunistic subscriptions */
612                 if (!mProfileSelector.hasOpprotunisticSub(availableNetworks)) {
613                     log("No opportunistic subscriptions received");
614                     if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
615                         sendUpdateNetworksCallbackHelper(callbackStub,
616                                 TelephonyManager
617                                         .UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
618                     } else {
619                         sendUpdateNetworksCallbackHelper(callbackStub,
620                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
621                     }
622                     return;
623                 }
624                 mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME,
625                         new ONSConfigInput(availableNetworks, callbackStub));
626                 /* reporting availability. proceed if carrier app has not requested any, but
627                    standalone opportunistic subscription should be handled in priority. */
628                 if (mIsEnabled) {
629                     if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null
630                             || mProfileSelector.containStandaloneOppSubs(availableNetworks)) {
631                         mProfileSelector.startProfileSelection(availableNetworks, callbackStub);
632                     }
633                 } else {
634                     if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
635                         sendUpdateNetworksCallbackHelper(callbackStub,
636                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED);
637                     } else {
638                         sendUpdateNetworksCallbackHelper(callbackStub,
639                                 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_ABORTED);
640                     }
641                 }
642             } else {
643                 if (!mIsEnabled) {
644                     mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME, null);
645                     sendUpdateNetworksCallbackHelper(callbackStub,
646                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
647                     return;
648                 }
649                 /* if system is reporting unavailability, then decide whether to start
650                    carrier app request or not. */
651                 mONSConfigInputHashMap.put(SYSTEM_APP_CONFIG_NAME, null);
652                 if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) == null) {
653                     mProfileSelector.stopProfileSelection(callbackStub);
654                 } else {
655                     sendUpdateNetworksCallbackHelper(callbackStub,
656                             TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
657                     log("Try to start carrier app request");
658                     mProfileSelector.startProfileSelection(
659                             mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
660                                     .getAvailableNetworkInfos(),
661                             mONSConfigInputHashMap.get(
662                                     CARRIER_APP_CONFIG_NAME).getAvailableNetworkCallback());
663                 }
664             }
665         } finally {
666             Binder.restoreCallingIdentity(identity);
667         }
668     }
669 
updateEnableState(boolean enable)670     private void updateEnableState(boolean enable) {
671         mIsEnabled = enable;
672         mSharedPref.edit().putBoolean(PREF_ENABLED, mIsEnabled).apply();
673     }
674 
675     /**
676      * update the enable state
677      * start profile selection if enabled.
678      * @param enable enable(true) or disable(false)
679      */
enableOpportunisticNetwork(boolean enable)680     private void enableOpportunisticNetwork(boolean enable) {
681         synchronized (mLock) {
682             if (mIsEnabled != enable) {
683                 updateEnableState(enable);
684                 if (!mIsEnabled) {
685                     mProfileSelector.stopProfileSelection(null);
686                 } else {
687                     if (mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME) != null &&
688                         mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
689                             .getAvailableNetworkInfos() != null) {
690                         mProfileSelector.startProfileSelection(
691                             mONSConfigInputHashMap.get(CARRIER_APP_CONFIG_NAME)
692                                 .getAvailableNetworkInfos(),
693                             mONSConfigInputHashMap.get(
694                                 CARRIER_APP_CONFIG_NAME).getAvailableNetworkCallback());
695                     } else if (mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME) != null &&
696                         mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME)
697                             .getAvailableNetworkInfos() != null) {
698                         mProfileSelector.startProfileSelection(
699                             mONSConfigInputHashMap.get(SYSTEM_APP_CONFIG_NAME)
700                                 .getAvailableNetworkInfos(),
701                             mONSConfigInputHashMap.get(
702                                 SYSTEM_APP_CONFIG_NAME).getAvailableNetworkCallback());
703                     }
704                 }
705             }
706         }
707         logDebug("service is enable state " + mIsEnabled);
708     }
709 
log(String msg)710     private void log(String msg) {
711         Rlog.d(TAG, msg);
712     }
713 
logDebug(String msg)714     private void logDebug(String msg) {
715         if (DBG) Rlog.d(TAG, msg);
716     }
717 }
718