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