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