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