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