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