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