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