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