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