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