• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 package com.android.server.audio;
17 
18 import android.annotation.NonNull;
19 import android.bluetooth.BluetoothA2dp;
20 import android.bluetooth.BluetoothDevice;
21 import android.bluetooth.BluetoothHeadset;
22 import android.bluetooth.BluetoothHearingAid;
23 import android.bluetooth.BluetoothProfile;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.media.AudioDeviceAttributes;
28 import android.media.AudioRoutesInfo;
29 import android.media.AudioSystem;
30 import android.media.IAudioRoutesObserver;
31 import android.media.IStrategyPreferredDeviceDispatcher;
32 import android.media.MediaMetrics;
33 import android.os.Binder;
34 import android.os.Handler;
35 import android.os.IBinder;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.PowerManager;
39 import android.os.RemoteException;
40 import android.os.SystemClock;
41 import android.text.TextUtils;
42 import android.util.Log;
43 import android.util.PrintWriterPrinter;
44 
45 import com.android.internal.annotations.GuardedBy;
46 
47 import java.io.PrintWriter;
48 import java.util.ArrayList;
49 import java.util.HashSet;
50 import java.util.NoSuchElementException;
51 import java.util.Set;
52 import java.util.concurrent.atomic.AtomicBoolean;
53 
54 
55 /** @hide */
56 /*package*/ final class AudioDeviceBroker {
57 
58     private static final String TAG = "AS.AudioDeviceBroker";
59 
60     private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s
61 
62     /*package*/ static final  int BTA2DP_DOCK_TIMEOUT_MS = 8000;
63     // Timeout for connection to bluetooth headset service
64     /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
65 
66     // Delay before checking it music should be unmuted after processing an A2DP message
67     private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 100;
68 
69     private final @NonNull AudioService mAudioService;
70     private final @NonNull Context mContext;
71 
72     /** Forced device usage for communications sent to AudioSystem */
73     private int mForcedUseForComm;
74     /**
75      * Externally reported force device usage state returned by getters: always consistent
76      * with requests by setters */
77     private int mForcedUseForCommExt;
78 
79     // Manages all connected devices, only ever accessed on the message loop
80     private final AudioDeviceInventory mDeviceInventory;
81     // Manages notifications to BT service
82     private final BtHelper mBtHelper;
83     // Adapter for system_server-reserved operations
84     private final SystemServerAdapter mSystemServer;
85 
86 
87     //-------------------------------------------------------------------
88     // we use a different lock than mDeviceStateLock so as not to create
89     // lock contention between enqueueing a message and handling them
90     private static final Object sLastDeviceConnectionMsgTimeLock = new Object();
91     @GuardedBy("sLastDeviceConnectionMsgTimeLock")
92     private static long sLastDeviceConnectMsgTime = 0;
93 
94     // General lock to be taken whenever the state of the audio devices is to be checked or changed
95     private final Object mDeviceStateLock = new Object();
96 
97     // Request to override default use of A2DP for media.
98     @GuardedBy("mDeviceStateLock")
99     private boolean mBluetoothA2dpEnabled;
100 
101     // lock always taken when accessing AudioService.mSetModeDeathHandlers
102     // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
103     /*package*/ final Object mSetModeLock = new Object();
104 
105     /** PID of current audio mode owner communicated by AudioService */
106     private int mModeOwnerPid = 0;
107 
108     //-------------------------------------------------------------------
AudioDeviceBroker(@onNull Context context, @NonNull AudioService service)109     /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
110         mContext = context;
111         mAudioService = service;
112         mBtHelper = new BtHelper(this);
113         mDeviceInventory = new AudioDeviceInventory(this);
114         mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext);
115 
116         init();
117     }
118 
119     /** for test purposes only, inject AudioDeviceInventory and adapter for operations running
120      *  in system_server */
AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioDeviceInventory mockDeviceInventory, @NonNull SystemServerAdapter mockSystemServer)121     AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
122                       @NonNull AudioDeviceInventory mockDeviceInventory,
123                       @NonNull SystemServerAdapter mockSystemServer) {
124         mContext = context;
125         mAudioService = service;
126         mBtHelper = new BtHelper(this);
127         mDeviceInventory = mockDeviceInventory;
128         mSystemServer = mockSystemServer;
129 
130         init();
131     }
132 
init()133     private void init() {
134         setupMessaging(mContext);
135 
136         mForcedUseForComm = AudioSystem.FORCE_NONE;
137         mForcedUseForCommExt = mForcedUseForComm;
138     }
139 
getContext()140     /*package*/ Context getContext() {
141         return mContext;
142     }
143 
144     //---------------------------------------------------------------------
145     // Communication from AudioService
146     // All methods are asynchronous and never block
147     // All permission checks are done in AudioService, all incoming calls are considered "safe"
148     // All post* methods are asynchronous
149 
onSystemReady()150     /*package*/ void onSystemReady() {
151         synchronized (mSetModeLock) {
152             synchronized (mDeviceStateLock) {
153                 mModeOwnerPid = mAudioService.getModeOwnerPid();
154                 mBtHelper.onSystemReady();
155             }
156         }
157     }
158 
onAudioServerDied()159     /*package*/ void onAudioServerDied() {
160         // Restore forced usage for communications and record
161         synchronized (mDeviceStateLock) {
162             AudioSystem.setParameters(
163                     "BT_SCO=" + (mForcedUseForComm == AudioSystem.FORCE_BT_SCO ? "on" : "off"));
164             onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm,
165                           false /*fromA2dp*/, "onAudioServerDied");
166             onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm,
167                           false /*fromA2dp*/, "onAudioServerDied");
168         }
169         // restore devices
170         sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE);
171     }
172 
setForceUse_Async(int useCase, int config, String eventSource)173     /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) {
174         sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
175                 useCase, config, eventSource);
176     }
177 
toggleHdmiIfConnected_Async()178     /*package*/ void toggleHdmiIfConnected_Async() {
179         sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE);
180     }
181 
disconnectAllBluetoothProfiles()182     /*package*/ void disconnectAllBluetoothProfiles() {
183         synchronized (mDeviceStateLock) {
184             mBtHelper.disconnectAllBluetoothProfiles();
185         }
186     }
187 
188     /**
189      * Handle BluetoothHeadset intents where the action is one of
190      *   {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or
191      *   {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}.
192      * @param intent
193      */
receiveBtEvent(@onNull Intent intent)194     /*package*/ void receiveBtEvent(@NonNull Intent intent) {
195         synchronized (mSetModeLock) {
196             synchronized (mDeviceStateLock) {
197                 mBtHelper.receiveBtEvent(intent);
198             }
199         }
200     }
201 
setBluetoothA2dpOn_Async(boolean on, String source)202     /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
203         synchronized (mDeviceStateLock) {
204             if (mBluetoothA2dpEnabled == on) {
205                 return;
206             }
207             mBluetoothA2dpEnabled = on;
208             mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
209             sendIILMsgNoDelay(MSG_IIL_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
210                     AudioSystem.FOR_MEDIA,
211                     mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
212                     source);
213         }
214     }
215 
216     /**
217      * Turns speakerphone on/off
218      * @param on
219      * @param eventSource for logging purposes
220      * @return true if speakerphone state changed
221      */
setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource)222     /*package*/ boolean setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) {
223         synchronized (mDeviceStateLock) {
224             if (!addSpeakerphoneClient(cb, pid, on)) {
225                 return false;
226             }
227             if (on) {
228                 // Cancel BT SCO ON request by this same client: speakerphone and BT SCO routes
229                 // are mutually exclusive.
230                 // See symmetrical operation for startBluetoothScoForClient_Sync().
231                 mBtHelper.stopBluetoothScoForPid(pid);
232             }
233             final boolean wasOn = isSpeakerphoneOn();
234             updateSpeakerphoneOn(eventSource);
235             return (wasOn != isSpeakerphoneOn());
236         }
237     }
238 
239     /**
240      * Turns speakerphone off for a given pid and update speakerphone state.
241      * @param pid
242      */
243     @GuardedBy("mDeviceStateLock")
setSpeakerphoneOffForPid(int pid)244     private void setSpeakerphoneOffForPid(int pid) {
245         SpeakerphoneClient client = getSpeakerphoneClientForPid(pid);
246         if (client == null) {
247             return;
248         }
249         client.unregisterDeathRecipient();
250         mSpeakerphoneClients.remove(client);
251         final String eventSource = new StringBuilder("setSpeakerphoneOffForPid(")
252                 .append(pid).append(")").toString();
253         updateSpeakerphoneOn(eventSource);
254     }
255 
256     @GuardedBy("mDeviceStateLock")
updateSpeakerphoneOn(String eventSource)257     private void updateSpeakerphoneOn(String eventSource) {
258         if (isSpeakerphoneOnRequested()) {
259             if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
260                 setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
261             }
262             mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
263         } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
264             if (mBtHelper.isBluetoothScoOn()) {
265                 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
266                 setForceUse_Async(
267                         AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
268             } else {
269                 mForcedUseForComm = AudioSystem.FORCE_NONE;
270             }
271         }
272         mForcedUseForCommExt = mForcedUseForComm;
273         setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
274     }
275 
276     /**
277      * Returns if speakerphone is requested ON or OFF.
278      * If the current audio mode owner is in the speakerphone client list, use this preference.
279      * Otherwise use first client's preference (first client corresponds to latest request).
280      * Speakerphone is requested OFF if no client is in the list.
281      * @return true if speakerphone is requested ON, false otherwise
282      */
283     @GuardedBy("mDeviceStateLock")
isSpeakerphoneOnRequested()284     private boolean isSpeakerphoneOnRequested() {
285         if (mSpeakerphoneClients.isEmpty()) {
286             return false;
287         }
288         for (SpeakerphoneClient cl : mSpeakerphoneClients) {
289             if (cl.getPid() == mModeOwnerPid) {
290                 return cl.isOn();
291             }
292         }
293         return mSpeakerphoneClients.get(0).isOn();
294     }
295 
isSpeakerphoneOn()296     /*package*/ boolean isSpeakerphoneOn() {
297         synchronized (mDeviceStateLock) {
298             return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
299         }
300     }
301 
setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state, String address, String name, String caller)302     /*package*/ void setWiredDeviceConnectionState(int type,
303             @AudioService.ConnectionState int state, String address, String name,
304             String caller) {
305         //TODO move logging here just like in setBluetooth* methods
306         synchronized (mDeviceStateLock) {
307             mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
308         }
309     }
310 
311     private static final class BtDeviceConnectionInfo {
312         final @NonNull BluetoothDevice mDevice;
313         final @AudioService.BtProfileConnectionState int mState;
314         final int mProfile;
315         final boolean mSupprNoisy;
316         final int mVolume;
317 
BtDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int vol)318         BtDeviceConnectionInfo(@NonNull BluetoothDevice device,
319                 @AudioService.BtProfileConnectionState int state,
320                 int profile, boolean suppressNoisyIntent, int vol) {
321             mDevice = device;
322             mState = state;
323             mProfile = profile;
324             mSupprNoisy = suppressNoisyIntent;
325             mVolume = vol;
326         }
327 
328         // redefine equality op so we can match messages intended for this device
329         @Override
equals(Object o)330         public boolean equals(Object o) {
331             if (o == null) {
332                 return false;
333             }
334             if (this == o) {
335                 return true;
336             }
337             if (o instanceof BtDeviceConnectionInfo) {
338                 return mDevice.equals(((BtDeviceConnectionInfo) o).mDevice);
339             }
340             return false;
341         }
342 
343         @Override
toString()344         public String toString() {
345             return "BtDeviceConnectionInfo dev=" + mDevice.toString();
346         }
347     }
348 
349 
postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)350     /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
351             @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
352             int profile, boolean suppressNoisyIntent, int a2dpVolume) {
353         final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
354                 suppressNoisyIntent, a2dpVolume);
355 
356         final String name = TextUtils.emptyIfNull(device.getName());
357         new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
358                 + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
359                 .set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED
360                         ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
361                 .set(MediaMetrics.Property.INDEX, a2dpVolume)
362                 .set(MediaMetrics.Property.NAME, name)
363                 .record();
364 
365         // operations of removing and posting messages related to A2DP device state change must be
366         // mutually exclusive
367         synchronized (mDeviceStateLock) {
368             // when receiving a request to change the connection state of a device, this last
369             // request is the source of truth, so cancel all previous requests that are already in
370             // the handler
371             removeScheduledA2dpEvents(device);
372 
373             sendLMsgNoDelay(
374                     state == BluetoothProfile.STATE_CONNECTED
375                             ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
376                             : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
377                     SENDMSG_QUEUE, info);
378         }
379     }
380 
381     /** remove all previously scheduled connection and state change events for the given device */
382     @GuardedBy("mDeviceStateLock")
removeScheduledA2dpEvents(@onNull BluetoothDevice device)383     private void removeScheduledA2dpEvents(@NonNull BluetoothDevice device) {
384         mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, device);
385 
386         final BtDeviceConnectionInfo connectionInfoToRemove = new BtDeviceConnectionInfo(device,
387                 // the next parameters of the constructor will be ignored when finding the message
388                 // to remove as the equality of the message's object is tested on the device itself
389                 // (see BtDeviceConnectionInfo.equals() method override)
390                 BluetoothProfile.STATE_CONNECTED, 0, false, -1);
391         mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
392                 connectionInfoToRemove);
393         mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION,
394                 connectionInfoToRemove);
395 
396         final BtHelper.BluetoothA2dpDeviceInfo devInfoToRemove =
397                 new BtHelper.BluetoothA2dpDeviceInfo(device);
398         mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
399                 devInfoToRemove);
400         mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
401                 devInfoToRemove);
402         mBrokerHandler.removeEqualMessages(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE,
403                 devInfoToRemove);
404     }
405 
406     private static final class HearingAidDeviceConnectionInfo {
407         final @NonNull BluetoothDevice mDevice;
408         final @AudioService.BtProfileConnectionState int mState;
409         final boolean mSupprNoisy;
410         final int mMusicDevice;
411         final @NonNull String mEventSource;
412 
HearingAidDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)413         HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device,
414                 @AudioService.BtProfileConnectionState int state,
415                 boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
416             mDevice = device;
417             mState = state;
418             mSupprNoisy = suppressNoisyIntent;
419             mMusicDevice = musicDevice;
420             mEventSource = eventSource;
421         }
422     }
423 
postBluetoothHearingAidDeviceConnectionState( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)424     /*package*/ void postBluetoothHearingAidDeviceConnectionState(
425             @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
426             boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
427         final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo(
428                 device, state, suppressNoisyIntent, musicDevice, eventSource);
429         sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
430     }
431 
432     // never called by system components
setBluetoothScoOnByApp(boolean on)433     /*package*/ void setBluetoothScoOnByApp(boolean on) {
434         synchronized (mDeviceStateLock) {
435             mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
436         }
437     }
438 
isBluetoothScoOnForApp()439     /*package*/ boolean isBluetoothScoOnForApp() {
440         synchronized (mDeviceStateLock) {
441             return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
442         }
443     }
444 
setBluetoothScoOn(boolean on, String eventSource)445     /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
446         //Log.i(TAG, "setBluetoothScoOn: " + on + " " + eventSource);
447         synchronized (mDeviceStateLock) {
448             if (on) {
449                 // do not accept SCO ON if SCO audio is not connected
450                 if (!mBtHelper.isBluetoothScoOn()) {
451                     mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
452                     return;
453                 }
454                 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
455             } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
456                 mForcedUseForComm = isSpeakerphoneOnRequested()
457                         ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
458             }
459             mForcedUseForCommExt = mForcedUseForComm;
460             AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
461             sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
462                     AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
463             sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
464                     AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
465         }
466         // Un-mute ringtone stream volume
467         mAudioService.postUpdateRingerModeServiceInt();
468     }
469 
startWatchingRoutes(IAudioRoutesObserver observer)470     /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
471         synchronized (mDeviceStateLock) {
472             return mDeviceInventory.startWatchingRoutes(observer);
473         }
474     }
475 
getCurAudioRoutes()476     /*package*/ AudioRoutesInfo getCurAudioRoutes() {
477         synchronized (mDeviceStateLock) {
478             return mDeviceInventory.getCurAudioRoutes();
479         }
480     }
481 
isAvrcpAbsoluteVolumeSupported()482     /*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
483         synchronized (mDeviceStateLock) {
484             return mBtHelper.isAvrcpAbsoluteVolumeSupported();
485         }
486     }
487 
isBluetoothA2dpOn()488     /*package*/ boolean isBluetoothA2dpOn() {
489         synchronized (mDeviceStateLock) {
490             return mBluetoothA2dpEnabled;
491         }
492     }
493 
postSetAvrcpAbsoluteVolumeIndex(int index)494     /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) {
495         sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index);
496     }
497 
postSetHearingAidVolumeIndex(int index, int streamType)498     /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) {
499         sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
500     }
501 
postSetModeOwnerPid(int pid, int mode)502     /*package*/ void postSetModeOwnerPid(int pid, int mode) {
503         sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
504     }
505 
postBluetoothA2dpDeviceConfigChange(@onNull BluetoothDevice device)506     /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
507         sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device);
508     }
509 
510     @GuardedBy("mSetModeLock")
startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, @NonNull String eventSource)511     /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
512                 @NonNull String eventSource) {
513         synchronized (mDeviceStateLock) {
514             // Cancel speakerphone ON request by this same client: speakerphone and BT SCO routes
515             // are mutually exclusive.
516             // See symmetrical operation for setSpeakerphoneOn(true).
517             setSpeakerphoneOffForPid(Binder.getCallingPid());
518             mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
519         }
520     }
521 
522     @GuardedBy("mSetModeLock")
stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource)523     /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) {
524         synchronized (mDeviceStateLock) {
525             mBtHelper.stopBluetoothScoForClient(cb, eventSource);
526         }
527     }
528 
setPreferredDeviceForStrategySync(int strategy, @NonNull AudioDeviceAttributes device)529     /*package*/ int setPreferredDeviceForStrategySync(int strategy,
530                                                       @NonNull AudioDeviceAttributes device) {
531         return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device);
532     }
533 
removePreferredDeviceForStrategySync(int strategy)534     /*package*/ int removePreferredDeviceForStrategySync(int strategy) {
535         return mDeviceInventory.removePreferredDeviceForStrategySync(strategy);
536     }
537 
registerStrategyPreferredDeviceDispatcher( @onNull IStrategyPreferredDeviceDispatcher dispatcher)538     /*package*/ void registerStrategyPreferredDeviceDispatcher(
539             @NonNull IStrategyPreferredDeviceDispatcher dispatcher) {
540         mDeviceInventory.registerStrategyPreferredDeviceDispatcher(dispatcher);
541     }
542 
unregisterStrategyPreferredDeviceDispatcher( @onNull IStrategyPreferredDeviceDispatcher dispatcher)543     /*package*/ void unregisterStrategyPreferredDeviceDispatcher(
544             @NonNull IStrategyPreferredDeviceDispatcher dispatcher) {
545         mDeviceInventory.unregisterStrategyPreferredDeviceDispatcher(dispatcher);
546     }
547 
548     //---------------------------------------------------------------------
549     // Communication with (to) AudioService
550     //TODO check whether the AudioService methods are candidates to move here
postAccessoryPlugMediaUnmute(int device)551     /*package*/ void postAccessoryPlugMediaUnmute(int device) {
552         mAudioService.postAccessoryPlugMediaUnmute(device);
553     }
554 
getVssVolumeForDevice(int streamType, int device)555     /*package*/ int getVssVolumeForDevice(int streamType, int device) {
556         return mAudioService.getVssVolumeForDevice(streamType, device);
557     }
558 
getModeOwnerPid()559     /*package*/ int getModeOwnerPid() {
560         return mModeOwnerPid;
561     }
562 
getDeviceForStream(int streamType)563     /*package*/ int getDeviceForStream(int streamType) {
564         return mAudioService.getDeviceForStream(streamType);
565     }
566 
postApplyVolumeOnDevice(int streamType, int device, String caller)567     /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) {
568         mAudioService.postApplyVolumeOnDevice(streamType, device, caller);
569     }
570 
postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller)571     /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
572                                                 String caller) {
573         mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller);
574     }
575 
postObserveDevicesForAllStreams()576     /*packages*/ void postObserveDevicesForAllStreams() {
577         mAudioService.postObserveDevicesForAllStreams();
578     }
579 
isInCommunication()580     /*package*/ boolean isInCommunication() {
581         return mAudioService.isInCommunication();
582     }
583 
hasMediaDynamicPolicy()584     /*package*/ boolean hasMediaDynamicPolicy() {
585         return mAudioService.hasMediaDynamicPolicy();
586     }
587 
getContentResolver()588     /*package*/ ContentResolver getContentResolver() {
589         return mAudioService.getContentResolver();
590     }
591 
checkMusicActive(int deviceType, String caller)592     /*package*/ void checkMusicActive(int deviceType, String caller) {
593         mAudioService.checkMusicActive(deviceType, caller);
594     }
595 
checkVolumeCecOnHdmiConnection( @udioService.ConnectionState int state, String caller)596     /*package*/ void checkVolumeCecOnHdmiConnection(
597             @AudioService.ConnectionState  int state, String caller) {
598         mAudioService.postCheckVolumeCecOnHdmiConnection(state, caller);
599     }
600 
hasAudioFocusUsers()601     /*package*/ boolean hasAudioFocusUsers() {
602         return mAudioService.hasAudioFocusUsers();
603     }
604 
605     //---------------------------------------------------------------------
606     // Message handling on behalf of helper classes
postBroadcastScoConnectionState(int state)607     /*package*/ void postBroadcastScoConnectionState(int state) {
608         sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
609     }
610 
postBroadcastBecomingNoisy()611     /*package*/ void postBroadcastBecomingNoisy() {
612         sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
613     }
614 
615     @GuardedBy("mDeviceStateLock")
postA2dpSinkConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)616     /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state,
617             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
618         sendILMsg(state == BluetoothA2dp.STATE_CONNECTED
619                         ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED
620                         : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
621                 SENDMSG_QUEUE,
622                 state, btDeviceInfo, delay);
623     }
624 
postA2dpSourceConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)625     /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state,
626             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
627         sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
628                 state, btDeviceInfo, delay);
629     }
630 
postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay)631     /*package*/ void postSetWiredDeviceConnectionState(
632             AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) {
633         sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
634     }
635 
postSetHearingAidConnectionState( @udioService.BtProfileConnectionState int state, @NonNull BluetoothDevice device, int delay)636     /*package*/ void postSetHearingAidConnectionState(
637             @AudioService.BtProfileConnectionState int state,
638             @NonNull BluetoothDevice device, int delay) {
639         sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE,
640                 state,
641                 device,
642                 delay);
643     }
644 
postDisconnectA2dp()645     /*package*/ void postDisconnectA2dp() {
646         sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
647     }
648 
postDisconnectA2dpSink()649     /*package*/ void postDisconnectA2dpSink() {
650         sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE);
651     }
652 
postDisconnectHearingAid()653     /*package*/ void postDisconnectHearingAid() {
654         sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
655     }
656 
postDisconnectHeadset()657     /*package*/ void postDisconnectHeadset() {
658         sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
659     }
660 
postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile)661     /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) {
662         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile);
663     }
664 
postBtA2dpSinkProfileConnected(BluetoothProfile profile)665     /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) {
666         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile);
667     }
668 
postBtHeasetProfileConnected(BluetoothHeadset headsetProfile)669     /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) {
670         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile);
671     }
672 
postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile)673     /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) {
674         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE,
675                 hearingAidProfile);
676     }
677 
postScoClientDied(Object obj)678     /*package*/ void postScoClientDied(Object obj) {
679         sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
680     }
681 
postSpeakerphoneClientDied(Object obj)682     /*package*/ void postSpeakerphoneClientDied(Object obj) {
683         sendLMsgNoDelay(MSG_L_SPEAKERPHONE_CLIENT_DIED, SENDMSG_QUEUE, obj);
684     }
685 
postSaveSetPreferredDeviceForStrategy(int strategy, AudioDeviceAttributes device)686     /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy,
687                                                            AudioDeviceAttributes device)
688     {
689         sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device);
690     }
691 
postSaveRemovePreferredDeviceForStrategy(int strategy)692     /*package*/ void postSaveRemovePreferredDeviceForStrategy(int strategy) {
693         sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy);
694     }
695 
696     //---------------------------------------------------------------------
697     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
698     // only call from a "handle"* method or "on"* method
699 
700     // Handles request to override default use of A2DP for media.
701     //@GuardedBy("mConnectedDevices")
setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source)702     /*package*/ void setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source) {
703         // for logging only
704         final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on)
705                 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
706                 .append(Binder.getCallingPid()).append(" src:").append(source).toString();
707 
708         synchronized (mDeviceStateLock) {
709             mBluetoothA2dpEnabled = on;
710             mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
711             onSetForceUse(
712                     AudioSystem.FOR_MEDIA,
713                     mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
714                     fromA2dp,
715                     eventSource);
716         }
717     }
718 
handleDeviceConnection(boolean connect, int device, String address, String deviceName)719     /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
720                                                        String deviceName) {
721         synchronized (mDeviceStateLock) {
722             return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
723         }
724     }
725 
postSetA2dpSourceConnectionState(@luetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)726     /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
727             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
728         final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
729         sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state,
730                 btDeviceInfo);
731     }
732 
handleFailureToConnectToBtHeadsetService(int delay)733     /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) {
734         sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay);
735     }
736 
handleCancelFailureToConnectToBtHeadsetService()737     /*package*/ void handleCancelFailureToConnectToBtHeadsetService() {
738         mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
739     }
740 
postReportNewRoutes(boolean fromA2dp)741     /*package*/ void postReportNewRoutes(boolean fromA2dp) {
742         sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP);
743     }
744 
postA2dpActiveDeviceChange( @onNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)745     /*package*/ void postA2dpActiveDeviceChange(
746                     @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
747         sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
748     }
749 
750     // must be called synchronized on mConnectedDevices
hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice)751     /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) {
752         final BtHelper.BluetoothA2dpDeviceInfo devInfoToCheck =
753                 new BtHelper.BluetoothA2dpDeviceInfo(btDevice);
754         return (mBrokerHandler.hasEqualMessages(
755                     MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck)
756             || mBrokerHandler.hasEqualMessages(
757                     MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck));
758     }
759 
setA2dpTimeout(String address, int a2dpCodec, int delayMs)760     /*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) {
761         sendILMsg(MSG_IL_BTA2DP_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs);
762     }
763 
setAvrcpAbsoluteVolumeSupported(boolean supported)764     /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
765         synchronized (mDeviceStateLock) {
766             mBtHelper.setAvrcpAbsoluteVolumeSupported(supported);
767         }
768     }
769 
getBluetoothA2dpEnabled()770     /*package*/ boolean getBluetoothA2dpEnabled() {
771         synchronized (mDeviceStateLock) {
772             return mBluetoothA2dpEnabled;
773         }
774     }
775 
getA2dpCodec(@onNull BluetoothDevice device)776     /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
777         synchronized (mDeviceStateLock) {
778             return mBtHelper.getA2dpCodec(device);
779         }
780     }
781 
dump(PrintWriter pw, String prefix)782     /*package*/ void dump(PrintWriter pw, String prefix) {
783         if (mBrokerHandler != null) {
784             pw.println(prefix + "Message handler (watch for unhandled messages):");
785             mBrokerHandler.dump(new PrintWriterPrinter(pw), prefix + "  ");
786         } else {
787             pw.println("Message handler is null");
788         }
789 
790         mDeviceInventory.dump(pw, prefix);
791 
792         pw.println("\n" + prefix + "mForcedUseForComm: "
793                 +  AudioSystem.forceUseConfigToString(mForcedUseForComm));
794         pw.println(prefix + "mForcedUseForCommExt: "
795                 + AudioSystem.forceUseConfigToString(mForcedUseForCommExt));
796         pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid);
797         pw.println(prefix + "Speakerphone clients:");
798         mSpeakerphoneClients.forEach((cl) -> {
799             pw.println("  " + prefix + "pid: " + cl.getPid() + " on: "
800                         + cl.isOn() + " cb: " + cl.getBinder()); });
801 
802         mBtHelper.dump(pw, prefix);
803     }
804 
805     //---------------------------------------------------------------------
806     // Internal handling of messages
807     // These methods are ALL synchronous, in response to message handling in BrokerHandler
808     // Blocking in any of those will block the message queue
809 
onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource)810     private void onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource) {
811         if (useCase == AudioSystem.FOR_MEDIA) {
812             postReportNewRoutes(fromA2dp);
813         }
814         AudioService.sForceUseLogger.log(
815                 new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource));
816         new MediaMetrics.Item(MediaMetrics.Name.AUDIO_FORCE_USE + MediaMetrics.SEPARATOR
817                 + AudioSystem.forceUseUsageToString(useCase))
818                 .set(MediaMetrics.Property.EVENT, "onSetForceUse")
819                 .set(MediaMetrics.Property.FORCE_USE_DUE_TO, eventSource)
820                 .set(MediaMetrics.Property.FORCE_USE_MODE,
821                         AudioSystem.forceUseConfigToString(config))
822                 .record();
823         AudioSystem.setForceUse(useCase, config);
824     }
825 
onSendBecomingNoisyIntent()826     private void onSendBecomingNoisyIntent() {
827         AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
828                 "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));
829         mSystemServer.sendDeviceBecomingNoisyIntent();
830     }
831 
832     //---------------------------------------------------------------------
833     // Message handling
834     private BrokerHandler mBrokerHandler;
835     private BrokerThread mBrokerThread;
836     private PowerManager.WakeLock mBrokerEventWakeLock;
837 
setupMessaging(Context ctxt)838     private void setupMessaging(Context ctxt) {
839         final PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE);
840         mBrokerEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
841                 "handleAudioDeviceEvent");
842         mBrokerThread = new BrokerThread();
843         mBrokerThread.start();
844         waitForBrokerHandlerCreation();
845     }
846 
waitForBrokerHandlerCreation()847     private void waitForBrokerHandlerCreation() {
848         synchronized (this) {
849             while (mBrokerHandler == null) {
850                 try {
851                     wait();
852                 } catch (InterruptedException e) {
853                     Log.e(TAG, "Interruption while waiting on BrokerHandler");
854                 }
855             }
856         }
857     }
858 
859     /** Class that handles the device broker's message queue */
860     private class BrokerThread extends Thread {
BrokerThread()861         BrokerThread() {
862             super("AudioDeviceBroker");
863         }
864 
865         @Override
run()866         public void run() {
867             // Set this thread up so the handler will work on it
868             Looper.prepare();
869 
870             synchronized (AudioDeviceBroker.this) {
871                 mBrokerHandler = new BrokerHandler();
872 
873                 // Notify that the handler has been created
874                 AudioDeviceBroker.this.notify();
875             }
876 
877             Looper.loop();
878         }
879     }
880 
881     /** Class that handles the message queue */
882     private class BrokerHandler extends Handler {
883 
884         @Override
handleMessage(Message msg)885         public void handleMessage(Message msg) {
886             switch (msg.what) {
887                 case MSG_RESTORE_DEVICES:
888                     synchronized (mDeviceStateLock) {
889                         mDeviceInventory.onRestoreDevices();
890                         mBtHelper.onAudioServerDiedRestoreA2dp();
891                     }
892                     break;
893                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
894                     synchronized (mDeviceStateLock) {
895                         mDeviceInventory.onSetWiredDeviceConnectionState(
896                                 (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
897                     }
898                     break;
899                 case MSG_I_BROADCAST_BT_CONNECTION_STATE:
900                     synchronized (mDeviceStateLock) {
901                         mBtHelper.onBroadcastScoConnectionState(msg.arg1);
902                     }
903                     break;
904                 case MSG_IIL_SET_FORCE_USE: // intended fall-through
905                 case MSG_IIL_SET_FORCE_BT_A2DP_USE:
906                     onSetForceUse(msg.arg1, msg.arg2,
907                                   (msg.what == MSG_IIL_SET_FORCE_BT_A2DP_USE), (String) msg.obj);
908                     break;
909                 case MSG_REPORT_NEW_ROUTES:
910                 case MSG_REPORT_NEW_ROUTES_A2DP:
911                     synchronized (mDeviceStateLock) {
912                         mDeviceInventory.onReportNewRoutes();
913                     }
914                     break;
915                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
916                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
917                     synchronized (mDeviceStateLock) {
918                         mDeviceInventory.onSetA2dpSinkConnectionState(
919                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
920                     }
921                     break;
922                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
923                     synchronized (mDeviceStateLock) {
924                         mDeviceInventory.onSetA2dpSourceConnectionState(
925                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
926                     }
927                     break;
928                 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
929                     synchronized (mDeviceStateLock) {
930                         mDeviceInventory.onSetHearingAidConnectionState(
931                                 (BluetoothDevice) msg.obj, msg.arg1,
932                                 mAudioService.getHearingAidStreamType());
933                     }
934                     break;
935                 case MSG_BT_HEADSET_CNCT_FAILED:
936                     synchronized (mSetModeLock) {
937                         synchronized (mDeviceStateLock) {
938                             mBtHelper.resetBluetoothSco();
939                         }
940                     }
941                     break;
942                 case MSG_IL_BTA2DP_TIMEOUT:
943                     // msg.obj  == address of BTA2DP device
944                     synchronized (mDeviceStateLock) {
945                         mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
946                     }
947                     break;
948                 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
949                     final int a2dpCodec;
950                     final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
951                     synchronized (mDeviceStateLock) {
952                         a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
953                         // TODO: name of method being called on AudioDeviceInventory is currently
954                         //       misleading (config change vs active device change), to be
955                         //       reconciliated once the BT side has been updated.
956                         mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
957                                 new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
958                                         BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
959                     }
960                     break;
961                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
962                     onSendBecomingNoisyIntent();
963                     break;
964                 case MSG_II_SET_HEARING_AID_VOLUME:
965                     synchronized (mDeviceStateLock) {
966                         mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
967                     }
968                     break;
969                 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
970                     synchronized (mDeviceStateLock) {
971                         mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
972                     }
973                     break;
974                 case MSG_I_SET_MODE_OWNER_PID:
975                     synchronized (mSetModeLock) {
976                         synchronized (mDeviceStateLock) {
977                             if (mModeOwnerPid != msg.arg1) {
978                                 mModeOwnerPid = msg.arg1;
979                                 if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
980                                     updateSpeakerphoneOn("setNewModeOwner");
981                                 }
982                                 if (mModeOwnerPid != 0) {
983                                     mBtHelper.disconnectBluetoothSco(mModeOwnerPid);
984                                 }
985                             }
986                         }
987                     }
988                     break;
989                 case MSG_L_SCOCLIENT_DIED:
990                     synchronized (mSetModeLock) {
991                         synchronized (mDeviceStateLock) {
992                             mBtHelper.scoClientDied(msg.obj);
993                         }
994                     }
995                     break;
996                 case MSG_L_SPEAKERPHONE_CLIENT_DIED:
997                     synchronized (mDeviceStateLock) {
998                         speakerphoneClientDied(msg.obj);
999                     }
1000                     break;
1001                 case MSG_TOGGLE_HDMI:
1002                     synchronized (mDeviceStateLock) {
1003                         mDeviceInventory.onToggleHdmi();
1004                     }
1005                     break;
1006                 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
1007                     synchronized (mDeviceStateLock) {
1008                         mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
1009                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj,
1010                                  BtHelper.EVENT_ACTIVE_DEVICE_CHANGE);
1011                     }
1012                     break;
1013                 case MSG_DISCONNECT_A2DP:
1014                     synchronized (mDeviceStateLock) {
1015                         mDeviceInventory.disconnectA2dp();
1016                     }
1017                     break;
1018                 case MSG_DISCONNECT_A2DP_SINK:
1019                     synchronized (mDeviceStateLock) {
1020                         mDeviceInventory.disconnectA2dpSink();
1021                     }
1022                     break;
1023                 case MSG_DISCONNECT_BT_HEARING_AID:
1024                     synchronized (mDeviceStateLock) {
1025                         mDeviceInventory.disconnectHearingAid();
1026                     }
1027                     break;
1028                 case MSG_DISCONNECT_BT_HEADSET:
1029                     synchronized (mSetModeLock) {
1030                         synchronized (mDeviceStateLock) {
1031                             mBtHelper.disconnectHeadset();
1032                         }
1033                     }
1034                     break;
1035                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
1036                     synchronized (mDeviceStateLock) {
1037                         mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
1038                     }
1039                     break;
1040                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK:
1041                     synchronized (mDeviceStateLock) {
1042                         mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj);
1043                     }
1044                     break;
1045                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID:
1046                     synchronized (mDeviceStateLock) {
1047                         mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
1048                     }
1049                     break;
1050                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
1051                     synchronized (mSetModeLock) {
1052                         synchronized (mDeviceStateLock) {
1053                             mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
1054                         }
1055                     }
1056                     break;
1057                 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
1058                 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: {
1059                     final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
1060                     AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
1061                             "msg: setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
1062                                     + " state=" + info.mState
1063                                     // only querying address as this is the only readily available
1064                                     // field on the device
1065                                     + " addr=" + info.mDevice.getAddress()
1066                                     + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
1067                                     + " vol=" + info.mVolume)).printLog(TAG));
1068                     synchronized (mDeviceStateLock) {
1069                         mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
1070                                 info.mDevice, info.mState, info.mProfile, info.mSupprNoisy,
1071                                 AudioSystem.DEVICE_NONE, info.mVolume);
1072                     }
1073                 } break;
1074                 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: {
1075                     final HearingAidDeviceConnectionInfo info =
1076                             (HearingAidDeviceConnectionInfo) msg.obj;
1077                     AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
1078                             "msg: setHearingAidDeviceConnectionState state=" + info.mState
1079                                     + " addr=" + info.mDevice.getAddress()
1080                                     + " supprNoisy=" + info.mSupprNoisy
1081                                     + " src=" + info.mEventSource)).printLog(TAG));
1082                     synchronized (mDeviceStateLock) {
1083                         mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
1084                                 info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
1085                     }
1086                 } break;
1087                 case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: {
1088                     final int strategy = msg.arg1;
1089                     final AudioDeviceAttributes device = (AudioDeviceAttributes) msg.obj;
1090                     mDeviceInventory.onSaveSetPreferredDevice(strategy, device);
1091                 } break;
1092                 case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: {
1093                     final int strategy = msg.arg1;
1094                     mDeviceInventory.onSaveRemovePreferredDevice(strategy);
1095                 } break;
1096                 case MSG_CHECK_MUTE_MUSIC:
1097                     checkMessagesMuteMusic(0);
1098                     break;
1099                 default:
1100                     Log.wtf(TAG, "Invalid message " + msg.what);
1101             }
1102 
1103             // Give some time to Bluetooth service to post a connection message
1104             // in case of active device switch
1105             if (MESSAGES_MUTE_MUSIC.contains(msg.what)) {
1106                 sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, BTA2DP_MUTE_CHECK_DELAY_MS);
1107             }
1108 
1109             if (isMessageHandledUnderWakelock(msg.what)) {
1110                 try {
1111                     mBrokerEventWakeLock.release();
1112                 } catch (Exception e) {
1113                     Log.e(TAG, "Exception releasing wakelock", e);
1114                 }
1115             }
1116         }
1117     }
1118 
1119     // List of all messages. If a message has be handled under wakelock, add it to
1120     //    the isMessageHandledUnderWakelock(int) method
1121     // Naming of msg indicates arguments, using JNI argument grammar
1122     // (e.g. II indicates two int args, IL indicates int and Obj arg)
1123     private static final int MSG_RESTORE_DEVICES = 1;
1124     private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2;
1125     private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3;
1126     private static final int MSG_IIL_SET_FORCE_USE = 4;
1127     private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5;
1128     private static final int MSG_TOGGLE_HDMI = 6;
1129     private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7;
1130     private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8;
1131     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
1132     private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
1133 
1134     // process change of A2DP device configuration, obj is BluetoothDevice
1135     private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11;
1136 
1137     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12;
1138     private static final int MSG_REPORT_NEW_ROUTES = 13;
1139     private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
1140     private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
1141     private static final int MSG_I_SET_MODE_OWNER_PID = 16;
1142 
1143     // process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo
1144     private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
1145 
1146     private static final int MSG_DISCONNECT_A2DP = 19;
1147     private static final int MSG_DISCONNECT_A2DP_SINK = 20;
1148     private static final int MSG_DISCONNECT_BT_HEARING_AID = 21;
1149     private static final int MSG_DISCONNECT_BT_HEADSET = 22;
1150     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23;
1151     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
1152     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
1153     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
1154 
1155     // process change of state, obj is BtHelper.BluetoothA2dpDeviceInfo
1156     private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27;
1157     private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28;
1158 
1159     // process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo
1160     private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29;
1161     private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
1162 
1163     // process external command to (dis)connect a hearing aid device
1164     private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
1165 
1166     // a ScoClient died in BtHelper
1167     private static final int MSG_L_SCOCLIENT_DIED = 32;
1168     private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33;
1169     private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
1170 
1171     private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35;
1172     private static final int MSG_CHECK_MUTE_MUSIC = 36;
1173     private static final int MSG_REPORT_NEW_ROUTES_A2DP = 37;
1174 
1175 
isMessageHandledUnderWakelock(int msgId)1176     private static boolean isMessageHandledUnderWakelock(int msgId) {
1177         switch(msgId) {
1178             case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
1179             case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
1180             case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
1181             case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
1182             case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
1183             case MSG_IL_BTA2DP_TIMEOUT:
1184             case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
1185             case MSG_TOGGLE_HDMI:
1186             case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
1187             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
1188             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
1189             case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
1190             case MSG_CHECK_MUTE_MUSIC:
1191                 return true;
1192             default:
1193                 return false;
1194         }
1195     }
1196 
1197     // Message helper methods
1198 
1199     // sendMsg() flags
1200     /** If the msg is already queued, replace it with this one. */
1201     private static final int SENDMSG_REPLACE = 0;
1202     /** If the msg is already queued, ignore this one and leave the old. */
1203     private static final int SENDMSG_NOOP = 1;
1204     /** If the msg is already queued, queue this one and leave the old. */
1205     private static final int SENDMSG_QUEUE = 2;
1206 
sendMsg(int msg, int existingMsgPolicy, int delay)1207     private void sendMsg(int msg, int existingMsgPolicy, int delay) {
1208         sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay);
1209     }
1210 
sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay)1211     private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) {
1212         sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay);
1213     }
1214 
sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay)1215     private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) {
1216         sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay);
1217     }
1218 
sendIMsg(int msg, int existingMsgPolicy, int arg, int delay)1219     private void sendIMsg(int msg, int existingMsgPolicy, int arg, int delay) {
1220         sendIILMsg(msg, existingMsgPolicy, arg, 0, null, delay);
1221     }
1222 
sendMsgNoDelay(int msg, int existingMsgPolicy)1223     private void sendMsgNoDelay(int msg, int existingMsgPolicy) {
1224         sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0);
1225     }
1226 
sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg)1227     private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) {
1228         sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0);
1229     }
1230 
sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2)1231     private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) {
1232         sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0);
1233     }
1234 
sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj)1235     private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) {
1236         sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0);
1237     }
1238 
sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj)1239     private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) {
1240         sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0);
1241     }
1242 
sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj)1243     private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) {
1244         sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0);
1245     }
1246 
sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)1247     private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj,
1248                             int delay) {
1249         if (existingMsgPolicy == SENDMSG_REPLACE) {
1250             mBrokerHandler.removeMessages(msg);
1251         } else if (existingMsgPolicy == SENDMSG_NOOP && mBrokerHandler.hasMessages(msg)) {
1252             return;
1253         }
1254 
1255         if (isMessageHandledUnderWakelock(msg)) {
1256             final long identity = Binder.clearCallingIdentity();
1257             try {
1258                 mBrokerEventWakeLock.acquire(BROKER_WAKELOCK_TIMEOUT_MS);
1259             } catch (Exception e) {
1260                 Log.e(TAG, "Exception acquiring wakelock", e);
1261             }
1262             Binder.restoreCallingIdentity(identity);
1263         }
1264 
1265         if (MESSAGES_MUTE_MUSIC.contains(msg)) {
1266             checkMessagesMuteMusic(msg);
1267         }
1268 
1269         synchronized (sLastDeviceConnectionMsgTimeLock) {
1270             long time = SystemClock.uptimeMillis() + delay;
1271 
1272             switch (msg) {
1273                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
1274                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
1275                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
1276                 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
1277                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
1278                 case MSG_IL_BTA2DP_TIMEOUT:
1279                 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
1280                 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
1281                     if (sLastDeviceConnectMsgTime >= time) {
1282                         // add a little delay to make sure messages are ordered as expected
1283                         time = sLastDeviceConnectMsgTime + 30;
1284                     }
1285                     sLastDeviceConnectMsgTime = time;
1286                     break;
1287                 default:
1288                     break;
1289             }
1290             mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj),
1291                     time);
1292         }
1293     }
1294 
1295     /** List of messages for which music is muted while processing is pending */
1296     private static final Set<Integer> MESSAGES_MUTE_MUSIC;
1297     static {
1298         MESSAGES_MUTE_MUSIC = new HashSet<>();
1299         MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED);
1300         MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED);
1301         MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
1302         MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE);
1303         MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION);
1304         MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION);
1305         MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
1306         MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP);
1307     }
1308 
1309     private AtomicBoolean mMusicMuted = new AtomicBoolean(false);
1310 
1311     /** Mutes or unmutes music according to pending A2DP messages */
checkMessagesMuteMusic(int message)1312     private void checkMessagesMuteMusic(int message) {
1313         boolean mute = message != 0;
1314         if (!mute) {
1315             for (int msg : MESSAGES_MUTE_MUSIC) {
1316                 if (mBrokerHandler.hasMessages(msg)) {
1317                     mute = true;
1318                     break;
1319                 }
1320             }
1321         }
1322 
1323         if (mute != mMusicMuted.getAndSet(mute)) {
1324             mAudioService.setMusicMute(mute);
1325         }
1326     }
1327 
1328     private class SpeakerphoneClient implements IBinder.DeathRecipient {
1329         private final IBinder mCb;
1330         private final int mPid;
1331         private final boolean mOn;
SpeakerphoneClient(IBinder cb, int pid, boolean on)1332         SpeakerphoneClient(IBinder cb, int pid, boolean on) {
1333             mCb = cb;
1334             mPid = pid;
1335             mOn = on;
1336         }
1337 
registerDeathRecipient()1338         public boolean registerDeathRecipient() {
1339             boolean status = false;
1340             try {
1341                 mCb.linkToDeath(this, 0);
1342                 status = true;
1343             } catch (RemoteException e) {
1344                 Log.w(TAG, "SpeakerphoneClient could not link to " + mCb + " binder death");
1345             }
1346             return status;
1347         }
1348 
unregisterDeathRecipient()1349         public void unregisterDeathRecipient() {
1350             try {
1351                 mCb.unlinkToDeath(this, 0);
1352             } catch (NoSuchElementException e) {
1353                 Log.w(TAG, "SpeakerphoneClient could not not unregistered to binder");
1354             }
1355         }
1356 
1357         @Override
binderDied()1358         public void binderDied() {
1359             postSpeakerphoneClientDied(this);
1360         }
1361 
getBinder()1362         IBinder getBinder() {
1363             return mCb;
1364         }
1365 
getPid()1366         int getPid() {
1367             return mPid;
1368         }
1369 
isOn()1370         boolean isOn() {
1371             return mOn;
1372         }
1373     }
1374 
1375     @GuardedBy("mDeviceStateLock")
speakerphoneClientDied(Object obj)1376     private void speakerphoneClientDied(Object obj) {
1377         if (obj == null) {
1378             return;
1379         }
1380         Log.w(TAG, "Speaker client died");
1381         if (removeSpeakerphoneClient(((SpeakerphoneClient) obj).getBinder(), false) != null) {
1382             updateSpeakerphoneOn("speakerphoneClientDied");
1383         }
1384     }
1385 
removeSpeakerphoneClient(IBinder cb, boolean unregister)1386     private SpeakerphoneClient removeSpeakerphoneClient(IBinder cb, boolean unregister) {
1387         for (SpeakerphoneClient cl : mSpeakerphoneClients) {
1388             if (cl.getBinder() == cb) {
1389                 if (unregister) {
1390                     cl.unregisterDeathRecipient();
1391                 }
1392                 mSpeakerphoneClients.remove(cl);
1393                 return cl;
1394             }
1395         }
1396         return null;
1397     }
1398 
1399     @GuardedBy("mDeviceStateLock")
addSpeakerphoneClient(IBinder cb, int pid, boolean on)1400     private boolean addSpeakerphoneClient(IBinder cb, int pid, boolean on) {
1401         // always insert new request at first position
1402         removeSpeakerphoneClient(cb, true);
1403         SpeakerphoneClient client = new SpeakerphoneClient(cb, pid, on);
1404         if (client.registerDeathRecipient()) {
1405             mSpeakerphoneClients.add(0, client);
1406             return true;
1407         }
1408         return false;
1409     }
1410 
1411     @GuardedBy("mDeviceStateLock")
getSpeakerphoneClientForPid(int pid)1412     private SpeakerphoneClient getSpeakerphoneClientForPid(int pid) {
1413         for (SpeakerphoneClient cl : mSpeakerphoneClients) {
1414             if (cl.getPid() == pid) {
1415                 return cl;
1416             }
1417         }
1418         return null;
1419     }
1420 
1421     // List of clients requesting speakerPhone ON
1422     @GuardedBy("mDeviceStateLock")
1423     private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
1424             new ArrayList<SpeakerphoneClient>();
1425 
1426 }
1427