1 /* 2 * Copyright 2014, 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.server.telecom; 18 19 import static android.Manifest.permission.MODIFY_PHONE_STATE; 20 21 import android.Manifest; 22 import android.app.AppOpsManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.graphics.drawable.Icon; 27 import android.location.Location; 28 import android.location.LocationManager; 29 import android.location.LocationRequest; 30 import android.net.Uri; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.CancellationSignal; 34 import android.os.IBinder; 35 import android.os.ParcelFileDescriptor; 36 import android.os.RemoteException; 37 import android.os.ResultReceiver; 38 import android.os.UserHandle; 39 import android.telecom.CallAudioState; 40 import android.telecom.CallEndpoint; 41 import android.telecom.Connection; 42 import android.telecom.ConnectionRequest; 43 import android.telecom.ConnectionService; 44 import android.telecom.DisconnectCause; 45 import android.telecom.GatewayInfo; 46 import android.telecom.Log; 47 import android.telecom.Logging.Runnable; 48 import android.telecom.Logging.Session; 49 import android.telecom.ParcelableConference; 50 import android.telecom.ParcelableConnection; 51 import android.telecom.PhoneAccountHandle; 52 import android.telecom.QueryLocationException; 53 import android.telecom.StatusHints; 54 import android.telecom.TelecomManager; 55 import android.telecom.VideoProfile; 56 import android.telephony.CellIdentity; 57 import android.telephony.TelephonyManager; 58 import android.util.Pair; 59 60 import androidx.annotation.Nullable; 61 62 import com.android.internal.annotations.VisibleForTesting; 63 import com.android.internal.telecom.IConnectionService; 64 import com.android.internal.telecom.IConnectionServiceAdapter; 65 import com.android.internal.telecom.IVideoProvider; 66 import com.android.internal.telecom.RemoteServiceCallback; 67 import com.android.internal.util.Preconditions; 68 import com.android.server.telecom.flags.FeatureFlags; 69 70 import java.util.ArrayList; 71 import java.util.Collection; 72 import java.util.Collections; 73 import java.util.HashMap; 74 import java.util.List; 75 import java.util.Map; 76 import java.util.Set; 77 import java.util.UUID; 78 import java.util.concurrent.CompletableFuture; 79 import java.util.concurrent.ConcurrentHashMap; 80 import java.util.concurrent.ExecutorService; 81 import java.util.concurrent.Executors; 82 import java.util.concurrent.ScheduledExecutorService; 83 import java.util.concurrent.ScheduledFuture; 84 import java.util.concurrent.TimeUnit; 85 import java.util.Objects; 86 87 /** 88 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps 89 * track of when the object can safely be unbound. Other classes should not use 90 * {@link IConnectionService} directly and instead should use this class to invoke methods of 91 * {@link IConnectionService}. 92 */ 93 @VisibleForTesting 94 public class ConnectionServiceWrapper extends ServiceBinder implements 95 ConnectionServiceFocusManager.ConnectionServiceFocus, CallSourceService { 96 97 /** 98 * Anomaly Report UUIDs and corresponding error descriptions specific to CallsManager. 99 */ 100 public static final UUID CREATE_CONNECTION_TIMEOUT_ERROR_UUID = 101 UUID.fromString("54b7203d-a79f-4cbd-b639-85cd93a39cbb"); 102 public static final String CREATE_CONNECTION_TIMEOUT_ERROR_MSG = 103 "Timeout expired before Telecom connection was created."; 104 public static final UUID CREATE_CONFERENCE_TIMEOUT_ERROR_UUID = 105 UUID.fromString("caafe5ea-2472-4c61-b2d8-acb9d47e13dd"); 106 public static final String CREATE_CONFERENCE_TIMEOUT_ERROR_MSG = 107 "Timeout expired before Telecom conference was created."; 108 109 private static final String TELECOM_ABBREVIATION = "cast"; 110 private static final long SERVICE_BINDING_TIMEOUT = 15000L; 111 private CompletableFuture<Pair<Integer, Location>> mQueryLocationFuture = null; 112 private @Nullable CancellationSignal mOngoingQueryLocationRequest = null; 113 private final ExecutorService mQueryLocationExecutor = Executors.newSingleThreadExecutor(); 114 private ScheduledExecutorService mScheduledExecutor = 115 Executors.newSingleThreadScheduledExecutor(); 116 // Pre-allocate space for 2 calls; realistically thats all we should ever need (tm) 117 private final Map<Call, ScheduledFuture<?>> mScheduledFutureMap = new ConcurrentHashMap<>(2); 118 private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl(); 119 private final class Adapter extends IConnectionServiceAdapter.Stub { 120 121 @Override handleCreateConnectionComplete(String callId, ConnectionRequest request, ParcelableConnection connection, Session.Info sessionInfo)122 public void handleCreateConnectionComplete(String callId, ConnectionRequest request, 123 ParcelableConnection connection, Session.Info sessionInfo) { 124 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE, 125 mPackageAbbreviation); 126 UserHandle callingUserHandle = Binder.getCallingUserHandle(); 127 long token = Binder.clearCallingIdentity(); 128 try { 129 synchronized (mLock) { 130 logIncoming("handleCreateConnectionComplete %s", callId); 131 Call call = mCallIdMapper.getCall(callId); 132 if (mScheduledFutureMap.containsKey(call)) { 133 ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call); 134 existingTimeout.cancel(false /* cancelIfRunning */); 135 mScheduledFutureMap.remove(call); 136 } 137 // Check status hints image for cross user access 138 if (connection.getStatusHints() != null) { 139 Icon icon = connection.getStatusHints().getIcon(); 140 connection.getStatusHints().setIcon(StatusHints. 141 validateAccountIconUserBoundary(icon, callingUserHandle)); 142 } 143 ConnectionServiceWrapper.this 144 .handleCreateConnectionComplete(callId, request, connection); 145 146 if (mServiceInterface != null) { 147 logOutgoing("createConnectionComplete %s", callId); 148 try { 149 mServiceInterface.createConnectionComplete(callId, 150 Log.getExternalSession()); 151 } catch (RemoteException e) { 152 logOutgoing("createConnectionComplete remote exception=%s", e); 153 } 154 } 155 } 156 } catch (Throwable t) { 157 Log.e(ConnectionServiceWrapper.this, t, ""); 158 throw t; 159 } finally { 160 Binder.restoreCallingIdentity(token); 161 Log.endSession(); 162 } 163 } 164 165 @Override handleCreateConferenceComplete(String callId, ConnectionRequest request, ParcelableConference conference, Session.Info sessionInfo)166 public void handleCreateConferenceComplete(String callId, ConnectionRequest request, 167 ParcelableConference conference, Session.Info sessionInfo) { 168 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE, 169 mPackageAbbreviation); 170 UserHandle callingUserHandle = Binder.getCallingUserHandle(); 171 long token = Binder.clearCallingIdentity(); 172 try { 173 synchronized (mLock) { 174 logIncoming("handleCreateConferenceComplete %s", callId); 175 // Check status hints image for cross user access 176 if (conference.getStatusHints() != null) { 177 Icon icon = conference.getStatusHints().getIcon(); 178 conference.getStatusHints().setIcon(StatusHints. 179 validateAccountIconUserBoundary(icon, callingUserHandle)); 180 } 181 Call call = mCallIdMapper.getCall(callId); 182 if (mScheduledFutureMap.containsKey(call)) { 183 ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call); 184 existingTimeout.cancel(false /* cancelIfRunning */); 185 mScheduledFutureMap.remove(call); 186 } 187 ConnectionServiceWrapper.this 188 .handleCreateConferenceComplete(callId, request, conference); 189 190 if (mServiceInterface != null) { 191 logOutgoing("createConferenceComplete %s", callId); 192 try { 193 mServiceInterface.createConferenceComplete(callId, 194 Log.getExternalSession()); 195 } catch (RemoteException e) { 196 } 197 } 198 } 199 } catch (Throwable t) { 200 Log.e(ConnectionServiceWrapper.this, t, ""); 201 throw t; 202 } finally { 203 Binder.restoreCallingIdentity(token); 204 Log.endSession(); 205 } 206 } 207 208 209 @Override setActive(String callId, Session.Info sessionInfo)210 public void setActive(String callId, Session.Info sessionInfo) { 211 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE, 212 mPackageAbbreviation); 213 long token = Binder.clearCallingIdentity(); 214 try { 215 synchronized (mLock) { 216 logIncoming("setActive %s", callId); 217 Call call = mCallIdMapper.getCall(callId); 218 if (call != null) { 219 mCallsManager.markCallAsActive(call); 220 } else { 221 // Log.w(this, "setActive, unknown call id: %s", msg.obj); 222 } 223 } 224 } catch (Throwable t) { 225 Log.e(ConnectionServiceWrapper.this, t, ""); 226 throw t; 227 } finally { 228 Binder.restoreCallingIdentity(token); 229 Log.endSession(); 230 } 231 } 232 233 @Override setRinging(String callId, Session.Info sessionInfo)234 public void setRinging(String callId, Session.Info sessionInfo) { 235 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING, mPackageAbbreviation); 236 long token = Binder.clearCallingIdentity(); 237 try { 238 synchronized (mLock) { 239 logIncoming("setRinging %s", callId); 240 Call call = mCallIdMapper.getCall(callId); 241 if (call != null) { 242 mCallsManager.markCallAsRinging(call); 243 } else { 244 // Log.w(this, "setRinging, unknown call id: %s", msg.obj); 245 } 246 } 247 } catch (Throwable t) { 248 Log.e(ConnectionServiceWrapper.this, t, ""); 249 throw t; 250 } finally { 251 Binder.restoreCallingIdentity(token); 252 Log.endSession(); 253 } 254 } 255 256 @Override resetConnectionTime(String callId, Session.Info sessionInfo)257 public void resetConnectionTime(String callId, Session.Info sessionInfo) { 258 Log.startSession(sessionInfo, "CSW.rCCT", mPackageAbbreviation); 259 long token = Binder.clearCallingIdentity(); 260 try { 261 synchronized (mLock) { 262 logIncoming("resetConnectionTime %s", callId); 263 Call call = mCallIdMapper.getCall(callId); 264 if (call != null) { 265 mCallsManager.resetConnectionTime(call); 266 } else { 267 // Log.w(this, "resetConnectionTime, unknown call id: %s", msg.obj); 268 } 269 } 270 } finally { 271 Binder.restoreCallingIdentity(token); 272 Log.endSession(); 273 } 274 } 275 276 @Override setVideoProvider(String callId, IVideoProvider videoProvider, Session.Info sessionInfo)277 public void setVideoProvider(String callId, IVideoProvider videoProvider, 278 Session.Info sessionInfo) { 279 Log.startSession(sessionInfo, "CSW.sVP", mPackageAbbreviation); 280 long token = Binder.clearCallingIdentity(); 281 try { 282 synchronized (mLock) { 283 logIncoming("setVideoProvider %s", callId); 284 Call call = mCallIdMapper.getCall(callId); 285 if (call != null) { 286 call.setVideoProvider(videoProvider); 287 } 288 } 289 } catch (Throwable t) { 290 Log.e(ConnectionServiceWrapper.this, t, ""); 291 throw t; 292 } finally { 293 Binder.restoreCallingIdentity(token); 294 Log.endSession(); 295 } 296 } 297 298 @Override setDialing(String callId, Session.Info sessionInfo)299 public void setDialing(String callId, Session.Info sessionInfo) { 300 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING, mPackageAbbreviation); 301 long token = Binder.clearCallingIdentity(); 302 try { 303 synchronized (mLock) { 304 logIncoming("setDialing %s", callId); 305 Call call = mCallIdMapper.getCall(callId); 306 if (call != null) { 307 mCallsManager.markCallAsDialing(call); 308 } else { 309 // Log.w(this, "setDialing, unknown call id: %s", msg.obj); 310 } 311 } 312 } catch (Throwable t) { 313 Log.e(ConnectionServiceWrapper.this, t, ""); 314 throw t; 315 } finally { 316 Binder.restoreCallingIdentity(token); 317 Log.endSession(); 318 } 319 } 320 321 @Override setPulling(String callId, Session.Info sessionInfo)322 public void setPulling(String callId, Session.Info sessionInfo) { 323 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING, mPackageAbbreviation); 324 long token = Binder.clearCallingIdentity(); 325 try { 326 synchronized (mLock) { 327 logIncoming("setPulling %s", callId); 328 Call call = mCallIdMapper.getCall(callId); 329 if (call != null) { 330 mCallsManager.markCallAsPulling(call); 331 } 332 } 333 } catch (Throwable t) { 334 Log.e(ConnectionServiceWrapper.this, t, ""); 335 throw t; 336 } finally { 337 Binder.restoreCallingIdentity(token); 338 Log.endSession(); 339 } 340 } 341 342 @Override setDisconnected(String callId, DisconnectCause disconnectCause, Session.Info sessionInfo)343 public void setDisconnected(String callId, DisconnectCause disconnectCause, 344 Session.Info sessionInfo) { 345 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED, 346 mPackageAbbreviation); 347 long token = Binder.clearCallingIdentity(); 348 try { 349 synchronized (mLock) { 350 logIncoming("setDisconnected %s %s", callId, disconnectCause); 351 Call call = mCallIdMapper.getCall(callId); 352 Log.d(this, "disconnect call %s %s", disconnectCause, call); 353 if (call != null) { 354 mCallsManager.markCallAsDisconnected(call, disconnectCause); 355 } else { 356 // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1); 357 } 358 } 359 } catch (Throwable t) { 360 Log.e(ConnectionServiceWrapper.this, t, ""); 361 throw t; 362 } finally { 363 Binder.restoreCallingIdentity(token); 364 Log.endSession(); 365 } 366 } 367 368 @Override setOnHold(String callId, Session.Info sessionInfo)369 public void setOnHold(String callId, Session.Info sessionInfo) { 370 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD, mPackageAbbreviation); 371 long token = Binder.clearCallingIdentity(); 372 try { 373 synchronized (mLock) { 374 logIncoming("setOnHold %s", callId); 375 Call call = mCallIdMapper.getCall(callId); 376 if (call != null) { 377 mCallsManager.markCallAsOnHold(call); 378 } else { 379 // Log.w(this, "setOnHold, unknown call id: %s", msg.obj); 380 } 381 } 382 } catch (Throwable t) { 383 Log.e(ConnectionServiceWrapper.this, t, ""); 384 throw t; 385 } finally { 386 Binder.restoreCallingIdentity(token); 387 Log.endSession(); 388 } 389 } 390 391 @Override setRingbackRequested(String callId, boolean ringback, Session.Info sessionInfo)392 public void setRingbackRequested(String callId, boolean ringback, 393 Session.Info sessionInfo) { 394 Log.startSession(sessionInfo, "CSW.SRR", mPackageAbbreviation); 395 long token = Binder.clearCallingIdentity(); 396 try { 397 synchronized (mLock) { 398 logIncoming("setRingbackRequested %s %b", callId, ringback); 399 Call call = mCallIdMapper.getCall(callId); 400 if (call != null) { 401 call.setRingbackRequested(ringback); 402 } else { 403 // Log.w(this, "setRingback, unknown call id: %s", args.arg1); 404 } 405 } 406 } catch (Throwable t) { 407 Log.e(ConnectionServiceWrapper.this, t, ""); 408 throw t; 409 } finally { 410 Binder.restoreCallingIdentity(token); 411 Log.endSession(); 412 } 413 } 414 415 @Override removeCall(String callId, Session.Info sessionInfo)416 public void removeCall(String callId, Session.Info sessionInfo) { 417 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL, mPackageAbbreviation); 418 long token = Binder.clearCallingIdentity(); 419 try { 420 synchronized (mLock) { 421 logIncoming("removeCall %s", callId); 422 Call call = mCallIdMapper.getCall(callId); 423 if (call != null) { 424 boolean isRemovalPending = mFlags.cancelRemovalOnEmergencyRedial() 425 && call.isRemovalPending(); 426 if (call.isAlive() && !call.isDisconnectHandledViaFuture() 427 && !isRemovalPending) { 428 Log.w(this, "call not disconnected when removeCall" 429 + " called, marking disconnected first."); 430 mCallsManager.markCallAsDisconnected( 431 call, new DisconnectCause(DisconnectCause.REMOTE)); 432 } 433 mCallsManager.markCallAsRemoved(call); 434 } 435 } 436 } catch (Throwable t) { 437 Log.e(ConnectionServiceWrapper.this, t, ""); 438 throw t; 439 } finally { 440 Binder.restoreCallingIdentity(token); 441 Log.endSession(); 442 } 443 } 444 445 @Override setConnectionCapabilities(String callId, int connectionCapabilities, Session.Info sessionInfo)446 public void setConnectionCapabilities(String callId, int connectionCapabilities, 447 Session.Info sessionInfo) { 448 Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation); 449 long token = Binder.clearCallingIdentity(); 450 try { 451 synchronized (mLock) { 452 logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities); 453 Call call = mCallIdMapper.getCall(callId); 454 if (call != null) { 455 call.setConnectionCapabilities(connectionCapabilities); 456 } else { 457 // Log.w(ConnectionServiceWrapper.this, 458 // "setConnectionCapabilities, unknown call id: %s", msg.obj); 459 } 460 } 461 } catch (Throwable t) { 462 Log.e(ConnectionServiceWrapper.this, t, ""); 463 throw t; 464 } finally { 465 Binder.restoreCallingIdentity(token); 466 Log.endSession(); 467 } 468 } 469 470 @Override setConnectionProperties(String callId, int connectionProperties, Session.Info sessionInfo)471 public void setConnectionProperties(String callId, int connectionProperties, 472 Session.Info sessionInfo) { 473 Log.startSession("CSW.sCP", mPackageAbbreviation); 474 long token = Binder.clearCallingIdentity(); 475 try { 476 synchronized (mLock) { 477 logIncoming("setConnectionProperties %s %d", callId, connectionProperties); 478 Call call = mCallIdMapper.getCall(callId); 479 if (call != null) { 480 call.setConnectionProperties(connectionProperties); 481 } 482 } 483 } catch (Throwable t) { 484 Log.e(ConnectionServiceWrapper.this, t, ""); 485 throw t; 486 } finally { 487 Binder.restoreCallingIdentity(token); 488 Log.endSession(); 489 } 490 } 491 492 @Override setIsConferenced(String callId, String conferenceCallId, Session.Info sessionInfo)493 public void setIsConferenced(String callId, String conferenceCallId, 494 Session.Info sessionInfo) { 495 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED, 496 mPackageAbbreviation); 497 long token = Binder.clearCallingIdentity(); 498 try { 499 synchronized (mLock) { 500 logIncoming("setIsConferenced %s %s", callId, conferenceCallId); 501 Call childCall = mCallIdMapper.getCall(callId); 502 if (childCall != null) { 503 if (conferenceCallId == null) { 504 Log.d(this, "unsetting parent: %s", conferenceCallId); 505 childCall.setParentAndChildCall(null); 506 } else { 507 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId); 508 // In a situation where a cmgr is used, the conference should be tracked 509 // by that cmgr's instance of CSW. The cmgr instance of CSW will track 510 // and properly set the parent and child calls so the request from the 511 // original Telephony instance of CSW can be ignored. 512 if (conferenceCall != null){ 513 childCall.setParentAndChildCall(conferenceCall); 514 } 515 } 516 } else { 517 // Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1); 518 } 519 } 520 } catch (Throwable t) { 521 Log.e(ConnectionServiceWrapper.this, t, ""); 522 throw t; 523 } finally { 524 Binder.restoreCallingIdentity(token); 525 Log.endSession(); 526 } 527 } 528 529 @Override setConferenceMergeFailed(String callId, Session.Info sessionInfo)530 public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) { 531 Log.startSession(sessionInfo, "CSW.sCMF", mPackageAbbreviation); 532 long token = Binder.clearCallingIdentity(); 533 try { 534 synchronized (mLock) { 535 logIncoming("setConferenceMergeFailed %s", callId); 536 // TODO: we should move the UI for indication a merge failure here 537 // from CallNotifier.onSuppServiceFailed(). This way the InCallUI can 538 // deliver the message anyway that they want. b/20530631. 539 Call call = mCallIdMapper.getCall(callId); 540 if (call != null) { 541 call.onConnectionEvent(Connection.EVENT_CALL_MERGE_FAILED, null); 542 } else { 543 Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId); 544 } 545 } 546 } catch (Throwable t) { 547 Log.e(ConnectionServiceWrapper.this, t, ""); 548 throw t; 549 } finally { 550 Binder.restoreCallingIdentity(token); 551 Log.endSession(); 552 } 553 } 554 555 @Override addConferenceCall(String callId, ParcelableConference parcelableConference, Session.Info sessionInfo)556 public void addConferenceCall(String callId, ParcelableConference parcelableConference, 557 Session.Info sessionInfo) { 558 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL, 559 mPackageAbbreviation); 560 561 UserHandle callingUserHandle = Binder.getCallingUserHandle(); 562 // Check status hints image for cross user access 563 if (parcelableConference.getStatusHints() != null) { 564 Icon icon = parcelableConference.getStatusHints().getIcon(); 565 parcelableConference.getStatusHints().setIcon(StatusHints 566 .validateAccountIconUserBoundary(icon, callingUserHandle)); 567 } 568 569 if (parcelableConference.getConnectElapsedTimeMillis() != 0 570 && mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 571 != PackageManager.PERMISSION_GRANTED) { 572 Log.w(this, "addConferenceCall from caller without permission!"); 573 parcelableConference = new ParcelableConference.Builder( 574 parcelableConference.getPhoneAccount(), 575 parcelableConference.getState()) 576 .setConnectionCapabilities(parcelableConference.getConnectionCapabilities()) 577 .setConnectionProperties(parcelableConference.getConnectionProperties()) 578 .setConnectionIds(parcelableConference.getConnectionIds()) 579 .setVideoAttributes(parcelableConference.getVideoProvider(), 580 parcelableConference.getVideoState()) 581 .setStatusHints(parcelableConference.getStatusHints()) 582 .setExtras(parcelableConference.getExtras()) 583 .setAddress(parcelableConference.getHandle(), 584 parcelableConference.getHandlePresentation()) 585 // no caller display name set. 586 .setDisconnectCause(parcelableConference.getDisconnectCause()) 587 .setRingbackRequested(parcelableConference.isRingbackRequested()) 588 .build(); 589 } 590 591 long token = Binder.clearCallingIdentity(); 592 try { 593 synchronized (mLock) { 594 if (mCallIdMapper.getCall(callId) != null) { 595 Log.w(this, "Attempting to add a conference call using an existing " + 596 "call id %s", callId); 597 return; 598 } 599 logIncoming("addConferenceCall %s %s [%s]", callId, parcelableConference, 600 parcelableConference.getConnectionIds()); 601 602 // Make sure that there's at least one valid call. For remote connections 603 // we'll get a add conference msg from both the remote connection service 604 // and from the real connection service. 605 boolean hasValidCalls = false; 606 for (String connId : parcelableConference.getConnectionIds()) { 607 if (mCallIdMapper.getCall(connId) != null) { 608 hasValidCalls = true; 609 } 610 } 611 // But don't bail out if the connection count is 0, because that is a valid 612 // IMS conference state. 613 if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) { 614 Log.d(this, "Attempting to add a conference with no valid calls"); 615 return; 616 } 617 618 PhoneAccountHandle phAcc = null; 619 if (parcelableConference != null && 620 parcelableConference.getPhoneAccount() != null) { 621 phAcc = parcelableConference.getPhoneAccount(); 622 } 623 624 Bundle connectionExtras = parcelableConference.getExtras(); 625 626 String connectIdToCheck = null; 627 if (connectionExtras != null && connectionExtras 628 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 629 // Conference was added via a connection manager, see if its original id is 630 // known. 631 connectIdToCheck = connectionExtras 632 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 633 } else { 634 connectIdToCheck = callId; 635 } 636 637 Call conferenceCall; 638 // Check to see if this conference has already been added. 639 Call alreadyAddedConnection = mCallsManager 640 .getAlreadyAddedConnection(connectIdToCheck); 641 if (alreadyAddedConnection != null && mCallIdMapper.getCall(callId) == null) { 642 // We are currently attempting to add the conference via a connection mgr, 643 // and the originating ConnectionService has already added it. Instead of 644 // making a new Telecom call, we will simply add it to the ID mapper here, 645 // and replace the ConnectionService on the call. 646 mCallIdMapper.addCall(alreadyAddedConnection, callId); 647 alreadyAddedConnection.replaceConnectionService( 648 ConnectionServiceWrapper.this); 649 conferenceCall = alreadyAddedConnection; 650 } else { 651 // need to create a new Call 652 Call newConferenceCall = mCallsManager.createConferenceCall(callId, 653 phAcc, parcelableConference); 654 mCallIdMapper.addCall(newConferenceCall, callId); 655 newConferenceCall.setConnectionService(ConnectionServiceWrapper.this); 656 conferenceCall = newConferenceCall; 657 } 658 659 Log.d(this, "adding children to conference %s phAcc %s", 660 parcelableConference.getConnectionIds(), phAcc); 661 for (String connId : parcelableConference.getConnectionIds()) { 662 Call childCall = mCallIdMapper.getCall(connId); 663 Log.d(this, "found child: %s", connId); 664 if (childCall != null) { 665 childCall.setParentAndChildCall(conferenceCall); 666 } 667 } 668 } 669 } catch (Throwable t) { 670 Log.e(ConnectionServiceWrapper.this, t, ""); 671 throw t; 672 } finally { 673 Binder.restoreCallingIdentity(token); 674 Log.endSession(); 675 } 676 } 677 678 @Override onPostDialWait(String callId, String remaining, Session.Info sessionInfo)679 public void onPostDialWait(String callId, String remaining, 680 Session.Info sessionInfo) throws RemoteException { 681 Log.startSession(sessionInfo, "CSW.oPDW", mPackageAbbreviation); 682 long token = Binder.clearCallingIdentity(); 683 try { 684 synchronized (mLock) { 685 logIncoming("onPostDialWait %s %s", callId, remaining); 686 Call call = mCallIdMapper.getCall(callId); 687 if (call != null) { 688 call.onPostDialWait(remaining); 689 } else { 690 // Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1); 691 } 692 } 693 } catch (Throwable t) { 694 Log.e(ConnectionServiceWrapper.this, t, ""); 695 throw t; 696 } finally { 697 Binder.restoreCallingIdentity(token); 698 Log.endSession(); 699 } 700 } 701 702 @Override onPostDialChar(String callId, char nextChar, Session.Info sessionInfo)703 public void onPostDialChar(String callId, char nextChar, 704 Session.Info sessionInfo) throws RemoteException { 705 Log.startSession(sessionInfo, "CSW.oPDC", mPackageAbbreviation); 706 long token = Binder.clearCallingIdentity(); 707 try { 708 synchronized (mLock) { 709 logIncoming("onPostDialChar %s %s", callId, nextChar); 710 Call call = mCallIdMapper.getCall(callId); 711 if (call != null) { 712 call.onPostDialChar(nextChar); 713 } else { 714 // Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1); 715 } 716 } 717 } catch (Throwable t) { 718 Log.e(ConnectionServiceWrapper.this, t, ""); 719 throw t; 720 } finally { 721 Binder.restoreCallingIdentity(token); 722 Log.endSession(); 723 } 724 } 725 726 @Override queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage, Session.Info sessionInfo)727 public void queryRemoteConnectionServices(RemoteServiceCallback callback, 728 String callingPackage, Session.Info sessionInfo) { 729 final UserHandle callingUserHandle = Binder.getCallingUserHandle(); 730 Log.startSession(sessionInfo, "CSW.qRCS", mPackageAbbreviation); 731 long token = Binder.clearCallingIdentity(); 732 try { 733 synchronized (mLock) { 734 logIncoming("queryRemoteConnectionServices callingPackage=" + callingPackage); 735 ConnectionServiceWrapper.this 736 .queryRemoteConnectionServices(callingUserHandle, callingPackage, 737 callback); 738 } 739 } catch (Throwable t) { 740 Log.e(ConnectionServiceWrapper.this, t, ""); 741 throw t; 742 } finally { 743 Binder.restoreCallingIdentity(token); 744 Log.endSession(); 745 } 746 } 747 748 @Override setVideoState(String callId, int videoState, Session.Info sessionInfo)749 public void setVideoState(String callId, int videoState, Session.Info sessionInfo) { 750 Log.startSession(sessionInfo, "CSW.sVS", mPackageAbbreviation); 751 long token = Binder.clearCallingIdentity(); 752 try { 753 synchronized (mLock) { 754 logIncoming("setVideoState %s %d", callId, videoState); 755 Call call = mCallIdMapper.getCall(callId); 756 if (call != null) { 757 call.setVideoState(videoState); 758 } 759 } 760 } catch (Throwable t) { 761 Log.e(ConnectionServiceWrapper.this, t, ""); 762 throw t; 763 } finally { 764 Binder.restoreCallingIdentity(token); 765 Log.endSession(); 766 } 767 } 768 769 @Override setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo)770 public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) { 771 Log.startSession(sessionInfo, "CSW.sIVAM", mPackageAbbreviation); 772 long token = Binder.clearCallingIdentity(); 773 try { 774 synchronized (mLock) { 775 logIncoming("setIsVoipAudioMode %s %b", callId, isVoip); 776 Call call = mCallIdMapper.getCall(callId); 777 if (call != null) { 778 call.setIsVoipAudioMode(isVoip); 779 } 780 } 781 } catch (Throwable t) { 782 Log.e(ConnectionServiceWrapper.this, t, ""); 783 throw t; 784 } finally { 785 Binder.restoreCallingIdentity(token); 786 Log.endSession(); 787 } 788 } 789 790 @Override setAudioRoute(String callId, int audioRoute, String bluetoothAddress, Session.Info sessionInfo)791 public void setAudioRoute(String callId, int audioRoute, 792 String bluetoothAddress, Session.Info sessionInfo) { 793 Log.startSession(sessionInfo, "CSW.sAR", mPackageAbbreviation); 794 long token = Binder.clearCallingIdentity(); 795 try { 796 synchronized (mLock) { 797 logIncoming("setAudioRoute %s %s", callId, 798 CallAudioState.audioRouteToString(audioRoute)); 799 mCallsManager.setAudioRoute(audioRoute, bluetoothAddress); 800 } 801 } catch (Throwable t) { 802 Log.e(ConnectionServiceWrapper.this, t, ""); 803 throw t; 804 } finally { 805 Binder.restoreCallingIdentity(token); 806 Log.endSession(); 807 } 808 } 809 810 @Override requestCallEndpointChange(String callId, CallEndpoint endpoint, ResultReceiver callback, Session.Info sessionInfo)811 public void requestCallEndpointChange(String callId, CallEndpoint endpoint, 812 ResultReceiver callback, Session.Info sessionInfo) { 813 Log.startSession(sessionInfo, "CSW.rCEC", mPackageAbbreviation); 814 long token = Binder.clearCallingIdentity(); 815 try { 816 synchronized (mLock) { 817 logIncoming("requestCallEndpointChange %s %s", callId, 818 endpoint.getEndpointName()); 819 mCallsManager.requestCallEndpointChange(endpoint, callback); 820 } 821 } catch (Throwable t) { 822 Log.e(ConnectionServiceWrapper.this, t, ""); 823 throw t; 824 } finally { 825 Binder.restoreCallingIdentity(token); 826 Log.endSession(); 827 } 828 } 829 830 @Override setStatusHints(String callId, StatusHints statusHints, Session.Info sessionInfo)831 public void setStatusHints(String callId, StatusHints statusHints, 832 Session.Info sessionInfo) { 833 Log.startSession(sessionInfo, "CSW.sSH", mPackageAbbreviation); 834 UserHandle callingUserHandle = Binder.getCallingUserHandle(); 835 long token = Binder.clearCallingIdentity(); 836 try { 837 synchronized (mLock) { 838 logIncoming("setStatusHints %s %s", callId, statusHints); 839 // Check status hints image for cross user access 840 if (statusHints != null) { 841 Icon icon = statusHints.getIcon(); 842 statusHints.setIcon(StatusHints.validateAccountIconUserBoundary( 843 icon, callingUserHandle)); 844 } 845 Call call = mCallIdMapper.getCall(callId); 846 if (call != null) { 847 call.setStatusHints(statusHints); 848 } 849 } 850 } catch (Throwable t) { 851 Log.e(ConnectionServiceWrapper.this, t, ""); 852 throw t; 853 } finally { 854 Binder.restoreCallingIdentity(token); 855 Log.endSession(); 856 } 857 } 858 859 @Override putExtras(String callId, Bundle extras, Session.Info sessionInfo)860 public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) { 861 Log.startSession(sessionInfo, "CSW.pE", mPackageAbbreviation); 862 long token = Binder.clearCallingIdentity(); 863 try { 864 synchronized (mLock) { 865 Bundle.setDefusable(extras, true); 866 Call call = mCallIdMapper.getCall(callId); 867 if (call != null) { 868 call.putConnectionServiceExtras(extras); 869 } 870 } 871 } catch (Throwable t) { 872 Log.e(ConnectionServiceWrapper.this, t, ""); 873 throw t; 874 } finally { 875 Binder.restoreCallingIdentity(token); 876 Log.endSession(); 877 } 878 } 879 880 @Override removeExtras(String callId, List<String> keys, Session.Info sessionInfo)881 public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) { 882 Log.startSession(sessionInfo, "CSW.rE", mPackageAbbreviation); 883 long token = Binder.clearCallingIdentity(); 884 try { 885 synchronized (mLock) { 886 logIncoming("removeExtra %s %s", callId, keys); 887 Call call = mCallIdMapper.getCall(callId); 888 if (call != null) { 889 call.removeExtras(Call.SOURCE_CONNECTION_SERVICE, keys); 890 } 891 } 892 } catch (Throwable t) { 893 Log.e(ConnectionServiceWrapper.this, t, ""); 894 throw t; 895 } finally { 896 Binder.restoreCallingIdentity(token); 897 Log.endSession(); 898 } 899 } 900 901 @Override setAddress(String callId, Uri address, int presentation, Session.Info sessionInfo)902 public void setAddress(String callId, Uri address, int presentation, 903 Session.Info sessionInfo) { 904 Log.startSession(sessionInfo, "CSW.sA", mPackageAbbreviation); 905 906 long token = Binder.clearCallingIdentity(); 907 try { 908 synchronized (mLock) { 909 logIncoming("setAddress %s %s %d", callId, address, presentation); 910 Call call = mCallIdMapper.getCall(callId); 911 if (call != null) { 912 call.setHandle(address, presentation); 913 } 914 } 915 } catch (Throwable t) { 916 Log.e(ConnectionServiceWrapper.this, t, ""); 917 throw t; 918 } finally { 919 Binder.restoreCallingIdentity(token); 920 Log.endSession(); 921 } 922 } 923 924 @Override setCallerDisplayName(String callId, String callerDisplayName, int presentation, Session.Info sessionInfo)925 public void setCallerDisplayName(String callId, String callerDisplayName, int presentation, 926 Session.Info sessionInfo) { 927 Log.startSession(sessionInfo, "CSW.sCDN", mPackageAbbreviation); 928 long token = Binder.clearCallingIdentity(); 929 try { 930 synchronized (mLock) { 931 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, 932 presentation); 933 Call call = mCallIdMapper.getCall(callId); 934 if (call != null) { 935 call.setCallerDisplayName(callerDisplayName, presentation); 936 } 937 } 938 } catch (Throwable t) { 939 Log.e(ConnectionServiceWrapper.this, t, ""); 940 throw t; 941 } finally { 942 Binder.restoreCallingIdentity(token); 943 Log.endSession(); 944 } 945 } 946 947 @Override setConferenceableConnections(String callId, List<String> conferenceableCallIds, Session.Info sessionInfo)948 public void setConferenceableConnections(String callId, List<String> conferenceableCallIds, 949 Session.Info sessionInfo) { 950 Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation); 951 long token = Binder.clearCallingIdentity(); 952 try { 953 synchronized (mLock) { 954 955 Call call = mCallIdMapper.getCall(callId); 956 if (call != null) { 957 logIncoming("setConferenceableConnections %s %s", callId, 958 conferenceableCallIds); 959 List<Call> conferenceableCalls = 960 new ArrayList<>(conferenceableCallIds.size()); 961 for (String otherId : conferenceableCallIds) { 962 Call otherCall = mCallIdMapper.getCall(otherId); 963 if (otherCall != null && otherCall != call) { 964 conferenceableCalls.add(otherCall); 965 } 966 } 967 call.setConferenceableCalls(conferenceableCalls); 968 } 969 } 970 } catch (Throwable t) { 971 Log.e(ConnectionServiceWrapper.this, t, ""); 972 throw t; 973 } finally { 974 Binder.restoreCallingIdentity(token); 975 Log.endSession(); 976 } 977 } 978 979 @Override addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo)980 public void addExistingConnection(String callId, ParcelableConnection connection, 981 Session.Info sessionInfo) { 982 Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation); 983 UserHandle userHandle = Binder.getCallingUserHandle(); 984 // Check that the Calling Package matches PhoneAccountHandle's Component Package 985 PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount(); 986 if (callingPhoneAccountHandle != null) { 987 mAppOpsManager.checkPackage(Binder.getCallingUid(), 988 callingPhoneAccountHandle.getComponentName().getPackageName()); 989 } 990 991 boolean hasCrossUserAccess = mContext.checkCallingOrSelfPermission( 992 android.Manifest.permission.INTERACT_ACROSS_USERS) 993 == PackageManager.PERMISSION_GRANTED; 994 long token = Binder.clearCallingIdentity(); 995 try { 996 synchronized (mLock) { 997 // Make sure that the PhoneAccount associated with the incoming 998 // ParcelableConnection is in fact registered to Telecom and is being called 999 // from the correct user. 1000 List<PhoneAccountHandle> accountHandles = 1001 // Include CAPABILITY_EMERGENCY_CALLS_ONLY in this list in case we are adding 1002 // an emergency call. 1003 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/, 1004 false /*includeDisabledAccounts*/, userHandle, 0 /*capabilities*/, 1005 0 /*excludedCapabilities*/, hasCrossUserAccess); 1006 PhoneAccountHandle phoneAccountHandle = null; 1007 for (PhoneAccountHandle accountHandle : accountHandles) { 1008 if(accountHandle.equals(callingPhoneAccountHandle)) { 1009 phoneAccountHandle = accountHandle; 1010 } 1011 } 1012 // Allow the Sim call manager account as well, even if its disabled. 1013 if (phoneAccountHandle == null && callingPhoneAccountHandle != null) { 1014 // Search all SIM PhoneAccounts to see if there is a SIM call manager 1015 // associated with any of them and verify that the calling handle matches. 1016 for (PhoneAccountHandle handle : 1017 mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 1018 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount( 1019 handle); 1020 PhoneAccountHandle connectionMgrHandle = 1021 mPhoneAccountRegistrar.getSimCallManager(subId, userHandle); 1022 if (callingPhoneAccountHandle.equals(connectionMgrHandle)) { 1023 phoneAccountHandle = connectionMgrHandle; 1024 break; 1025 } 1026 } 1027 } 1028 if (phoneAccountHandle != null) { 1029 logIncoming("addExistingConnection %s %s", callId, connection); 1030 1031 Bundle connectionExtras = connection.getExtras(); 1032 String connectIdToCheck = null; 1033 if (connectionExtras != null && connectionExtras 1034 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 1035 connectIdToCheck = connectionExtras 1036 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 1037 } else { 1038 connectIdToCheck = callId; 1039 } 1040 1041 // Check status hints image for cross user access 1042 if (connection.getStatusHints() != null) { 1043 Icon icon = connection.getStatusHints().getIcon(); 1044 connection.getStatusHints().setIcon(StatusHints. 1045 validateAccountIconUserBoundary(icon, userHandle)); 1046 } 1047 // Handle the case where an existing connection was added by Telephony via 1048 // a connection manager. The remote connection service API does not include 1049 // the ability to specify a parent connection when adding an existing 1050 // connection, so we stash the desired parent in the connection extras. 1051 if (connectionExtras != null 1052 && connectionExtras.containsKey( 1053 Connection.EXTRA_ADD_TO_CONFERENCE_ID) 1054 && connection.getParentCallId() == null) { 1055 String parentId = connectionExtras.getString( 1056 Connection.EXTRA_ADD_TO_CONFERENCE_ID); 1057 Log.i(ConnectionServiceWrapper.this, "addExistingConnection: remote " 1058 + "connection will auto-add to parent %s", parentId); 1059 // Replace parcelable connection instance, swapping the new desired 1060 // parent in. 1061 connection = new ParcelableConnection( 1062 connection.getPhoneAccount(), 1063 connection.getState(), 1064 connection.getConnectionCapabilities(), 1065 connection.getConnectionProperties(), 1066 connection.getSupportedAudioRoutes(), 1067 connection.getHandle(), 1068 connection.getHandlePresentation(), 1069 connection.getCallerDisplayName(), 1070 connection.getCallerDisplayNamePresentation(), 1071 connection.getVideoProvider(), 1072 connection.getVideoState(), 1073 connection.isRingbackRequested(), 1074 connection.getIsVoipAudioMode(), 1075 connection.getConnectTimeMillis(), 1076 connection.getConnectElapsedTimeMillis(), 1077 connection.getStatusHints(), 1078 connection.getDisconnectCause(), 1079 connection.getConferenceableConnectionIds(), 1080 connection.getExtras(), 1081 parentId, 1082 connection.getCallDirection(), 1083 connection.getCallerNumberVerificationStatus()); 1084 } 1085 // Check to see if this Connection has already been added. 1086 Call alreadyAddedConnection = mCallsManager 1087 .getAlreadyAddedConnection(connectIdToCheck); 1088 1089 if (alreadyAddedConnection != null 1090 && mCallIdMapper.getCall(callId) == null) { 1091 if (!Objects.equals(connection.getHandle(), 1092 alreadyAddedConnection.getHandle())) { 1093 alreadyAddedConnection.setHandle(connection.getHandle()); 1094 } 1095 if (connection.getHandlePresentation() != 1096 alreadyAddedConnection.getHandlePresentation()) { 1097 alreadyAddedConnection.setHandle(connection.getHandle(), 1098 connection.getHandlePresentation()); 1099 } 1100 if (!Objects.equals(connection.getCallerDisplayName(), 1101 alreadyAddedConnection.getCallerDisplayName())) { 1102 alreadyAddedConnection.setCallerDisplayName(connection 1103 .getCallerDisplayName(), 1104 connection.getCallerDisplayNamePresentation()); 1105 } 1106 if (connection.getConnectionCapabilities() != 1107 alreadyAddedConnection.getConnectionCapabilities()) { 1108 alreadyAddedConnection.setConnectionCapabilities(connection 1109 .getConnectionCapabilities()); 1110 } 1111 if (connection.getConnectionProperties() != 1112 alreadyAddedConnection.getConnectionProperties()) { 1113 alreadyAddedConnection.setConnectionCapabilities(connection 1114 .getConnectionProperties()); 1115 } 1116 mCallIdMapper.addCall(alreadyAddedConnection, callId); 1117 alreadyAddedConnection 1118 .replaceConnectionService(ConnectionServiceWrapper.this); 1119 return; 1120 } 1121 1122 Call existingCall = mCallsManager 1123 .createCallForExistingConnection(callId, connection); 1124 mCallIdMapper.addCall(existingCall, callId); 1125 existingCall.setConnectionService(ConnectionServiceWrapper.this); 1126 } else { 1127 Log.e(this, new RemoteException("The PhoneAccount being used is not " + 1128 "currently registered with Telecom."), "Unable to " + 1129 "addExistingConnection."); 1130 } 1131 } 1132 } catch (Throwable t) { 1133 Log.e(ConnectionServiceWrapper.this, t, ""); 1134 throw t; 1135 } finally { 1136 Binder.restoreCallingIdentity(token); 1137 Log.endSession(); 1138 } 1139 } 1140 1141 @Override onConnectionEvent(String callId, String event, Bundle extras, Session.Info sessionInfo)1142 public void onConnectionEvent(String callId, String event, Bundle extras, 1143 Session.Info sessionInfo) { 1144 Log.startSession(sessionInfo, "CSW.oCE", mPackageAbbreviation); 1145 long token = Binder.clearCallingIdentity(); 1146 try { 1147 synchronized (mLock) { 1148 Bundle.setDefusable(extras, true); 1149 Call call = mCallIdMapper.getCall(callId); 1150 if (call != null) { 1151 call.onConnectionEvent(event, extras); 1152 } 1153 } 1154 } catch (Throwable t) { 1155 Log.e(ConnectionServiceWrapper.this, t, ""); 1156 throw t; 1157 } finally { 1158 Binder.restoreCallingIdentity(token); 1159 Log.endSession(); 1160 } 1161 } 1162 1163 @Override onRttInitiationSuccess(String callId, Session.Info sessionInfo)1164 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo) 1165 throws RemoteException { 1166 1167 } 1168 1169 @Override onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)1170 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo) 1171 throws RemoteException { 1172 Log.startSession(sessionInfo, "CSW.oRIF", mPackageAbbreviation); 1173 long token = Binder.clearCallingIdentity(); 1174 try { 1175 synchronized (mLock) { 1176 Call call = mCallIdMapper.getCall(callId); 1177 if (call != null) { 1178 call.onRttConnectionFailure(reason); 1179 } 1180 } 1181 } catch (Throwable t) { 1182 Log.e(ConnectionServiceWrapper.this, t, ""); 1183 throw t; 1184 } finally { 1185 Binder.restoreCallingIdentity(token); 1186 Log.endSession(); 1187 } 1188 } 1189 1190 @Override onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)1191 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo) 1192 throws RemoteException { 1193 1194 } 1195 1196 @Override onRemoteRttRequest(String callId, Session.Info sessionInfo)1197 public void onRemoteRttRequest(String callId, Session.Info sessionInfo) 1198 throws RemoteException { 1199 Log.startSession(sessionInfo, "CSW.oRRR", mPackageAbbreviation); 1200 long token = Binder.clearCallingIdentity(); 1201 try { 1202 synchronized (mLock) { 1203 Call call = mCallIdMapper.getCall(callId); 1204 if (call != null) { 1205 call.onRemoteRttRequest(); 1206 } 1207 } 1208 } catch (Throwable t) { 1209 Log.e(ConnectionServiceWrapper.this, t, ""); 1210 throw t; 1211 } finally { 1212 Binder.restoreCallingIdentity(token); 1213 Log.endSession(); 1214 } 1215 } 1216 1217 @Override onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, Session.Info sessionInfo)1218 public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, 1219 Session.Info sessionInfo) throws RemoteException { 1220 // Check that the Calling Package matches PhoneAccountHandle's Component Package 1221 if (pHandle != null) { 1222 mAppOpsManager.checkPackage(Binder.getCallingUid(), 1223 pHandle.getComponentName().getPackageName()); 1224 } 1225 Log.startSession(sessionInfo, "CSW.oPAC", mPackageAbbreviation); 1226 long token = Binder.clearCallingIdentity(); 1227 try { 1228 synchronized (mLock) { 1229 Call call = mCallIdMapper.getCall(callId); 1230 if (call != null) { 1231 call.setTargetPhoneAccount(pHandle); 1232 } 1233 } 1234 } catch (Throwable t) { 1235 Log.e(ConnectionServiceWrapper.this, t, ""); 1236 throw t; 1237 } finally { 1238 Binder.restoreCallingIdentity(token); 1239 Log.endSession(); 1240 } 1241 } 1242 1243 @Override onConnectionServiceFocusReleased(Session.Info sessionInfo)1244 public void onConnectionServiceFocusReleased(Session.Info sessionInfo) 1245 throws RemoteException { 1246 Log.startSession(sessionInfo, "CSW.oCSFR", mPackageAbbreviation); 1247 long token = Binder.clearCallingIdentity(); 1248 try { 1249 synchronized (mLock) { 1250 mConnSvrFocusListener.onConnectionServiceReleased( 1251 ConnectionServiceWrapper.this); 1252 } 1253 } catch (Throwable t) { 1254 Log.e(ConnectionServiceWrapper.this, t, ""); 1255 throw t; 1256 } finally { 1257 Binder.restoreCallingIdentity(token); 1258 Log.endSession(); 1259 } 1260 } 1261 1262 @Override setConferenceState(String callId, boolean isConference, Session.Info sessionInfo)1263 public void setConferenceState(String callId, boolean isConference, 1264 Session.Info sessionInfo) throws RemoteException { 1265 Log.startSession(sessionInfo, "CSW.sCS", mPackageAbbreviation); 1266 1267 if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 1268 != PackageManager.PERMISSION_GRANTED) { 1269 Log.w(this, "setConferenceState from caller without permission."); 1270 Log.endSession(); 1271 return; 1272 } 1273 1274 long token = Binder.clearCallingIdentity(); 1275 try { 1276 synchronized (mLock) { 1277 Call call = mCallIdMapper.getCall(callId); 1278 if (call != null) { 1279 call.setConferenceState(isConference); 1280 } 1281 } 1282 } catch (Throwable t) { 1283 Log.e(ConnectionServiceWrapper.this, t, ""); 1284 throw t; 1285 } finally { 1286 Binder.restoreCallingIdentity(token); 1287 Log.endSession(); 1288 } 1289 } 1290 1291 @Override setCallDirection(String callId, int direction, Session.Info sessionInfo)1292 public void setCallDirection(String callId, int direction, Session.Info sessionInfo) { 1293 Log.startSession(sessionInfo, "CSW.sCD", mPackageAbbreviation); 1294 1295 if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 1296 != PackageManager.PERMISSION_GRANTED) { 1297 Log.w(this, "setCallDirection from caller without permission."); 1298 Log.endSession(); 1299 return; 1300 } 1301 1302 long token = Binder.clearCallingIdentity(); 1303 try { 1304 synchronized (mLock) { 1305 logIncoming("setCallDirection %s %d", callId, direction); 1306 Call call = mCallIdMapper.getCall(callId); 1307 if (call != null) { 1308 call.setCallDirection(Call.getRemappedCallDirection(direction)); 1309 } 1310 } 1311 } catch (Throwable t) { 1312 Log.e(ConnectionServiceWrapper.this, t, ""); 1313 throw t; 1314 } finally { 1315 Binder.restoreCallingIdentity(token); 1316 Log.endSession(); 1317 } 1318 } 1319 1320 @Override queryLocation(String callId, long timeoutMillis, String provider, ResultReceiver callback, Session.Info sessionInfo)1321 public void queryLocation(String callId, long timeoutMillis, String provider, 1322 ResultReceiver callback, Session.Info sessionInfo) { 1323 Log.startSession(sessionInfo, "CSW.qL", mPackageAbbreviation); 1324 1325 TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); 1326 if (telecomManager == null || !telecomManager.getSimCallManager().getComponentName() 1327 .equals(getComponentName())) { 1328 callback.send(0 /* isSuccess */, 1329 getQueryLocationErrorResult(QueryLocationException.ERROR_NOT_PERMITTED)); 1330 Log.endSession(); 1331 return; 1332 } 1333 1334 String opPackageName = mContext.getOpPackageName(); 1335 int packageUid = -1; 1336 try { 1337 packageUid = mContext.getPackageManager().getPackageUid(opPackageName, 1338 PackageManager.PackageInfoFlags.of(0)); 1339 } catch (PackageManager.NameNotFoundException e) { 1340 // packageUid is -1 1341 } 1342 1343 try { 1344 mAppOpsManager.noteProxyOp( 1345 AppOpsManager.OPSTR_FINE_LOCATION, 1346 opPackageName, 1347 packageUid, 1348 null, 1349 null); 1350 } catch (SecurityException e) { 1351 Log.e(ConnectionServiceWrapper.this, e, ""); 1352 } 1353 1354 if (!callingUidMatchesPackageManagerRecords(getComponentName().getPackageName())) { 1355 throw new SecurityException(String.format("queryCurrentLocation: " 1356 + "uid mismatch found : callingPackageName=[%s], callingUid=[%d]", 1357 getComponentName().getPackageName(), Binder.getCallingUid())); 1358 } 1359 1360 Call call = mCallIdMapper.getCall(callId); 1361 if (call == null || !call.isEmergencyCall()) { 1362 callback.send(0 /* isSuccess */, 1363 getQueryLocationErrorResult(QueryLocationException 1364 .ERROR_NOT_ALLOWED_FOR_NON_EMERGENCY_CONNECTIONS)); 1365 Log.endSession(); 1366 return; 1367 } 1368 1369 long token = Binder.clearCallingIdentity(); 1370 try { 1371 synchronized (mLock) { 1372 logIncoming("queryLocation %s %d", callId, timeoutMillis); 1373 ConnectionServiceWrapper.this.queryCurrentLocation(timeoutMillis, provider, 1374 callback); 1375 } 1376 } catch (Throwable t) { 1377 Log.e(ConnectionServiceWrapper.this, t, ""); 1378 throw t; 1379 } finally { 1380 Binder.restoreCallingIdentity(token); 1381 Log.endSession(); 1382 } 1383 } 1384 } 1385 1386 private final Adapter mAdapter = new Adapter(); 1387 private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId); 1388 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>(); 1389 1390 private Binder2 mBinder = new Binder2(); 1391 private IConnectionService mServiceInterface; 1392 private final ConnectionServiceRepository mConnectionServiceRepository; 1393 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 1394 private final CallsManager mCallsManager; 1395 private final AppOpsManager mAppOpsManager; 1396 private final Context mContext; 1397 1398 private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener; 1399 1400 /** 1401 * Creates a connection service. 1402 * 1403 * @param componentName The component name of the service with which to bind. 1404 * @param connectionServiceRepository Connection service repository. 1405 * @param phoneAccountRegistrar Phone account registrar 1406 * @param callsManager Calls manager 1407 * @param context The context. 1408 * @param userHandle The {@link UserHandle} to use when binding. 1409 */ 1410 @VisibleForTesting ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, CallsManager callsManager, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle, FeatureFlags featureFlags)1411 public ConnectionServiceWrapper( 1412 ComponentName componentName, 1413 ConnectionServiceRepository connectionServiceRepository, 1414 PhoneAccountRegistrar phoneAccountRegistrar, 1415 CallsManager callsManager, 1416 Context context, 1417 TelecomSystem.SyncRoot lock, 1418 UserHandle userHandle, 1419 FeatureFlags featureFlags) { 1420 super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle, 1421 featureFlags); 1422 mConnectionServiceRepository = connectionServiceRepository; 1423 phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { 1424 // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections 1425 // To do this, we must proxy remote ConnectionService objects 1426 }); 1427 mPhoneAccountRegistrar = phoneAccountRegistrar; 1428 mCallsManager = callsManager; 1429 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 1430 mContext = context; 1431 } 1432 1433 /** See {@link IConnectionService#addConnectionServiceAdapter}. */ addConnectionServiceAdapter(IConnectionServiceAdapter adapter)1434 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 1435 if (isServiceValid("addConnectionServiceAdapter")) { 1436 try { 1437 logOutgoing("addConnectionServiceAdapter %s", adapter); 1438 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession()); 1439 } catch (RemoteException e) { 1440 } 1441 } 1442 } 1443 1444 /** See {@link IConnectionService#removeConnectionServiceAdapter}. */ removeConnectionServiceAdapter(IConnectionServiceAdapter adapter)1445 private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 1446 if (isServiceValid("removeConnectionServiceAdapter")) { 1447 try { 1448 logOutgoing("removeConnectionServiceAdapter %s", adapter); 1449 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession()); 1450 } catch (RemoteException e) { 1451 } 1452 } 1453 } 1454 1455 @VisibleForTesting getLastKnownCellIdentity()1456 public CellIdentity getLastKnownCellIdentity() { 1457 TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); 1458 if (telephonyManager != null) { 1459 try { 1460 CellIdentity lastKnownCellIdentity = telephonyManager.getLastKnownCellIdentity(); 1461 mAppOpsManager.noteOp(AppOpsManager.OP_FINE_LOCATION, 1462 mContext.getPackageManager().getPackageUid( 1463 getComponentName().getPackageName(), 0), 1464 getComponentName().getPackageName()); 1465 return lastKnownCellIdentity; 1466 } catch (UnsupportedOperationException ignored) { 1467 Log.w(this, "getLastKnownCellIdentity - no telephony on this device"); 1468 } catch (PackageManager.NameNotFoundException nameNotFoundException) { 1469 Log.e(this, nameNotFoundException, "could not find the package -- %s", 1470 getComponentName().getPackageName()); 1471 } 1472 } 1473 return null; 1474 } 1475 1476 @VisibleForTesting 1477 @SuppressWarnings("FutureReturnValueIgnored") queryCurrentLocation(long timeoutMillis, String provider, ResultReceiver callback)1478 public void queryCurrentLocation(long timeoutMillis, String provider, ResultReceiver callback) { 1479 1480 if (mQueryLocationFuture != null && !mQueryLocationFuture.isDone()) { 1481 callback.send(0 /* isSuccess */, 1482 getQueryLocationErrorResult( 1483 QueryLocationException.ERROR_PREVIOUS_REQUEST_EXISTS)); 1484 return; 1485 } 1486 1487 LocationManager locationManager = (LocationManager) mContext.createAttributionContext( 1488 ConnectionServiceWrapper.class.getSimpleName()).getSystemService( 1489 Context.LOCATION_SERVICE); 1490 1491 if (locationManager == null) { 1492 callback.send(0 /* isSuccess */, 1493 getQueryLocationErrorResult(QueryLocationException.ERROR_SERVICE_UNAVAILABLE)); 1494 } 1495 1496 mQueryLocationFuture = new CompletableFuture<Pair<Integer, Location>>() 1497 .completeOnTimeout( 1498 Pair.create(QueryLocationException.ERROR_REQUEST_TIME_OUT, null), 1499 timeoutMillis, TimeUnit.MILLISECONDS); 1500 1501 mOngoingQueryLocationRequest = new CancellationSignal(); 1502 locationManager.getCurrentLocation( 1503 provider, 1504 new LocationRequest.Builder(0) 1505 .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY) 1506 .setLocationSettingsIgnored(true) 1507 .build(), 1508 mOngoingQueryLocationRequest, 1509 mQueryLocationExecutor, 1510 (location) -> mQueryLocationFuture.complete(Pair.create(null, location))); 1511 1512 mQueryLocationFuture.whenComplete((result, e) -> { 1513 if (e != null) { 1514 callback.send(0, 1515 getQueryLocationErrorResult(QueryLocationException.ERROR_UNSPECIFIED)); 1516 } 1517 //make sure we don't pass mock locations diretly, always reset() mock locations 1518 if (result.second != null) { 1519 if(result.second.isMock()) { 1520 result.second.reset(); 1521 } 1522 callback.send(1, getQueryLocationResult(result.second)); 1523 } else { 1524 callback.send(0, getQueryLocationErrorResult(result.first)); 1525 } 1526 1527 if (mOngoingQueryLocationRequest != null) { 1528 mOngoingQueryLocationRequest.cancel(); 1529 mOngoingQueryLocationRequest = null; 1530 } 1531 1532 if (mQueryLocationFuture != null) { 1533 mQueryLocationFuture = null; 1534 } 1535 }); 1536 } 1537 getQueryLocationResult(Location location)1538 private Bundle getQueryLocationResult(Location location) { 1539 Bundle extras = new Bundle(); 1540 extras.putParcelable(Connection.EXTRA_KEY_QUERY_LOCATION, location); 1541 return extras; 1542 } 1543 getQueryLocationErrorResult(int result)1544 private Bundle getQueryLocationErrorResult(int result) { 1545 String message; 1546 1547 switch (result) { 1548 case QueryLocationException.ERROR_REQUEST_TIME_OUT: 1549 message = "The operation was not completed on time"; 1550 break; 1551 case QueryLocationException.ERROR_PREVIOUS_REQUEST_EXISTS: 1552 message = "The operation was rejected due to a previous request exists"; 1553 break; 1554 case QueryLocationException.ERROR_NOT_PERMITTED: 1555 message = "The operation is not permitted"; 1556 break; 1557 case QueryLocationException.ERROR_NOT_ALLOWED_FOR_NON_EMERGENCY_CONNECTIONS: 1558 message = "Non-emergency call connection are not allowed"; 1559 break; 1560 case QueryLocationException.ERROR_SERVICE_UNAVAILABLE: 1561 message = "The operation has failed due to service is not available"; 1562 break; 1563 default: 1564 message = "The operation has failed due to an unknown or unspecified error"; 1565 } 1566 1567 QueryLocationException exception = new QueryLocationException(message, result); 1568 Bundle extras = new Bundle(); 1569 extras.putParcelable(QueryLocationException.QUERY_LOCATION_ERROR, exception); 1570 return extras; 1571 } 1572 1573 /** 1574 * helper method that compares the binder_uid to what the packageManager_uid reports for the 1575 * passed in packageName. 1576 * 1577 * returns true if the binder_uid matches the packageManager_uid records 1578 */ callingUidMatchesPackageManagerRecords(String packageName)1579 private boolean callingUidMatchesPackageManagerRecords(String packageName) { 1580 int packageUid = -1; 1581 int callingUid = Binder.getCallingUid(); 1582 1583 PackageManager pm; 1584 try{ 1585 pm = mContext.createContextAsUser( 1586 UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager(); 1587 } 1588 catch (Exception e){ 1589 Log.i(this, "callingUidMatchesPackageManagerRecords:" 1590 + " createContextAsUser hit exception=[%s]", e.toString()); 1591 return false; 1592 } 1593 1594 if (pm != null) { 1595 try { 1596 packageUid = pm.getPackageUid(packageName, PackageManager.PackageInfoFlags.of(0)); 1597 } catch (PackageManager.NameNotFoundException e) { 1598 // packageUid is -1. 1599 } 1600 } 1601 1602 if (packageUid != callingUid) { 1603 Log.i(this, "callingUidMatchesPackageManagerRecords: uid mismatch found for " 1604 + "packageName=[%s]. packageManager reports packageUid=[%d] but " 1605 + "binder reports callingUid=[%d]", packageName, packageUid, callingUid); 1606 } 1607 1608 return packageUid == callingUid; 1609 } 1610 1611 /** 1612 * Creates a conference for a new outgoing call or attach to an existing incoming call. 1613 */ createConference(final Call call, final CreateConnectionResponse response)1614 public void createConference(final Call call, final CreateConnectionResponse response) { 1615 Log.d(this, "createConference(%s) via %s.", call, getComponentName()); 1616 BindCallback callback = new BindCallback() { 1617 @Override 1618 public void onSuccess() { 1619 String callId = mCallIdMapper.getCallId(call); 1620 mPendingResponses.put(callId, response); 1621 1622 Bundle extras = call.getIntentExtras(); 1623 if (extras == null) { 1624 extras = new Bundle(); 1625 } 1626 extras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId); 1627 1628 Log.addEvent(call, LogUtils.Events.START_CONFERENCE, 1629 Log.piiHandle(call.getHandle())); 1630 1631 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 1632 .setAccountHandle(call.getTargetPhoneAccount()) 1633 .setAddress(call.getHandle()) 1634 .setExtras(extras) 1635 .setVideoState(call.getVideoState()) 1636 .setTelecomCallId(callId) 1637 // For self-managed incoming calls, if there is another ongoing call Telecom 1638 // is responsible for showing a UI to ask the user if they'd like to answer 1639 // this new incoming call. 1640 .setShouldShowIncomingCallUi( 1641 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 1642 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 1643 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 1644 .setParticipants(call.getParticipants()) 1645 .setIsAdhocConferenceCall(call.isAdhocConferenceCall()) 1646 .build(); 1647 Runnable r = new Runnable("CSW.cC", mLock) { 1648 @Override 1649 public void loggedRun() { 1650 if (!call.isCreateConnectionComplete()) { 1651 Log.e(this, new Exception(), 1652 "Conference %s creation timeout", 1653 getComponentName()); 1654 Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_TIMEOUT, 1655 Log.piiHandle(call.getHandle()) + " via:" + 1656 getComponentName().getPackageName()); 1657 mAnomalyReporter.reportAnomaly( 1658 CREATE_CONFERENCE_TIMEOUT_ERROR_UUID, 1659 CREATE_CONFERENCE_TIMEOUT_ERROR_MSG); 1660 response.handleCreateConferenceFailure( 1661 new DisconnectCause(DisconnectCause.ERROR)); 1662 } 1663 } 1664 }; 1665 // Post cleanup to the executor service and cache the future, so we can cancel it if 1666 // needed. 1667 ScheduledFuture<?> future = mScheduledExecutor.schedule(r.getRunnableToCancel(), 1668 SERVICE_BINDING_TIMEOUT, TimeUnit.MILLISECONDS); 1669 mScheduledFutureMap.put(call, future); 1670 try { 1671 mServiceInterface.createConference( 1672 call.getConnectionManagerPhoneAccount(), 1673 callId, 1674 connectionRequest, 1675 call.shouldAttachToExistingConnection(), 1676 call.isUnknown(), 1677 Log.getExternalSession(TELECOM_ABBREVIATION)); 1678 } catch (RemoteException e) { 1679 Log.e(this, e, "Failure to createConference -- %s", getComponentName()); 1680 mPendingResponses.remove(callId).handleCreateConferenceFailure( 1681 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 1682 } 1683 } 1684 1685 @Override 1686 public void onFailure() { 1687 Log.e(this, new Exception(), "Failure to conference %s", getComponentName()); 1688 response.handleCreateConferenceFailure(new DisconnectCause(DisconnectCause.ERROR)); 1689 } 1690 }; 1691 1692 mBinder.bind(callback, call); 1693 1694 } 1695 1696 /** 1697 * Creates a new connection for a new outgoing call or to attach to an existing incoming call. 1698 */ 1699 @VisibleForTesting createConnection(final Call call, final CreateConnectionResponse response)1700 public void createConnection(final Call call, final CreateConnectionResponse response) { 1701 Log.i(this, "createConnection(%s) via %s.", call, getComponentName()); 1702 BindCallback callback = new BindCallback() { 1703 @Override 1704 public void onSuccess() { 1705 String callId = mCallIdMapper.getCallId(call); 1706 if (callId == null) { 1707 Log.i(ConnectionServiceWrapper.this, "Call not present" 1708 + " in call id mapper, maybe it was aborted before the bind" 1709 + " completed successfully?"); 1710 response.handleCreateConnectionFailure( 1711 new DisconnectCause(DisconnectCause.CANCELED)); 1712 return; 1713 } 1714 mPendingResponses.put(callId, response); 1715 1716 GatewayInfo gatewayInfo = call.getGatewayInfo(); 1717 Bundle extras = call.getIntentExtras(); 1718 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && 1719 gatewayInfo.getOriginalAddress() != null) { 1720 extras = (Bundle) extras.clone(); 1721 extras.putString( 1722 TelecomManager.GATEWAY_PROVIDER_PACKAGE, 1723 gatewayInfo.getGatewayProviderPackageName()); 1724 extras.putParcelable( 1725 TelecomManager.GATEWAY_ORIGINAL_ADDRESS, 1726 gatewayInfo.getOriginalAddress()); 1727 } 1728 1729 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper() 1730 .getLastEmergencyCallTimeMillis() > 0) { 1731 // Add the last emergency call time to the connection request for incoming calls 1732 if (extras == call.getIntentExtras()) { 1733 extras = (Bundle) extras.clone(); 1734 } 1735 extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 1736 mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis()); 1737 } 1738 1739 // Call is incoming and added because we're handing over from another; tell CS 1740 // that its expected to handover. 1741 if (call.isIncoming() && call.getHandoverSourceCall() != null) { 1742 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true); 1743 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 1744 call.getHandoverSourceCall().getTargetPhoneAccount()); 1745 } 1746 1747 Log.addEvent(call, LogUtils.Events.START_CONNECTION, 1748 Log.piiHandle(call.getHandle()) + " via:" + 1749 getComponentName().getPackageName()); 1750 1751 if (call.isEmergencyCall()) { 1752 extras.putParcelable(Connection.EXTRA_LAST_KNOWN_CELL_IDENTITY, 1753 getLastKnownCellIdentity()); 1754 } 1755 1756 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 1757 .setAccountHandle(call.getTargetPhoneAccount()) 1758 .setAddress(call.getHandle()) 1759 .setExtras(extras) 1760 .setVideoState(call.getVideoState()) 1761 .setTelecomCallId(callId) 1762 // For self-managed incoming calls, if there is another ongoing call Telecom 1763 // is responsible for showing a UI to ask the user if they'd like to answer 1764 // this new incoming call. 1765 .setShouldShowIncomingCallUi( 1766 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 1767 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 1768 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 1769 .build(); 1770 Runnable r = new Runnable("CSW.cC", mLock) { 1771 @Override 1772 public void loggedRun() { 1773 if (!call.isCreateConnectionComplete()) { 1774 Log.e(this, new Exception(), 1775 "Connection %s creation timeout", 1776 getComponentName()); 1777 Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_TIMEOUT, 1778 Log.piiHandle(call.getHandle()) + " via:" + 1779 getComponentName().getPackageName()); 1780 mAnomalyReporter.reportAnomaly( 1781 CREATE_CONNECTION_TIMEOUT_ERROR_UUID, 1782 CREATE_CONNECTION_TIMEOUT_ERROR_MSG); 1783 response.handleCreateConnectionFailure( 1784 new DisconnectCause(DisconnectCause.ERROR)); 1785 } 1786 } 1787 }; 1788 // Post cleanup to the executor service and cache the future, so we can cancel it if 1789 // needed. 1790 ScheduledFuture<?> future = mScheduledExecutor.schedule(r.getRunnableToCancel(), 1791 SERVICE_BINDING_TIMEOUT, TimeUnit.MILLISECONDS); 1792 mScheduledFutureMap.put(call, future); 1793 try { 1794 mServiceInterface.createConnection( 1795 call.getConnectionManagerPhoneAccount(), 1796 callId, 1797 connectionRequest, 1798 call.shouldAttachToExistingConnection(), 1799 call.isUnknown(), 1800 Log.getExternalSession(TELECOM_ABBREVIATION)); 1801 1802 } catch (RemoteException e) { 1803 Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); 1804 mPendingResponses.remove(callId).handleCreateConnectionFailure( 1805 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 1806 } 1807 } 1808 1809 @Override 1810 public void onFailure() { 1811 Log.e(this, new Exception(), "Failure to call %s", getComponentName()); 1812 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); 1813 } 1814 }; 1815 1816 mBinder.bind(callback, call); 1817 } 1818 1819 /** 1820 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 1821 * create a connection has been denied or failed. 1822 * @param call The call. 1823 */ 1824 @VisibleForTesting createConnectionFailed(final Call call)1825 public void createConnectionFailed(final Call call) { 1826 Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName()); 1827 BindCallback callback = new BindCallback() { 1828 @Override 1829 public void onSuccess() { 1830 final String callId = mCallIdMapper.getCallId(call); 1831 // If still bound, tell the connection service create connection has failed. 1832 if (callId != null && isServiceValid("createConnectionFailed")) { 1833 Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED, 1834 Log.piiHandle(call.getHandle())); 1835 try { 1836 logOutgoing("createConnectionFailed %s", callId); 1837 mServiceInterface.createConnectionFailed( 1838 call.getConnectionManagerPhoneAccount(), 1839 callId, 1840 new ConnectionRequest( 1841 call.getTargetPhoneAccount(), 1842 call.getHandle(), 1843 call.getIntentExtras(), 1844 call.getVideoState(), 1845 callId, 1846 false), 1847 call.isIncoming(), 1848 Log.getExternalSession(TELECOM_ABBREVIATION)); 1849 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1850 call.disconnect(); 1851 } catch (RemoteException e) { 1852 } 1853 } 1854 } 1855 1856 @Override 1857 public void onFailure() { 1858 // Binding failed. Oh no. 1859 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId()); 1860 } 1861 }; 1862 1863 mBinder.bind(callback, call); 1864 } 1865 1866 /** 1867 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 1868 * create a conference has been denied or failed. 1869 * @param call The call. 1870 */ createConferenceFailed(final Call call)1871 void createConferenceFailed(final Call call) { 1872 Log.d(this, "createConferenceFailed(%s) via %s.", call, getComponentName()); 1873 BindCallback callback = new BindCallback() { 1874 @Override 1875 public void onSuccess() { 1876 final String callId = mCallIdMapper.getCallId(call); 1877 // If still bound, tell the connection service create connection has failed. 1878 if (callId != null && isServiceValid("createConferenceFailed")) { 1879 Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_FAILED, 1880 Log.piiHandle(call.getHandle())); 1881 try { 1882 logOutgoing("createConferenceFailed %s", callId); 1883 mServiceInterface.createConferenceFailed( 1884 call.getConnectionManagerPhoneAccount(), 1885 callId, 1886 new ConnectionRequest( 1887 call.getTargetPhoneAccount(), 1888 call.getHandle(), 1889 call.getIntentExtras(), 1890 call.getVideoState(), 1891 callId, 1892 false), 1893 call.isIncoming(), 1894 Log.getExternalSession(TELECOM_ABBREVIATION)); 1895 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1896 call.disconnect(); 1897 } catch (RemoteException e) { 1898 } 1899 } 1900 } 1901 1902 @Override 1903 public void onFailure() { 1904 // Binding failed. Oh no. 1905 Log.w(this, "onFailure - could not bind to CS for conf call %s", call.getId()); 1906 } 1907 }; 1908 1909 mBinder.bind(callback, call); 1910 } 1911 1912 handoverFailed(final Call call, final int reason)1913 void handoverFailed(final Call call, final int reason) { 1914 Log.d(this, "handoverFailed(%s) via %s.", call, getComponentName()); 1915 BindCallback callback = new BindCallback() { 1916 @Override 1917 public void onSuccess() { 1918 final String callId = mCallIdMapper.getCallId(call); 1919 // If still bound, tell the connection service create connection has failed. 1920 if (callId != null && isServiceValid("handoverFailed")) { 1921 Log.addEvent(call, LogUtils.Events.HANDOVER_FAILED, 1922 Log.piiHandle(call.getHandle())); 1923 try { 1924 mServiceInterface.handoverFailed( 1925 callId, 1926 new ConnectionRequest( 1927 call.getTargetPhoneAccount(), 1928 call.getHandle(), 1929 call.getIntentExtras(), 1930 call.getVideoState(), 1931 callId, 1932 false), 1933 reason, 1934 Log.getExternalSession(TELECOM_ABBREVIATION)); 1935 } catch (RemoteException e) { 1936 } 1937 } 1938 } 1939 1940 @Override 1941 public void onFailure() { 1942 // Binding failed. 1943 Log.w(this, "onFailure - could not bind to CS for call %s", 1944 call.getId()); 1945 } 1946 }; 1947 1948 mBinder.bind(callback, call); 1949 } 1950 handoverComplete(final Call call)1951 void handoverComplete(final Call call) { 1952 Log.d(this, "handoverComplete(%s) via %s.", call, getComponentName()); 1953 BindCallback callback = new BindCallback() { 1954 @Override 1955 public void onSuccess() { 1956 final String callId = mCallIdMapper.getCallId(call); 1957 // If still bound, tell the connection service create connection has failed. 1958 if (callId != null && isServiceValid("handoverComplete")) { 1959 try { 1960 mServiceInterface.handoverComplete( 1961 callId, 1962 Log.getExternalSession(TELECOM_ABBREVIATION)); 1963 } catch (RemoteException e) { 1964 } 1965 } 1966 } 1967 1968 @Override 1969 public void onFailure() { 1970 // Binding failed. 1971 Log.w(this, "onFailure - could not bind to CS for call %s", 1972 call.getId()); 1973 } 1974 }; 1975 1976 mBinder.bind(callback, call); 1977 } 1978 1979 /** @see IConnectionService#abort(String, Session.Info) */ abort(Call call)1980 void abort(Call call) { 1981 // Clear out any pending outgoing call data 1982 final String callId = mCallIdMapper.getCallId(call); 1983 1984 // If still bound, tell the connection service to abort. 1985 if (callId != null && isServiceValid("abort")) { 1986 try { 1987 logOutgoing("abort %s", callId); 1988 mServiceInterface.abort(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1989 } catch (RemoteException e) { 1990 } 1991 } 1992 1993 removeCall(call, new DisconnectCause(DisconnectCause.LOCAL)); 1994 } 1995 1996 /** @see IConnectionService#silence(String, Session.Info) */ silence(Call call)1997 void silence(Call call) { 1998 final String callId = mCallIdMapper.getCallId(call); 1999 if (callId != null && isServiceValid("silence")) { 2000 try { 2001 logOutgoing("silence %s", callId); 2002 mServiceInterface.silence(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2003 } catch (RemoteException e) { 2004 } 2005 } 2006 } 2007 2008 /** @see IConnectionService#hold(String, Session.Info) */ hold(Call call)2009 void hold(Call call) { 2010 final String callId = mCallIdMapper.getCallId(call); 2011 if (callId != null && isServiceValid("hold")) { 2012 try { 2013 logOutgoing("hold %s", callId); 2014 mServiceInterface.hold(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2015 } catch (RemoteException e) { 2016 } 2017 } 2018 } 2019 2020 /** @see IConnectionService#unhold(String, Session.Info) */ unhold(Call call)2021 void unhold(Call call) { 2022 final String callId = mCallIdMapper.getCallId(call); 2023 if (callId != null && isServiceValid("unhold")) { 2024 try { 2025 logOutgoing("unhold %s", callId); 2026 mServiceInterface.unhold(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2027 } catch (RemoteException e) { 2028 } 2029 } 2030 } 2031 2032 /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */ 2033 @VisibleForTesting onCallAudioStateChanged(Call activeCall, CallAudioState audioState)2034 public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) { 2035 final String callId = mCallIdMapper.getCallId(activeCall); 2036 if (callId != null && isServiceValid("onCallAudioStateChanged")) { 2037 try { 2038 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState); 2039 mServiceInterface.onCallAudioStateChanged(callId, audioState, 2040 Log.getExternalSession(TELECOM_ABBREVIATION)); 2041 } catch (RemoteException e) { 2042 } 2043 } 2044 } 2045 2046 /** @see IConnectionService#onCallEndpointChanged(String, CallEndpoint, Session.Info) */ 2047 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 2048 @Override onCallEndpointChanged(Call activeCall, CallEndpoint callEndpoint)2049 public void onCallEndpointChanged(Call activeCall, CallEndpoint callEndpoint) { 2050 final String callId = mCallIdMapper.getCallId(activeCall); 2051 if (callId != null && isServiceValid("onCallEndpointChanged")) { 2052 try { 2053 logOutgoing("onCallEndpointChanged %s %s", callId, callEndpoint); 2054 mServiceInterface.onCallEndpointChanged(callId, callEndpoint, 2055 Log.getExternalSession(TELECOM_ABBREVIATION)); 2056 } catch (RemoteException e) { 2057 Log.d(this, "Remote exception calling onCallEndpointChanged"); 2058 } 2059 } 2060 } 2061 2062 /** @see IConnectionService#onAvailableCallEndpointsChanged(String, List, Session.Info) */ 2063 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 2064 @Override onAvailableCallEndpointsChanged(Call activeCall, Set<CallEndpoint> availableCallEndpoints)2065 public void onAvailableCallEndpointsChanged(Call activeCall, 2066 Set<CallEndpoint> availableCallEndpoints) { 2067 final String callId = mCallIdMapper.getCallId(activeCall); 2068 if (callId != null && isServiceValid("onAvailableCallEndpointsChanged")) { 2069 try { 2070 logOutgoing("onAvailableCallEndpointsChanged %s", callId); 2071 List<CallEndpoint> availableEndpoints = new ArrayList<>(availableCallEndpoints); 2072 mServiceInterface.onAvailableCallEndpointsChanged(callId, availableEndpoints, 2073 Log.getExternalSession(TELECOM_ABBREVIATION)); 2074 } catch (RemoteException e) { 2075 Log.d(this, 2076 "Remote exception calling onAvailableCallEndpointsChanged"); 2077 } 2078 } 2079 } 2080 2081 @Override onVideoStateChanged(Call call, int videoState)2082 public void onVideoStateChanged(Call call, int videoState){ 2083 // pass through. ConnectionService does not implement this method. 2084 } 2085 2086 /** @see IConnectionService#onMuteStateChanged(String, boolean, Session.Info) */ 2087 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 2088 @Override onMuteStateChanged(Call activeCall, boolean isMuted)2089 public void onMuteStateChanged(Call activeCall, boolean isMuted) { 2090 final String callId = mCallIdMapper.getCallId(activeCall); 2091 if (callId != null && isServiceValid("onMuteStateChanged")) { 2092 try { 2093 logOutgoing("onMuteStateChanged %s %s", callId, isMuted); 2094 mServiceInterface.onMuteStateChanged(callId, isMuted, 2095 Log.getExternalSession(TELECOM_ABBREVIATION)); 2096 } catch (RemoteException e) { 2097 Log.d(this, "Remote exception calling onMuteStateChanged"); 2098 } 2099 } 2100 } 2101 2102 /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */ 2103 @VisibleForTesting onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi)2104 public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) { 2105 final String callId = mCallIdMapper.getCallId(activeCall); 2106 if (callId != null && isServiceValid("onUsingAlternativeUi")) { 2107 try { 2108 logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi); 2109 mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi, 2110 Log.getExternalSession(TELECOM_ABBREVIATION)); 2111 } catch (RemoteException e) { 2112 } 2113 } 2114 } 2115 2116 /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */ 2117 @VisibleForTesting onTrackedByNonUiService(Call activeCall, boolean isTracked)2118 public void onTrackedByNonUiService(Call activeCall, boolean isTracked) { 2119 final String callId = mCallIdMapper.getCallId(activeCall); 2120 if (callId != null && isServiceValid("onTrackedByNonUiService")) { 2121 try { 2122 logOutgoing("onTrackedByNonUiService %s", isTracked); 2123 mServiceInterface.onTrackedByNonUiService(callId, isTracked, 2124 Log.getExternalSession(TELECOM_ABBREVIATION)); 2125 } catch (RemoteException e) { 2126 } 2127 } 2128 } 2129 2130 /** @see IConnectionService#disconnect(String, Session.Info) */ 2131 @VisibleForTesting disconnect(Call call)2132 public void disconnect(Call call) { 2133 final String callId = mCallIdMapper.getCallId(call); 2134 if (callId != null && isServiceValid("disconnect")) { 2135 try { 2136 logOutgoing("disconnect %s", callId); 2137 mServiceInterface.disconnect(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2138 } catch (RemoteException e) { 2139 } 2140 } 2141 } 2142 2143 /** @see IConnectionService#answer(String, Session.Info) */ answer(Call call, int videoState)2144 void answer(Call call, int videoState) { 2145 final String callId = mCallIdMapper.getCallId(call); 2146 if (callId != null && isServiceValid("answer")) { 2147 try { 2148 logOutgoing("answer %s %d", callId, videoState); 2149 if (VideoProfile.isAudioOnly(videoState)) { 2150 mServiceInterface.answer(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2151 } else { 2152 mServiceInterface.answerVideo(callId, videoState, 2153 Log.getExternalSession(TELECOM_ABBREVIATION)); 2154 } 2155 } catch (RemoteException e) { 2156 } 2157 } 2158 } 2159 2160 /** @see IConnectionService#deflect(String, Uri , Session.Info) */ deflect(Call call, Uri address)2161 void deflect(Call call, Uri address) { 2162 final String callId = mCallIdMapper.getCallId(call); 2163 if (callId != null && isServiceValid("deflect")) { 2164 try { 2165 logOutgoing("deflect %s", callId); 2166 mServiceInterface.deflect(callId, address, 2167 Log.getExternalSession(TELECOM_ABBREVIATION)); 2168 } catch (RemoteException e) { 2169 } 2170 } 2171 } 2172 2173 /** @see IConnectionService#reject(String, Session.Info) */ reject(Call call, boolean rejectWithMessage, String message)2174 void reject(Call call, boolean rejectWithMessage, String message) { 2175 final String callId = mCallIdMapper.getCallId(call); 2176 if (callId != null && isServiceValid("reject")) { 2177 try { 2178 logOutgoing("reject %s", callId); 2179 2180 if (rejectWithMessage && call.can( 2181 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 2182 mServiceInterface.rejectWithMessage(callId, message, 2183 Log.getExternalSession(TELECOM_ABBREVIATION)); 2184 } else { 2185 mServiceInterface.reject(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2186 } 2187 } catch (RemoteException e) { 2188 } 2189 } 2190 } 2191 2192 /** @see IConnectionService#reject(String, Session.Info) */ rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason)2193 void rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason) { 2194 final String callId = mCallIdMapper.getCallId(call); 2195 if (callId != null && isServiceValid("rejectReason")) { 2196 try { 2197 logOutgoing("rejectReason %s, %d", callId, rejectReason); 2198 2199 mServiceInterface.rejectWithReason(callId, rejectReason, 2200 Log.getExternalSession(TELECOM_ABBREVIATION)); 2201 } catch (RemoteException e) { 2202 } 2203 } 2204 } 2205 2206 /** @see IConnectionService#transfer(String, Uri , boolean, Session.Info) */ transfer(Call call, Uri number, boolean isConfirmationRequired)2207 void transfer(Call call, Uri number, boolean isConfirmationRequired) { 2208 final String callId = mCallIdMapper.getCallId(call); 2209 if (callId != null && isServiceValid("transfer")) { 2210 try { 2211 logOutgoing("transfer %s", callId); 2212 mServiceInterface.transfer(callId, number, isConfirmationRequired, 2213 Log.getExternalSession(TELECOM_ABBREVIATION)); 2214 } catch (RemoteException e) { 2215 } 2216 } 2217 } 2218 2219 /** @see IConnectionService#consultativeTransfer(String, String, Session.Info) */ transfer(Call call, Call otherCall)2220 void transfer(Call call, Call otherCall) { 2221 final String callId = mCallIdMapper.getCallId(call); 2222 final String otherCallId = mCallIdMapper.getCallId(otherCall); 2223 if (callId != null && otherCallId != null && isServiceValid("consultativeTransfer")) { 2224 try { 2225 logOutgoing("consultativeTransfer %s", callId); 2226 mServiceInterface.consultativeTransfer(callId, otherCallId, 2227 Log.getExternalSession(TELECOM_ABBREVIATION)); 2228 } catch (RemoteException e) { 2229 } 2230 } 2231 } 2232 2233 /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */ playDtmfTone(Call call, char digit)2234 void playDtmfTone(Call call, char digit) { 2235 final String callId = mCallIdMapper.getCallId(call); 2236 if (callId != null && isServiceValid("playDtmfTone")) { 2237 try { 2238 logOutgoing("playDtmfTone %s %c", callId, digit); 2239 mServiceInterface.playDtmfTone(callId, digit, 2240 Log.getExternalSession(TELECOM_ABBREVIATION)); 2241 } catch (RemoteException e) { 2242 } 2243 } 2244 } 2245 2246 /** @see IConnectionService#stopDtmfTone(String, Session.Info) */ stopDtmfTone(Call call)2247 void stopDtmfTone(Call call) { 2248 final String callId = mCallIdMapper.getCallId(call); 2249 if (callId != null && isServiceValid("stopDtmfTone")) { 2250 try { 2251 logOutgoing("stopDtmfTone %s", callId); 2252 mServiceInterface.stopDtmfTone(callId, 2253 Log.getExternalSession(TELECOM_ABBREVIATION)); 2254 } catch (RemoteException e) { 2255 } 2256 } 2257 } 2258 2259 @VisibleForTesting addCall(Call call)2260 public void addCall(Call call) { 2261 if (mCallIdMapper.getCallId(call) == null) { 2262 mCallIdMapper.addCall(call); 2263 } 2264 } 2265 2266 /** 2267 * Associates newCall with this connection service by replacing callToReplace. 2268 */ replaceCall(Call newCall, Call callToReplace)2269 void replaceCall(Call newCall, Call callToReplace) { 2270 Preconditions.checkState(callToReplace.getConnectionService() == this); 2271 mCallIdMapper.replaceCall(newCall, callToReplace); 2272 } 2273 removeCall(Call call)2274 void removeCall(Call call) { 2275 removeCall(call, new DisconnectCause(DisconnectCause.ERROR)); 2276 } 2277 removeCall(String callId, DisconnectCause disconnectCause)2278 void removeCall(String callId, DisconnectCause disconnectCause) { 2279 CreateConnectionResponse response = mPendingResponses.remove(callId); 2280 if (response != null) { 2281 response.handleCreateConnectionFailure(disconnectCause); 2282 } 2283 2284 mCallIdMapper.removeCall(callId); 2285 } 2286 removeCall(Call call, DisconnectCause disconnectCause)2287 void removeCall(Call call, DisconnectCause disconnectCause) { 2288 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call)); 2289 if (response != null) { 2290 response.handleCreateConnectionFailure(disconnectCause); 2291 } 2292 2293 mCallIdMapper.removeCall(call); 2294 } 2295 onPostDialContinue(Call call, boolean proceed)2296 void onPostDialContinue(Call call, boolean proceed) { 2297 final String callId = mCallIdMapper.getCallId(call); 2298 if (callId != null && isServiceValid("onPostDialContinue")) { 2299 try { 2300 logOutgoing("onPostDialContinue %s %b", callId, proceed); 2301 mServiceInterface.onPostDialContinue(callId, proceed, 2302 Log.getExternalSession(TELECOM_ABBREVIATION)); 2303 } catch (RemoteException ignored) { 2304 } 2305 } 2306 } 2307 conference(final Call call, Call otherCall)2308 void conference(final Call call, Call otherCall) { 2309 final String callId = mCallIdMapper.getCallId(call); 2310 final String otherCallId = mCallIdMapper.getCallId(otherCall); 2311 if (callId != null && otherCallId != null && isServiceValid("conference")) { 2312 try { 2313 logOutgoing("conference %s %s", callId, otherCallId); 2314 mServiceInterface.conference(callId, otherCallId, 2315 Log.getExternalSession(TELECOM_ABBREVIATION)); 2316 } catch (RemoteException ignored) { 2317 } 2318 } 2319 } 2320 splitFromConference(Call call)2321 void splitFromConference(Call call) { 2322 final String callId = mCallIdMapper.getCallId(call); 2323 if (callId != null && isServiceValid("splitFromConference")) { 2324 try { 2325 logOutgoing("splitFromConference %s", callId); 2326 mServiceInterface.splitFromConference(callId, 2327 Log.getExternalSession(TELECOM_ABBREVIATION)); 2328 } catch (RemoteException ignored) { 2329 } 2330 } 2331 } 2332 mergeConference(Call call)2333 void mergeConference(Call call) { 2334 final String callId = mCallIdMapper.getCallId(call); 2335 if (callId != null && isServiceValid("mergeConference")) { 2336 try { 2337 logOutgoing("mergeConference %s", callId); 2338 mServiceInterface.mergeConference(callId, 2339 Log.getExternalSession(TELECOM_ABBREVIATION)); 2340 } catch (RemoteException ignored) { 2341 } 2342 } 2343 } 2344 swapConference(Call call)2345 void swapConference(Call call) { 2346 final String callId = mCallIdMapper.getCallId(call); 2347 if (callId != null && isServiceValid("swapConference")) { 2348 try { 2349 logOutgoing("swapConference %s", callId); 2350 mServiceInterface.swapConference(callId, 2351 Log.getExternalSession(TELECOM_ABBREVIATION)); 2352 } catch (RemoteException ignored) { 2353 } 2354 } 2355 } 2356 addConferenceParticipants(Call call, List<Uri> participants)2357 void addConferenceParticipants(Call call, List<Uri> participants) { 2358 final String callId = mCallIdMapper.getCallId(call); 2359 if (callId != null && isServiceValid("addConferenceParticipants")) { 2360 try { 2361 logOutgoing("addConferenceParticipants %s", callId); 2362 mServiceInterface.addConferenceParticipants(callId, participants, 2363 Log.getExternalSession(TELECOM_ABBREVIATION)); 2364 } catch (RemoteException ignored) { 2365 } 2366 } 2367 } 2368 2369 @VisibleForTesting pullExternalCall(Call call)2370 public void pullExternalCall(Call call) { 2371 final String callId = mCallIdMapper.getCallId(call); 2372 if (callId != null && isServiceValid("pullExternalCall")) { 2373 try { 2374 logOutgoing("pullExternalCall %s", callId); 2375 mServiceInterface.pullExternalCall(callId, 2376 Log.getExternalSession(TELECOM_ABBREVIATION)); 2377 } catch (RemoteException ignored) { 2378 } 2379 } 2380 } 2381 sendCallEvent(Call call, String event, Bundle extras)2382 void sendCallEvent(Call call, String event, Bundle extras) { 2383 final String callId = mCallIdMapper.getCallId(call); 2384 if (callId != null && isServiceValid("sendCallEvent")) { 2385 try { 2386 logOutgoing("sendCallEvent %s %s", callId, event); 2387 mServiceInterface.sendCallEvent(callId, event, extras, 2388 Log.getExternalSession(TELECOM_ABBREVIATION)); 2389 } catch (RemoteException ignored) { 2390 } 2391 } 2392 } 2393 onCallFilteringCompleted(Call call, Connection.CallFilteringCompletionInfo completionInfo)2394 void onCallFilteringCompleted(Call call, 2395 Connection.CallFilteringCompletionInfo completionInfo) { 2396 final String callId = mCallIdMapper.getCallId(call); 2397 if (callId != null && isServiceValid("onCallFilteringCompleted")) { 2398 try { 2399 logOutgoing("onCallFilteringCompleted %s", completionInfo); 2400 int contactsPermission = mContext.getPackageManager() 2401 .checkPermission(Manifest.permission.READ_CONTACTS, 2402 getComponentName().getPackageName()); 2403 if (contactsPermission == PackageManager.PERMISSION_GRANTED) { 2404 mServiceInterface.onCallFilteringCompleted(callId, completionInfo, 2405 Log.getExternalSession(TELECOM_ABBREVIATION)); 2406 } else { 2407 logOutgoing("Skipping call filtering complete message for %s due" 2408 + " to lack of READ_CONTACTS", getComponentName().getPackageName()); 2409 } 2410 } catch (RemoteException e) { 2411 Log.e(this, e, "Remote exception calling onCallFilteringCompleted"); 2412 } 2413 } 2414 } 2415 onExtrasChanged(Call call, Bundle extras)2416 void onExtrasChanged(Call call, Bundle extras) { 2417 final String callId = mCallIdMapper.getCallId(call); 2418 if (callId != null && isServiceValid("onExtrasChanged")) { 2419 try { 2420 logOutgoing("onExtrasChanged %s %s", callId, extras); 2421 mServiceInterface.onExtrasChanged(callId, extras, 2422 Log.getExternalSession(TELECOM_ABBREVIATION)); 2423 } catch (RemoteException ignored) { 2424 } 2425 } 2426 } 2427 startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)2428 void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 2429 final String callId = mCallIdMapper.getCallId(call); 2430 if (callId != null && isServiceValid("startRtt")) { 2431 try { 2432 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall); 2433 mServiceInterface.startRtt(callId, fromInCall, toInCall, 2434 Log.getExternalSession(TELECOM_ABBREVIATION)); 2435 } catch (RemoteException ignored) { 2436 } 2437 } 2438 } 2439 stopRtt(Call call)2440 void stopRtt(Call call) { 2441 final String callId = mCallIdMapper.getCallId(call); 2442 if (callId != null && isServiceValid("stopRtt")) { 2443 try { 2444 logOutgoing("stopRtt: %s", callId); 2445 mServiceInterface.stopRtt(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 2446 } catch (RemoteException ignored) { 2447 } 2448 } 2449 } 2450 respondToRttRequest( Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)2451 void respondToRttRequest( 2452 Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 2453 final String callId = mCallIdMapper.getCallId(call); 2454 if (callId != null && isServiceValid("respondToRttRequest")) { 2455 try { 2456 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall); 2457 mServiceInterface.respondToRttUpgradeRequest( 2458 callId, fromInCall, toInCall, Log.getExternalSession(TELECOM_ABBREVIATION)); 2459 } catch (RemoteException ignored) { 2460 } 2461 } 2462 } 2463 2464 /** {@inheritDoc} */ 2465 @Override setServiceInterface(IBinder binder)2466 protected void setServiceInterface(IBinder binder) { 2467 mServiceInterface = IConnectionService.Stub.asInterface(binder); 2468 Log.v(this, "Adding Connection Service Adapter."); 2469 addConnectionServiceAdapter(mAdapter); 2470 } 2471 2472 /** {@inheritDoc} */ 2473 @Override removeServiceInterface()2474 protected void removeServiceInterface() { 2475 Log.v(this, "Removing Connection Service Adapter."); 2476 removeConnectionServiceAdapter(mAdapter); 2477 // We have lost our service connection. Notify the world that this service is done. 2478 // We must notify the adapter before CallsManager. The adapter will force any pending 2479 // outgoing calls to try the next service. This needs to happen before CallsManager 2480 // tries to clean up any calls still associated with this service. 2481 handleConnectionServiceDeath(); 2482 mCallsManager.handleConnectionServiceDeath(this); 2483 mServiceInterface = null; 2484 } 2485 2486 @Override connectionServiceFocusLost()2487 public void connectionServiceFocusLost() { 2488 // Immediately response to the Telecom that it has released the call resources. 2489 // TODO(mpq): Change back to the default implementation once b/69651192 done. 2490 if (mConnSvrFocusListener != null) { 2491 mConnSvrFocusListener.onConnectionServiceReleased(ConnectionServiceWrapper.this); 2492 } 2493 BindCallback callback = new BindCallback() { 2494 @Override 2495 public void onSuccess() { 2496 if (!isServiceValid("connectionServiceFocusLost")) return; 2497 try { 2498 mServiceInterface.connectionServiceFocusLost( 2499 Log.getExternalSession(TELECOM_ABBREVIATION)); 2500 } catch (RemoteException ignored) { 2501 Log.d(this, "failed to inform the focus lost event"); 2502 } 2503 } 2504 2505 @Override 2506 public void onFailure() {} 2507 }; 2508 mBinder.bind(callback, null /* null call */); 2509 } 2510 2511 @Override connectionServiceFocusGained()2512 public void connectionServiceFocusGained() { 2513 BindCallback callback = new BindCallback() { 2514 @Override 2515 public void onSuccess() { 2516 if (!isServiceValid("connectionServiceFocusGained")) return; 2517 try { 2518 mServiceInterface.connectionServiceFocusGained( 2519 Log.getExternalSession(TELECOM_ABBREVIATION)); 2520 } catch (RemoteException ignored) { 2521 Log.d(this, "failed to inform the focus gained event"); 2522 } 2523 } 2524 2525 @Override 2526 public void onFailure() {} 2527 }; 2528 mBinder.bind(callback, null /* null call */); 2529 } 2530 2531 @Override setConnectionServiceFocusListener( ConnectionServiceFocusManager.ConnectionServiceFocusListener listener)2532 public void setConnectionServiceFocusListener( 2533 ConnectionServiceFocusManager.ConnectionServiceFocusListener listener) { 2534 mConnSvrFocusListener = listener; 2535 } 2536 handleCreateConnectionComplete( String callId, ConnectionRequest request, ParcelableConnection connection)2537 private void handleCreateConnectionComplete( 2538 String callId, 2539 ConnectionRequest request, 2540 ParcelableConnection connection) { 2541 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 2542 // assumption that we have at most one outgoing connection attempt per ConnectionService. 2543 // This may not continue to be the case. 2544 if (connection.getState() == Connection.STATE_DISCONNECTED) { 2545 // A connection that begins in the DISCONNECTED state is an indication of 2546 // failure to connect; we handle all failures uniformly 2547 Call foundCall = mCallIdMapper.getCall(callId); 2548 2549 if (foundCall != null) { 2550 if (connection.getConnectTimeMillis() != 0) { 2551 foundCall.setConnectTimeMillis(connection.getConnectTimeMillis()); 2552 } 2553 2554 // The post-dial digits are created when the call is first created. Normally 2555 // the ConnectionService is responsible for stripping them from the address, but 2556 // since a failed connection will not have done this, we could end up with duplicate 2557 // post-dial digits. 2558 foundCall.clearPostDialDigits(); 2559 } 2560 removeCall(callId, connection.getDisconnectCause()); 2561 } else { 2562 // Successful connection 2563 if (mPendingResponses.containsKey(callId)) { 2564 mPendingResponses.remove(callId) 2565 .handleCreateConnectionSuccess(mCallIdMapper, connection); 2566 } 2567 } 2568 } 2569 handleCreateConferenceComplete( String callId, ConnectionRequest request, ParcelableConference conference)2570 private void handleCreateConferenceComplete( 2571 String callId, 2572 ConnectionRequest request, 2573 ParcelableConference conference) { 2574 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 2575 // assumption that we have at most one outgoing conference attempt per ConnectionService. 2576 // This may not continue to be the case. 2577 if (conference.getState() == Connection.STATE_DISCONNECTED) { 2578 // A conference that begins in the DISCONNECTED state is an indication of 2579 // failure to connect; we handle all failures uniformly 2580 removeCall(callId, conference.getDisconnectCause()); 2581 } else { 2582 // Successful connection 2583 if (mPendingResponses.containsKey(callId)) { 2584 mPendingResponses.remove(callId) 2585 .handleCreateConferenceSuccess(mCallIdMapper, conference); 2586 } 2587 } 2588 } 2589 2590 /** 2591 * Called when the associated connection service dies. 2592 */ handleConnectionServiceDeath()2593 private void handleConnectionServiceDeath() { 2594 if (!mPendingResponses.isEmpty()) { 2595 Collection<CreateConnectionResponse> responses = mPendingResponses.values(); 2596 mPendingResponses.clear(); 2597 for (CreateConnectionResponse response : responses) { 2598 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR, 2599 "CS_DEATH")); 2600 } 2601 } 2602 mCallIdMapper.clear(); 2603 2604 if (mConnSvrFocusListener != null) { 2605 mConnSvrFocusListener.onConnectionServiceDeath(this); 2606 } 2607 } 2608 logIncoming(String msg, Object... params)2609 private void logIncoming(String msg, Object... params) { 2610 // Keep these as debug; the incoming logging is traced on a package level through the 2611 // session logging. 2612 Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: " 2613 + msg, params); 2614 } 2615 logOutgoing(String msg, Object... params)2616 private void logOutgoing(String msg, Object... params) { 2617 Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: " 2618 + msg, params); 2619 } 2620 queryRemoteConnectionServices(final UserHandle userHandle, final String callingPackage, final RemoteServiceCallback callback)2621 private void queryRemoteConnectionServices(final UserHandle userHandle, 2622 final String callingPackage, final RemoteServiceCallback callback) { 2623 boolean isCallerConnectionManager = false; 2624 // For each Sim ConnectionService, use its subid to find the correct connection manager for 2625 // that ConnectionService; return those Sim ConnectionServices which match the connection 2626 // manager. 2627 final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap( 2628 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1)); 2629 for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 2630 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle); 2631 PhoneAccountHandle connectionMgrHandle = mPhoneAccountRegistrar.getSimCallManager(subId, 2632 userHandle); 2633 if (connectionMgrHandle == null 2634 || !connectionMgrHandle.getComponentName().getPackageName().equals( 2635 callingPackage)) { 2636 Log.v(this, "queryRemoteConnectionServices: callingPackage=%s skipped; " 2637 + "doesn't match mgr %s for tfa %s", 2638 callingPackage, connectionMgrHandle, handle); 2639 } else { 2640 isCallerConnectionManager = true; 2641 } 2642 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 2643 handle.getComponentName(), handle.getUserHandle()); 2644 if (service != null && service != this) { 2645 simServices.add(service); 2646 } else { 2647 // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not 2648 // also CAPABILITY_CONNECTION_MANAGER 2649 Log.w(this, "call provider also detected as SIM call manager: " + service); 2650 } 2651 } 2652 2653 Log.i(this, "queryRemoteConnectionServices, simServices = %s", simServices); 2654 // Bail early if the caller isn't the sim connection mgr or no sim connection service 2655 // other than caller available. 2656 if (!isCallerConnectionManager || simServices.isEmpty()) { 2657 Log.d(this, "queryRemoteConnectionServices: not sim call mgr or no simservices."); 2658 noRemoteServices(callback); 2659 return; 2660 } 2661 2662 final List<ComponentName> simServiceComponentNames = new ArrayList<>(); 2663 final List<IBinder> simServiceBinders = new ArrayList<>(); 2664 2665 for (ConnectionServiceWrapper simService : simServices) { 2666 final ConnectionServiceWrapper currentSimService = simService; 2667 2668 currentSimService.mBinder.bind(new BindCallback() { 2669 @Override 2670 public void onSuccess() { 2671 Log.d(this, "queryRemoteConnectionServices: Adding simService %s", 2672 currentSimService.getComponentName()); 2673 if (currentSimService.mServiceInterface == null) { 2674 // The remote ConnectionService died, so do not add it. 2675 // We will still perform maybeComplete() and notify the caller with an empty 2676 // list of sim services via maybeComplete(). 2677 Log.w(this, "queryRemoteConnectionServices: simService %s died - Skipping.", 2678 currentSimService.getComponentName()); 2679 } else { 2680 simServiceComponentNames.add(currentSimService.getComponentName()); 2681 simServiceBinders.add(currentSimService.mServiceInterface.asBinder()); 2682 } 2683 maybeComplete(); 2684 } 2685 2686 @Override 2687 public void onFailure() { 2688 Log.d(this, "queryRemoteConnectionServices: Failed simService %s", 2689 currentSimService.getComponentName()); 2690 // We know maybeComplete() will always be a no-op from now on, so go ahead and 2691 // signal failure of the entire request 2692 noRemoteServices(callback); 2693 } 2694 2695 private void maybeComplete() { 2696 if (simServiceComponentNames.size() == simServices.size()) { 2697 setRemoteServices(callback, simServiceComponentNames, simServiceBinders); 2698 } 2699 } 2700 }, null); 2701 } 2702 } 2703 setRemoteServices( RemoteServiceCallback callback, List<ComponentName> componentNames, List<IBinder> binders)2704 private void setRemoteServices( 2705 RemoteServiceCallback callback, 2706 List<ComponentName> componentNames, 2707 List<IBinder> binders) { 2708 try { 2709 callback.onResult(componentNames, binders); 2710 } catch (RemoteException e) { 2711 Log.e(this, e, "setRemoteServices: Contacting ConnectionService %s", 2712 ConnectionServiceWrapper.this.getComponentName()); 2713 } 2714 } 2715 noRemoteServices(RemoteServiceCallback callback)2716 private void noRemoteServices(RemoteServiceCallback callback) { 2717 setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST); 2718 } 2719 2720 @Override toString()2721 public String toString() { 2722 StringBuilder sb = new StringBuilder(); 2723 sb.append("[ConnectionServiceWrapper componentName="); 2724 sb.append(mComponentName); 2725 sb.append("]"); 2726 return sb.toString(); 2727 } 2728 2729 @VisibleForTesting setScheduledExecutorService(ScheduledExecutorService service)2730 public void setScheduledExecutorService(ScheduledExecutorService service) { 2731 mScheduledExecutor = service; 2732 } 2733 2734 @VisibleForTesting setAnomalyReporterAdapter(AnomalyReporterAdapter mAnomalyReporterAdapter)2735 public void setAnomalyReporterAdapter(AnomalyReporterAdapter mAnomalyReporterAdapter){ 2736 mAnomalyReporter = mAnomalyReporterAdapter; 2737 } 2738 } 2739