1 /* 2 * Copyright (C) 2017 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.internal.telephony; 18 19 import static android.os.Binder.withCleanCallingIdentity; 20 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; 21 import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN; 22 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; 23 24 import android.content.Context; 25 import android.hardware.radio.V1_0.RadioError; 26 import android.os.AsyncResult; 27 import android.os.Build; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.IBinder; 31 import android.os.Message; 32 import android.os.Messenger; 33 import android.os.Process; 34 import android.os.RemoteException; 35 import android.telephony.CellInfo; 36 import android.telephony.LocationAccessPolicy; 37 import android.telephony.NetworkScan; 38 import android.telephony.NetworkScanRequest; 39 import android.telephony.RadioAccessSpecifier; 40 import android.telephony.SubscriptionInfo; 41 import android.telephony.TelephonyScanManager; 42 import android.util.Log; 43 44 import java.util.Collection; 45 import java.util.List; 46 import java.util.Set; 47 import java.util.concurrent.atomic.AtomicInteger; 48 import java.util.stream.Collectors; 49 import java.util.stream.Stream; 50 51 /** 52 * Manages radio access network scan requests. 53 * 54 * Provides methods to start and stop network scan requests, and keeps track of all the live scans. 55 * 56 * {@hide} 57 */ 58 public final class NetworkScanRequestTracker { 59 60 private static final String TAG = "ScanRequestTracker"; 61 62 private static final int CMD_START_NETWORK_SCAN = 1; 63 private static final int EVENT_START_NETWORK_SCAN_DONE = 2; 64 private static final int EVENT_RECEIVE_NETWORK_SCAN_RESULT = 3; 65 private static final int CMD_STOP_NETWORK_SCAN = 4; 66 private static final int EVENT_STOP_NETWORK_SCAN_DONE = 5; 67 private static final int CMD_INTERRUPT_NETWORK_SCAN = 6; 68 private static final int EVENT_INTERRUPT_NETWORK_SCAN_DONE = 7; 69 70 private final Handler mHandler = new Handler() { 71 @Override 72 public void handleMessage(Message msg) { 73 switch (msg.what) { 74 case CMD_START_NETWORK_SCAN: 75 mScheduler.doStartScan((NetworkScanRequestInfo) msg.obj); 76 break; 77 78 case EVENT_START_NETWORK_SCAN_DONE: 79 mScheduler.startScanDone((AsyncResult) msg.obj); 80 break; 81 82 case EVENT_RECEIVE_NETWORK_SCAN_RESULT: 83 mScheduler.receiveResult((AsyncResult) msg.obj); 84 break; 85 86 case CMD_STOP_NETWORK_SCAN: 87 mScheduler.doStopScan(msg.arg1); 88 break; 89 90 case EVENT_STOP_NETWORK_SCAN_DONE: 91 mScheduler.stopScanDone((AsyncResult) msg.obj); 92 break; 93 94 case CMD_INTERRUPT_NETWORK_SCAN: 95 mScheduler.doInterruptScan(msg.arg1); 96 break; 97 98 case EVENT_INTERRUPT_NETWORK_SCAN_DONE: 99 mScheduler.interruptScanDone((AsyncResult) msg.obj); 100 break; 101 } 102 } 103 }; 104 105 // The sequence number of NetworkScanRequests 106 private final AtomicInteger mNextNetworkScanRequestId = new AtomicInteger(1); 107 private final NetworkScanRequestScheduler mScheduler = new NetworkScanRequestScheduler(); 108 logEmptyResultOrException(AsyncResult ar)109 private void logEmptyResultOrException(AsyncResult ar) { 110 if (ar.result == null) { 111 Log.e(TAG, "NetworkScanResult: Empty result"); 112 } else { 113 Log.e(TAG, "NetworkScanResult: Exception: " + ar.exception); 114 } 115 } 116 isValidScan(NetworkScanRequestInfo nsri)117 private boolean isValidScan(NetworkScanRequestInfo nsri) { 118 if (nsri.mRequest == null || nsri.mRequest.getSpecifiers() == null) { 119 return false; 120 } 121 if (nsri.mRequest.getSpecifiers().length > NetworkScanRequest.MAX_RADIO_ACCESS_NETWORKS) { 122 return false; 123 } 124 for (RadioAccessSpecifier ras : nsri.mRequest.getSpecifiers()) { 125 if (ras.getRadioAccessNetwork() != GERAN && ras.getRadioAccessNetwork() != UTRAN 126 && ras.getRadioAccessNetwork() != EUTRAN) { 127 return false; 128 } 129 if (ras.getBands() != null && ras.getBands().length > NetworkScanRequest.MAX_BANDS) { 130 return false; 131 } 132 if (ras.getChannels() != null 133 && ras.getChannels().length > NetworkScanRequest.MAX_CHANNELS) { 134 return false; 135 } 136 } 137 138 if ((nsri.mRequest.getSearchPeriodicity() < NetworkScanRequest.MIN_SEARCH_PERIODICITY_SEC) 139 || (nsri.mRequest.getSearchPeriodicity() 140 > NetworkScanRequest.MAX_SEARCH_PERIODICITY_SEC)) { 141 return false; 142 } 143 144 if ((nsri.mRequest.getMaxSearchTime() < NetworkScanRequest.MIN_SEARCH_MAX_SEC) 145 || (nsri.mRequest.getMaxSearchTime() > NetworkScanRequest.MAX_SEARCH_MAX_SEC)) { 146 return false; 147 } 148 149 if ((nsri.mRequest.getIncrementalResultsPeriodicity() 150 < NetworkScanRequest.MIN_INCREMENTAL_PERIODICITY_SEC) 151 || (nsri.mRequest.getIncrementalResultsPeriodicity() 152 > NetworkScanRequest.MAX_INCREMENTAL_PERIODICITY_SEC)) { 153 return false; 154 } 155 156 if ((nsri.mRequest.getSearchPeriodicity() > nsri.mRequest.getMaxSearchTime()) 157 || (nsri.mRequest.getIncrementalResultsPeriodicity() 158 > nsri.mRequest.getMaxSearchTime())) { 159 return false; 160 } 161 162 if ((nsri.mRequest.getPlmns() != null) 163 && (nsri.mRequest.getPlmns().size() > NetworkScanRequest.MAX_MCC_MNC_LIST_SIZE)) { 164 return false; 165 } 166 return true; 167 } 168 doesCellInfoCorrespondToKnownMccMnc(CellInfo ci, Collection<String> knownMccMncs)169 private static boolean doesCellInfoCorrespondToKnownMccMnc(CellInfo ci, 170 Collection<String> knownMccMncs) { 171 String mccMnc = ci.getCellIdentity().getMccString() 172 + ci.getCellIdentity().getMncString(); 173 return knownMccMncs.contains(mccMnc); 174 } 175 176 /** 177 * @return A list of MCC/MNC ids that apps should be allowed to see as results from a network 178 * scan when scan results are restricted due to location privacy. 179 */ getAllowedMccMncsForLocationRestrictedScan(Context context)180 public static Set<String> getAllowedMccMncsForLocationRestrictedScan(Context context) { 181 return withCleanCallingIdentity(() -> SubscriptionController.getInstance() 182 .getAvailableSubscriptionInfoList(context.getOpPackageName()).stream() 183 .flatMap(NetworkScanRequestTracker::getAllowableMccMncsFromSubscriptionInfo) 184 .collect(Collectors.toSet())); 185 } 186 getAllowableMccMncsFromSubscriptionInfo(SubscriptionInfo info)187 private static Stream<String> getAllowableMccMncsFromSubscriptionInfo(SubscriptionInfo info) { 188 Stream<String> plmns = Stream.of(info.getEhplmns(), info.getHplmns()).flatMap(List::stream); 189 if (info.getMccString() != null && info.getMncString() != null) { 190 plmns = Stream.concat(plmns, Stream.of(info.getMccString() + info.getMncString())); 191 } 192 return plmns; 193 } 194 195 /** Sends a message back to the application via its callback. */ notifyMessenger(NetworkScanRequestInfo nsri, int what, int err, List<CellInfo> result)196 private void notifyMessenger(NetworkScanRequestInfo nsri, int what, int err, 197 List<CellInfo> result) { 198 Messenger messenger = nsri.mMessenger; 199 Message message = Message.obtain(); 200 message.what = what; 201 message.arg1 = err; 202 message.arg2 = nsri.mScanId; 203 204 if (result != null) { 205 if (what == TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS) { 206 Set<String> allowedMccMncs = 207 getAllowedMccMncsForLocationRestrictedScan(nsri.mPhone.getContext()); 208 209 result = result.stream().map(CellInfo::sanitizeLocationInfo) 210 .filter(ci -> doesCellInfoCorrespondToKnownMccMnc(ci, allowedMccMncs)) 211 .collect(Collectors.toList()); 212 } 213 214 CellInfo[] ci = result.toArray(new CellInfo[result.size()]); 215 Bundle b = new Bundle(); 216 b.putParcelableArray(TelephonyScanManager.SCAN_RESULT_KEY, ci); 217 message.setData(b); 218 } else { 219 message.obj = null; 220 } 221 try { 222 messenger.send(message); 223 } catch (RemoteException e) { 224 Log.e(TAG, "Exception in notifyMessenger: " + e); 225 } 226 } 227 228 /** 229 * Tracks info about the radio network scan. 230 * 231 * Also used to notice when the calling process dies so we can self-expire. 232 */ 233 class NetworkScanRequestInfo implements IBinder.DeathRecipient { 234 private final NetworkScanRequest mRequest; 235 private final Messenger mMessenger; 236 private final IBinder mBinder; 237 private final Phone mPhone; 238 private final int mScanId; 239 private final int mUid; 240 private final int mPid; 241 private final String mCallingPackage; 242 private boolean mIsBinderDead; 243 NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, Phone phone, int callingUid, int callingPid, String callingPackage)244 NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, Phone phone, 245 int callingUid, int callingPid, String callingPackage) { 246 super(); 247 mRequest = r; 248 mMessenger = m; 249 mBinder = b; 250 mScanId = id; 251 mPhone = phone; 252 mUid = callingUid; 253 mPid = callingPid; 254 mCallingPackage = callingPackage; 255 mIsBinderDead = false; 256 257 try { 258 mBinder.linkToDeath(this, 0); 259 } catch (RemoteException e) { 260 binderDied(); 261 } 262 } 263 setIsBinderDead(boolean val)264 synchronized void setIsBinderDead(boolean val) { 265 mIsBinderDead = val; 266 } 267 getIsBinderDead()268 synchronized boolean getIsBinderDead() { 269 return mIsBinderDead; 270 } 271 getRequest()272 NetworkScanRequest getRequest() { 273 return mRequest; 274 } 275 unlinkDeathRecipient()276 void unlinkDeathRecipient() { 277 if (mBinder != null) { 278 mBinder.unlinkToDeath(this, 0); 279 } 280 } 281 282 @Override binderDied()283 public void binderDied() { 284 Log.e(TAG, "PhoneInterfaceManager NetworkScanRequestInfo binderDied(" 285 + mRequest + ", " + mBinder + ")"); 286 setIsBinderDead(true); 287 interruptNetworkScan(mScanId); 288 } 289 } 290 291 /** 292 * Handles multiplexing and scheduling for multiple requests. 293 */ 294 private class NetworkScanRequestScheduler { 295 296 private NetworkScanRequestInfo mLiveRequestInfo; 297 private NetworkScanRequestInfo mPendingRequestInfo; 298 rilErrorToScanError(int rilError)299 private int rilErrorToScanError(int rilError) { 300 switch (rilError) { 301 case RadioError.NONE: 302 return NetworkScan.SUCCESS; 303 case RadioError.RADIO_NOT_AVAILABLE: 304 Log.e(TAG, "rilErrorToScanError: RADIO_NOT_AVAILABLE"); 305 return NetworkScan.ERROR_MODEM_ERROR; 306 case RadioError.REQUEST_NOT_SUPPORTED: 307 Log.e(TAG, "rilErrorToScanError: REQUEST_NOT_SUPPORTED"); 308 return NetworkScan.ERROR_UNSUPPORTED; 309 case RadioError.NO_MEMORY: 310 Log.e(TAG, "rilErrorToScanError: NO_MEMORY"); 311 return NetworkScan.ERROR_MODEM_ERROR; 312 case RadioError.INTERNAL_ERR: 313 Log.e(TAG, "rilErrorToScanError: INTERNAL_ERR"); 314 return NetworkScan.ERROR_MODEM_ERROR; 315 case RadioError.MODEM_ERR: 316 Log.e(TAG, "rilErrorToScanError: MODEM_ERR"); 317 return NetworkScan.ERROR_MODEM_ERROR; 318 case RadioError.OPERATION_NOT_ALLOWED: 319 Log.e(TAG, "rilErrorToScanError: OPERATION_NOT_ALLOWED"); 320 return NetworkScan.ERROR_MODEM_ERROR; 321 case RadioError.INVALID_ARGUMENTS: 322 Log.e(TAG, "rilErrorToScanError: INVALID_ARGUMENTS"); 323 return NetworkScan.ERROR_INVALID_SCAN; 324 case RadioError.DEVICE_IN_USE: 325 Log.e(TAG, "rilErrorToScanError: DEVICE_IN_USE"); 326 return NetworkScan.ERROR_MODEM_UNAVAILABLE; 327 default: 328 Log.e(TAG, "rilErrorToScanError: Unexpected RadioError " + rilError); 329 return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; 330 } 331 } 332 commandExceptionErrorToScanError(CommandException.Error error)333 private int commandExceptionErrorToScanError(CommandException.Error error) { 334 switch (error) { 335 case RADIO_NOT_AVAILABLE: 336 Log.e(TAG, "commandExceptionErrorToScanError: RADIO_NOT_AVAILABLE"); 337 return NetworkScan.ERROR_MODEM_ERROR; 338 case REQUEST_NOT_SUPPORTED: 339 Log.e(TAG, "commandExceptionErrorToScanError: REQUEST_NOT_SUPPORTED"); 340 return NetworkScan.ERROR_UNSUPPORTED; 341 case NO_MEMORY: 342 Log.e(TAG, "commandExceptionErrorToScanError: NO_MEMORY"); 343 return NetworkScan.ERROR_MODEM_ERROR; 344 case INTERNAL_ERR: 345 Log.e(TAG, "commandExceptionErrorToScanError: INTERNAL_ERR"); 346 return NetworkScan.ERROR_MODEM_ERROR; 347 case MODEM_ERR: 348 Log.e(TAG, "commandExceptionErrorToScanError: MODEM_ERR"); 349 return NetworkScan.ERROR_MODEM_ERROR; 350 case OPERATION_NOT_ALLOWED: 351 Log.e(TAG, "commandExceptionErrorToScanError: OPERATION_NOT_ALLOWED"); 352 return NetworkScan.ERROR_MODEM_ERROR; 353 case INVALID_ARGUMENTS: 354 Log.e(TAG, "commandExceptionErrorToScanError: INVALID_ARGUMENTS"); 355 return NetworkScan.ERROR_INVALID_SCAN; 356 case DEVICE_IN_USE: 357 Log.e(TAG, "commandExceptionErrorToScanError: DEVICE_IN_USE"); 358 return NetworkScan.ERROR_MODEM_UNAVAILABLE; 359 default: 360 Log.e(TAG, "commandExceptionErrorToScanError: Unexpected CommandExceptionError " 361 + error); 362 return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; 363 } 364 } 365 doStartScan(NetworkScanRequestInfo nsri)366 private void doStartScan(NetworkScanRequestInfo nsri) { 367 if (nsri == null) { 368 Log.e(TAG, "CMD_START_NETWORK_SCAN: nsri is null"); 369 return; 370 } 371 if (!isValidScan(nsri)) { 372 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, 373 NetworkScan.ERROR_INVALID_SCAN, null); 374 return; 375 } 376 if (nsri.getIsBinderDead()) { 377 Log.e(TAG, "CMD_START_NETWORK_SCAN: Binder has died"); 378 return; 379 } 380 if (!startNewScan(nsri)) { 381 if (!interruptLiveScan(nsri)) { 382 if (!cacheScan(nsri)) { 383 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, 384 NetworkScan.ERROR_MODEM_UNAVAILABLE, null); 385 } 386 } 387 } 388 } 389 startScanDone(AsyncResult ar)390 private synchronized void startScanDone(AsyncResult ar) { 391 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 392 if (nsri == null) { 393 Log.e(TAG, "EVENT_START_NETWORK_SCAN_DONE: nsri is null"); 394 return; 395 } 396 if (mLiveRequestInfo == null || nsri.mScanId != mLiveRequestInfo.mScanId) { 397 Log.e(TAG, "EVENT_START_NETWORK_SCAN_DONE: nsri does not match mLiveRequestInfo"); 398 return; 399 } 400 if (ar.exception == null && ar.result != null) { 401 // Register for the scan results if the scan started successfully. 402 nsri.mPhone.mCi.registerForNetworkScanResult(mHandler, 403 EVENT_RECEIVE_NETWORK_SCAN_RESULT, nsri); 404 } else { 405 logEmptyResultOrException(ar); 406 if (ar.exception != null) { 407 CommandException.Error error = 408 ((CommandException) (ar.exception)).getCommandError(); 409 deleteScanAndMayNotify(nsri, commandExceptionErrorToScanError(error), true); 410 } else { 411 Log.wtf(TAG, "EVENT_START_NETWORK_SCAN_DONE: ar.exception can not be null!"); 412 } 413 } 414 } 415 receiveResult(AsyncResult ar)416 private void receiveResult(AsyncResult ar) { 417 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 418 if (nsri == null) { 419 Log.e(TAG, "EVENT_RECEIVE_NETWORK_SCAN_RESULT: nsri is null"); 420 return; 421 } 422 LocationAccessPolicy.LocationPermissionQuery locationQuery = 423 new LocationAccessPolicy.LocationPermissionQuery.Builder() 424 .setCallingPackage(nsri.mCallingPackage) 425 .setCallingPid(nsri.mPid) 426 .setCallingUid(nsri.mUid) 427 .setMinSdkVersionForFine(Build.VERSION_CODES.Q) 428 .setMethod("NetworkScanTracker#onResult") 429 .build(); 430 if (ar.exception == null && ar.result != null) { 431 NetworkScanResult nsr = (NetworkScanResult) ar.result; 432 boolean isLocationAccessAllowed = LocationAccessPolicy.checkLocationPermission( 433 nsri.mPhone.getContext(), locationQuery) 434 == LocationAccessPolicy.LocationPermissionResult.ALLOWED; 435 int notifyMsg = isLocationAccessAllowed 436 ? TelephonyScanManager.CALLBACK_SCAN_RESULTS 437 : TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS; 438 if (nsr.scanError == NetworkScan.SUCCESS) { 439 if (nsri.mPhone.getServiceStateTracker() != null) { 440 nsri.mPhone.getServiceStateTracker().updateOperatorNameForCellInfo( 441 nsr.networkInfos); 442 } 443 444 notifyMessenger(nsri, notifyMsg, 445 rilErrorToScanError(nsr.scanError), nsr.networkInfos); 446 if (nsr.scanStatus == NetworkScanResult.SCAN_STATUS_COMPLETE) { 447 deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); 448 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 449 } 450 } else { 451 if (nsr.networkInfos != null) { 452 notifyMessenger(nsri, notifyMsg, 453 rilErrorToScanError(nsr.scanError), nsr.networkInfos); 454 } 455 deleteScanAndMayNotify(nsri, rilErrorToScanError(nsr.scanError), true); 456 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 457 } 458 } else { 459 logEmptyResultOrException(ar); 460 deleteScanAndMayNotify(nsri, NetworkScan.ERROR_RADIO_INTERFACE_ERROR, true); 461 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 462 } 463 } 464 465 // Stops the scan if the scanId and uid match the mScanId and mUid. 466 // If the scan to be stopped is the live scan, we only send the request to RIL, while the 467 // mLiveRequestInfo will not be cleared and the user will not be notified either. 468 // If the scan to be stopped is the pending scan, we will clear mPendingRequestInfo and 469 // notify the user. doStopScan(int scanId)470 private synchronized void doStopScan(int scanId) { 471 if (mLiveRequestInfo != null && scanId == mLiveRequestInfo.mScanId) { 472 mLiveRequestInfo.mPhone.stopNetworkScan( 473 mHandler.obtainMessage(EVENT_STOP_NETWORK_SCAN_DONE, mLiveRequestInfo)); 474 } else if (mPendingRequestInfo != null && scanId == mPendingRequestInfo.mScanId) { 475 notifyMessenger(mPendingRequestInfo, 476 TelephonyScanManager.CALLBACK_SCAN_COMPLETE, NetworkScan.SUCCESS, null); 477 mPendingRequestInfo = null; 478 } else { 479 Log.e(TAG, "stopScan: scan " + scanId + " does not exist!"); 480 } 481 } 482 stopScanDone(AsyncResult ar)483 private void stopScanDone(AsyncResult ar) { 484 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 485 if (nsri == null) { 486 Log.e(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: nsri is null"); 487 return; 488 } 489 if (ar.exception == null && ar.result != null) { 490 deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); 491 } else { 492 logEmptyResultOrException(ar); 493 if (ar.exception != null) { 494 CommandException.Error error = 495 ((CommandException) (ar.exception)).getCommandError(); 496 deleteScanAndMayNotify(nsri, commandExceptionErrorToScanError(error), true); 497 } else { 498 Log.wtf(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: ar.exception can not be null!"); 499 } 500 } 501 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 502 } 503 504 // Interrupts the live scan is the scanId matches the mScanId of the mLiveRequestInfo. doInterruptScan(int scanId)505 private synchronized void doInterruptScan(int scanId) { 506 if (mLiveRequestInfo != null && scanId == mLiveRequestInfo.mScanId) { 507 mLiveRequestInfo.mPhone.stopNetworkScan(mHandler.obtainMessage( 508 EVENT_INTERRUPT_NETWORK_SCAN_DONE, mLiveRequestInfo)); 509 } else { 510 Log.e(TAG, "doInterruptScan: scan " + scanId + " does not exist!"); 511 } 512 } 513 interruptScanDone(AsyncResult ar)514 private void interruptScanDone(AsyncResult ar) { 515 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 516 if (nsri == null) { 517 Log.e(TAG, "EVENT_INTERRUPT_NETWORK_SCAN_DONE: nsri is null"); 518 return; 519 } 520 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 521 deleteScanAndMayNotify(nsri, 0, false); 522 } 523 524 // Interrupts the live scan and caches nsri in mPendingRequestInfo. Once the live scan is 525 // stopped, a new scan will automatically start with nsri. 526 // The new scan can interrupt the live scan only when all the below requirements are met: 527 // 1. There is 1 live scan and no other pending scan 528 // 2. The new scan is requested by mobile network setting menu (owned by PHONE process) 529 // 3. The live scan is not requested by mobile network setting menu interruptLiveScan(NetworkScanRequestInfo nsri)530 private synchronized boolean interruptLiveScan(NetworkScanRequestInfo nsri) { 531 if (mLiveRequestInfo != null && mPendingRequestInfo == null 532 && nsri.mUid == Process.PHONE_UID 533 && mLiveRequestInfo.mUid != Process.PHONE_UID) { 534 doInterruptScan(mLiveRequestInfo.mScanId); 535 mPendingRequestInfo = nsri; 536 notifyMessenger(mLiveRequestInfo, TelephonyScanManager.CALLBACK_SCAN_ERROR, 537 NetworkScan.ERROR_INTERRUPTED, null); 538 return true; 539 } 540 return false; 541 } 542 cacheScan(NetworkScanRequestInfo nsri)543 private boolean cacheScan(NetworkScanRequestInfo nsri) { 544 // TODO(30954762): Cache periodic scan for OC-MR1. 545 return false; 546 } 547 548 // Starts a new scan with nsri if there is no live scan running. startNewScan(NetworkScanRequestInfo nsri)549 private synchronized boolean startNewScan(NetworkScanRequestInfo nsri) { 550 if (mLiveRequestInfo == null) { 551 mLiveRequestInfo = nsri; 552 nsri.mPhone.startNetworkScan(nsri.getRequest(), 553 mHandler.obtainMessage(EVENT_START_NETWORK_SCAN_DONE, nsri)); 554 return true; 555 } 556 return false; 557 } 558 559 560 // Deletes the mLiveRequestInfo and notify the user if it matches nsri. deleteScanAndMayNotify(NetworkScanRequestInfo nsri, int error, boolean notify)561 private synchronized void deleteScanAndMayNotify(NetworkScanRequestInfo nsri, int error, 562 boolean notify) { 563 if (mLiveRequestInfo != null && nsri.mScanId == mLiveRequestInfo.mScanId) { 564 if (notify) { 565 if (error == NetworkScan.SUCCESS) { 566 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, error, 567 null); 568 } else { 569 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, error, 570 null); 571 } 572 } 573 mLiveRequestInfo = null; 574 if (mPendingRequestInfo != null) { 575 startNewScan(mPendingRequestInfo); 576 mPendingRequestInfo = null; 577 } 578 } 579 } 580 } 581 582 /** 583 * Interrupts an ongoing network scan 584 * 585 * This method is similar to stopNetworkScan, since they both stops an ongoing scan. The 586 * difference is that stopNetworkScan is only used by the callers to stop their own scans, so 587 * sanity check will be done to make sure the request is valid; while this method is only 588 * internally used by NetworkScanRequestTracker so sanity check is not needed. 589 */ interruptNetworkScan(int scanId)590 private void interruptNetworkScan(int scanId) { 591 // scanId will be stored at Message.arg1 592 mHandler.obtainMessage(CMD_INTERRUPT_NETWORK_SCAN, scanId, 0).sendToTarget(); 593 } 594 595 /** 596 * Starts a new network scan 597 * 598 * This function only wraps all the incoming information and delegate then to the handler thread 599 * which will actually handles the scan request. So a new scanId will always be generated and 600 * returned to the user, no matter how this scan will be actually handled. 601 */ startNetworkScan( NetworkScanRequest request, Messenger messenger, IBinder binder, Phone phone, int callingUid, int callingPid, String callingPackage)602 public int startNetworkScan( 603 NetworkScanRequest request, Messenger messenger, IBinder binder, Phone phone, 604 int callingUid, int callingPid, String callingPackage) { 605 int scanId = mNextNetworkScanRequestId.getAndIncrement(); 606 NetworkScanRequestInfo nsri = 607 new NetworkScanRequestInfo(request, messenger, binder, scanId, phone, 608 callingUid, callingPid, callingPackage); 609 // nsri will be stored as Message.obj 610 mHandler.obtainMessage(CMD_START_NETWORK_SCAN, nsri).sendToTarget(); 611 return scanId; 612 } 613 614 /** 615 * Stops an ongoing network scan 616 * 617 * The ongoing scan will be stopped only when the input scanId and caller's uid matches the 618 * corresponding information associated with it. 619 */ stopNetworkScan(int scanId, int callingUid)620 public void stopNetworkScan(int scanId, int callingUid) { 621 synchronized (mScheduler) { 622 if ((mScheduler.mLiveRequestInfo != null 623 && scanId == mScheduler.mLiveRequestInfo.mScanId 624 && callingUid == mScheduler.mLiveRequestInfo.mUid) 625 || (mScheduler.mPendingRequestInfo != null 626 && scanId == mScheduler.mPendingRequestInfo.mScanId 627 && callingUid == mScheduler.mPendingRequestInfo.mUid)) { 628 // scanId will be stored at Message.arg1 629 mHandler.obtainMessage(CMD_STOP_NETWORK_SCAN, scanId, 0).sendToTarget(); 630 } else { 631 throw new IllegalArgumentException("Scan with id: " + scanId + " does not exist!"); 632 } 633 } 634 } 635 } 636