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