1 /* 2 * Copyright (C) 2022 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.domainselection; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.AsyncResult; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.os.Message; 25 import android.os.RemoteException; 26 import android.telephony.AccessNetworkConstants; 27 import android.telephony.AccessNetworkConstants.AccessNetworkType; 28 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; 29 import android.telephony.AccessNetworkConstants.TransportType; 30 import android.telephony.Annotation.ApnType; 31 import android.telephony.Annotation.DisconnectCauses; 32 import android.telephony.DisconnectCause; 33 import android.telephony.DomainSelectionService; 34 import android.telephony.DomainSelectionService.EmergencyScanType; 35 import android.telephony.DomainSelector; 36 import android.telephony.EmergencyRegistrationResult; 37 import android.telephony.NetworkRegistrationInfo; 38 import android.telephony.PreciseDisconnectCause; 39 import android.telephony.data.ApnSetting; 40 import android.telephony.ims.ImsReasonInfo; 41 import android.util.LocalLog; 42 import android.util.Log; 43 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.infra.AndroidFuture; 46 import com.android.internal.telephony.CommandException; 47 import com.android.internal.telephony.IDomainSelector; 48 import com.android.internal.telephony.ITransportSelectorCallback; 49 import com.android.internal.telephony.ITransportSelectorResultCallback; 50 import com.android.internal.telephony.IWwanSelectorCallback; 51 import com.android.internal.telephony.IWwanSelectorResultCallback; 52 import com.android.internal.telephony.Phone; 53 import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; 54 import com.android.internal.telephony.flags.Flags; 55 import com.android.internal.telephony.util.TelephonyUtils; 56 57 import java.io.PrintWriter; 58 import java.util.List; 59 import java.util.concurrent.CompletableFuture; 60 61 62 /** 63 * Manages the information of request and the callback binder. 64 */ 65 public class DomainSelectionConnection { 66 67 private static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE; 68 69 protected static final int EVENT_EMERGENCY_NETWORK_SCAN_RESULT = 1; 70 protected static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 2; 71 protected static final int EVENT_SERVICE_CONNECTED = 3; 72 protected static final int EVENT_SERVICE_BINDING_TIMEOUT = 4; 73 protected static final int EVENT_RESET_NETWORK_SCAN_DONE = 5; 74 protected static final int EVENT_TRIGGER_NETWORK_SCAN_DONE = 6; 75 protected static final int EVENT_MODEM_RESET = 7; 76 protected static final int EVENT_LAST = EVENT_MODEM_RESET; 77 78 private static final int DEFAULT_BIND_RETRY_TIMEOUT_MS = 4 * 1000; 79 80 private static final int STATUS_DISPOSED = 1 << 0; 81 private static final int STATUS_DOMAIN_SELECTED = 1 << 1; 82 private static final int STATUS_WAIT_BINDING = 1 << 2; 83 private static final int STATUS_WAIT_SCAN_RESULT = 1 << 3; 84 private static final int STATUS_WAIT_RESET_SCAN_RESULT = 1 << 4; 85 86 /** Callback to receive responses from DomainSelectionConnection. */ 87 public interface DomainSelectionConnectionCallback { 88 /** 89 * Notifies that selection has terminated because there is no decision that can be made 90 * or a timeout has occurred. The call should be terminated when this method is called. 91 * 92 * @param cause Indicates the reason. 93 */ onSelectionTerminated(@isconnectCauses int cause)94 void onSelectionTerminated(@DisconnectCauses int cause); 95 } 96 97 private static class ScanRequest { 98 final int[] mPreferredNetworks; 99 final int mScanType; 100 ScanRequest(int[] preferredNetworks, int scanType)101 ScanRequest(int[] preferredNetworks, int scanType) { 102 mPreferredNetworks = preferredNetworks; 103 mScanType = scanType; 104 } 105 } 106 107 /** 108 * A wrapper class for {@link ITransportSelectorCallback} interface. 109 */ 110 private final class TransportSelectorCallbackAdaptor extends ITransportSelectorCallback.Stub { 111 @Override onCreated(@onNull IDomainSelector selector)112 public void onCreated(@NonNull IDomainSelector selector) { 113 synchronized (mLock) { 114 mDomainSelector = selector; 115 if (checkState(STATUS_DISPOSED)) { 116 try { 117 selector.finishSelection(); 118 } catch (RemoteException e) { 119 // ignore exception 120 } 121 return; 122 } 123 DomainSelectionConnection.this.onCreated(); 124 } 125 } 126 127 @Override onWlanSelected(boolean useEmergencyPdn)128 public void onWlanSelected(boolean useEmergencyPdn) { 129 synchronized (mLock) { 130 if (checkState(STATUS_DISPOSED)) { 131 return; 132 } 133 setState(STATUS_DOMAIN_SELECTED); 134 DomainSelectionConnection.this.onWlanSelected(useEmergencyPdn); 135 } 136 } 137 138 @Override onWwanSelectedAsync(@onNull final ITransportSelectorResultCallback cb)139 public void onWwanSelectedAsync(@NonNull final ITransportSelectorResultCallback cb) { 140 synchronized (mLock) { 141 if (checkState(STATUS_DISPOSED)) { 142 return; 143 } 144 if (mWwanSelectorCallback == null) { 145 mWwanSelectorCallback = new WwanSelectorCallbackAdaptor(); 146 } 147 if (mIsTestMode || !mIsEmergency 148 || (mSelectorType != DomainSelectionService.SELECTOR_TYPE_CALLING)) { 149 initHandler(); 150 mHandler.post(() -> { 151 onWwanSelectedAsyncInternal(cb); 152 }); 153 } else { 154 Thread workerThread = new Thread(new Runnable() { 155 @Override 156 public void run() { 157 onWwanSelectedAsyncInternal(cb); 158 } 159 }); 160 workerThread.start(); 161 } 162 } 163 } 164 onWwanSelectedAsyncInternal( @onNull final ITransportSelectorResultCallback cb)165 private void onWwanSelectedAsyncInternal( 166 @NonNull final ITransportSelectorResultCallback cb) { 167 synchronized (mLock) { 168 if (checkState(STATUS_DISPOSED)) { 169 return; 170 } 171 } 172 DomainSelectionConnection.this.onWwanSelected(); 173 try { 174 cb.onCompleted(mWwanSelectorCallback); 175 } catch (RemoteException e) { 176 loge("onWwanSelectedAsync executor exception=" + e); 177 synchronized (mLock) { 178 // Since remote service is not available, 179 // wait for binding or timeout. 180 waitForServiceBinding(null); 181 } 182 } 183 } 184 185 @Override onSelectionTerminated(int cause)186 public void onSelectionTerminated(int cause) { 187 synchronized (mLock) { 188 if (checkState(STATUS_DISPOSED)) { 189 return; 190 } 191 DomainSelectionConnection.this.onSelectionTerminated(cause); 192 if (!Flags.hangupEmergencyCallForCrossSimRedialing() 193 || !mIsEmergency || !checkState(STATUS_DOMAIN_SELECTED)) { 194 dispose(); 195 } 196 } 197 } 198 } 199 200 /** 201 * A wrapper class for {@link IWwanSelectorCallback} interface. 202 */ 203 private final class WwanSelectorCallbackAdaptor extends IWwanSelectorCallback.Stub { 204 @Override onRequestEmergencyNetworkScan( @onNull @adioAccessNetworkType int[] preferredNetworks, @EmergencyScanType int scanType, boolean resetScan, @NonNull IWwanSelectorResultCallback cb)205 public void onRequestEmergencyNetworkScan( 206 @NonNull @RadioAccessNetworkType int[] preferredNetworks, 207 @EmergencyScanType int scanType, boolean resetScan, 208 @NonNull IWwanSelectorResultCallback cb) { 209 synchronized (mLock) { 210 if (checkState(STATUS_DISPOSED)) { 211 return; 212 } 213 mResultCallback = cb; 214 initHandler(); 215 mHandler.post(() -> { 216 synchronized (mLock) { 217 DomainSelectionConnection.this.onRequestEmergencyNetworkScan( 218 preferredNetworks, scanType, resetScan); 219 } 220 }); 221 } 222 } 223 224 @Override onDomainSelected(@etworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn)225 public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, 226 boolean useEmergencyPdn) { 227 synchronized (mLock) { 228 if (checkState(STATUS_DISPOSED)) { 229 return; 230 } 231 setState(STATUS_DOMAIN_SELECTED); 232 DomainSelectionConnection.this.onDomainSelected(domain, useEmergencyPdn); 233 } 234 } 235 236 @Override onCancel()237 public void onCancel() { 238 synchronized (mLock) { 239 if (checkState(STATUS_DISPOSED) || mHandler == null) { 240 return; 241 } 242 mHandler.post(() -> { 243 DomainSelectionConnection.this.onCancel(); 244 }); 245 } 246 } 247 } 248 249 protected final class DomainSelectionConnectionHandler extends Handler { DomainSelectionConnectionHandler(Looper looper)250 DomainSelectionConnectionHandler(Looper looper) { 251 super(looper); 252 } 253 254 @Override handleMessage(Message msg)255 public void handleMessage(Message msg) { 256 AsyncResult ar; 257 switch (msg.what) { 258 case EVENT_EMERGENCY_NETWORK_SCAN_RESULT: 259 ar = (AsyncResult) msg.obj; 260 EmergencyRegistrationResult regResult = (EmergencyRegistrationResult) ar.result; 261 if (DBG) logd("EVENT_EMERGENCY_NETWORK_SCAN_RESULT result=" + regResult); 262 synchronized (mLock) { 263 clearState(STATUS_WAIT_SCAN_RESULT); 264 if (mResultCallback != null) { 265 try { 266 mResultCallback.onComplete(regResult); 267 } catch (RemoteException e) { 268 loge("EVENT_EMERGENCY_NETWORK_SCAN_RESULT exception=" + e); 269 // Since remote service is not available, 270 // wait for binding or timeout. 271 waitForServiceBinding(null); 272 } 273 } 274 } 275 break; 276 case EVENT_QUALIFIED_NETWORKS_CHANGED: 277 ar = (AsyncResult) msg.obj; 278 if (ar == null || ar.result == null) { 279 loge("handleMessage EVENT_QUALIFIED_NETWORKS_CHANGED null result"); 280 break; 281 } 282 onQualifiedNetworksChanged((List<QualifiedNetworks>) ar.result); 283 break; 284 case EVENT_SERVICE_CONNECTED: 285 synchronized (mLock) { 286 if (checkState(STATUS_DISPOSED) || !checkState(STATUS_WAIT_BINDING)) { 287 loge("EVENT_SERVICE_CONNECTED disposed or not waiting for binding"); 288 break; 289 } 290 if (mController.selectDomain(mSelectionAttributes, 291 mTransportSelectorCallback)) { 292 clearWaitingForServiceBinding(); 293 } 294 } 295 break; 296 case EVENT_SERVICE_BINDING_TIMEOUT: 297 synchronized (mLock) { 298 if (!checkState(STATUS_DISPOSED) && checkState(STATUS_WAIT_BINDING)) { 299 onServiceBindingTimeout(); 300 } 301 } 302 break; 303 case EVENT_RESET_NETWORK_SCAN_DONE: 304 synchronized (mLock) { 305 clearState(STATUS_WAIT_RESET_SCAN_RESULT); 306 if (checkState(STATUS_DISPOSED) 307 || (mPendingScanRequest == null)) { 308 return; 309 } 310 onRequestEmergencyNetworkScan(mPendingScanRequest.mPreferredNetworks, 311 mPendingScanRequest.mScanType, false); 312 } 313 break; 314 case EVENT_TRIGGER_NETWORK_SCAN_DONE: 315 synchronized (mLock) { 316 if (checkState(STATUS_DISPOSED) || !checkState(STATUS_WAIT_SCAN_RESULT)) { 317 return; 318 } 319 ar = (AsyncResult) msg.obj; 320 if (ar != null && ar.exception != null) { 321 onTriggerNetworkScanError((Integer) ar.userObj, 322 ((CommandException) ar.exception).getCommandError()); 323 } 324 } 325 break; 326 case EVENT_MODEM_RESET: 327 synchronized (mLock) { 328 onModemReset(); 329 } 330 break; 331 default: 332 loge("handleMessage unexpected msg=" + msg.what); 333 break; 334 } 335 } 336 } 337 338 protected String mTag = "DomainSelectionConnection"; 339 340 private final Object mLock = new Object(); 341 private final LocalLog mLocalLog = new LocalLog(30); 342 private final @NonNull ITransportSelectorCallback mTransportSelectorCallback; 343 344 /** 345 * Controls the communication between {@link DomainSelectionConnection} and 346 * {@link DomainSelectionService}. 347 */ 348 private final @NonNull DomainSelectionController mController; 349 /** Indicates whether the requested service is for emergency services. */ 350 private final boolean mIsEmergency; 351 352 /** Interface to receive the request to trigger emergency network scan and selected domain. */ 353 private @Nullable IWwanSelectorCallback mWwanSelectorCallback; 354 /** Interface to return the result of emergency network scan. */ 355 private @Nullable IWwanSelectorResultCallback mResultCallback; 356 /** Interface to the {@link DomainSelector} created for this service. */ 357 private @Nullable IDomainSelector mDomainSelector; 358 359 /** The bit-wise OR of STATUS_* values. */ 360 private int mStatus; 361 362 /** The slot requested this connection. */ 363 protected @NonNull Phone mPhone; 364 /** The requested domain selector type. */ 365 private @DomainSelectionService.SelectorType int mSelectorType; 366 367 /** The attributes required to determine the domain. */ 368 private @Nullable DomainSelectionService.SelectionAttributes mSelectionAttributes; 369 370 private final @NonNull Looper mLooper; 371 protected @Nullable DomainSelectionConnectionHandler mHandler; 372 private boolean mRegisteredRegistrant; 373 374 private @NonNull AndroidFuture<Integer> mOnComplete; 375 376 private @Nullable ScanRequest mPendingScanRequest; 377 378 private boolean mIsTestMode = false; 379 380 private int mDisconnectCause = DisconnectCause.NOT_VALID; 381 private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID; 382 private String mReasonMessage = null; 383 384 /** 385 * Creates an instance. 386 * 387 * @param phone For which this service is requested. 388 * @param selectorType Indicates the type of the requested service. 389 * @param isEmergency Indicates whether this request is for emergency service. 390 * @param controller The controller to communicate with the domain selection service. 391 */ DomainSelectionConnection(@onNull Phone phone, @DomainSelectionService.SelectorType int selectorType, boolean isEmergency, @NonNull DomainSelectionController controller)392 public DomainSelectionConnection(@NonNull Phone phone, 393 @DomainSelectionService.SelectorType int selectorType, boolean isEmergency, 394 @NonNull DomainSelectionController controller) { 395 mController = controller; 396 mPhone = phone; 397 mSelectorType = selectorType; 398 mIsEmergency = isEmergency; 399 mLooper = Looper.getMainLooper(); 400 401 mTransportSelectorCallback = new TransportSelectorCallbackAdaptor(); 402 mOnComplete = new AndroidFuture<>(); 403 } 404 405 /** 406 * Returns the attributes required to determine the domain for a telephony service. 407 * 408 * @return The attributes required to determine the domain. 409 */ getSelectionAttributes()410 public @Nullable DomainSelectionService.SelectionAttributes getSelectionAttributes() { 411 return mSelectionAttributes; 412 } 413 414 /** 415 * Returns the callback binder interface. 416 * 417 * @return The {@link ITransportSelectorCallback} interface. 418 */ getTransportSelectorCallback()419 public @Nullable ITransportSelectorCallback getTransportSelectorCallback() { 420 return mTransportSelectorCallback; 421 } 422 423 /** 424 * Returns the callback binder interface to handle the emergency scan result. 425 * 426 * @return The {@link IWwanSelectorResultCallback} interface. 427 */ getWwanSelectorResultCallback()428 public @Nullable IWwanSelectorResultCallback getWwanSelectorResultCallback() { 429 return mResultCallback; 430 } 431 432 /** 433 * Returns the {@link CompletableFuture} to receive the selected domain. 434 * 435 * @return The callback to receive response. 436 */ getCompletableFuture()437 public @NonNull CompletableFuture<Integer> getCompletableFuture() { 438 return mOnComplete; 439 } 440 441 /** 442 * Returs the {@link Phone} which requested this connection. 443 * 444 * @return The {@link Phone} instance. 445 */ getPhone()446 public @NonNull Phone getPhone() { 447 return mPhone; 448 } 449 450 /** 451 * Requests the domain selection service to select a domain. 452 * 453 * @param attr The attributes required to determine the domain. 454 */ 455 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) selectDomain(@onNull DomainSelectionService.SelectionAttributes attr)456 public void selectDomain(@NonNull DomainSelectionService.SelectionAttributes attr) { 457 synchronized (mLock) { 458 mSelectionAttributes = attr; 459 if (mController.selectDomain(attr, mTransportSelectorCallback)) { 460 clearWaitingForServiceBinding(); 461 } else { 462 waitForServiceBinding(attr); 463 } 464 } 465 } 466 467 /** 468 * Notifies that {@link DomainSelector} instance has been created for the selection request. 469 */ onCreated()470 public void onCreated() { 471 // Can be overridden if required 472 } 473 474 /** 475 * Notifies that WLAN transport has been selected. 476 */ onWlanSelected()477 public void onWlanSelected() { 478 // Can be overridden. 479 } 480 481 /** 482 * Notifies that WLAN transport has been selected. 483 * 484 * @param useEmergencyPdn Indicates whether Wi-Fi emergency services use emergency PDN or not. 485 */ onWlanSelected(boolean useEmergencyPdn)486 public void onWlanSelected(boolean useEmergencyPdn) { 487 // Can be overridden. 488 onWlanSelected(); 489 } 490 491 /** 492 * Notifies that WWAN transport has been selected. 493 */ onWwanSelected()494 public void onWwanSelected() { 495 // Can be overridden. 496 } 497 498 /** 499 * Notifies that selection has terminated because there is no decision that can be made 500 * or a timeout has occurred. The call should be terminated when this method is called. 501 * 502 * @param cause Indicates the reason. 503 */ onSelectionTerminated(@isconnectCauses int cause)504 public void onSelectionTerminated(@DisconnectCauses int cause) { 505 // Can be overridden. 506 } 507 508 /** 509 * Requests the emergency network scan. 510 * 511 * @param preferredNetworks The ordered list of preferred networks to scan. 512 * @param scanType Indicates the scan preference, such as full service or limited service. 513 * @param resetScan Indicates that the previous scan result shall be reset before scanning. 514 */ onRequestEmergencyNetworkScan( @onNull @adioAccessNetworkType int[] preferredNetworks, @EmergencyScanType int scanType, boolean resetScan)515 public void onRequestEmergencyNetworkScan( 516 @NonNull @RadioAccessNetworkType int[] preferredNetworks, 517 @EmergencyScanType int scanType, boolean resetScan) { 518 // Can be overridden if required 519 520 synchronized (mLock) { 521 if (mHandler == null 522 || checkState(STATUS_DISPOSED) 523 || checkState(STATUS_WAIT_SCAN_RESULT)) { 524 logi("onRequestEmergencyNetworkScan waitResult=" 525 + checkState(STATUS_WAIT_SCAN_RESULT)); 526 return; 527 } 528 529 if (checkState(STATUS_WAIT_RESET_SCAN_RESULT)) { 530 if (mPendingScanRequest != null) { 531 /* Consecutive scan requests without cancellation is not an expected use case. 532 * DomainSelector should cancel the previous request or wait for the result 533 * before requesting a new scan.*/ 534 logi("onRequestEmergencyNetworkScan consecutive scan requests"); 535 return; 536 } else { 537 // The reset has not been completed. 538 // case1) Long delay in cancelEmergencyNetworkScan by modem. 539 // case2) A consecutive scan requests with short interval from DomainSelector. 540 logi("onRequestEmergencyNetworkScan reset not completed"); 541 } 542 mPendingScanRequest = new ScanRequest(preferredNetworks, scanType); 543 return; 544 } else if (resetScan) { 545 setState(STATUS_WAIT_RESET_SCAN_RESULT); 546 mPendingScanRequest = new ScanRequest(preferredNetworks, scanType); 547 mPhone.cancelEmergencyNetworkScan(resetScan, 548 mHandler.obtainMessage(EVENT_RESET_NETWORK_SCAN_DONE)); 549 return; 550 } 551 552 if (!mRegisteredRegistrant) { 553 mPhone.registerForEmergencyNetworkScan(mHandler, 554 EVENT_EMERGENCY_NETWORK_SCAN_RESULT, null); 555 mPhone.mCi.registerForModemReset(mHandler, EVENT_MODEM_RESET, null); 556 mRegisteredRegistrant = true; 557 } 558 setState(STATUS_WAIT_SCAN_RESULT); 559 mPhone.triggerEmergencyNetworkScan(preferredNetworks, scanType, 560 mHandler.obtainMessage(EVENT_TRIGGER_NETWORK_SCAN_DONE, 561 Integer.valueOf(scanType))); 562 mPendingScanRequest = null; 563 } 564 } 565 566 /** 567 * Notifies the domain selected. 568 * 569 * @param domain The selected domain. 570 */ onDomainSelected(@etworkRegistrationInfo.Domain int domain)571 public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { 572 // Can be overridden if required 573 CompletableFuture<Integer> future = getCompletableFuture(); 574 future.complete(domain); 575 } 576 577 /** 578 * Notifies the domain selected. 579 * 580 * @param domain The selected domain. 581 * @param useEmergencyPdn Indicates whether emergency services use emergency PDN or not. 582 */ onDomainSelected(@etworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn)583 public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, 584 boolean useEmergencyPdn) { 585 // Can be overridden if required 586 onDomainSelected(domain); 587 } 588 589 /** 590 * Notifies that the emergency network scan is canceled. 591 */ onCancel()592 public void onCancel() { 593 // Can be overridden if required 594 onCancel(false); 595 } 596 onCancel(boolean resetScan)597 private void onCancel(boolean resetScan) { 598 mPendingScanRequest = null; 599 if (checkState(STATUS_WAIT_SCAN_RESULT)) { 600 clearState(STATUS_WAIT_SCAN_RESULT); 601 mPhone.cancelEmergencyNetworkScan(resetScan, null); 602 } 603 } 604 605 /** 606 * Cancels an ongoing selection operation. It is up to the {@link DomainSelectionService} 607 * to clean up all ongoing operations with the framework. 608 */ cancelSelection()609 public void cancelSelection() { 610 finishSelection(); 611 } 612 613 /** 614 * Requests the domain selection service to reselect a domain. 615 * 616 * @param attr The attributes required to determine the domain. 617 * @return The callback to receive the response. 618 */ reselectDomain( @onNull DomainSelectionService.SelectionAttributes attr)619 public @NonNull CompletableFuture<Integer> reselectDomain( 620 @NonNull DomainSelectionService.SelectionAttributes attr) { 621 synchronized (mLock) { 622 mSelectionAttributes = attr; 623 mOnComplete = new AndroidFuture<>(); 624 clearState(STATUS_DOMAIN_SELECTED); 625 try { 626 if (mDomainSelector == null) { 627 // Service connection has been disconnected. 628 mSelectionAttributes = getSelectionAttributesToRebindService(); 629 if (mController.selectDomain(mSelectionAttributes, 630 mTransportSelectorCallback)) { 631 clearWaitingForServiceBinding(); 632 } else { 633 waitForServiceBinding(null); 634 } 635 } else { 636 mDomainSelector.reselectDomain(attr); 637 } 638 } catch (RemoteException e) { 639 loge("reselectDomain exception=" + e); 640 // Since remote service is not available, wait for binding or timeout. 641 waitForServiceBinding(null); 642 } finally { 643 return mOnComplete; 644 } 645 } 646 } 647 648 /** 649 * Finishes the selection procedure and cleans everything up. 650 */ finishSelection()651 public void finishSelection() { 652 synchronized (mLock) { 653 try { 654 if (mDomainSelector != null) { 655 mDomainSelector.finishSelection(); 656 } 657 } catch (RemoteException e) { 658 loge("finishSelection exception=" + e); 659 } finally { 660 dispose(); 661 } 662 } 663 } 664 665 /** Indicates that the service connection has been connected. */ onServiceConnected()666 public void onServiceConnected() { 667 synchronized (mLock) { 668 if (checkState(STATUS_DISPOSED) || !checkState(STATUS_WAIT_BINDING)) { 669 logi("onServiceConnected disposed or not waiting for the binding"); 670 return; 671 } 672 initHandler(); 673 mHandler.sendEmptyMessage(EVENT_SERVICE_CONNECTED); 674 } 675 } 676 677 /** Indicates that the service connection has been removed. */ onServiceDisconnected()678 public void onServiceDisconnected() { 679 synchronized (mLock) { 680 if (mHandler != null) { 681 mHandler.removeMessages(EVENT_SERVICE_CONNECTED); 682 } 683 if (checkState(STATUS_DISPOSED) || checkState(STATUS_DOMAIN_SELECTED)) { 684 // If there is an on-going dialing, recovery shall happen 685 // when dialing fails and reselectDomain() is called. 686 mDomainSelector = null; 687 mResultCallback = null; 688 return; 689 } 690 // Since remote service is not available, wait for binding or timeout. 691 waitForServiceBinding(null); 692 } 693 } 694 waitForServiceBinding(DomainSelectionService.SelectionAttributes attr)695 private void waitForServiceBinding(DomainSelectionService.SelectionAttributes attr) { 696 if (checkState(STATUS_DISPOSED) || checkState(STATUS_WAIT_BINDING)) { 697 // Already done. 698 return; 699 } 700 setState(STATUS_WAIT_BINDING); 701 mDomainSelector = null; 702 mResultCallback = null; 703 mSelectionAttributes = (attr != null) ? attr : getSelectionAttributesToRebindService(); 704 initHandler(); 705 mHandler.sendEmptyMessageDelayed(EVENT_SERVICE_BINDING_TIMEOUT, 706 DEFAULT_BIND_RETRY_TIMEOUT_MS); 707 } 708 clearWaitingForServiceBinding()709 private void clearWaitingForServiceBinding() { 710 if (checkState(STATUS_WAIT_BINDING)) { 711 clearState(STATUS_WAIT_BINDING); 712 if (mHandler != null) { 713 mHandler.removeMessages(EVENT_SERVICE_BINDING_TIMEOUT); 714 } 715 } 716 } 717 onServiceBindingTimeout()718 protected void onServiceBindingTimeout() { 719 // Can be overridden if required 720 synchronized (mLock) { 721 if (checkState(STATUS_DISPOSED)) { 722 logi("onServiceBindingTimeout disposed"); 723 return; 724 } 725 DomainSelectionConnection.this.onSelectionTerminated( 726 getTerminationCauseForSelectionTimeout()); 727 dispose(); 728 } 729 } 730 getTerminationCauseForSelectionTimeout()731 protected int getTerminationCauseForSelectionTimeout() { 732 // Can be overridden if required 733 return DisconnectCause.TIMED_OUT; 734 } 735 736 protected DomainSelectionService.SelectionAttributes getSelectionAttributesToRebindService()737 getSelectionAttributesToRebindService() { 738 // Can be overridden if required 739 return mSelectionAttributes; 740 } 741 742 /** Returns whether the client is waiting for the service binding. */ isWaitingForServiceBinding()743 public boolean isWaitingForServiceBinding() { 744 return checkState(STATUS_WAIT_BINDING) && !checkState(STATUS_DISPOSED); 745 } 746 dispose()747 private void dispose() { 748 setState(STATUS_DISPOSED); 749 if (mRegisteredRegistrant) { 750 mPhone.unregisterForEmergencyNetworkScan(mHandler); 751 mPhone.mCi.unregisterForModemReset(mHandler); 752 mRegisteredRegistrant = false; 753 } 754 onCancel(true); 755 mController.removeConnection(this); 756 if (mHandler != null) mHandler.removeCallbacksAndMessages(null); 757 mHandler = null; 758 } 759 initHandler()760 protected void initHandler() { 761 if (mHandler == null) mHandler = new DomainSelectionConnectionHandler(mLooper); 762 } 763 764 /** 765 * Notifies the change of qualified networks. 766 */ onQualifiedNetworksChanged(List<QualifiedNetworks> networksList)767 protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) { 768 if (mIsEmergency 769 && (mSelectorType == DomainSelectionService.SELECTOR_TYPE_CALLING)) { 770 // DomainSelectionConnection for emergency calls shall override this. 771 throw new IllegalStateException("DomainSelectionConnection for emergency calls" 772 + " should override onQualifiedNetworksChanged()"); 773 } 774 } 775 onTriggerNetworkScanError(int scanType, CommandException.Error error)776 private void onTriggerNetworkScanError(int scanType, CommandException.Error error) { 777 loge("onTriggerNetworkScanError scanType=" + scanType + ", error=" + error); 778 779 if (shouldTerminateCallOnRadioNotAvailable() 780 && error == CommandException.Error.RADIO_NOT_AVAILABLE) { 781 clearState(STATUS_WAIT_SCAN_RESULT); 782 onSelectionTerminated(DisconnectCause.POWER_OFF); 783 dispose(); 784 return; 785 } 786 787 if (scanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE) { 788 // Handle as unknown network. 789 EmergencyRegistrationResult result = new EmergencyRegistrationResult( 790 AccessNetworkConstants.AccessNetworkType.UNKNOWN, 791 NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN, 792 NetworkRegistrationInfo.DOMAIN_UNKNOWN, false, false, 0, 0, "", "", ""); 793 794 if (mHandler != null) { 795 Message msg = mHandler.obtainMessage(EVENT_EMERGENCY_NETWORK_SCAN_RESULT, 796 new AsyncResult(null, result, null)); 797 msg.sendToTarget(); 798 } 799 } 800 } 801 onModemReset()802 private void onModemReset() { 803 loge("onModemReset status=" + mStatus); 804 if (!shouldTerminateCallOnRadioNotAvailable()) { 805 return; 806 } 807 if (checkState(STATUS_DISPOSED) || checkState(STATUS_DOMAIN_SELECTED)) { 808 return; 809 } 810 onSelectionTerminated(DisconnectCause.POWER_OFF); 811 dispose(); 812 } 813 shouldTerminateCallOnRadioNotAvailable()814 private boolean shouldTerminateCallOnRadioNotAvailable() { 815 return mIsEmergency && mSelectorType == DomainSelectionService.SELECTOR_TYPE_CALLING; 816 } 817 818 /** 819 * Get the preferred transport. 820 * 821 * @param apnType APN type. 822 * @return The preferred transport. 823 */ 824 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) getPreferredTransport(@pnType int apnType, List<QualifiedNetworks> networksList)825 public int getPreferredTransport(@ApnType int apnType, 826 List<QualifiedNetworks> networksList) { 827 for (QualifiedNetworks networks : networksList) { 828 if (networks.qualifiedNetworks.length > 0) { 829 if (networks.apnType == apnType) { 830 return getTransportFromAccessNetwork(networks.qualifiedNetworks[0]); 831 } 832 } 833 } 834 835 loge("getPreferredTransport no network found for " + ApnSetting.getApnTypeString(apnType)); 836 return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 837 } 838 getTransportFromAccessNetwork(int accessNetwork)839 private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) { 840 return accessNetwork == AccessNetworkType.IWLAN 841 ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN 842 : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 843 } 844 setState(int stateBit)845 private void setState(int stateBit) { 846 mStatus |= stateBit; 847 } 848 clearState(int stateBit)849 private void clearState(int stateBit) { 850 mStatus &= ~stateBit; 851 } 852 checkState(int stateBit)853 private boolean checkState(int stateBit) { 854 return (mStatus & stateBit) == stateBit; 855 } 856 857 /** 858 * Set whether it is unit test or not. 859 * 860 * @param testMode Indicates whether it is unit test or not. 861 */ 862 @VisibleForTesting setTestMode(boolean testMode)863 public void setTestMode(boolean testMode) { 864 mIsTestMode = testMode; 865 } 866 867 /** 868 * Save call disconnect info for error propagation. 869 * @param disconnectCause The code for the reason for the disconnect. 870 * @param preciseDisconnectCause The code for the precise reason for the disconnect. 871 * @param reasonMessage Description of the reason for the disconnect, not intended for the user 872 * to see. 873 */ setDisconnectCause(int disconnectCause, int preciseDisconnectCause, String reasonMessage)874 public void setDisconnectCause(int disconnectCause, int preciseDisconnectCause, 875 String reasonMessage) { 876 mDisconnectCause = disconnectCause; 877 mPreciseDisconnectCause = preciseDisconnectCause; 878 mReasonMessage = reasonMessage; 879 } 880 getDisconnectCause()881 public int getDisconnectCause() { 882 return mDisconnectCause; 883 } 884 getPreciseDisconnectCause()885 public int getPreciseDisconnectCause() { 886 return mPreciseDisconnectCause; 887 } 888 getReasonMessage()889 public String getReasonMessage() { 890 return mReasonMessage; 891 } 892 893 /** 894 * @return imsReasonInfo Reason for the IMS call failure. 895 */ getImsReasonInfo()896 public @Nullable ImsReasonInfo getImsReasonInfo() { 897 if (getSelectionAttributes() == null) { 898 // Neither selectDomain(...) nor reselectDomain(...) has been called yet. 899 return null; 900 } 901 902 return getSelectionAttributes().getPsDisconnectCause(); 903 } 904 905 /** 906 * @return phoneId To support localized message based on phoneId 907 */ getPhoneId()908 public int getPhoneId() { 909 return getPhone().getPhoneId(); 910 } 911 912 /** 913 * Dumps local log. 914 */ dump(@onNull PrintWriter printWriter)915 public void dump(@NonNull PrintWriter printWriter) { 916 mLocalLog.dump(printWriter); 917 } 918 logd(String msg)919 protected void logd(String msg) { 920 Log.d(mTag, msg); 921 } 922 logi(String msg)923 protected void logi(String msg) { 924 Log.i(mTag, msg); 925 mLocalLog.log(msg); 926 } 927 loge(String msg)928 protected void loge(String msg) { 929 Log.e(mTag, msg); 930 mLocalLog.log(msg); 931 } 932 } 933