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.NGRAN; 23 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; 24 25 import android.content.Context; 26 import android.hardware.radio.V1_0.RadioError; 27 import android.os.AsyncResult; 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 return withCleanCallingIdentity(() -> SubscriptionController.getInstance() 197 .getAvailableSubscriptionInfoList(context.getOpPackageName(), null).stream() 198 .flatMap(NetworkScanRequestTracker::getAllowableMccMncsFromSubscriptionInfo) 199 .collect(Collectors.toSet())); 200 } 201 getAllowableMccMncsFromSubscriptionInfo(SubscriptionInfo info)202 private static Stream<String> getAllowableMccMncsFromSubscriptionInfo(SubscriptionInfo info) { 203 Stream<String> plmns = Stream.of(info.getEhplmns(), info.getHplmns()).flatMap(List::stream); 204 if (info.getMccString() != null && info.getMncString() != null) { 205 plmns = Stream.concat(plmns, Stream.of(info.getMccString() + info.getMncString())); 206 } 207 return plmns; 208 } 209 210 /** Sends a message back to the application via its callback. */ notifyMessenger(NetworkScanRequestInfo nsri, int what, int err, List<CellInfo> result)211 private void notifyMessenger(NetworkScanRequestInfo nsri, int what, int err, 212 List<CellInfo> result) { 213 Messenger messenger = nsri.mMessenger; 214 Message message = Message.obtain(); 215 message.what = what; 216 message.arg1 = err; 217 message.arg2 = nsri.mScanId; 218 219 if (result != null) { 220 if (what == TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS) { 221 Set<String> allowedMccMncs = 222 getAllowedMccMncsForLocationRestrictedScan(nsri.mPhone.getContext()); 223 224 result = result.stream().map(CellInfo::sanitizeLocationInfo) 225 .filter(ci -> doesCellInfoCorrespondToKnownMccMnc(ci, allowedMccMncs)) 226 .collect(Collectors.toList()); 227 } 228 229 CellInfo[] ci = result.toArray(new CellInfo[result.size()]); 230 Bundle b = new Bundle(); 231 b.putParcelableArray(TelephonyScanManager.SCAN_RESULT_KEY, ci); 232 message.setData(b); 233 } else { 234 message.obj = null; 235 } 236 try { 237 messenger.send(message); 238 } catch (RemoteException e) { 239 Log.e(TAG, "Exception in notifyMessenger: " + e); 240 } 241 } 242 243 /** 244 * Tracks info about the radio network scan. 245 * 246 * Also used to notice when the calling process dies so we can self-expire. 247 */ 248 class NetworkScanRequestInfo implements IBinder.DeathRecipient { 249 private final NetworkScanRequest mRequest; 250 private final Messenger mMessenger; 251 private final IBinder mBinder; 252 private final Phone mPhone; 253 private final int mScanId; 254 private final int mUid; 255 private final int mPid; 256 private final String mCallingPackage; 257 private boolean mIsBinderDead; 258 NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, Phone phone, int callingUid, int callingPid, String callingPackage)259 NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, Phone phone, 260 int callingUid, int callingPid, String callingPackage) { 261 super(); 262 mRequest = r; 263 mMessenger = m; 264 mBinder = b; 265 mScanId = id; 266 mPhone = phone; 267 mUid = callingUid; 268 mPid = callingPid; 269 mCallingPackage = callingPackage; 270 mIsBinderDead = false; 271 272 try { 273 mBinder.linkToDeath(this, 0); 274 } catch (RemoteException e) { 275 binderDied(); 276 } 277 } 278 setIsBinderDead(boolean val)279 synchronized void setIsBinderDead(boolean val) { 280 mIsBinderDead = val; 281 } 282 getIsBinderDead()283 synchronized boolean getIsBinderDead() { 284 return mIsBinderDead; 285 } 286 getRequest()287 NetworkScanRequest getRequest() { 288 return mRequest; 289 } 290 unlinkDeathRecipient()291 void unlinkDeathRecipient() { 292 if (mBinder != null) { 293 mBinder.unlinkToDeath(this, 0); 294 } 295 } 296 297 @Override binderDied()298 public void binderDied() { 299 Log.e(TAG, "PhoneInterfaceManager NetworkScanRequestInfo binderDied(" 300 + mRequest + ", " + mBinder + ")"); 301 setIsBinderDead(true); 302 interruptNetworkScan(mScanId); 303 } 304 } 305 306 /** 307 * Handles multiplexing and scheduling for multiple requests. 308 */ 309 private class NetworkScanRequestScheduler { 310 311 private NetworkScanRequestInfo mLiveRequestInfo; 312 private NetworkScanRequestInfo mPendingRequestInfo; 313 rilErrorToScanError(int rilError)314 private int rilErrorToScanError(int rilError) { 315 switch (rilError) { 316 case RadioError.NONE: 317 return NetworkScan.SUCCESS; 318 case RadioError.RADIO_NOT_AVAILABLE: 319 Log.e(TAG, "rilErrorToScanError: RADIO_NOT_AVAILABLE"); 320 return NetworkScan.ERROR_MODEM_ERROR; 321 case RadioError.REQUEST_NOT_SUPPORTED: 322 Log.e(TAG, "rilErrorToScanError: REQUEST_NOT_SUPPORTED"); 323 return NetworkScan.ERROR_UNSUPPORTED; 324 case RadioError.NO_MEMORY: 325 Log.e(TAG, "rilErrorToScanError: NO_MEMORY"); 326 return NetworkScan.ERROR_MODEM_ERROR; 327 case RadioError.INTERNAL_ERR: 328 Log.e(TAG, "rilErrorToScanError: INTERNAL_ERR"); 329 return NetworkScan.ERROR_MODEM_ERROR; 330 case RadioError.MODEM_ERR: 331 Log.e(TAG, "rilErrorToScanError: MODEM_ERR"); 332 return NetworkScan.ERROR_MODEM_ERROR; 333 case RadioError.OPERATION_NOT_ALLOWED: 334 Log.e(TAG, "rilErrorToScanError: OPERATION_NOT_ALLOWED"); 335 return NetworkScan.ERROR_MODEM_ERROR; 336 case RadioError.INVALID_ARGUMENTS: 337 Log.e(TAG, "rilErrorToScanError: INVALID_ARGUMENTS"); 338 return NetworkScan.ERROR_INVALID_SCAN; 339 case RadioError.DEVICE_IN_USE: 340 Log.e(TAG, "rilErrorToScanError: DEVICE_IN_USE"); 341 return NetworkScan.ERROR_MODEM_UNAVAILABLE; 342 default: 343 Log.e(TAG, "rilErrorToScanError: Unexpected RadioError " + rilError); 344 return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; 345 } 346 } 347 commandExceptionErrorToScanError(CommandException.Error error)348 private int commandExceptionErrorToScanError(CommandException.Error error) { 349 switch (error) { 350 case RADIO_NOT_AVAILABLE: 351 Log.e(TAG, "commandExceptionErrorToScanError: RADIO_NOT_AVAILABLE"); 352 return NetworkScan.ERROR_MODEM_ERROR; 353 case REQUEST_NOT_SUPPORTED: 354 Log.e(TAG, "commandExceptionErrorToScanError: REQUEST_NOT_SUPPORTED"); 355 return NetworkScan.ERROR_UNSUPPORTED; 356 case NO_MEMORY: 357 Log.e(TAG, "commandExceptionErrorToScanError: NO_MEMORY"); 358 return NetworkScan.ERROR_MODEM_ERROR; 359 case INTERNAL_ERR: 360 Log.e(TAG, "commandExceptionErrorToScanError: INTERNAL_ERR"); 361 return NetworkScan.ERROR_MODEM_ERROR; 362 case MODEM_ERR: 363 Log.e(TAG, "commandExceptionErrorToScanError: MODEM_ERR"); 364 return NetworkScan.ERROR_MODEM_ERROR; 365 case OPERATION_NOT_ALLOWED: 366 Log.e(TAG, "commandExceptionErrorToScanError: OPERATION_NOT_ALLOWED"); 367 return NetworkScan.ERROR_MODEM_ERROR; 368 case INVALID_ARGUMENTS: 369 Log.e(TAG, "commandExceptionErrorToScanError: INVALID_ARGUMENTS"); 370 return NetworkScan.ERROR_INVALID_SCAN; 371 case DEVICE_IN_USE: 372 Log.e(TAG, "commandExceptionErrorToScanError: DEVICE_IN_USE"); 373 return NetworkScan.ERROR_MODEM_UNAVAILABLE; 374 default: 375 Log.e(TAG, "commandExceptionErrorToScanError: Unexpected CommandExceptionError " 376 + error); 377 return NetworkScan.ERROR_RADIO_INTERFACE_ERROR; 378 } 379 } 380 doStartScan(NetworkScanRequestInfo nsri)381 private void doStartScan(NetworkScanRequestInfo nsri) { 382 if (nsri == null) { 383 Log.e(TAG, "CMD_START_NETWORK_SCAN: nsri is null"); 384 return; 385 } 386 if (!isValidScan(nsri)) { 387 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, 388 NetworkScan.ERROR_INVALID_SCAN, null); 389 return; 390 } 391 if (nsri.getIsBinderDead()) { 392 Log.e(TAG, "CMD_START_NETWORK_SCAN: Binder has died"); 393 return; 394 } 395 if (!startNewScan(nsri)) { 396 if (!interruptLiveScan(nsri)) { 397 if (!cacheScan(nsri)) { 398 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, 399 NetworkScan.ERROR_MODEM_UNAVAILABLE, null); 400 } 401 } 402 } 403 } 404 startScanDone(AsyncResult ar)405 private synchronized void startScanDone(AsyncResult ar) { 406 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 407 if (nsri == null) { 408 Log.e(TAG, "EVENT_START_NETWORK_SCAN_DONE: nsri is null"); 409 return; 410 } 411 if (mLiveRequestInfo == null || nsri.mScanId != mLiveRequestInfo.mScanId) { 412 Log.e(TAG, "EVENT_START_NETWORK_SCAN_DONE: nsri does not match mLiveRequestInfo"); 413 return; 414 } 415 if (ar.exception == null && ar.result != null) { 416 // Register for the scan results if the scan started successfully. 417 nsri.mPhone.mCi.registerForNetworkScanResult(mHandler, 418 EVENT_RECEIVE_NETWORK_SCAN_RESULT, nsri); 419 } else { 420 logEmptyResultOrException(ar); 421 if (ar.exception != null) { 422 CommandException.Error error = 423 ((CommandException) (ar.exception)).getCommandError(); 424 deleteScanAndMayNotify(nsri, commandExceptionErrorToScanError(error), true); 425 } else { 426 Log.wtf(TAG, "EVENT_START_NETWORK_SCAN_DONE: ar.exception can not be null!"); 427 } 428 } 429 } 430 receiveResult(AsyncResult ar)431 private void receiveResult(AsyncResult ar) { 432 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 433 if (nsri == null) { 434 Log.e(TAG, "EVENT_RECEIVE_NETWORK_SCAN_RESULT: nsri is null"); 435 return; 436 } 437 LocationAccessPolicy.LocationPermissionQuery locationQuery = 438 new LocationAccessPolicy.LocationPermissionQuery.Builder() 439 .setCallingPackage(nsri.mCallingPackage) 440 .setCallingPid(nsri.mPid) 441 .setCallingUid(nsri.mUid) 442 .setMinSdkVersionForFine(Build.VERSION_CODES.Q) 443 .setMethod("NetworkScanTracker#onResult") 444 .build(); 445 if (ar.exception == null && ar.result != null) { 446 NetworkScanResult nsr = (NetworkScanResult) ar.result; 447 boolean isLocationAccessAllowed = LocationAccessPolicy.checkLocationPermission( 448 nsri.mPhone.getContext(), locationQuery) 449 == LocationAccessPolicy.LocationPermissionResult.ALLOWED; 450 int notifyMsg = isLocationAccessAllowed 451 ? TelephonyScanManager.CALLBACK_SCAN_RESULTS 452 : TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS; 453 if (nsr.scanError == NetworkScan.SUCCESS) { 454 if (nsri.mPhone.getServiceStateTracker() != null) { 455 nsri.mPhone.getServiceStateTracker().updateOperatorNameForCellInfo( 456 nsr.networkInfos); 457 } 458 459 notifyMessenger(nsri, notifyMsg, 460 rilErrorToScanError(nsr.scanError), nsr.networkInfos); 461 if (nsr.scanStatus == NetworkScanResult.SCAN_STATUS_COMPLETE) { 462 deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); 463 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 464 } 465 } else { 466 if (nsr.networkInfos != null) { 467 notifyMessenger(nsri, notifyMsg, 468 rilErrorToScanError(nsr.scanError), nsr.networkInfos); 469 } 470 deleteScanAndMayNotify(nsri, rilErrorToScanError(nsr.scanError), true); 471 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 472 } 473 } else { 474 logEmptyResultOrException(ar); 475 deleteScanAndMayNotify(nsri, NetworkScan.ERROR_RADIO_INTERFACE_ERROR, true); 476 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 477 } 478 } 479 480 // Stops the scan if the scanId and uid match the mScanId and mUid. 481 // If the scan to be stopped is the live scan, we only send the request to RIL, while the 482 // mLiveRequestInfo will not be cleared and the user will not be notified either. 483 // If the scan to be stopped is the pending scan, we will clear mPendingRequestInfo and 484 // notify the user. doStopScan(int scanId)485 private synchronized void doStopScan(int scanId) { 486 if (mLiveRequestInfo != null && scanId == mLiveRequestInfo.mScanId) { 487 mLiveRequestInfo.mPhone.stopNetworkScan( 488 mHandler.obtainMessage(EVENT_STOP_NETWORK_SCAN_DONE, mLiveRequestInfo)); 489 } else if (mPendingRequestInfo != null && scanId == mPendingRequestInfo.mScanId) { 490 notifyMessenger(mPendingRequestInfo, 491 TelephonyScanManager.CALLBACK_SCAN_COMPLETE, NetworkScan.SUCCESS, null); 492 mPendingRequestInfo = null; 493 } else { 494 Log.e(TAG, "stopScan: scan " + scanId + " does not exist!"); 495 } 496 } 497 stopScanDone(AsyncResult ar)498 private void stopScanDone(AsyncResult ar) { 499 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 500 if (nsri == null) { 501 Log.e(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: nsri is null"); 502 return; 503 } 504 if (ar.exception == null && ar.result != null) { 505 deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); 506 } else { 507 logEmptyResultOrException(ar); 508 if (ar.exception != null) { 509 CommandException.Error error = 510 ((CommandException) (ar.exception)).getCommandError(); 511 deleteScanAndMayNotify(nsri, commandExceptionErrorToScanError(error), true); 512 } else { 513 Log.wtf(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: ar.exception can not be null!"); 514 } 515 } 516 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 517 } 518 519 // Interrupts the live scan is the scanId matches the mScanId of the mLiveRequestInfo. doInterruptScan(int scanId)520 private synchronized void doInterruptScan(int scanId) { 521 if (mLiveRequestInfo != null && scanId == mLiveRequestInfo.mScanId) { 522 mLiveRequestInfo.mPhone.stopNetworkScan(mHandler.obtainMessage( 523 EVENT_INTERRUPT_NETWORK_SCAN_DONE, mLiveRequestInfo)); 524 } else { 525 Log.e(TAG, "doInterruptScan: scan " + scanId + " does not exist!"); 526 } 527 } 528 interruptScanDone(AsyncResult ar)529 private void interruptScanDone(AsyncResult ar) { 530 NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj; 531 if (nsri == null) { 532 Log.e(TAG, "EVENT_INTERRUPT_NETWORK_SCAN_DONE: nsri is null"); 533 return; 534 } 535 nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); 536 deleteScanAndMayNotify(nsri, 0, false); 537 } 538 539 // Interrupts the live scan and caches nsri in mPendingRequestInfo. Once the live scan is 540 // stopped, a new scan will automatically start with nsri. 541 // The new scan can interrupt the live scan only when all the below requirements are met: 542 // 1. There is 1 live scan and no other pending scan 543 // 2. The new scan is requested by mobile network setting menu (owned by SYSTEM process) 544 // 3. The live scan is not requested by mobile network setting menu interruptLiveScan(NetworkScanRequestInfo nsri)545 private synchronized boolean interruptLiveScan(NetworkScanRequestInfo nsri) { 546 if (mLiveRequestInfo != null && mPendingRequestInfo == null 547 && nsri.mUid == Process.SYSTEM_UID 548 && mLiveRequestInfo.mUid != Process.SYSTEM_UID) { 549 doInterruptScan(mLiveRequestInfo.mScanId); 550 mPendingRequestInfo = nsri; 551 notifyMessenger(mLiveRequestInfo, TelephonyScanManager.CALLBACK_SCAN_ERROR, 552 NetworkScan.ERROR_INTERRUPTED, null); 553 return true; 554 } 555 return false; 556 } 557 cacheScan(NetworkScanRequestInfo nsri)558 private boolean cacheScan(NetworkScanRequestInfo nsri) { 559 // TODO(30954762): Cache periodic scan for OC-MR1. 560 return false; 561 } 562 563 // Starts a new scan with nsri if there is no live scan running. startNewScan(NetworkScanRequestInfo nsri)564 private synchronized boolean startNewScan(NetworkScanRequestInfo nsri) { 565 if (mLiveRequestInfo == null) { 566 mLiveRequestInfo = nsri; 567 nsri.mPhone.startNetworkScan(nsri.getRequest(), 568 mHandler.obtainMessage(EVENT_START_NETWORK_SCAN_DONE, nsri)); 569 nsri.mPhone.mCi.registerForModemReset(mHandler, EVENT_MODEM_RESET, nsri); 570 nsri.mPhone.mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, nsri); 571 return true; 572 } 573 return false; 574 } 575 576 577 // Deletes the mLiveRequestInfo and notify the user if it matches nsri. deleteScanAndMayNotify(NetworkScanRequestInfo nsri, int error, boolean notify)578 private synchronized void deleteScanAndMayNotify(NetworkScanRequestInfo nsri, int error, 579 boolean notify) { 580 if (mLiveRequestInfo != null && nsri.mScanId == mLiveRequestInfo.mScanId) { 581 if (notify) { 582 if (error == NetworkScan.SUCCESS) { 583 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, error, 584 null); 585 } else { 586 notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, error, 587 null); 588 } 589 } 590 mLiveRequestInfo.mPhone.mCi.unregisterForModemReset(mHandler); 591 mLiveRequestInfo.mPhone.mCi.unregisterForNotAvailable(mHandler); 592 mLiveRequestInfo = null; 593 if (mPendingRequestInfo != null) { 594 startNewScan(mPendingRequestInfo); 595 mPendingRequestInfo = null; 596 } 597 } 598 } 599 } 600 601 /** 602 * Interrupts an ongoing network scan 603 * 604 * This method is similar to stopNetworkScan, since they both stops an ongoing scan. The 605 * difference is that stopNetworkScan is only used by the callers to stop their own scans, so 606 * correctness check will be done to make sure the request is valid; while this method is only 607 * internally used by NetworkScanRequestTracker so correctness check is not needed. 608 */ interruptNetworkScan(int scanId)609 private void interruptNetworkScan(int scanId) { 610 // scanId will be stored at Message.arg1 611 mHandler.obtainMessage(CMD_INTERRUPT_NETWORK_SCAN, scanId, 0).sendToTarget(); 612 } 613 614 /** 615 * Starts a new network scan 616 * 617 * This function only wraps all the incoming information and delegate then to the handler thread 618 * which will actually handles the scan request. So a new scanId will always be generated and 619 * returned to the user, no matter how this scan will be actually handled. 620 */ startNetworkScan( NetworkScanRequest request, Messenger messenger, IBinder binder, Phone phone, int callingUid, int callingPid, String callingPackage)621 public int startNetworkScan( 622 NetworkScanRequest request, Messenger messenger, IBinder binder, Phone phone, 623 int callingUid, int callingPid, String callingPackage) { 624 int scanId = mNextNetworkScanRequestId.getAndIncrement(); 625 NetworkScanRequestInfo nsri = 626 new NetworkScanRequestInfo(request, messenger, binder, scanId, phone, 627 callingUid, callingPid, callingPackage); 628 // nsri will be stored as Message.obj 629 mHandler.obtainMessage(CMD_START_NETWORK_SCAN, nsri).sendToTarget(); 630 return scanId; 631 } 632 633 /** 634 * Stops an ongoing network scan 635 * 636 * The ongoing scan will be stopped only when the input scanId and caller's uid matches the 637 * corresponding information associated with it. 638 */ stopNetworkScan(int scanId, int callingUid)639 public void stopNetworkScan(int scanId, int callingUid) { 640 synchronized (mScheduler) { 641 if ((mScheduler.mLiveRequestInfo != null 642 && scanId == mScheduler.mLiveRequestInfo.mScanId 643 && callingUid == mScheduler.mLiveRequestInfo.mUid) 644 || (mScheduler.mPendingRequestInfo != null 645 && scanId == mScheduler.mPendingRequestInfo.mScanId 646 && callingUid == mScheduler.mPendingRequestInfo.mUid)) { 647 // scanId will be stored at Message.arg1 648 mHandler.obtainMessage(CMD_STOP_NETWORK_SCAN, scanId, 0).sendToTarget(); 649 } else { 650 throw new IllegalArgumentException("Scan with id: " + scanId + " does not exist!"); 651 } 652 } 653 } 654 } 655