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.AudioManager;
28 import android.media.AudioRoutesInfo;
29 import android.media.AudioSystem;
30 import android.media.IAudioRoutesObserver;
31 import android.os.Binder;
32 import android.os.Handler;
33 import android.os.IBinder;
34 import android.os.Looper;
35 import android.os.Message;
36 import android.os.PowerManager;
37 import android.os.SystemClock;
38 import android.os.UserHandle;
39 import android.util.Log;
40 import android.util.PrintWriterPrinter;
41 
42 import com.android.internal.annotations.GuardedBy;
43 
44 import java.io.PrintWriter;
45 
46 /** @hide */
47 /*package*/ final class AudioDeviceBroker {
48 
49     private static final String TAG = "AS.AudioDeviceBroker";
50 
51     private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s
52 
53     /*package*/ static final  int BTA2DP_DOCK_TIMEOUT_MS = 8000;
54     // Timeout for connection to bluetooth headset service
55     /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
56 
57     private final @NonNull AudioService mAudioService;
58     private final @NonNull Context mContext;
59 
60     /** Forced device usage for communications sent to AudioSystem */
61     private int mForcedUseForComm;
62     /**
63      * Externally reported force device usage state returned by getters: always consistent
64      * with requests by setters */
65     private int mForcedUseForCommExt;
66 
67     // Manages all connected devices, only ever accessed on the message loop
68     private final AudioDeviceInventory mDeviceInventory;
69     // Manages notifications to BT service
70     private final BtHelper mBtHelper;
71 
72 
73     //-------------------------------------------------------------------
74     // we use a different lock than mDeviceStateLock so as not to create
75     // lock contention between enqueueing a message and handling them
76     private static final Object sLastDeviceConnectionMsgTimeLock = new Object();
77     @GuardedBy("sLastDeviceConnectionMsgTimeLock")
78     private static long sLastDeviceConnectMsgTime = 0;
79 
80     // General lock to be taken whenever the state of the audio devices is to be checked or changed
81     private final Object mDeviceStateLock = new Object();
82 
83     // Request to override default use of A2DP for media.
84     @GuardedBy("mDeviceStateLock")
85     private boolean mBluetoothA2dpEnabled;
86 
87     // lock always taken when accessing AudioService.mSetModeDeathHandlers
88     // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
89     /*package*/ final Object mSetModeLock = new Object();
90 
91     //-------------------------------------------------------------------
AudioDeviceBroker(@onNull Context context, @NonNull AudioService service)92     /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
93         mContext = context;
94         mAudioService = service;
95         mBtHelper = new BtHelper(this);
96         mDeviceInventory = new AudioDeviceInventory(this);
97 
98         init();
99     }
100 
101     /** for test purposes only, inject AudioDeviceInventory */
AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioDeviceInventory mockDeviceInventory)102     AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
103                       @NonNull AudioDeviceInventory mockDeviceInventory) {
104         mContext = context;
105         mAudioService = service;
106         mBtHelper = new BtHelper(this);
107         mDeviceInventory = mockDeviceInventory;
108 
109         init();
110     }
111 
init()112     private void init() {
113         setupMessaging(mContext);
114 
115         mForcedUseForComm = AudioSystem.FORCE_NONE;
116         mForcedUseForCommExt = mForcedUseForComm;
117     }
118 
getContext()119     /*package*/ Context getContext() {
120         return mContext;
121     }
122 
123     //---------------------------------------------------------------------
124     // Communication from AudioService
125     // All methods are asynchronous and never block
126     // All permission checks are done in AudioService, all incoming calls are considered "safe"
127     // All post* methods are asynchronous
128 
onSystemReady()129     /*package*/ void onSystemReady() {
130         synchronized (mSetModeLock) {
131             synchronized (mDeviceStateLock) {
132                 mBtHelper.onSystemReady();
133             }
134         }
135     }
136 
onAudioServerDied()137     /*package*/ void onAudioServerDied() {
138         // Restore forced usage for communications and record
139         synchronized (mDeviceStateLock) {
140             AudioSystem.setParameters(
141                     "BT_SCO=" + (mForcedUseForComm == AudioSystem.FORCE_BT_SCO ? "on" : "off"));
142             onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
143             onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
144         }
145         // restore devices
146         sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE);
147     }
148 
setForceUse_Async(int useCase, int config, String eventSource)149     /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) {
150         sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
151                 useCase, config, eventSource);
152     }
153 
toggleHdmiIfConnected_Async()154     /*package*/ void toggleHdmiIfConnected_Async() {
155         sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE);
156     }
157 
disconnectAllBluetoothProfiles()158     /*package*/ void disconnectAllBluetoothProfiles() {
159         synchronized (mDeviceStateLock) {
160             mBtHelper.disconnectAllBluetoothProfiles();
161         }
162     }
163 
164     /**
165      * Handle BluetoothHeadset intents where the action is one of
166      *   {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or
167      *   {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}.
168      * @param intent
169      */
receiveBtEvent(@onNull Intent intent)170     /*package*/ void receiveBtEvent(@NonNull Intent intent) {
171         synchronized (mSetModeLock) {
172             synchronized (mDeviceStateLock) {
173                 mBtHelper.receiveBtEvent(intent);
174             }
175         }
176     }
177 
setBluetoothA2dpOn_Async(boolean on, String source)178     /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
179         synchronized (mDeviceStateLock) {
180             if (mBluetoothA2dpEnabled == on) {
181                 return;
182             }
183             mBluetoothA2dpEnabled = on;
184             mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
185             sendIILMsgNoDelay(MSG_IIL_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
186                     AudioSystem.FOR_MEDIA,
187                     mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
188                     source);
189         }
190     }
191 
192     /**
193      * Turns speakerphone on/off
194      * @param on
195      * @param eventSource for logging purposes
196      * @return true if speakerphone state changed
197      */
setSpeakerphoneOn(boolean on, String eventSource)198     /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) {
199         synchronized (mDeviceStateLock) {
200             final boolean wasOn = isSpeakerphoneOn();
201             if (on) {
202                 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
203                     setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
204                 }
205                 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
206             } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
207                 mForcedUseForComm = AudioSystem.FORCE_NONE;
208             }
209 
210             mForcedUseForCommExt = mForcedUseForComm;
211             setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
212             return (wasOn != isSpeakerphoneOn());
213         }
214     }
215 
isSpeakerphoneOn()216     /*package*/ boolean isSpeakerphoneOn() {
217         synchronized (mDeviceStateLock) {
218             return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
219         }
220     }
221 
setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state, String address, String name, String caller)222     /*package*/ void setWiredDeviceConnectionState(int type,
223             @AudioService.ConnectionState int state, String address, String name,
224             String caller) {
225         //TODO move logging here just like in setBluetooth* methods
226         synchronized (mDeviceStateLock) {
227             mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
228         }
229     }
230 
231     private static final class BtDeviceConnectionInfo {
232         final @NonNull BluetoothDevice mDevice;
233         final @AudioService.BtProfileConnectionState int mState;
234         final int mProfile;
235         final boolean mSupprNoisy;
236         final int mVolume;
237 
BtDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int vol)238         BtDeviceConnectionInfo(@NonNull BluetoothDevice device,
239                 @AudioService.BtProfileConnectionState int state,
240                 int profile, boolean suppressNoisyIntent, int vol) {
241             mDevice = device;
242             mState = state;
243             mProfile = profile;
244             mSupprNoisy = suppressNoisyIntent;
245             mVolume = vol;
246         }
247 
248         // redefine equality op so we can match messages intended for this device
249         @Override
equals(Object o)250         public boolean equals(Object o) {
251             return mDevice.equals(o);
252         }
253     }
254 
255 
postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)256     /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
257             @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
258             int profile, boolean suppressNoisyIntent, int a2dpVolume) {
259         final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
260                 suppressNoisyIntent, a2dpVolume);
261 
262         // when receiving a request to change the connection state of a device, this last request
263         // is the source of truth, so cancel all previous requests
264         removeAllA2dpConnectionEvents(device);
265 
266         sendLMsgNoDelay(
267                 state == BluetoothProfile.STATE_CONNECTED
268                         ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
269                         : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
270                 SENDMSG_QUEUE, info);
271     }
272 
273     /** remove all previously scheduled connection and disconnection events for the given device */
removeAllA2dpConnectionEvents(@onNull BluetoothDevice device)274     private void removeAllA2dpConnectionEvents(@NonNull BluetoothDevice device) {
275         mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
276                 device);
277         mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION,
278                 device);
279         mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
280                 device);
281         mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
282                 device);
283     }
284 
285     private static final class HearingAidDeviceConnectionInfo {
286         final @NonNull BluetoothDevice mDevice;
287         final @AudioService.BtProfileConnectionState int mState;
288         final boolean mSupprNoisy;
289         final int mMusicDevice;
290         final @NonNull String mEventSource;
291 
HearingAidDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)292         HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device,
293                 @AudioService.BtProfileConnectionState int state,
294                 boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
295             mDevice = device;
296             mState = state;
297             mSupprNoisy = suppressNoisyIntent;
298             mMusicDevice = musicDevice;
299             mEventSource = eventSource;
300         }
301     }
302 
postBluetoothHearingAidDeviceConnectionState( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)303     /*package*/ void postBluetoothHearingAidDeviceConnectionState(
304             @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
305             boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
306         final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo(
307                 device, state, suppressNoisyIntent, musicDevice, eventSource);
308         sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
309     }
310 
311     // never called by system components
setBluetoothScoOnByApp(boolean on)312     /*package*/ void setBluetoothScoOnByApp(boolean on) {
313         synchronized (mDeviceStateLock) {
314             mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
315         }
316     }
317 
isBluetoothScoOnForApp()318     /*package*/ boolean isBluetoothScoOnForApp() {
319         synchronized (mDeviceStateLock) {
320             return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
321         }
322     }
323 
setBluetoothScoOn(boolean on, String eventSource)324     /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
325         //Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
326         synchronized (mDeviceStateLock) {
327             if (on) {
328                 // do not accept SCO ON if SCO audio is not connected
329                 if (!mBtHelper.isBluetoothScoOn()) {
330                     mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
331                     return;
332                 }
333                 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
334             } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
335                 mForcedUseForComm = AudioSystem.FORCE_NONE;
336             }
337             mForcedUseForCommExt = mForcedUseForComm;
338             AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
339             sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
340                     AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
341             sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
342                     AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
343         }
344         // Un-mute ringtone stream volume
345         mAudioService.postUpdateRingerModeServiceInt();
346     }
347 
startWatchingRoutes(IAudioRoutesObserver observer)348     /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
349         synchronized (mDeviceStateLock) {
350             return mDeviceInventory.startWatchingRoutes(observer);
351         }
352     }
353 
getCurAudioRoutes()354     /*package*/ AudioRoutesInfo getCurAudioRoutes() {
355         synchronized (mDeviceStateLock) {
356             return mDeviceInventory.getCurAudioRoutes();
357         }
358     }
359 
isAvrcpAbsoluteVolumeSupported()360     /*package*/ boolean isAvrcpAbsoluteVolumeSupported() {
361         synchronized (mDeviceStateLock) {
362             return mBtHelper.isAvrcpAbsoluteVolumeSupported();
363         }
364     }
365 
isBluetoothA2dpOn()366     /*package*/ boolean isBluetoothA2dpOn() {
367         synchronized (mDeviceStateLock) {
368             return mBluetoothA2dpEnabled;
369         }
370     }
371 
postSetAvrcpAbsoluteVolumeIndex(int index)372     /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) {
373         sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index);
374     }
375 
postSetHearingAidVolumeIndex(int index, int streamType)376     /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) {
377         sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
378     }
379 
postDisconnectBluetoothSco(int exceptPid)380     /*package*/ void postDisconnectBluetoothSco(int exceptPid) {
381         sendIMsgNoDelay(MSG_I_DISCONNECT_BT_SCO, SENDMSG_REPLACE, exceptPid);
382     }
383 
postBluetoothA2dpDeviceConfigChange(@onNull BluetoothDevice device)384     /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
385         sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device);
386     }
387 
388     @GuardedBy("mSetModeLock")
startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, @NonNull String eventSource)389     /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
390                 @NonNull String eventSource) {
391         synchronized (mDeviceStateLock) {
392             mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
393         }
394     }
395 
396     @GuardedBy("mSetModeLock")
stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource)397     /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) {
398         synchronized (mDeviceStateLock) {
399             mBtHelper.stopBluetoothScoForClient(cb, eventSource);
400         }
401     }
402 
403     //---------------------------------------------------------------------
404     // Communication with (to) AudioService
405     //TODO check whether the AudioService methods are candidates to move here
postAccessoryPlugMediaUnmute(int device)406     /*package*/ void postAccessoryPlugMediaUnmute(int device) {
407         mAudioService.postAccessoryPlugMediaUnmute(device);
408     }
409 
getVssVolumeForDevice(int streamType, int device)410     /*package*/ int getVssVolumeForDevice(int streamType, int device) {
411         return mAudioService.getVssVolumeForDevice(streamType, device);
412     }
413 
getModeOwnerPid()414     /*package*/ int getModeOwnerPid() {
415         return mAudioService.getModeOwnerPid();
416     }
417 
getDeviceForStream(int streamType)418     /*package*/ int getDeviceForStream(int streamType) {
419         return mAudioService.getDeviceForStream(streamType);
420     }
421 
postApplyVolumeOnDevice(int streamType, int device, String caller)422     /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) {
423         mAudioService.postApplyVolumeOnDevice(streamType, device, caller);
424     }
425 
postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller)426     /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
427                                                 String caller) {
428         mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller);
429     }
430 
postObserveDevicesForAllStreams()431     /*packages*/ void postObserveDevicesForAllStreams() {
432         mAudioService.postObserveDevicesForAllStreams();
433     }
434 
isInCommunication()435     /*package*/ boolean isInCommunication() {
436         return mAudioService.isInCommunication();
437     }
438 
hasMediaDynamicPolicy()439     /*package*/ boolean hasMediaDynamicPolicy() {
440         return mAudioService.hasMediaDynamicPolicy();
441     }
442 
getContentResolver()443     /*package*/ ContentResolver getContentResolver() {
444         return mAudioService.getContentResolver();
445     }
446 
checkMusicActive(int deviceType, String caller)447     /*package*/ void checkMusicActive(int deviceType, String caller) {
448         mAudioService.checkMusicActive(deviceType, caller);
449     }
450 
checkVolumeCecOnHdmiConnection( @udioService.ConnectionState int state, String caller)451     /*package*/ void checkVolumeCecOnHdmiConnection(
452             @AudioService.ConnectionState  int state, String caller) {
453         mAudioService.postCheckVolumeCecOnHdmiConnection(state, caller);
454     }
455 
hasAudioFocusUsers()456     /*package*/ boolean hasAudioFocusUsers() {
457         return mAudioService.hasAudioFocusUsers();
458     }
459 
460     //---------------------------------------------------------------------
461     // Message handling on behalf of helper classes
postBroadcastScoConnectionState(int state)462     /*package*/ void postBroadcastScoConnectionState(int state) {
463         sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
464     }
465 
postBroadcastBecomingNoisy()466     /*package*/ void postBroadcastBecomingNoisy() {
467         sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
468     }
469 
postA2dpSinkConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)470     /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state,
471             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
472         sendILMsg(state == BluetoothA2dp.STATE_CONNECTED
473                         ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED
474                         : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
475                 SENDMSG_QUEUE,
476                 state, btDeviceInfo, delay);
477     }
478 
postA2dpSourceConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)479     /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state,
480             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
481         sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
482                 state, btDeviceInfo, delay);
483     }
484 
postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay)485     /*package*/ void postSetWiredDeviceConnectionState(
486             AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) {
487         sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
488     }
489 
postSetHearingAidConnectionState( @udioService.BtProfileConnectionState int state, @NonNull BluetoothDevice device, int delay)490     /*package*/ void postSetHearingAidConnectionState(
491             @AudioService.BtProfileConnectionState int state,
492             @NonNull BluetoothDevice device, int delay) {
493         sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE,
494                 state,
495                 device,
496                 delay);
497     }
498 
postDisconnectA2dp()499     /*package*/ void postDisconnectA2dp() {
500         sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
501     }
502 
postDisconnectA2dpSink()503     /*package*/ void postDisconnectA2dpSink() {
504         sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE);
505     }
506 
postDisconnectHearingAid()507     /*package*/ void postDisconnectHearingAid() {
508         sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
509     }
510 
postDisconnectHeadset()511     /*package*/ void postDisconnectHeadset() {
512         sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
513     }
514 
postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile)515     /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) {
516         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile);
517     }
518 
postBtA2dpSinkProfileConnected(BluetoothProfile profile)519     /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) {
520         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile);
521     }
522 
postBtHeasetProfileConnected(BluetoothHeadset headsetProfile)523     /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) {
524         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile);
525     }
526 
postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile)527     /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) {
528         sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE,
529                 hearingAidProfile);
530     }
531 
postScoClientDied(Object obj)532     /*package*/ void postScoClientDied(Object obj) {
533         sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
534     }
535 
536     //---------------------------------------------------------------------
537     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
538     // only call from a "handle"* method or "on"* method
539 
540     // Handles request to override default use of A2DP for media.
541     //@GuardedBy("mConnectedDevices")
setBluetoothA2dpOnInt(boolean on, String source)542     /*package*/ void setBluetoothA2dpOnInt(boolean on, String source) {
543         // for logging only
544         final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on)
545                 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
546                 .append(Binder.getCallingPid()).append(" src:").append(source).toString();
547 
548         synchronized (mDeviceStateLock) {
549             mBluetoothA2dpEnabled = on;
550             mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE);
551             onSetForceUse(
552                     AudioSystem.FOR_MEDIA,
553                     mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
554                     eventSource);
555         }
556     }
557 
handleDeviceConnection(boolean connect, int device, String address, String deviceName)558     /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
559                                                        String deviceName) {
560         synchronized (mDeviceStateLock) {
561             return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName);
562         }
563     }
564 
postSetA2dpSourceConnectionState(@luetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)565     /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
566             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
567         final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
568         sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state,
569                 btDeviceInfo);
570     }
571 
handleFailureToConnectToBtHeadsetService(int delay)572     /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) {
573         sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay);
574     }
575 
handleCancelFailureToConnectToBtHeadsetService()576     /*package*/ void handleCancelFailureToConnectToBtHeadsetService() {
577         mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
578     }
579 
postReportNewRoutes()580     /*package*/ void postReportNewRoutes() {
581         sendMsgNoDelay(MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP);
582     }
583 
cancelA2dpDockTimeout()584     /*package*/ void cancelA2dpDockTimeout() {
585         mBrokerHandler.removeMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT);
586     }
587 
postA2dpActiveDeviceChange( @onNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)588     /*package*/ void postA2dpActiveDeviceChange(
589                     @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
590         sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
591     }
592 
hasScheduledA2dpDockTimeout()593     /*package*/ boolean hasScheduledA2dpDockTimeout() {
594         return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT);
595     }
596 
597     // must be called synchronized on mConnectedDevices
hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice)598     /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) {
599         return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
600                         new BtHelper.BluetoothA2dpDeviceInfo(btDevice))
601                 || mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
602                         new BtHelper.BluetoothA2dpDeviceInfo(btDevice)));
603     }
604 
setA2dpDockTimeout(String address, int a2dpCodec, int delayMs)605     /*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) {
606         sendILMsg(MSG_IL_BTA2DP_DOCK_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs);
607     }
608 
setAvrcpAbsoluteVolumeSupported(boolean supported)609     /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
610         synchronized (mDeviceStateLock) {
611             mBtHelper.setAvrcpAbsoluteVolumeSupported(supported);
612         }
613     }
614 
getBluetoothA2dpEnabled()615     /*package*/ boolean getBluetoothA2dpEnabled() {
616         synchronized (mDeviceStateLock) {
617             return mBluetoothA2dpEnabled;
618         }
619     }
620 
getA2dpCodec(@onNull BluetoothDevice device)621     /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
622         synchronized (mDeviceStateLock) {
623             return mBtHelper.getA2dpCodec(device);
624         }
625     }
626 
dump(PrintWriter pw, String prefix)627     /*package*/ void dump(PrintWriter pw, String prefix) {
628         if (mBrokerHandler != null) {
629             pw.println(prefix + "Message handler (watch for unhandled messages):");
630             mBrokerHandler.dump(new PrintWriterPrinter(pw), prefix + "  ");
631         } else {
632             pw.println("Message handler is null");
633         }
634     }
635 
636     //---------------------------------------------------------------------
637     // Internal handling of messages
638     // These methods are ALL synchronous, in response to message handling in BrokerHandler
639     // Blocking in any of those will block the message queue
640 
onSetForceUse(int useCase, int config, String eventSource)641     private void onSetForceUse(int useCase, int config, String eventSource) {
642         if (useCase == AudioSystem.FOR_MEDIA) {
643             postReportNewRoutes();
644         }
645         AudioService.sForceUseLogger.log(
646                 new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource));
647         AudioSystem.setForceUse(useCase, config);
648     }
649 
onSendBecomingNoisyIntent()650     private void onSendBecomingNoisyIntent() {
651         AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
652                 "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));
653         sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
654     }
655 
656     //---------------------------------------------------------------------
657     // Message handling
658     private BrokerHandler mBrokerHandler;
659     private BrokerThread mBrokerThread;
660     private PowerManager.WakeLock mBrokerEventWakeLock;
661 
setupMessaging(Context ctxt)662     private void setupMessaging(Context ctxt) {
663         final PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE);
664         mBrokerEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
665                 "handleAudioDeviceEvent");
666         mBrokerThread = new BrokerThread();
667         mBrokerThread.start();
668         waitForBrokerHandlerCreation();
669     }
670 
waitForBrokerHandlerCreation()671     private void waitForBrokerHandlerCreation() {
672         synchronized (this) {
673             while (mBrokerHandler == null) {
674                 try {
675                     wait();
676                 } catch (InterruptedException e) {
677                     Log.e(TAG, "Interruption while waiting on BrokerHandler");
678                 }
679             }
680         }
681     }
682 
683     /** Class that handles the device broker's message queue */
684     private class BrokerThread extends Thread {
BrokerThread()685         BrokerThread() {
686             super("AudioDeviceBroker");
687         }
688 
689         @Override
run()690         public void run() {
691             // Set this thread up so the handler will work on it
692             Looper.prepare();
693 
694             synchronized (AudioDeviceBroker.this) {
695                 mBrokerHandler = new BrokerHandler();
696 
697                 // Notify that the handler has been created
698                 AudioDeviceBroker.this.notify();
699             }
700 
701             Looper.loop();
702         }
703     }
704 
705     /** Class that handles the message queue */
706     private class BrokerHandler extends Handler {
707 
708         @Override
handleMessage(Message msg)709         public void handleMessage(Message msg) {
710             switch (msg.what) {
711                 case MSG_RESTORE_DEVICES:
712                     synchronized (mDeviceStateLock) {
713                         mDeviceInventory.onRestoreDevices();
714                         mBtHelper.onAudioServerDiedRestoreA2dp();
715                     }
716                     break;
717                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
718                     synchronized (mDeviceStateLock) {
719                         mDeviceInventory.onSetWiredDeviceConnectionState(
720                                 (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
721                     }
722                     break;
723                 case MSG_I_BROADCAST_BT_CONNECTION_STATE:
724                     synchronized (mDeviceStateLock) {
725                         mBtHelper.onBroadcastScoConnectionState(msg.arg1);
726                     }
727                     break;
728                 case MSG_IIL_SET_FORCE_USE: // intended fall-through
729                 case MSG_IIL_SET_FORCE_BT_A2DP_USE:
730                     onSetForceUse(msg.arg1, msg.arg2, (String) msg.obj);
731                     break;
732                 case MSG_REPORT_NEW_ROUTES:
733                     synchronized (mDeviceStateLock) {
734                         mDeviceInventory.onReportNewRoutes();
735                     }
736                     break;
737                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
738                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
739                     synchronized (mDeviceStateLock) {
740                         mDeviceInventory.onSetA2dpSinkConnectionState(
741                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
742                     }
743                     break;
744                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
745                     synchronized (mDeviceStateLock) {
746                         mDeviceInventory.onSetA2dpSourceConnectionState(
747                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
748                     }
749                     break;
750                 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
751                     synchronized (mDeviceStateLock) {
752                         mDeviceInventory.onSetHearingAidConnectionState(
753                                 (BluetoothDevice) msg.obj, msg.arg1,
754                                 mAudioService.getHearingAidStreamType());
755                     }
756                     break;
757                 case MSG_BT_HEADSET_CNCT_FAILED:
758                     synchronized (mSetModeLock) {
759                         synchronized (mDeviceStateLock) {
760                             mBtHelper.resetBluetoothSco();
761                         }
762                     }
763                     break;
764                 case MSG_IL_BTA2DP_DOCK_TIMEOUT:
765                     // msg.obj  == address of BTA2DP device
766                     synchronized (mDeviceStateLock) {
767                         mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
768                     }
769                     break;
770                 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
771                     final int a2dpCodec;
772                     final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
773                     synchronized (mDeviceStateLock) {
774                         a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
775                         mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
776                                 new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
777                                         BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
778                     }
779                     break;
780                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
781                     onSendBecomingNoisyIntent();
782                     break;
783                 case MSG_II_SET_HEARING_AID_VOLUME:
784                     synchronized (mDeviceStateLock) {
785                         mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
786                     }
787                     break;
788                 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
789                     synchronized (mDeviceStateLock) {
790                         mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
791                     }
792                     break;
793                 case MSG_I_DISCONNECT_BT_SCO:
794                     synchronized (mSetModeLock) {
795                         synchronized (mDeviceStateLock) {
796                             mBtHelper.disconnectBluetoothSco(msg.arg1);
797                         }
798                     }
799                     break;
800                 case MSG_L_SCOCLIENT_DIED:
801                     synchronized (mSetModeLock) {
802                         synchronized (mDeviceStateLock) {
803                             mBtHelper.scoClientDied(msg.obj);
804                         }
805                     }
806                     break;
807                 case MSG_TOGGLE_HDMI:
808                     synchronized (mDeviceStateLock) {
809                         mDeviceInventory.onToggleHdmi();
810                     }
811                     break;
812                 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
813                     synchronized (mDeviceStateLock) {
814                         mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
815                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj,
816                                  BtHelper.EVENT_ACTIVE_DEVICE_CHANGE);
817                     }
818                     break;
819                 case MSG_DISCONNECT_A2DP:
820                     synchronized (mDeviceStateLock) {
821                         mDeviceInventory.disconnectA2dp();
822                     }
823                     break;
824                 case MSG_DISCONNECT_A2DP_SINK:
825                     synchronized (mDeviceStateLock) {
826                         mDeviceInventory.disconnectA2dpSink();
827                     }
828                     break;
829                 case MSG_DISCONNECT_BT_HEARING_AID:
830                     synchronized (mDeviceStateLock) {
831                         mDeviceInventory.disconnectHearingAid();
832                     }
833                     break;
834                 case MSG_DISCONNECT_BT_HEADSET:
835                     synchronized (mSetModeLock) {
836                         synchronized (mDeviceStateLock) {
837                             mBtHelper.disconnectHeadset();
838                         }
839                     }
840                     break;
841                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
842                     synchronized (mDeviceStateLock) {
843                         mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
844                     }
845                     break;
846                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK:
847                     synchronized (mDeviceStateLock) {
848                         mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj);
849                     }
850                     break;
851                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID:
852                     synchronized (mDeviceStateLock) {
853                         mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
854                     }
855                     break;
856                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
857                     synchronized (mSetModeLock) {
858                         synchronized (mDeviceStateLock) {
859                             mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
860                         }
861                     }
862                     break;
863                 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
864                 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: {
865                     final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
866                     AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
867                             "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
868                                     + " state=" + info.mState
869                                     // only querying address as this is the only readily available
870                                     // field on the device
871                                     + " addr=" + info.mDevice.getAddress()
872                                     + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
873                                     + " vol=" + info.mVolume)).printLog(TAG));
874                     synchronized (mDeviceStateLock) {
875                         mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
876                                 info.mDevice, info.mState, info.mProfile, info.mSupprNoisy,
877                                 AudioSystem.DEVICE_NONE, info.mVolume);
878                     }
879                 } break;
880                 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: {
881                     final HearingAidDeviceConnectionInfo info =
882                             (HearingAidDeviceConnectionInfo) msg.obj;
883                     AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
884                             "setHearingAidDeviceConnectionState state=" + info.mState
885                                     + " addr=" + info.mDevice.getAddress()
886                                     + " supprNoisy=" + info.mSupprNoisy
887                                     + " src=" + info.mEventSource)).printLog(TAG));
888                     synchronized (mDeviceStateLock) {
889                         mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
890                                 info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
891                     }
892                 } break;
893                 default:
894                     Log.wtf(TAG, "Invalid message " + msg.what);
895             }
896             if (isMessageHandledUnderWakelock(msg.what)) {
897                 try {
898                     mBrokerEventWakeLock.release();
899                 } catch (Exception e) {
900                     Log.e(TAG, "Exception releasing wakelock", e);
901                 }
902             }
903         }
904     }
905 
906     // List of all messages. If a message has be handled under wakelock, add it to
907     //    the isMessageHandledUnderWakelock(int) method
908     // Naming of msg indicates arguments, using JNI argument grammar
909     // (e.g. II indicates two int args, IL indicates int and Obj arg)
910     private static final int MSG_RESTORE_DEVICES = 1;
911     private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2;
912     private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3;
913     private static final int MSG_IIL_SET_FORCE_USE = 4;
914     private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5;
915     private static final int MSG_TOGGLE_HDMI = 6;
916     private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7;
917     private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8;
918     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
919     private static final int MSG_IL_BTA2DP_DOCK_TIMEOUT = 10;
920     private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11;
921     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12;
922     private static final int MSG_REPORT_NEW_ROUTES = 13;
923     private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
924     private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
925     private static final int MSG_I_DISCONNECT_BT_SCO = 16;
926     private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
927     private static final int MSG_DISCONNECT_A2DP = 19;
928     private static final int MSG_DISCONNECT_A2DP_SINK = 20;
929     private static final int MSG_DISCONNECT_BT_HEARING_AID = 21;
930     private static final int MSG_DISCONNECT_BT_HEADSET = 22;
931     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23;
932     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
933     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
934     private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
935     private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27;
936     private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28;
937     // process external command to (dis)connect an A2DP device
938     private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29;
939     private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
940     // process external command to (dis)connect a hearing aid device
941     private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
942     // a ScoClient died in BtHelper
943     private static final int MSG_L_SCOCLIENT_DIED = 32;
944 
945 
isMessageHandledUnderWakelock(int msgId)946     private static boolean isMessageHandledUnderWakelock(int msgId) {
947         switch(msgId) {
948             case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
949             case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
950             case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
951             case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
952             case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
953             case MSG_IL_BTA2DP_DOCK_TIMEOUT:
954             case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
955             case MSG_TOGGLE_HDMI:
956             case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
957             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
958             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
959             case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
960                 return true;
961             default:
962                 return false;
963         }
964     }
965 
966     // Message helper methods
967 
968     // sendMsg() flags
969     /** If the msg is already queued, replace it with this one. */
970     private static final int SENDMSG_REPLACE = 0;
971     /** If the msg is already queued, ignore this one and leave the old. */
972     private static final int SENDMSG_NOOP = 1;
973     /** If the msg is already queued, queue this one and leave the old. */
974     private static final int SENDMSG_QUEUE = 2;
975 
sendMsg(int msg, int existingMsgPolicy, int delay)976     private void sendMsg(int msg, int existingMsgPolicy, int delay) {
977         sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay);
978     }
979 
sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay)980     private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) {
981         sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay);
982     }
983 
sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay)984     private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) {
985         sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay);
986     }
987 
sendIMsg(int msg, int existingMsgPolicy, int arg, int delay)988     private void sendIMsg(int msg, int existingMsgPolicy, int arg, int delay) {
989         sendIILMsg(msg, existingMsgPolicy, arg, 0, null, delay);
990     }
991 
sendMsgNoDelay(int msg, int existingMsgPolicy)992     private void sendMsgNoDelay(int msg, int existingMsgPolicy) {
993         sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0);
994     }
995 
sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg)996     private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) {
997         sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0);
998     }
999 
sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2)1000     private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) {
1001         sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0);
1002     }
1003 
sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj)1004     private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) {
1005         sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0);
1006     }
1007 
sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj)1008     private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) {
1009         sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0);
1010     }
1011 
sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj)1012     private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) {
1013         sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0);
1014     }
1015 
sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)1016     private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj,
1017                             int delay) {
1018         if (existingMsgPolicy == SENDMSG_REPLACE) {
1019             mBrokerHandler.removeMessages(msg);
1020         } else if (existingMsgPolicy == SENDMSG_NOOP && mBrokerHandler.hasMessages(msg)) {
1021             return;
1022         }
1023 
1024         if (isMessageHandledUnderWakelock(msg)) {
1025             final long identity = Binder.clearCallingIdentity();
1026             try {
1027                 mBrokerEventWakeLock.acquire(BROKER_WAKELOCK_TIMEOUT_MS);
1028             } catch (Exception e) {
1029                 Log.e(TAG, "Exception acquiring wakelock", e);
1030             }
1031             Binder.restoreCallingIdentity(identity);
1032         }
1033 
1034         synchronized (sLastDeviceConnectionMsgTimeLock) {
1035             long time = SystemClock.uptimeMillis() + delay;
1036 
1037             switch (msg) {
1038                 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
1039                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
1040                 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
1041                 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
1042                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
1043                 case MSG_IL_BTA2DP_DOCK_TIMEOUT:
1044                 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
1045                 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
1046                     if (sLastDeviceConnectMsgTime >= time) {
1047                         // add a little delay to make sure messages are ordered as expected
1048                         time = sLastDeviceConnectMsgTime + 30;
1049                     }
1050                     sLastDeviceConnectMsgTime = time;
1051                     break;
1052                 default:
1053                     break;
1054             }
1055 
1056             mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj),
1057                     time);
1058         }
1059     }
1060 
1061     //-------------------------------------------------------------
1062     // internal utilities
sendBroadcastToAll(Intent intent)1063     private void sendBroadcastToAll(Intent intent) {
1064         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1065         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1066         final long ident = Binder.clearCallingIdentity();
1067         try {
1068             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1069         } finally {
1070             Binder.restoreCallingIdentity(ident);
1071         }
1072     }
1073 }
1074