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 17package com.android.server.telecom; 18 19import android.app.AppOpsManager; 20import android.content.ComponentName; 21import android.content.Context; 22import android.net.Uri; 23import android.os.Binder; 24import android.os.Bundle; 25import android.os.IBinder; 26import android.os.ParcelFileDescriptor; 27import android.os.RemoteException; 28import android.os.UserHandle; 29import android.telecom.CallAudioState; 30import android.telecom.Connection; 31import android.telecom.ConnectionRequest; 32import android.telecom.ConnectionService; 33import android.telecom.DisconnectCause; 34import android.telecom.GatewayInfo; 35import android.telecom.Log; 36import android.telecom.Logging.Session; 37import android.telecom.ParcelableConference; 38import android.telecom.ParcelableConnection; 39import android.telecom.PhoneAccountHandle; 40import android.telecom.StatusHints; 41import android.telecom.TelecomManager; 42import android.telecom.VideoProfile; 43 44import com.android.internal.annotations.VisibleForTesting; 45import com.android.internal.telecom.IConnectionService; 46import com.android.internal.telecom.IConnectionServiceAdapter; 47import com.android.internal.telecom.IVideoProvider; 48import com.android.internal.telecom.RemoteServiceCallback; 49import com.android.internal.util.Preconditions; 50 51import java.util.ArrayList; 52import java.util.Collections; 53import java.util.HashMap; 54import java.util.List; 55import java.util.Map; 56import java.util.Set; 57import java.util.concurrent.ConcurrentHashMap; 58 59/** 60 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps 61 * track of when the object can safely be unbound. Other classes should not use 62 * {@link IConnectionService} directly and instead should use this class to invoke methods of 63 * {@link IConnectionService}. 64 */ 65@VisibleForTesting 66public class ConnectionServiceWrapper extends ServiceBinder { 67 68 private final class Adapter extends IConnectionServiceAdapter.Stub { 69 70 @Override 71 public void handleCreateConnectionComplete(String callId, ConnectionRequest request, 72 ParcelableConnection connection, Session.Info sessionInfo) { 73 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE); 74 long token = Binder.clearCallingIdentity(); 75 try { 76 synchronized (mLock) { 77 logIncoming("handleCreateConnectionComplete %s", callId); 78 ConnectionServiceWrapper.this 79 .handleCreateConnectionComplete(callId, request, connection); 80 81 if (mServiceInterface != null) { 82 logOutgoing("createConnectionComplete %s", callId); 83 try { 84 mServiceInterface.createConnectionComplete(callId, 85 Log.getExternalSession()); 86 } catch (RemoteException e) { 87 } 88 } 89 } 90 } finally { 91 Binder.restoreCallingIdentity(token); 92 Log.endSession(); 93 } 94 } 95 96 @Override 97 public void setActive(String callId, Session.Info sessionInfo) { 98 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE); 99 long token = Binder.clearCallingIdentity(); 100 try { 101 synchronized (mLock) { 102 logIncoming("setActive %s", callId); 103 Call call = mCallIdMapper.getCall(callId); 104 if (call != null) { 105 mCallsManager.markCallAsActive(call); 106 } else { 107 // Log.w(this, "setActive, unknown call id: %s", msg.obj); 108 } 109 } 110 } finally { 111 Binder.restoreCallingIdentity(token); 112 Log.endSession(); 113 } 114 } 115 116 @Override 117 public void setRinging(String callId, Session.Info sessionInfo) { 118 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING); 119 long token = Binder.clearCallingIdentity(); 120 try { 121 synchronized (mLock) { 122 logIncoming("setRinging %s", callId); 123 Call call = mCallIdMapper.getCall(callId); 124 if (call != null) { 125 mCallsManager.markCallAsRinging(call); 126 } else { 127 // Log.w(this, "setRinging, unknown call id: %s", msg.obj); 128 } 129 } 130 } finally { 131 Binder.restoreCallingIdentity(token); 132 Log.endSession(); 133 } 134 } 135 136 @Override 137 public void setVideoProvider(String callId, IVideoProvider videoProvider, 138 Session.Info sessionInfo) { 139 Log.startSession(sessionInfo, "CSW.sVP"); 140 long token = Binder.clearCallingIdentity(); 141 try { 142 synchronized (mLock) { 143 logIncoming("setVideoProvider %s", callId); 144 Call call = mCallIdMapper.getCall(callId); 145 if (call != null) { 146 call.setVideoProvider(videoProvider); 147 } 148 } 149 } finally { 150 Binder.restoreCallingIdentity(token); 151 Log.endSession(); 152 } 153 } 154 155 @Override 156 public void setDialing(String callId, Session.Info sessionInfo) { 157 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING); 158 long token = Binder.clearCallingIdentity(); 159 try { 160 synchronized (mLock) { 161 logIncoming("setDialing %s", callId); 162 Call call = mCallIdMapper.getCall(callId); 163 if (call != null) { 164 mCallsManager.markCallAsDialing(call); 165 } else { 166 // Log.w(this, "setDialing, unknown call id: %s", msg.obj); 167 } 168 } 169 } finally { 170 Binder.restoreCallingIdentity(token); 171 Log.endSession(); 172 } 173 } 174 175 @Override 176 public void setPulling(String callId, Session.Info sessionInfo) { 177 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING); 178 long token = Binder.clearCallingIdentity(); 179 try { 180 synchronized (mLock) { 181 logIncoming("setPulling %s", callId); 182 Call call = mCallIdMapper.getCall(callId); 183 if (call != null) { 184 mCallsManager.markCallAsPulling(call); 185 } 186 } 187 } finally { 188 Binder.restoreCallingIdentity(token); 189 Log.endSession(); 190 } 191 } 192 193 @Override 194 public void setDisconnected(String callId, DisconnectCause disconnectCause, 195 Session.Info sessionInfo) { 196 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED); 197 long token = Binder.clearCallingIdentity(); 198 try { 199 synchronized (mLock) { 200 logIncoming("setDisconnected %s %s", callId, disconnectCause); 201 Call call = mCallIdMapper.getCall(callId); 202 Log.d(this, "disconnect call %s %s", disconnectCause, call); 203 if (call != null) { 204 mCallsManager.markCallAsDisconnected(call, disconnectCause); 205 } else { 206 // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1); 207 } 208 } 209 } finally { 210 Binder.restoreCallingIdentity(token); 211 Log.endSession(); 212 } 213 } 214 215 @Override 216 public void setOnHold(String callId, Session.Info sessionInfo) { 217 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD); 218 long token = Binder.clearCallingIdentity(); 219 try { 220 synchronized (mLock) { 221 logIncoming("setOnHold %s", callId); 222 Call call = mCallIdMapper.getCall(callId); 223 if (call != null) { 224 mCallsManager.markCallAsOnHold(call); 225 } else { 226 // Log.w(this, "setOnHold, unknown call id: %s", msg.obj); 227 } 228 } 229 } finally { 230 Binder.restoreCallingIdentity(token); 231 Log.endSession(); 232 } 233 } 234 235 @Override 236 public void setRingbackRequested(String callId, boolean ringback, 237 Session.Info sessionInfo) { 238 Log.startSession(sessionInfo, "CSW.SRR"); 239 long token = Binder.clearCallingIdentity(); 240 try { 241 synchronized (mLock) { 242 logIncoming("setRingbackRequested %s %b", callId, ringback); 243 Call call = mCallIdMapper.getCall(callId); 244 if (call != null) { 245 call.setRingbackRequested(ringback); 246 } else { 247 // Log.w(this, "setRingback, unknown call id: %s", args.arg1); 248 } 249 } 250 } finally { 251 Binder.restoreCallingIdentity(token); 252 Log.endSession(); 253 } 254 } 255 256 @Override 257 public void removeCall(String callId, Session.Info sessionInfo) { 258 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL); 259 long token = Binder.clearCallingIdentity(); 260 try { 261 synchronized (mLock) { 262 logIncoming("removeCall %s", callId); 263 Call call = mCallIdMapper.getCall(callId); 264 if (call != null) { 265 if (call.isAlive()) { 266 mCallsManager.markCallAsDisconnected( 267 call, new DisconnectCause(DisconnectCause.REMOTE)); 268 } else { 269 mCallsManager.markCallAsRemoved(call); 270 } 271 } 272 } 273 } finally { 274 Binder.restoreCallingIdentity(token); 275 Log.endSession(); 276 } 277 } 278 279 @Override 280 public void setConnectionCapabilities(String callId, int connectionCapabilities, 281 Session.Info sessionInfo) { 282 Log.startSession(sessionInfo, "CSW.sCC"); 283 long token = Binder.clearCallingIdentity(); 284 try { 285 synchronized (mLock) { 286 logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities); 287 Call call = mCallIdMapper.getCall(callId); 288 if (call != null) { 289 call.setConnectionCapabilities(connectionCapabilities); 290 } else { 291 // Log.w(ConnectionServiceWrapper.this, 292 // "setConnectionCapabilities, unknown call id: %s", msg.obj); 293 } 294 } 295 } finally { 296 Binder.restoreCallingIdentity(token); 297 Log.endSession(); 298 } 299 } 300 301 @Override 302 public void setConnectionProperties(String callId, int connectionProperties, 303 Session.Info sessionInfo) { 304 Log.startSession("CSW.sCP"); 305 long token = Binder.clearCallingIdentity(); 306 try { 307 synchronized (mLock) { 308 logIncoming("setConnectionProperties %s %d", callId, connectionProperties); 309 Call call = mCallIdMapper.getCall(callId); 310 if (call != null) { 311 call.setConnectionProperties(connectionProperties); 312 } 313 } 314 } finally { 315 Binder.restoreCallingIdentity(token); 316 Log.endSession(); 317 } 318 } 319 320 @Override 321 public void setIsConferenced(String callId, String conferenceCallId, 322 Session.Info sessionInfo) { 323 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED); 324 long token = Binder.clearCallingIdentity(); 325 try { 326 synchronized (mLock) { 327 logIncoming("setIsConferenced %s %s", callId, conferenceCallId); 328 Call childCall = mCallIdMapper.getCall(callId); 329 if (childCall != null) { 330 if (conferenceCallId == null) { 331 Log.d(this, "unsetting parent: %s", conferenceCallId); 332 childCall.setParentAndChildCall(null); 333 } else { 334 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId); 335 childCall.setParentAndChildCall(conferenceCall); 336 } 337 } else { 338 // Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1); 339 } 340 } 341 } finally { 342 Binder.restoreCallingIdentity(token); 343 Log.endSession(); 344 } 345 } 346 347 @Override 348 public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) { 349 Log.startSession(sessionInfo, "CSW.sCMF"); 350 long token = Binder.clearCallingIdentity(); 351 try { 352 synchronized (mLock) { 353 logIncoming("setConferenceMergeFailed %s", callId); 354 // TODO: we should move the UI for indication a merge failure here 355 // from CallNotifier.onSuppServiceFailed(). This way the InCallUI can 356 // deliver the message anyway that they want. b/20530631. 357 Call call = mCallIdMapper.getCall(callId); 358 if (call != null) { 359 call.onConnectionEvent(Connection.EVENT_CALL_MERGE_FAILED, null); 360 } else { 361 Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId); 362 } 363 } 364 } finally { 365 Binder.restoreCallingIdentity(token); 366 Log.endSession(); 367 } 368 } 369 370 @Override 371 public void addConferenceCall(String callId, ParcelableConference parcelableConference, 372 Session.Info sessionInfo) { 373 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL); 374 long token = Binder.clearCallingIdentity(); 375 try { 376 synchronized (mLock) { 377 if (mCallIdMapper.getCall(callId) != null) { 378 Log.w(this, "Attempting to add a conference call using an existing " + 379 "call id %s", callId); 380 return; 381 } 382 logIncoming("addConferenceCall %s %s [%s]", callId, parcelableConference, 383 parcelableConference.getConnectionIds()); 384 385 // Make sure that there's at least one valid call. For remote connections 386 // we'll get a add conference msg from both the remote connection service 387 // and from the real connection service. 388 boolean hasValidCalls = false; 389 for (String connId : parcelableConference.getConnectionIds()) { 390 if (mCallIdMapper.getCall(connId) != null) { 391 hasValidCalls = true; 392 } 393 } 394 // But don't bail out if the connection count is 0, because that is a valid 395 // IMS conference state. 396 if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) { 397 Log.d(this, "Attempting to add a conference with no valid calls"); 398 return; 399 } 400 401 PhoneAccountHandle phAcc = null; 402 if (parcelableConference != null && 403 parcelableConference.getPhoneAccount() != null) { 404 phAcc = parcelableConference.getPhoneAccount(); 405 } 406 407 Bundle connectionExtras = parcelableConference.getExtras(); 408 409 String connectIdToCheck = null; 410 if (connectionExtras != null && connectionExtras 411 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 412 // Conference was added via a connection manager, see if its original id is 413 // known. 414 connectIdToCheck = connectionExtras 415 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 416 } else { 417 connectIdToCheck = callId; 418 } 419 420 Call conferenceCall; 421 // Check to see if this conference has already been added. 422 Call alreadyAddedConnection = mCallsManager 423 .getAlreadyAddedConnection(connectIdToCheck); 424 if (alreadyAddedConnection != null && mCallIdMapper.getCall(callId) == null) { 425 // We are currently attempting to add the conference via a connection mgr, 426 // and the originating ConnectionService has already added it. Instead of 427 // making a new Telecom call, we will simply add it to the ID mapper here, 428 // and replace the ConnectionService on the call. 429 mCallIdMapper.addCall(alreadyAddedConnection, callId); 430 alreadyAddedConnection.replaceConnectionService( 431 ConnectionServiceWrapper.this); 432 conferenceCall = alreadyAddedConnection; 433 } else { 434 // need to create a new Call 435 Call newConferenceCall = mCallsManager.createConferenceCall(callId, 436 phAcc, parcelableConference); 437 mCallIdMapper.addCall(newConferenceCall, callId); 438 newConferenceCall.setConnectionService(ConnectionServiceWrapper.this); 439 conferenceCall = newConferenceCall; 440 } 441 442 Log.d(this, "adding children to conference %s phAcc %s", 443 parcelableConference.getConnectionIds(), phAcc); 444 for (String connId : parcelableConference.getConnectionIds()) { 445 Call childCall = mCallIdMapper.getCall(connId); 446 Log.d(this, "found child: %s", connId); 447 if (childCall != null) { 448 childCall.setParentAndChildCall(conferenceCall); 449 } 450 } 451 } 452 } finally { 453 Binder.restoreCallingIdentity(token); 454 Log.endSession(); 455 } 456 } 457 458 @Override 459 public void onPostDialWait(String callId, String remaining, 460 Session.Info sessionInfo) throws RemoteException { 461 Log.startSession(sessionInfo, "CSW.oPDW"); 462 long token = Binder.clearCallingIdentity(); 463 try { 464 synchronized (mLock) { 465 logIncoming("onPostDialWait %s %s", callId, remaining); 466 Call call = mCallIdMapper.getCall(callId); 467 if (call != null) { 468 call.onPostDialWait(remaining); 469 } else { 470 // Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1); 471 } 472 } 473 } finally { 474 Binder.restoreCallingIdentity(token); 475 Log.endSession(); 476 } 477 } 478 479 @Override 480 public void onPostDialChar(String callId, char nextChar, 481 Session.Info sessionInfo) throws RemoteException { 482 Log.startSession(sessionInfo, "CSW.oPDC"); 483 long token = Binder.clearCallingIdentity(); 484 try { 485 synchronized (mLock) { 486 logIncoming("onPostDialChar %s %s", callId, nextChar); 487 Call call = mCallIdMapper.getCall(callId); 488 if (call != null) { 489 call.onPostDialChar(nextChar); 490 } else { 491 // Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1); 492 } 493 } 494 } finally { 495 Binder.restoreCallingIdentity(token); 496 Log.endSession(); 497 } 498 } 499 500 @Override 501 public void queryRemoteConnectionServices(RemoteServiceCallback callback, 502 Session.Info sessionInfo) { 503 final UserHandle callingUserHandle = Binder.getCallingUserHandle(); 504 Log.startSession(sessionInfo, "CSW.qRCS"); 505 long token = Binder.clearCallingIdentity(); 506 try { 507 synchronized (mLock) { 508 logIncoming("queryRemoteConnectionServices %s", callback); 509 ConnectionServiceWrapper.this 510 .queryRemoteConnectionServices(callingUserHandle, callback); 511 } 512 } finally { 513 Binder.restoreCallingIdentity(token); 514 Log.endSession(); 515 } 516 } 517 518 @Override 519 public void setVideoState(String callId, int videoState, Session.Info sessionInfo) { 520 Log.startSession(sessionInfo, "CSW.sVS"); 521 long token = Binder.clearCallingIdentity(); 522 try { 523 synchronized (mLock) { 524 logIncoming("setVideoState %s %d", callId, videoState); 525 Call call = mCallIdMapper.getCall(callId); 526 if (call != null) { 527 call.setVideoState(videoState); 528 } 529 } 530 } finally { 531 Binder.restoreCallingIdentity(token); 532 Log.endSession(); 533 } 534 } 535 536 @Override 537 public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) { 538 Log.startSession(sessionInfo, "CSW.sIVAM"); 539 long token = Binder.clearCallingIdentity(); 540 try { 541 synchronized (mLock) { 542 logIncoming("setIsVoipAudioMode %s %b", callId, isVoip); 543 Call call = mCallIdMapper.getCall(callId); 544 if (call != null) { 545 call.setIsVoipAudioMode(isVoip); 546 } 547 } 548 } finally { 549 Binder.restoreCallingIdentity(token); 550 Log.endSession(); 551 } 552 } 553 554 @Override 555 public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) { 556 Log.startSession(sessionInfo, "CSW.sAR"); 557 long token = Binder.clearCallingIdentity(); 558 try { 559 synchronized (mLock) { 560 logIncoming("setAudioRoute %s %s", callId, 561 CallAudioState.audioRouteToString(audioRoute)); 562 mCallsManager.setAudioRoute(audioRoute); 563 } 564 } finally { 565 Binder.restoreCallingIdentity(token); 566 Log.endSession(); 567 } 568 } 569 570 @Override 571 public void setStatusHints(String callId, StatusHints statusHints, 572 Session.Info sessionInfo) { 573 Log.startSession(sessionInfo, "CSW.sSH"); 574 long token = Binder.clearCallingIdentity(); 575 try { 576 synchronized (mLock) { 577 logIncoming("setStatusHints %s %s", callId, statusHints); 578 Call call = mCallIdMapper.getCall(callId); 579 if (call != null) { 580 call.setStatusHints(statusHints); 581 } 582 } 583 } finally { 584 Binder.restoreCallingIdentity(token); 585 Log.endSession(); 586 } 587 } 588 589 @Override 590 public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) { 591 Log.startSession(sessionInfo, "CSW.pE"); 592 long token = Binder.clearCallingIdentity(); 593 try { 594 synchronized (mLock) { 595 Bundle.setDefusable(extras, true); 596 Call call = mCallIdMapper.getCall(callId); 597 if (call != null) { 598 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras); 599 } 600 } 601 } finally { 602 Binder.restoreCallingIdentity(token); 603 Log.endSession(); 604 } 605 } 606 607 @Override 608 public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) { 609 Log.startSession(sessionInfo, "CSW.rE"); 610 long token = Binder.clearCallingIdentity(); 611 try { 612 synchronized (mLock) { 613 logIncoming("removeExtra %s %s", callId, keys); 614 Call call = mCallIdMapper.getCall(callId); 615 if (call != null) { 616 call.removeExtras(Call.SOURCE_CONNECTION_SERVICE, keys); 617 } 618 } 619 } finally { 620 Binder.restoreCallingIdentity(token); 621 Log.endSession(); 622 } 623 } 624 625 @Override 626 public void setAddress(String callId, Uri address, int presentation, 627 Session.Info sessionInfo) { 628 Log.startSession(sessionInfo, "CSW.sA"); 629 long token = Binder.clearCallingIdentity(); 630 try { 631 synchronized (mLock) { 632 logIncoming("setAddress %s %s %d", callId, address, presentation); 633 Call call = mCallIdMapper.getCall(callId); 634 if (call != null) { 635 call.setHandle(address, presentation); 636 } 637 } 638 } finally { 639 Binder.restoreCallingIdentity(token); 640 Log.endSession(); 641 } 642 } 643 644 @Override 645 public void setCallerDisplayName(String callId, String callerDisplayName, int presentation, 646 Session.Info sessionInfo) { 647 Log.startSession(sessionInfo, "CSW.sCDN"); 648 long token = Binder.clearCallingIdentity(); 649 try { 650 synchronized (mLock) { 651 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, 652 presentation); 653 Call call = mCallIdMapper.getCall(callId); 654 if (call != null) { 655 call.setCallerDisplayName(callerDisplayName, presentation); 656 } 657 } 658 } finally { 659 Binder.restoreCallingIdentity(token); 660 Log.endSession(); 661 } 662 } 663 664 @Override 665 public void setConferenceableConnections(String callId, List<String> conferenceableCallIds, 666 Session.Info sessionInfo) { 667 Log.startSession(sessionInfo, "CSW.sCC"); 668 long token = Binder.clearCallingIdentity(); 669 try { 670 synchronized (mLock) { 671 672 Call call = mCallIdMapper.getCall(callId); 673 if (call != null) { 674 logIncoming("setConferenceableConnections %s %s", callId, 675 conferenceableCallIds); 676 List<Call> conferenceableCalls = 677 new ArrayList<>(conferenceableCallIds.size()); 678 for (String otherId : conferenceableCallIds) { 679 Call otherCall = mCallIdMapper.getCall(otherId); 680 if (otherCall != null && otherCall != call) { 681 conferenceableCalls.add(otherCall); 682 } 683 } 684 call.setConferenceableCalls(conferenceableCalls); 685 } 686 } 687 } finally { 688 Binder.restoreCallingIdentity(token); 689 Log.endSession(); 690 } 691 } 692 693 @Override 694 public void addExistingConnection(String callId, ParcelableConnection connection, 695 Session.Info sessionInfo) { 696 Log.startSession(sessionInfo, "CSW.aEC"); 697 UserHandle userHandle = Binder.getCallingUserHandle(); 698 // Check that the Calling Package matches PhoneAccountHandle's Component Package 699 PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount(); 700 if (callingPhoneAccountHandle != null) { 701 mAppOpsManager.checkPackage(Binder.getCallingUid(), 702 callingPhoneAccountHandle.getComponentName().getPackageName()); 703 } 704 long token = Binder.clearCallingIdentity(); 705 try { 706 synchronized (mLock) { 707 // Make sure that the PhoneAccount associated with the incoming 708 // ParcelableConnection is in fact registered to Telecom and is being called 709 // from the correct user. 710 List<PhoneAccountHandle> accountHandles = 711 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/, 712 false /*includeDisabledAccounts*/, userHandle); 713 PhoneAccountHandle phoneAccountHandle = null; 714 for (PhoneAccountHandle accountHandle : accountHandles) { 715 if(accountHandle.equals(callingPhoneAccountHandle)) { 716 phoneAccountHandle = accountHandle; 717 } 718 } 719 // Allow the Sim call manager account as well, even if its disabled. 720 if (phoneAccountHandle == null && callingPhoneAccountHandle != null) { 721 if (callingPhoneAccountHandle.equals( 722 mPhoneAccountRegistrar.getSimCallManager(userHandle))) { 723 phoneAccountHandle = callingPhoneAccountHandle; 724 } 725 } 726 if (phoneAccountHandle != null) { 727 logIncoming("addExistingConnection %s %s", callId, connection); 728 729 Bundle connectionExtras = connection.getExtras(); 730 String connectIdToCheck = null; 731 if (connectionExtras != null && connectionExtras 732 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 733 connectIdToCheck = connectionExtras 734 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 735 } else { 736 connectIdToCheck = callId; 737 } 738 // Check to see if this Connection has already been added. 739 Call alreadyAddedConnection = mCallsManager 740 .getAlreadyAddedConnection(connectIdToCheck); 741 742 if (alreadyAddedConnection != null 743 && mCallIdMapper.getCall(callId) == null) { 744 mCallIdMapper.addCall(alreadyAddedConnection, callId); 745 alreadyAddedConnection 746 .replaceConnectionService(ConnectionServiceWrapper.this); 747 return; 748 } 749 750 Call existingCall = mCallsManager 751 .createCallForExistingConnection(callId, connection); 752 mCallIdMapper.addCall(existingCall, callId); 753 existingCall.setConnectionService(ConnectionServiceWrapper.this); 754 } else { 755 Log.e(this, new RemoteException("The PhoneAccount being used is not " + 756 "currently registered with Telecom."), "Unable to " + 757 "addExistingConnection."); 758 } 759 } 760 } finally { 761 Binder.restoreCallingIdentity(token); 762 Log.endSession(); 763 } 764 } 765 766 @Override 767 public void onConnectionEvent(String callId, String event, Bundle extras, 768 Session.Info sessionInfo) { 769 Log.startSession(sessionInfo, "CSW.oCE"); 770 long token = Binder.clearCallingIdentity(); 771 try { 772 synchronized (mLock) { 773 Bundle.setDefusable(extras, true); 774 Call call = mCallIdMapper.getCall(callId); 775 if (call != null) { 776 call.onConnectionEvent(event, extras); 777 } 778 } 779 } finally { 780 Binder.restoreCallingIdentity(token); 781 Log.endSession(); 782 } 783 } 784 785 @Override 786 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo) 787 throws RemoteException { 788 789 } 790 791 @Override 792 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo) 793 throws RemoteException { 794 Log.startSession(sessionInfo, "CSW.oRIF"); 795 long token = Binder.clearCallingIdentity(); 796 try { 797 synchronized (mLock) { 798 Call call = mCallIdMapper.getCall(callId); 799 if (call != null) { 800 call.onRttConnectionFailure(reason); 801 } 802 } 803 } finally { 804 Binder.restoreCallingIdentity(token); 805 Log.endSession(); 806 } 807 } 808 809 @Override 810 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo) 811 throws RemoteException { 812 813 } 814 815 @Override 816 public void onRemoteRttRequest(String callId, Session.Info sessionInfo) 817 throws RemoteException { 818 Log.startSession(sessionInfo, "CSW.oRRR"); 819 long token = Binder.clearCallingIdentity(); 820 try { 821 synchronized (mLock) { 822 Call call = mCallIdMapper.getCall(callId); 823 if (call != null) { 824 call.onRemoteRttRequest(); 825 } 826 } 827 } finally { 828 Binder.restoreCallingIdentity(token); 829 Log.endSession(); 830 } 831 } 832 } 833 834 private final Adapter mAdapter = new Adapter(); 835 private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId); 836 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>(); 837 838 private Binder2 mBinder = new Binder2(); 839 private IConnectionService mServiceInterface; 840 private final ConnectionServiceRepository mConnectionServiceRepository; 841 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 842 private final CallsManager mCallsManager; 843 private final AppOpsManager mAppOpsManager; 844 845 /** 846 * Creates a connection service. 847 * 848 * @param componentName The component name of the service with which to bind. 849 * @param connectionServiceRepository Connection service repository. 850 * @param phoneAccountRegistrar Phone account registrar 851 * @param callsManager Calls manager 852 * @param context The context. 853 * @param userHandle The {@link UserHandle} to use when binding. 854 */ 855 ConnectionServiceWrapper( 856 ComponentName componentName, 857 ConnectionServiceRepository connectionServiceRepository, 858 PhoneAccountRegistrar phoneAccountRegistrar, 859 CallsManager callsManager, 860 Context context, 861 TelecomSystem.SyncRoot lock, 862 UserHandle userHandle) { 863 super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle); 864 mConnectionServiceRepository = connectionServiceRepository; 865 phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { 866 // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections 867 // To do this, we must proxy remote ConnectionService objects 868 }); 869 mPhoneAccountRegistrar = phoneAccountRegistrar; 870 mCallsManager = callsManager; 871 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 872 } 873 874 /** See {@link IConnectionService#addConnectionServiceAdapter}. */ 875 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 876 if (isServiceValid("addConnectionServiceAdapter")) { 877 try { 878 logOutgoing("addConnectionServiceAdapter %s", adapter); 879 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession()); 880 } catch (RemoteException e) { 881 } 882 } 883 } 884 885 /** See {@link IConnectionService#removeConnectionServiceAdapter}. */ 886 private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 887 if (isServiceValid("removeConnectionServiceAdapter")) { 888 try { 889 logOutgoing("removeConnectionServiceAdapter %s", adapter); 890 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession()); 891 } catch (RemoteException e) { 892 } 893 } 894 } 895 896 /** 897 * Creates a new connection for a new outgoing call or to attach to an existing incoming call. 898 */ 899 @VisibleForTesting 900 public void createConnection(final Call call, final CreateConnectionResponse response) { 901 Log.d(this, "createConnection(%s) via %s.", call, getComponentName()); 902 BindCallback callback = new BindCallback() { 903 @Override 904 public void onSuccess() { 905 String callId = mCallIdMapper.getCallId(call); 906 mPendingResponses.put(callId, response); 907 908 GatewayInfo gatewayInfo = call.getGatewayInfo(); 909 Bundle extras = call.getIntentExtras(); 910 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && 911 gatewayInfo.getOriginalAddress() != null) { 912 extras = (Bundle) extras.clone(); 913 extras.putString( 914 TelecomManager.GATEWAY_PROVIDER_PACKAGE, 915 gatewayInfo.getGatewayProviderPackageName()); 916 extras.putParcelable( 917 TelecomManager.GATEWAY_ORIGINAL_ADDRESS, 918 gatewayInfo.getOriginalAddress()); 919 } 920 921 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper() 922 .getLastEmergencyCallTimeMillis() > 0) { 923 // Add the last emergency call time to the connection request for incoming calls 924 if (extras == call.getIntentExtras()) { 925 extras = (Bundle) extras.clone(); 926 } 927 extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 928 mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis()); 929 } 930 931 Log.addEvent(call, LogUtils.Events.START_CONNECTION, 932 Log.piiHandle(call.getHandle())); 933 934 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 935 .setAccountHandle(call.getTargetPhoneAccount()) 936 .setAddress(call.getHandle()) 937 .setExtras(extras) 938 .setVideoState(call.getVideoState()) 939 .setTelecomCallId(callId) 940 // For self-managed incoming calls, if there is another ongoing call Telecom 941 // is responsible for showing a UI to ask the user if they'd like to answer 942 // this new incoming call. 943 .setShouldShowIncomingCallUi( 944 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 945 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 946 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 947 .build(); 948 949 try { 950 mServiceInterface.createConnection( 951 call.getConnectionManagerPhoneAccount(), 952 callId, 953 connectionRequest, 954 call.shouldAttachToExistingConnection(), 955 call.isUnknown(), 956 Log.getExternalSession()); 957 958 } catch (RemoteException e) { 959 Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); 960 mPendingResponses.remove(callId).handleCreateConnectionFailure( 961 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 962 } 963 } 964 965 @Override 966 public void onFailure() { 967 Log.e(this, new Exception(), "Failure to call %s", getComponentName()); 968 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); 969 } 970 }; 971 972 mBinder.bind(callback, call); 973 } 974 975 /** 976 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 977 * create a connection has been denied or failed. 978 * @param call The call. 979 */ 980 void createConnectionFailed(final Call call) { 981 Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName()); 982 BindCallback callback = new BindCallback() { 983 @Override 984 public void onSuccess() { 985 final String callId = mCallIdMapper.getCallId(call); 986 // If still bound, tell the connection service create connection has failed. 987 if (callId != null && isServiceValid("createConnectionFailed")) { 988 Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED, 989 Log.piiHandle(call.getHandle())); 990 try { 991 logOutgoing("createConnectionFailed %s", callId); 992 mServiceInterface.createConnectionFailed( 993 call.getConnectionManagerPhoneAccount(), 994 callId, 995 new ConnectionRequest( 996 call.getTargetPhoneAccount(), 997 call.getHandle(), 998 call.getIntentExtras(), 999 call.getVideoState(), 1000 callId, 1001 false), 1002 call.isIncoming(), 1003 Log.getExternalSession()); 1004 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1005 call.disconnect(); 1006 } catch (RemoteException e) { 1007 } 1008 } 1009 } 1010 1011 @Override 1012 public void onFailure() { 1013 // Binding failed. Oh no. 1014 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId()); 1015 } 1016 }; 1017 1018 mBinder.bind(callback, call); 1019 } 1020 1021 /** @see IConnectionService#abort(String, Session.Info) */ 1022 void abort(Call call) { 1023 // Clear out any pending outgoing call data 1024 final String callId = mCallIdMapper.getCallId(call); 1025 1026 // If still bound, tell the connection service to abort. 1027 if (callId != null && isServiceValid("abort")) { 1028 try { 1029 logOutgoing("abort %s", callId); 1030 mServiceInterface.abort(callId, Log.getExternalSession()); 1031 } catch (RemoteException e) { 1032 } 1033 } 1034 1035 removeCall(call, new DisconnectCause(DisconnectCause.LOCAL)); 1036 } 1037 1038 /** @see IConnectionService#silence(String, Session.Info) */ 1039 void silence(Call call) { 1040 final String callId = mCallIdMapper.getCallId(call); 1041 if (callId != null && isServiceValid("silence")) { 1042 try { 1043 logOutgoing("silence %s", callId); 1044 mServiceInterface.silence(callId, Log.getExternalSession()); 1045 } catch (RemoteException e) { 1046 } 1047 } 1048 } 1049 1050 /** @see IConnectionService#hold(String, Session.Info) */ 1051 void hold(Call call) { 1052 final String callId = mCallIdMapper.getCallId(call); 1053 if (callId != null && isServiceValid("hold")) { 1054 try { 1055 logOutgoing("hold %s", callId); 1056 mServiceInterface.hold(callId, Log.getExternalSession()); 1057 } catch (RemoteException e) { 1058 } 1059 } 1060 } 1061 1062 /** @see IConnectionService#unhold(String, Session.Info) */ 1063 void unhold(Call call) { 1064 final String callId = mCallIdMapper.getCallId(call); 1065 if (callId != null && isServiceValid("unhold")) { 1066 try { 1067 logOutgoing("unhold %s", callId); 1068 mServiceInterface.unhold(callId, Log.getExternalSession()); 1069 } catch (RemoteException e) { 1070 } 1071 } 1072 } 1073 1074 /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */ 1075 @VisibleForTesting 1076 public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) { 1077 final String callId = mCallIdMapper.getCallId(activeCall); 1078 if (callId != null && isServiceValid("onCallAudioStateChanged")) { 1079 try { 1080 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState); 1081 mServiceInterface.onCallAudioStateChanged(callId, audioState, 1082 Log.getExternalSession()); 1083 } catch (RemoteException e) { 1084 } 1085 } 1086 } 1087 1088 /** @see IConnectionService#disconnect(String, Session.Info) */ 1089 void disconnect(Call call) { 1090 final String callId = mCallIdMapper.getCallId(call); 1091 if (callId != null && isServiceValid("disconnect")) { 1092 try { 1093 logOutgoing("disconnect %s", callId); 1094 mServiceInterface.disconnect(callId, Log.getExternalSession()); 1095 } catch (RemoteException e) { 1096 } 1097 } 1098 } 1099 1100 /** @see IConnectionService#answer(String, Session.Info) */ 1101 void answer(Call call, int videoState) { 1102 final String callId = mCallIdMapper.getCallId(call); 1103 if (callId != null && isServiceValid("answer")) { 1104 try { 1105 logOutgoing("answer %s %d", callId, videoState); 1106 if (VideoProfile.isAudioOnly(videoState)) { 1107 mServiceInterface.answer(callId, Log.getExternalSession()); 1108 } else { 1109 mServiceInterface.answerVideo(callId, videoState, Log.getExternalSession()); 1110 } 1111 } catch (RemoteException e) { 1112 } 1113 } 1114 } 1115 1116 /** @see IConnectionService#reject(String, Session.Info) */ 1117 void reject(Call call, boolean rejectWithMessage, String message) { 1118 final String callId = mCallIdMapper.getCallId(call); 1119 if (callId != null && isServiceValid("reject")) { 1120 try { 1121 logOutgoing("reject %s", callId); 1122 1123 if (rejectWithMessage && call.can( 1124 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 1125 mServiceInterface.rejectWithMessage(callId, message, Log.getExternalSession()); 1126 } else { 1127 mServiceInterface.reject(callId, Log.getExternalSession()); 1128 } 1129 } catch (RemoteException e) { 1130 } 1131 } 1132 } 1133 1134 /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */ 1135 void playDtmfTone(Call call, char digit) { 1136 final String callId = mCallIdMapper.getCallId(call); 1137 if (callId != null && isServiceValid("playDtmfTone")) { 1138 try { 1139 logOutgoing("playDtmfTone %s %c", callId, digit); 1140 mServiceInterface.playDtmfTone(callId, digit, Log.getExternalSession()); 1141 } catch (RemoteException e) { 1142 } 1143 } 1144 } 1145 1146 /** @see IConnectionService#stopDtmfTone(String, Session.Info) */ 1147 void stopDtmfTone(Call call) { 1148 final String callId = mCallIdMapper.getCallId(call); 1149 if (callId != null && isServiceValid("stopDtmfTone")) { 1150 try { 1151 logOutgoing("stopDtmfTone %s", callId); 1152 mServiceInterface.stopDtmfTone(callId, Log.getExternalSession()); 1153 } catch (RemoteException e) { 1154 } 1155 } 1156 } 1157 1158 void addCall(Call call) { 1159 if (mCallIdMapper.getCallId(call) == null) { 1160 mCallIdMapper.addCall(call); 1161 } 1162 } 1163 1164 /** 1165 * Associates newCall with this connection service by replacing callToReplace. 1166 */ 1167 void replaceCall(Call newCall, Call callToReplace) { 1168 Preconditions.checkState(callToReplace.getConnectionService() == this); 1169 mCallIdMapper.replaceCall(newCall, callToReplace); 1170 } 1171 1172 void removeCall(Call call) { 1173 removeCall(call, new DisconnectCause(DisconnectCause.ERROR)); 1174 } 1175 1176 void removeCall(String callId, DisconnectCause disconnectCause) { 1177 CreateConnectionResponse response = mPendingResponses.remove(callId); 1178 if (response != null) { 1179 response.handleCreateConnectionFailure(disconnectCause); 1180 } 1181 1182 mCallIdMapper.removeCall(callId); 1183 } 1184 1185 void removeCall(Call call, DisconnectCause disconnectCause) { 1186 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call)); 1187 if (response != null) { 1188 response.handleCreateConnectionFailure(disconnectCause); 1189 } 1190 1191 mCallIdMapper.removeCall(call); 1192 } 1193 1194 void onPostDialContinue(Call call, boolean proceed) { 1195 final String callId = mCallIdMapper.getCallId(call); 1196 if (callId != null && isServiceValid("onPostDialContinue")) { 1197 try { 1198 logOutgoing("onPostDialContinue %s %b", callId, proceed); 1199 mServiceInterface.onPostDialContinue(callId, proceed, Log.getExternalSession()); 1200 } catch (RemoteException ignored) { 1201 } 1202 } 1203 } 1204 1205 void conference(final Call call, Call otherCall) { 1206 final String callId = mCallIdMapper.getCallId(call); 1207 final String otherCallId = mCallIdMapper.getCallId(otherCall); 1208 if (callId != null && otherCallId != null && isServiceValid("conference")) { 1209 try { 1210 logOutgoing("conference %s %s", callId, otherCallId); 1211 mServiceInterface.conference(callId, otherCallId, Log.getExternalSession()); 1212 } catch (RemoteException ignored) { 1213 } 1214 } 1215 } 1216 1217 void splitFromConference(Call call) { 1218 final String callId = mCallIdMapper.getCallId(call); 1219 if (callId != null && isServiceValid("splitFromConference")) { 1220 try { 1221 logOutgoing("splitFromConference %s", callId); 1222 mServiceInterface.splitFromConference(callId, Log.getExternalSession()); 1223 } catch (RemoteException ignored) { 1224 } 1225 } 1226 } 1227 1228 void mergeConference(Call call) { 1229 final String callId = mCallIdMapper.getCallId(call); 1230 if (callId != null && isServiceValid("mergeConference")) { 1231 try { 1232 logOutgoing("mergeConference %s", callId); 1233 mServiceInterface.mergeConference(callId, Log.getExternalSession()); 1234 } catch (RemoteException ignored) { 1235 } 1236 } 1237 } 1238 1239 void swapConference(Call call) { 1240 final String callId = mCallIdMapper.getCallId(call); 1241 if (callId != null && isServiceValid("swapConference")) { 1242 try { 1243 logOutgoing("swapConference %s", callId); 1244 mServiceInterface.swapConference(callId, Log.getExternalSession()); 1245 } catch (RemoteException ignored) { 1246 } 1247 } 1248 } 1249 1250 void pullExternalCall(Call call) { 1251 final String callId = mCallIdMapper.getCallId(call); 1252 if (callId != null && isServiceValid("pullExternalCall")) { 1253 try { 1254 logOutgoing("pullExternalCall %s", callId); 1255 mServiceInterface.pullExternalCall(callId, Log.getExternalSession()); 1256 } catch (RemoteException ignored) { 1257 } 1258 } 1259 } 1260 1261 void sendCallEvent(Call call, String event, Bundle extras) { 1262 final String callId = mCallIdMapper.getCallId(call); 1263 if (callId != null && isServiceValid("sendCallEvent")) { 1264 try { 1265 logOutgoing("sendCallEvent %s %s", callId, event); 1266 mServiceInterface.sendCallEvent(callId, event, extras, Log.getExternalSession()); 1267 } catch (RemoteException ignored) { 1268 } 1269 } 1270 } 1271 1272 void onExtrasChanged(Call call, Bundle extras) { 1273 final String callId = mCallIdMapper.getCallId(call); 1274 if (callId != null && isServiceValid("onExtrasChanged")) { 1275 try { 1276 logOutgoing("onExtrasChanged %s %s", callId, extras); 1277 mServiceInterface.onExtrasChanged(callId, extras, Log.getExternalSession()); 1278 } catch (RemoteException ignored) { 1279 } 1280 } 1281 } 1282 1283 void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1284 final String callId = mCallIdMapper.getCallId(call); 1285 if (callId != null && isServiceValid("startRtt")) { 1286 try { 1287 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall); 1288 mServiceInterface.startRtt(callId, fromInCall, toInCall, Log.getExternalSession()); 1289 } catch (RemoteException ignored) { 1290 } 1291 } 1292 } 1293 1294 void stopRtt(Call call) { 1295 final String callId = mCallIdMapper.getCallId(call); 1296 if (callId != null && isServiceValid("stopRtt")) { 1297 try { 1298 logOutgoing("stopRtt: %s", callId); 1299 mServiceInterface.stopRtt(callId, Log.getExternalSession()); 1300 } catch (RemoteException ignored) { 1301 } 1302 } 1303 } 1304 1305 void respondToRttRequest( 1306 Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1307 final String callId = mCallIdMapper.getCallId(call); 1308 if (callId != null && isServiceValid("respondToRttRequest")) { 1309 try { 1310 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall); 1311 mServiceInterface.respondToRttUpgradeRequest( 1312 callId, fromInCall, toInCall, Log.getExternalSession()); 1313 } catch (RemoteException ignored) { 1314 } 1315 } 1316 } 1317 1318 /** {@inheritDoc} */ 1319 @Override 1320 protected void setServiceInterface(IBinder binder) { 1321 mServiceInterface = IConnectionService.Stub.asInterface(binder); 1322 Log.v(this, "Adding Connection Service Adapter."); 1323 addConnectionServiceAdapter(mAdapter); 1324 } 1325 1326 /** {@inheritDoc} */ 1327 @Override 1328 protected void removeServiceInterface() { 1329 Log.v(this, "Removing Connection Service Adapter."); 1330 removeConnectionServiceAdapter(mAdapter); 1331 // We have lost our service connection. Notify the world that this service is done. 1332 // We must notify the adapter before CallsManager. The adapter will force any pending 1333 // outgoing calls to try the next service. This needs to happen before CallsManager 1334 // tries to clean up any calls still associated with this service. 1335 handleConnectionServiceDeath(); 1336 mCallsManager.handleConnectionServiceDeath(this); 1337 mServiceInterface = null; 1338 } 1339 1340 private void handleCreateConnectionComplete( 1341 String callId, 1342 ConnectionRequest request, 1343 ParcelableConnection connection) { 1344 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 1345 // assumption that we have at most one outgoing connection attempt per ConnectionService. 1346 // This may not continue to be the case. 1347 if (connection.getState() == Connection.STATE_DISCONNECTED) { 1348 // A connection that begins in the DISCONNECTED state is an indication of 1349 // failure to connect; we handle all failures uniformly 1350 removeCall(callId, connection.getDisconnectCause()); 1351 } else { 1352 // Successful connection 1353 if (mPendingResponses.containsKey(callId)) { 1354 mPendingResponses.remove(callId) 1355 .handleCreateConnectionSuccess(mCallIdMapper, connection); 1356 } 1357 } 1358 } 1359 1360 /** 1361 * Called when the associated connection service dies. 1362 */ 1363 private void handleConnectionServiceDeath() { 1364 if (!mPendingResponses.isEmpty()) { 1365 CreateConnectionResponse[] responses = mPendingResponses.values().toArray( 1366 new CreateConnectionResponse[mPendingResponses.values().size()]); 1367 mPendingResponses.clear(); 1368 for (int i = 0; i < responses.length; i++) { 1369 responses[i].handleCreateConnectionFailure( 1370 new DisconnectCause(DisconnectCause.ERROR)); 1371 } 1372 } 1373 mCallIdMapper.clear(); 1374 } 1375 1376 private void logIncoming(String msg, Object... params) { 1377 Log.d(this, "ConnectionService -> Telecom[" + mComponentName.flattenToShortString() + "]: " 1378 + msg, params); 1379 } 1380 1381 private void logOutgoing(String msg, Object... params) { 1382 Log.d(this, "Telecom -> ConnectionService[" + mComponentName.flattenToShortString() + "]: " 1383 + msg, params); 1384 } 1385 1386 private void queryRemoteConnectionServices(final UserHandle userHandle, 1387 final RemoteServiceCallback callback) { 1388 // Only give remote connection services to this connection service if it is listed as 1389 // the connection manager. 1390 PhoneAccountHandle simCallManager = mPhoneAccountRegistrar.getSimCallManager(userHandle); 1391 Log.d(this, "queryRemoteConnectionServices finds simCallManager = %s", simCallManager); 1392 if (simCallManager == null || 1393 !simCallManager.getComponentName().equals(getComponentName())) { 1394 noRemoteServices(callback); 1395 return; 1396 } 1397 1398 // Make a list of ConnectionServices that are listed as being associated with SIM accounts 1399 final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap( 1400 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1)); 1401 for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 1402 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 1403 handle.getComponentName(), handle.getUserHandle()); 1404 if (service != null) { 1405 simServices.add(service); 1406 } 1407 } 1408 1409 final List<ComponentName> simServiceComponentNames = new ArrayList<>(); 1410 final List<IBinder> simServiceBinders = new ArrayList<>(); 1411 1412 Log.v(this, "queryRemoteConnectionServices, simServices = %s", simServices); 1413 1414 for (ConnectionServiceWrapper simService : simServices) { 1415 if (simService == this) { 1416 // Only happens in the unlikely case that a SIM service is also a SIM call manager 1417 continue; 1418 } 1419 1420 final ConnectionServiceWrapper currentSimService = simService; 1421 1422 currentSimService.mBinder.bind(new BindCallback() { 1423 @Override 1424 public void onSuccess() { 1425 Log.d(this, "Adding simService %s", currentSimService.getComponentName()); 1426 simServiceComponentNames.add(currentSimService.getComponentName()); 1427 simServiceBinders.add(currentSimService.mServiceInterface.asBinder()); 1428 maybeComplete(); 1429 } 1430 1431 @Override 1432 public void onFailure() { 1433 Log.d(this, "Failed simService %s", currentSimService.getComponentName()); 1434 // We know maybeComplete() will always be a no-op from now on, so go ahead and 1435 // signal failure of the entire request 1436 noRemoteServices(callback); 1437 } 1438 1439 private void maybeComplete() { 1440 if (simServiceComponentNames.size() == simServices.size()) { 1441 setRemoteServices(callback, simServiceComponentNames, simServiceBinders); 1442 } 1443 } 1444 }, null); 1445 } 1446 } 1447 1448 private void setRemoteServices( 1449 RemoteServiceCallback callback, 1450 List<ComponentName> componentNames, 1451 List<IBinder> binders) { 1452 try { 1453 callback.onResult(componentNames, binders); 1454 } catch (RemoteException e) { 1455 Log.e(this, e, "Contacting ConnectionService %s", 1456 ConnectionServiceWrapper.this.getComponentName()); 1457 } 1458 } 1459 1460 private void noRemoteServices(RemoteServiceCallback callback) { 1461 setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST); 1462 } 1463} 1464