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