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