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