• 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 android.media.audio.Flags.scoManagedByAudio;
19 import static android.media.AudioSystem.DEVICE_IN_ALL_SCO_SET;
20 import static android.media.AudioSystem.DEVICE_IN_BLE_HEADSET;
21 import static android.media.AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
22 import static android.media.AudioSystem.DEVICE_IN_USB_HEADSET;
23 import static android.media.AudioSystem.DEVICE_IN_WIRED_HEADSET;
24 import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO_SET;
25 import static android.media.AudioSystem.DEVICE_OUT_BLE_HEADSET;
26 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
27 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
28 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
29 import static android.media.AudioSystem.DEVICE_OUT_BUS;
30 import static android.media.AudioSystem.DEVICE_OUT_EARPIECE;
31 import static android.media.AudioSystem.DEVICE_OUT_SPEAKER;
32 import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
33 import static android.media.AudioSystem.DEVICE_OUT_WIRED_HEADSET;
34 import static android.media.AudioSystem.isBluetoothScoOutDevice;
35 
36 import static com.android.media.audio.Flags.equalScoLeaVcIndexRange;
37 import static com.android.media.audio.Flags.optimizeBtDeviceSwitch;
38 import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_HEADSET;
39 import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER;
40 import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_SCO;
41 
42 import android.annotation.NonNull;
43 import android.annotation.Nullable;
44 import android.app.compat.CompatChanges;
45 import android.bluetooth.BluetoothDevice;
46 import android.bluetooth.BluetoothHeadset;
47 import android.bluetooth.BluetoothProfile;
48 import android.compat.annotation.ChangeId;
49 import android.compat.annotation.EnabledSince;
50 import android.content.AttributionSource;
51 import android.content.ContentResolver;
52 import android.content.Context;
53 import android.content.Intent;
54 import android.media.AudioAttributes;
55 import android.media.AudioDeviceAttributes;
56 import android.media.AudioDeviceInfo;
57 import android.media.AudioManager;
58 import android.media.AudioManager.AudioDeviceCategory;
59 import android.media.AudioPlaybackConfiguration;
60 import android.media.AudioRecordingConfiguration;
61 import android.media.AudioRoutesInfo;
62 import android.media.AudioSystem;
63 import android.media.BluetoothProfileConnectionInfo;
64 import android.media.IAudioRoutesObserver;
65 import android.media.ICapturePresetDevicesRoleDispatcher;
66 import android.media.ICommunicationDeviceDispatcher;
67 import android.media.IStrategyNonDefaultDevicesDispatcher;
68 import android.media.IStrategyPreferredDevicesDispatcher;
69 import android.media.MediaMetrics;
70 import android.media.audiopolicy.AudioProductStrategy;
71 import android.os.Binder;
72 import android.os.Handler;
73 import android.os.IBinder;
74 import android.os.Looper;
75 import android.os.Message;
76 import android.os.PowerManager;
77 import android.os.Process;
78 import android.os.RemoteCallbackList;
79 import android.os.RemoteException;
80 import android.os.SystemClock;
81 import android.os.UserHandle;
82 import android.provider.Settings;
83 import android.sysprop.BluetoothProperties;
84 import android.text.TextUtils;
85 import android.util.Log;
86 import android.util.Pair;
87 import android.util.PrintWriterPrinter;
88 
89 import com.android.internal.annotations.GuardedBy;
90 import com.android.server.audio.AudioService.BtCommDeviceActiveType;
91 import com.android.server.utils.EventLogger;
92 
93 import java.io.PrintWriter;
94 import java.util.ArrayList;
95 import java.util.Arrays;
96 import java.util.Collection;
97 import java.util.HashMap;
98 import java.util.HashSet;
99 import java.util.LinkedList;
100 import java.util.List;
101 import java.util.Map;
102 import java.util.NoSuchElementException;
103 import java.util.Objects;
104 import java.util.Set;
105 import java.util.concurrent.atomic.AtomicBoolean;
106 
107 /**
108  * @hide
109  * (non final for mocking/spying)
110  */
111 public class AudioDeviceBroker {
112 
113     private static final String TAG = "AS.AudioDeviceBroker";
114 
115     private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s
116 
117     /*package*/ static final  int BTA2DP_DOCK_TIMEOUT_MS = 8000;
118     // Timeout for connection to bluetooth headset service
119     /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
120 
121     // Delay before checking it music should be unmuted after processing an A2DP message
122     private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 100;
123 
124     private final @NonNull AudioService mAudioService;
125     private final @NonNull Context mContext;
126     private final @NonNull AudioSystemAdapter mAudioSystem;
127 
128     /** ID for Communication strategy retrieved form audio policy manager */
129     /*package*/  int mCommunicationStrategyId = -1;
130 
131     /** ID for Accessibility strategy retrieved form audio policy manager */
132     private int mAccessibilityStrategyId = -1;
133 
134 
135     /** Active communication device reported by audio policy manager */
136     /*package*/ AudioDeviceInfo mActiveCommunicationDevice;
137     /** Last preferred device set for communication strategy */
138     private AudioDeviceAttributes mPreferredCommunicationDevice;
139 
140     // Manages all connected devices, only ever accessed on the message loop
141     private final AudioDeviceInventory mDeviceInventory;
142     // Manages notifications to BT service
143     private final BtHelper mBtHelper;
144     // Adapter for system_server-reserved operations
145     private final SystemServerAdapter mSystemServer;
146 
147 
148     //-------------------------------------------------------------------
149     // we use a different lock than mDeviceStateLock so as not to create
150     // lock contention between enqueueing a message and handling them
151     private static final Object sLastDeviceConnectionMsgTimeLock = new Object();
152     @GuardedBy("sLastDeviceConnectionMsgTimeLock")
153     private static long sLastDeviceConnectMsgTime = 0;
154 
155     // General lock to be taken whenever the state of the audio devices is to be checked or changed
156     private final Object mDeviceStateLock = new Object();
157 
158     // Request to override default use of A2DP for media.
159     private AtomicBoolean mBluetoothA2dpEnabled = new AtomicBoolean(false);
160 
161     // lock always taken when accessing AudioService.mSetModeDeathHandlers
162     // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
163     /*package*/ final Object mSetModeLock = new Object();
164 
165     /** AudioModeInfo contains information on current audio mode owner
166      * communicated by AudioService */
167     /* package */ static final class AudioModeInfo {
168         /** Current audio mode */
169         final int mMode;
170         /** PID of current audio mode owner */
171         final int mPid;
172         /** UID of current audio mode owner */
173         final int mUid;
174 
AudioModeInfo(int mode, int pid, int uid)175         AudioModeInfo(int mode, int pid, int uid) {
176             mMode = mode;
177             mPid = pid;
178             mUid = uid;
179         }
180 
181         @Override
toString()182         public String toString() {
183             return "AudioModeInfo: mMode=" + AudioSystem.modeToString(mMode)
184                     + ", mPid=" + mPid
185                     + ", mUid=" + mUid;
186         }
187     };
188 
189     private AudioModeInfo mAudioModeOwner = new AudioModeInfo(AudioSystem.MODE_NORMAL, 0, 0);
190 
191     /**
192      * Indicates that default communication device is chosen by routing rules in audio policy
193      * manager and not forced by AudioDeviceBroker.
194      */
195     @ChangeId
196     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
197     public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L;
198 
199     /** Indicates if headset profile connection and SCO audio control use the new implementation
200      * aligned with other BT profiles. True if both the feature flag Flags.scoManagedByAudio() and
201      * the system property audio.sco.managed.by.audio are true.
202      */
203     private final boolean mScoManagedByAudio;
isScoManagedByAudio()204     /*package*/ boolean isScoManagedByAudio() {
205         return mScoManagedByAudio;
206     }
207 
208     //-------------------------------------------------------------------
AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioSystemAdapter audioSystem)209     /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
210             @NonNull AudioSystemAdapter audioSystem) {
211         mContext = context;
212         mAudioService = service;
213         mBtHelper = new BtHelper(this, context);
214         mDeviceInventory = new AudioDeviceInventory(this);
215         mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext);
216         mAudioSystem = audioSystem;
217         mScoManagedByAudio = scoManagedByAudio()
218                 && BluetoothProperties.isScoManagedByAudioEnabled().orElse(false);
219         init();
220     }
221 
222     /** for test purposes only, inject AudioDeviceInventory and adapter for operations running
223      *  in system_server */
AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioDeviceInventory mockDeviceInventory, @NonNull SystemServerAdapter mockSystemServer, @NonNull AudioSystemAdapter audioSystem)224     AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
225                       @NonNull AudioDeviceInventory mockDeviceInventory,
226                       @NonNull SystemServerAdapter mockSystemServer,
227                       @NonNull AudioSystemAdapter audioSystem) {
228         mContext = context;
229         mAudioService = service;
230         mBtHelper = new BtHelper(this, context);
231         mDeviceInventory = mockDeviceInventory;
232         mSystemServer = mockSystemServer;
233         mAudioSystem = audioSystem;
234         mScoManagedByAudio = scoManagedByAudio()
235                 && BluetoothProperties.isScoManagedByAudioEnabled().orElse(false);
236         init();
237     }
238 
initRoutingStrategyIds()239     private void initRoutingStrategyIds() {
240         List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies();
241         mCommunicationStrategyId = -1;
242         mAccessibilityStrategyId = -1;
243         for (AudioProductStrategy strategy : strategies) {
244             if (mCommunicationStrategyId == -1
245                     && strategy.getAudioAttributesForLegacyStreamType(
246                             AudioSystem.STREAM_VOICE_CALL) != null) {
247                 mCommunicationStrategyId = strategy.getId();
248             }
249             if (mAccessibilityStrategyId == -1
250                     && strategy.getAudioAttributesForLegacyStreamType(
251                             AudioSystem.STREAM_ACCESSIBILITY) != null) {
252                 mAccessibilityStrategyId = strategy.getId();
253             }
254         }
255     }
256 
init()257     private void init() {
258         setupMessaging(mContext);
259 
260         initAudioHalBluetoothState();
261         initRoutingStrategyIds();
262         mPreferredCommunicationDevice = null;
263         updateActiveCommunicationDevice();
264 
265         mSystemServer.registerUserStartedReceiver(mContext);
266     }
267 
getContext()268     /*package*/ Context getContext() {
269         return mContext;
270     }
271 
272     //---------------------------------------------------------------------
273     // Communication from AudioService
274     // All methods are asynchronous and never block
275     // All permission checks are done in AudioService, all incoming calls are considered "safe"
276     // All post* methods are asynchronous
277 
onSystemReady()278     /*package*/ void onSystemReady() {
279         synchronized (mSetModeLock) {
280             synchronized (mDeviceStateLock) {
281                 mAudioModeOwner = mAudioService.getAudioModeOwner();
282                 mBtHelper.onSystemReady();
283             }
284         }
285     }
286 
onAudioServerDied()287     /*package*/ void onAudioServerDied() {
288         // restore devices
289         sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE);
290     }
291 
setForceUse_Async(int useCase, int config, String eventSource)292     /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) {
293         sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
294                 useCase, config, eventSource);
295     }
296 
toggleHdmiIfConnected_Async()297     /*package*/ void toggleHdmiIfConnected_Async() {
298         sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE);
299     }
300 
301     /**
302      * Handle BluetoothHeadset intents where the action is one of
303      *   {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or
304      *   {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}.
305      * @param intent the Intent received from BT service
306      */
onReceiveBtEvent(@onNull Intent intent)307     private void onReceiveBtEvent(@NonNull Intent intent) {
308         mBtHelper.onReceiveBtEvent(intent);
309     }
310 
311     @GuardedBy("mDeviceStateLock")
onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch)312     /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch) {
313         mBtHelper.onSetBtScoActiveDevice(btDevice, deviceSwitch);
314     }
315 
setBluetoothA2dpOn_Async(boolean on, String source)316     /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) {
317         boolean wasOn = mBluetoothA2dpEnabled.getAndSet(on);
318         // do not mute music if we do not anticipate a change in A2DP ON state
319         sendLMsgNoDelay(wasOn == on
320                 ? MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE : MSG_L_SET_FORCE_BT_A2DP_USE,
321                 SENDMSG_REPLACE, source);
322     }
323 
324     /**
325      * Turns speakerphone on/off
326      * @param on true to enable speakerphone
327      * @param eventSource for logging purposes
328      */
setSpeakerphoneOn(IBinder cb, @NonNull AttributionSource attributionSource, boolean on, boolean isPrivileged, String eventSource)329     /*package*/ void setSpeakerphoneOn(IBinder cb, @NonNull AttributionSource attributionSource,
330             boolean on, boolean isPrivileged, String eventSource) {
331         if (AudioService.DEBUG_COMM_RTE) {
332             Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + attributionSource.getUid());
333         }
334         postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(cb, attributionSource,
335                 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
336                 on, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged));
337     }
338 
339     private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000;
340 
341     /** synchronization for setCommunicationDevice() and getCommunicationDevice */
342     private final Object mCommunicationDeviceLock = new Object();
343     @GuardedBy("mCommunicationDeviceLock")
344     private int mCommunicationDeviceUpdateCount = 0;
345 
346     /**
347      * Select device for use for communication use cases.
348      * @param cb Client binder for death detection
349      * @param uid Client uid
350      * @param device Device selected or null to unselect.
351      * @param eventSource for logging purposes
352      * @return false if there is no device and no communication client
353      */
setCommunicationDevice(IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceInfo device, boolean isPrivileged, String eventSource)354     /*package*/ boolean setCommunicationDevice(IBinder cb,
355             @NonNull AttributionSource attributionSource, AudioDeviceInfo device,
356             boolean isPrivileged, String eventSource) {
357         if (AudioService.DEBUG_COMM_RTE) {
358             Log.v(TAG, "setCommunicationDevice, device: " + device
359                     + ", uid: " + attributionSource.getUid());
360         }
361 
362         if (device == null) {
363             synchronized (mDeviceStateLock) {
364                 CommunicationRouteClient client =
365                         getCommunicationRouteClientForUid(attributionSource.getUid());
366                 if (client == null) {
367                     return false;
368                 }
369             }
370         }
371         synchronized (mCommunicationDeviceLock) {
372             mCommunicationDeviceUpdateCount++;
373             AudioDeviceAttributes deviceAttr =
374                     (device != null) ? new AudioDeviceAttributes(device) : null;
375             CommunicationDeviceInfo deviceInfo =
376                     new CommunicationDeviceInfo(cb, attributionSource, deviceAttr,
377                     device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged);
378             postSetCommunicationDeviceForClient(deviceInfo);
379         }
380         return true;
381     }
382 
383     /**
384      * Sets or resets the communication device for matching client. If no client matches and the
385      * request is to reset for a given device (deviceInfo.mOn == false), the method is a noop.
386      * @param deviceInfo information on the device and requester {@link #CommunicationDeviceInfo}
387      */
388     @GuardedBy("mDeviceStateLock")
onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo)389     /*package*/ void onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo) {
390         if (AudioService.DEBUG_COMM_RTE) {
391             Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo);
392         }
393         if (!deviceInfo.mOn) {
394             CommunicationRouteClient client =
395                     getCommunicationRouteClientForUid(deviceInfo.mAttributionSource.getUid());
396             if (client == null || (deviceInfo.mDevice != null
397                     && !deviceInfo.mDevice.equals(client.getDevice()))) {
398                 return;
399             }
400         }
401 
402         AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null;
403         setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mAttributionSource,
404                 device, deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged,
405                 deviceInfo.mEventSource);
406     }
407 
408     /**
409      * Indicates if a Bluetooth SCO activation request owner is controlling
410      * the SCO audio state itself or not.
411      * @param attributionSource the AttributionSource of the SCO request owner app
412      * @return true if we should control SCO audio state, false otherwise
413      */
shouldStartScoForAttributionSource(AttributionSource attributionSource)414     private boolean shouldStartScoForAttributionSource(AttributionSource attributionSource) {
415         if (attributionSource == null) {
416             return true;
417         }
418         int uid = attributionSource.getUid();
419         return !(UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)
420                 || UserHandle.isSameApp(uid, Process.PHONE_UID)
421                 || (UserHandle.isSameApp(uid, Process.SYSTEM_UID)
422                     && "com.android.server.telecom".equals(attributionSource.getPackageName())));
423     }
424 
425     @GuardedBy("mDeviceStateLock")
setCommunicationRouteForClient( IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device, int scoAudioMode, boolean isPrivileged, String eventSource)426     /*package*/ void setCommunicationRouteForClient(
427             IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device,
428             int scoAudioMode, boolean isPrivileged, String eventSource) {
429         if (AudioService.DEBUG_COMM_RTE) {
430             Log.v(TAG, "setCommunicationRouteForClient: device: " + device
431                     + ", eventSource: " + eventSource);
432         }
433         AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
434                                         "setCommunicationRouteForClient for uid: "
435                                         + attributionSource.getUid()
436                                         + " device: " + device + " isPrivileged: " + isPrivileged
437                                         + " from API: " + eventSource)).printLog(TAG));
438 
439         final AttributionSource previousBtScoRequesterAS =
440                 bluetoothScoRequestOwnerAttributionSource();
441         CommunicationRouteClient client;
442 
443         // Save previous client route in case of failure to start BT SCO audio
444         AudioDeviceAttributes prevClientDevice = null;
445         boolean prevPrivileged = false;
446         client = getCommunicationRouteClientForUid(attributionSource.getUid());
447         if (client != null) {
448             prevClientDevice = client.getDevice();
449             prevPrivileged = client.isPrivileged();
450         }
451 
452         if (device != null) {
453             client = addCommunicationRouteClient(cb, attributionSource, device, isPrivileged);
454             if (client == null) {
455                 Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: "
456                         + attributionSource.getUid() + " and device: " + device);
457             }
458         } else {
459             client = removeCommunicationRouteClient(cb, true);
460         }
461         if (client == null) {
462             return;
463         }
464         final AttributionSource btScoRequesterAS = bluetoothScoRequestOwnerAttributionSource();
465         final boolean isBtScoRequested = btScoRequesterAS != null;
466         final boolean wasBtScoRequested = previousBtScoRequesterAS != null;
467 
468         if (mScoManagedByAudio) {
469             if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive()
470                     || !mBtHelper.isBluetoothScoRequestedInternally())) {
471                 boolean scoStarted = false;
472                 if (shouldStartScoForAttributionSource(btScoRequesterAS)) {
473                     scoStarted = mBtHelper.startBluetoothSco(scoAudioMode, eventSource);
474                     if (!scoStarted) {
475                         Log.w(TAG, "setCommunicationRouteForClient: "
476                                 + "failure to start BT SCO for uid: " + attributionSource.getUid());
477                         // clean up or restore previous client selection
478                         if (prevClientDevice != null) {
479                             addCommunicationRouteClient(cb, attributionSource,
480                                     prevClientDevice, prevPrivileged);
481                         } else {
482                             removeCommunicationRouteClient(cb, true);
483                         }
484                         postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
485                     }
486                 } else {
487                     scoStarted = true;
488                 }
489                 if (scoStarted) {
490                     setBluetoothScoOn(true, "setCommunicationRouteForClient");
491                 }
492             } else if (!isBtScoRequested && wasBtScoRequested) {
493                 if (shouldStartScoForAttributionSource(previousBtScoRequesterAS)) {
494                     mBtHelper.stopBluetoothSco(eventSource);
495                 }
496                 setBluetoothScoOn(false, "setCommunicationRouteForClient");
497             }
498         } else {
499             if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive()
500                     || !mBtHelper.isBluetoothScoRequestedInternally())) {
501                 if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
502                     Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: "
503                             + attributionSource.getUid());
504                     // clean up or restore previous client selection
505                     if (prevClientDevice != null) {
506                         addCommunicationRouteClient(cb, attributionSource,
507                                 prevClientDevice, prevPrivileged);
508                     } else {
509                         removeCommunicationRouteClient(cb, true);
510                     }
511                     postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
512                 }
513             } else if (!isBtScoRequested && wasBtScoRequested) {
514                 mBtHelper.stopBluetoothSco(eventSource);
515             }
516         }
517         // In BT classic for communication, the device changes from a2dp to sco device,
518         // but for LE Audio or Hearing Aid it stays the same and we must trigger the proper
519         // stream volume alignment.
520         mAudioService.postUpdateContextualVolumes();
521 
522         updateCommunicationRoute(eventSource);
523     }
524 
525     /**
526      * Returns the communication client with the highest priority:
527      * - 1) the client which is currently also controlling the audio mode
528      * - 2) the first client in the stack if there is no audio mode owner
529      * - 3) no client otherwise
530      * @return CommunicationRouteClient the client driving the communication use case routing.
531      */
532     @GuardedBy("mDeviceStateLock")
topCommunicationRouteClient()533     private CommunicationRouteClient topCommunicationRouteClient() {
534         for (CommunicationRouteClient crc : mCommunicationRouteClients) {
535             if (crc.getUid() == mAudioModeOwner.mUid && !crc.isDisabled()) {
536                 return crc;
537             }
538         }
539         if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0
540                 && mCommunicationRouteClients.get(0).isActive()) {
541             return mCommunicationRouteClients.get(0);
542         }
543         return null;
544     }
545 
546     /**
547      * Returns the device currently requested for communication use case.
548      * Use the device requested by the communication route client selected by
549      * {@link #topCommunicationRouteClient()} if any or none otherwise.
550      * @return AudioDeviceAttributes the requested device for communication.
551      */
552     @GuardedBy("mDeviceStateLock")
requestedCommunicationDevice()553     private AudioDeviceAttributes requestedCommunicationDevice() {
554         CommunicationRouteClient crc = topCommunicationRouteClient();
555         AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
556         if (AudioService.DEBUG_COMM_RTE) {
557             Log.v(TAG, "requestedCommunicationDevice: "
558                     + device + " mAudioModeOwner: " + mAudioModeOwner.toString());
559         }
560         return device;
561     }
562 
563     private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
564             AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
565             AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
566             AudioDeviceInfo.TYPE_WIRED_HEADSET,
567             AudioDeviceInfo.TYPE_USB_HEADSET,
568             AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
569             AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
570             AudioDeviceInfo.TYPE_HEARING_AID,
571             AudioDeviceInfo.TYPE_BLE_HEADSET,
572             AudioDeviceInfo.TYPE_USB_DEVICE,
573             AudioDeviceInfo.TYPE_BLE_SPEAKER,
574             AudioDeviceInfo.TYPE_LINE_ANALOG,
575             AudioDeviceInfo.TYPE_HDMI,
576             AudioDeviceInfo.TYPE_AUX_LINE,
577             AudioDeviceInfo.TYPE_BUS
578     };
579 
isValidCommunicationDevice(@onNull AudioDeviceInfo device)580     /*package */ static boolean isValidCommunicationDevice(@NonNull AudioDeviceInfo device) {
581         Objects.requireNonNull(device, "device must not be null");
582         return device.isSink() && isValidCommunicationDeviceType(device.getType());
583     }
584 
isValidCommunicationDeviceType( @udioDeviceInfo.AudioDeviceType int deviceType)585     private static boolean isValidCommunicationDeviceType(
586             @AudioDeviceInfo.AudioDeviceType int deviceType) {
587         for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
588             if (deviceType == type) {
589                 return true;
590             }
591         }
592         return false;
593     }
594 
595 
596     // check playback or record activity after 6 seconds for UIDs
597     private static final int CHECK_CLIENT_STATE_DELAY_MS = 6000;
598 
599     /*package */
postCheckCommunicationRouteClientState(int uid, boolean wasActive, int delay)600     void postCheckCommunicationRouteClientState(int uid, boolean wasActive, int delay) {
601         CommunicationRouteClient client = getCommunicationRouteClientForUid(uid);
602         if (client != null) {
603             sendMsgForCheckClientState(MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE,
604                                         SENDMSG_REPLACE,
605                                         uid,
606                                         wasActive ? 1 : 0,
607                                         client,
608                                         delay);
609         }
610     }
611 
612     @GuardedBy("mDeviceStateLock")
onCheckCommunicationRouteClientState(int uid, boolean wasActive)613     void onCheckCommunicationRouteClientState(int uid, boolean wasActive) {
614         CommunicationRouteClient client = getCommunicationRouteClientForUid(uid);
615         if (client == null) {
616             return;
617         }
618         updateCommunicationRouteClientState(client, wasActive);
619     }
620 
621     @GuardedBy("mDeviceStateLock")
updateCommunicationRouteClientState( CommunicationRouteClient client, boolean wasActive)622     /*package*/ void updateCommunicationRouteClientState(
623                             CommunicationRouteClient client, boolean wasActive) {
624         client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid()));
625         client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid()));
626         if (wasActive != client.isActive()) {
627             postUpdateCommunicationRouteClient(wasActive ?
628                     client.getAttributionSource() : null,
629                     "updateCommunicationRouteClientState");
630         }
631     }
632 
633     @GuardedBy("mDeviceStateLock")
setForceCommunicationClientStateAndDelayedCheck( CommunicationRouteClient client, boolean forcePlaybackActive, boolean forceRecordingActive)634     /*package*/ void setForceCommunicationClientStateAndDelayedCheck(
635                             CommunicationRouteClient client,
636                             boolean forcePlaybackActive,
637                             boolean forceRecordingActive) {
638         if (client == null) {
639             return;
640         }
641         if (forcePlaybackActive) {
642             client.setPlaybackActive(true);
643         }
644         if (forceRecordingActive) {
645             client.setRecordingActive(true);
646         }
647         postCheckCommunicationRouteClientState(
648                 client.getUid(), client.isActive(), CHECK_CLIENT_STATE_DELAY_MS);
649     }
650 
getAvailableCommunicationDevices()651     /* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
652         ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
653         AudioDeviceInfo[] allDevices =
654                 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
655         for (AudioDeviceInfo device : allDevices) {
656             if (isValidCommunicationDevice(device)) {
657                 commDevices.add(device);
658             }
659         }
660         return commDevices;
661     }
662 
getCommunicationDeviceOfType(int type)663     private @Nullable AudioDeviceInfo getCommunicationDeviceOfType(int type) {
664         return getAvailableCommunicationDevices().stream().filter(d -> d.getType() == type)
665                 .findFirst().orElse(null);
666     }
667 
668     /**
669      * Returns the device currently requested for communication use case.
670      * @return AudioDeviceInfo the requested device for communication.
671      */
getCommunicationDevice()672     /* package */ AudioDeviceInfo getCommunicationDevice() {
673         synchronized (mCommunicationDeviceLock) {
674             final long start = System.currentTimeMillis();
675             long elapsed = 0;
676             while (mCommunicationDeviceUpdateCount > 0) {
677                 try {
678                     mCommunicationDeviceLock.wait(
679                             SET_COMMUNICATION_DEVICE_TIMEOUT_MS - elapsed);
680                 } catch (InterruptedException e) {
681                     Log.w(TAG, "Interrupted while waiting for communication device update.");
682                 }
683                 elapsed = System.currentTimeMillis() - start;
684                 if (elapsed >= SET_COMMUNICATION_DEVICE_TIMEOUT_MS) {
685                     Log.e(TAG, "Timeout waiting for communication device update.");
686                     // reset counter to avoid sticky out of sync condition
687                     mCommunicationDeviceUpdateCount = 0;
688                     break;
689                 }
690             }
691         }
692         synchronized (mDeviceStateLock) {
693             return getCommunicationDeviceInt();
694         }
695     }
696 
697     @GuardedBy("mDeviceStateLock")
getCommunicationDeviceInt()698     private AudioDeviceInfo  getCommunicationDeviceInt() {
699         updateActiveCommunicationDevice();
700         AudioDeviceInfo device = mActiveCommunicationDevice;
701         // make sure we return a valid communication device (i.e. a device that is allowed by
702         // setCommunicationDevice()) for consistency.
703         if (device != null) {
704             // a digital dock is used instead of the speaker in speakerphone mode and should
705             // be reflected as such
706             if (device.getType() == AudioDeviceInfo.TYPE_DOCK) {
707                 device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
708             }
709         }
710         // Try to default to earpiece when current communication device is not valid. This can
711         // happen for instance if no call is active. If no earpiece device is available take the
712         // first valid communication device
713         if (device == null || !AudioDeviceBroker.isValidCommunicationDevice(device)) {
714             device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE);
715             if (device == null) {
716                 List<AudioDeviceInfo> commDevices = getAvailableCommunicationDevices();
717                 if (!commDevices.isEmpty()) {
718                     device = commDevices.get(0);
719                 }
720             }
721         }
722         return device;
723     }
724 
725     /**
726      * Updates currently active communication device (mActiveCommunicationDevice).
727      */
728     @GuardedBy("mDeviceStateLock")
updateActiveCommunicationDevice()729     void updateActiveCommunicationDevice() {
730         AudioDeviceAttributes device = preferredCommunicationDevice();
731         if (device == null) {
732             AudioAttributes attr =
733                     AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
734                             AudioSystem.STREAM_VOICE_CALL);
735             List<AudioDeviceAttributes> devices = mAudioSystem.getDevicesForAttributes(
736                     attr, false /* forVolume */);
737             if (devices.isEmpty()) {
738                 if (mAudioService.isPlatformVoice()) {
739                     Log.w(TAG,
740                             "updateActiveCommunicationDevice(): no device for phone strategy");
741                 }
742                 mActiveCommunicationDevice = null;
743                 return;
744             }
745             device = devices.get(0);
746         }
747         mActiveCommunicationDevice = AudioManager.getDeviceInfoFromTypeAndAddress(
748                 device.getType(), device.getAddress());
749     }
750 
751     /**
752      * Indicates if the device which type is passed as argument is currently resquested to be used
753      * for communication.
754      * @param deviceType the device type the query applies to.
755      * @return true if this device type is requested for communication.
756      */
isDeviceRequestedForCommunication( @udioDeviceInfo.AudioDeviceType int deviceType)757     private boolean isDeviceRequestedForCommunication(
758             @AudioDeviceInfo.AudioDeviceType int deviceType) {
759         synchronized (mDeviceStateLock) {
760             AudioDeviceAttributes device = requestedCommunicationDevice();
761             return device != null && device.getType() == deviceType;
762         }
763     }
764 
765     /**
766      * Indicates if the device which type is passed as argument is currently either resquested
767      * to be used for communication or selected for an other reason (e.g bluetooth SCO audio
768      * is active for SCO device).
769      * @param deviceType the device type the query applies to.
770      * @return true if this device type is requested for communication.
771      */
isDeviceOnForCommunication( @udioDeviceInfo.AudioDeviceType int deviceType)772     private boolean isDeviceOnForCommunication(
773             @AudioDeviceInfo.AudioDeviceType int deviceType) {
774         synchronized (mDeviceStateLock) {
775             AudioDeviceAttributes device = preferredCommunicationDevice();
776             return device != null && device.getType() == deviceType;
777         }
778     }
779 
780     /**
781      * Indicates if the device which type is passed as argument is active for communication.
782      * Active means not only currently used by audio policy manager for communication strategy
783      * but also explicitly requested for use by communication strategy.
784      * @param deviceType the device type the query applies to.
785      * @return true if this device type is requested for communication.
786      */
isDeviceActiveForCommunication( @udioDeviceInfo.AudioDeviceType int deviceType)787     private boolean isDeviceActiveForCommunication(
788             @AudioDeviceInfo.AudioDeviceType int deviceType) {
789         return mActiveCommunicationDevice != null
790                 && mActiveCommunicationDevice.getType() == deviceType
791                 && mPreferredCommunicationDevice != null
792                 && mPreferredCommunicationDevice.getType() == deviceType;
793     }
794 
795     /**
796      * Indicates if preferred route selection for communication is speakerphone.
797      * @return true if speakerphone is active, false otherwise.
798      */
isSpeakerphoneOn()799     /*package*/ boolean isSpeakerphoneOn() {
800         return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
801     }
802 
isSpeakerphoneActive()803     private boolean isSpeakerphoneActive() {
804         return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
805     }
806 
807     /**
808      * Helper method on top of isDeviceRequestedForCommunication() indicating if
809      * Bluetooth SCO ON is currently requested or not.
810      * @return true if Bluetooth SCO ON is requested, false otherwise.
811      */
isBluetoothScoRequested()812     /*package*/ boolean isBluetoothScoRequested() {
813         return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
814     }
815 
816     /**
817      * Helper method on top of isBluetoothScoRequested() returning the Attribution Source of the
818      * BT SCO route request owner or null if SCO is not requested.
819      * @return the AttributionSource of the BT SCO route request owner of null.
820      */
821     @GuardedBy("mDeviceStateLock")
bluetoothScoRequestOwnerAttributionSource()822     /*package*/ @Nullable AttributionSource bluetoothScoRequestOwnerAttributionSource() {
823         if (!isBluetoothScoRequested()) {
824             return null;
825         }
826         CommunicationRouteClient crc = topCommunicationRouteClient();
827         if (crc == null) {
828             return null;
829         }
830         return crc.getAttributionSource();
831     }
832 
safeUidFromAttributionSource(AttributionSource attributionSource)833     private static int safeUidFromAttributionSource(AttributionSource attributionSource) {
834         return (attributionSource != null) ? attributionSource.getUid() : -1;
835     }
836 
837     /**
838      * Helper method on top of isDeviceRequestedForCommunication() indicating if
839      * Bluetooth LE Audio communication device is currently requested or not.
840      * @return true if Bluetooth LE Audio device is requested, false otherwise.
841      */
isBluetoothLeAudioRequested()842     /*package*/ boolean isBluetoothLeAudioRequested() {
843         return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET)
844                 || isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER);
845     }
846 
847     /**
848      * Indicates if preferred route selection for communication is Bluetooth SCO.
849      * @return true if Bluetooth SCO is preferred , false otherwise.
850      */
isBluetoothScoOn()851     /*package*/ boolean isBluetoothScoOn() {
852         return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
853     }
854 
isBluetoothScoActive()855     private boolean isBluetoothScoActive() {
856         return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
857     }
858 
isBluetoothBleHeadsetActive()859     private boolean isBluetoothBleHeadsetActive() {
860         return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET);
861     }
862 
isBluetoothBleSpeakerActive()863     private boolean isBluetoothBleSpeakerActive() {
864         return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER);
865     }
866 
isDeviceConnected(@onNull AudioDeviceAttributes device)867     /*package*/ boolean isDeviceConnected(@NonNull AudioDeviceAttributes device) {
868         synchronized (mDeviceStateLock) {
869             return mDeviceInventory.isDeviceConnected(device);
870         }
871     }
872 
setWiredDeviceConnectionState(AudioDeviceAttributes attributes, @AudioService.ConnectionState int state, String caller)873     /*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
874             @AudioService.ConnectionState int state, String caller) {
875         //TODO move logging here just like in setBluetooth* methods
876         synchronized (mDeviceStateLock) {
877             mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);
878         }
879     }
880 
setTestDeviceConnectionState(@onNull AudioDeviceAttributes device, @AudioService.ConnectionState int state)881     /*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
882             @AudioService.ConnectionState int state) {
883         synchronized (mDeviceStateLock) {
884             mDeviceInventory.setTestDeviceConnectionState(device, state);
885         }
886     }
887 
888     /*package*/ static final class BleVolumeInfo {
889         final int mIndex;
890         final int mMaxIndex;
891         final int mStreamType;
892 
BleVolumeInfo(int index, int maxIndex, int streamType)893         BleVolumeInfo(int index, int maxIndex, int streamType) {
894             mIndex = index;
895             mMaxIndex = maxIndex;
896             mStreamType = streamType;
897         }
898     };
899 
900     /*package*/ static final class BtDeviceChangedData {
901         final @Nullable BluetoothDevice mNewDevice;
902         final @Nullable BluetoothDevice mPreviousDevice;
903         final @NonNull BluetoothProfileConnectionInfo mInfo;
904         final @NonNull String mEventSource;
905 
BtDeviceChangedData(@ullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource)906         BtDeviceChangedData(@Nullable BluetoothDevice newDevice,
907                 @Nullable BluetoothDevice previousDevice,
908                 @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource) {
909             mNewDevice = newDevice;
910             mPreviousDevice = previousDevice;
911             mInfo = info;
912             mEventSource = eventSource;
913         }
914 
915         @Override
toString()916         public String toString() {
917             return "BtDeviceChangedData profile=" + BluetoothProfile.getProfileName(
918                     mInfo.getProfile())
919                 + ", switch device: [" + mPreviousDevice + "] -> [" + mNewDevice + "]";
920         }
921     }
922 
923     /*package*/ static final class BtDeviceInfo {
924         final @NonNull BluetoothDevice mDevice;
925         final @AudioService.BtProfileConnectionState int mState;
926         final @AudioService.BtProfile int mProfile;
927         final boolean mSupprNoisy;
928         final int mVolume;
929         final boolean mIsLeOutput;
930         final @NonNull String mEventSource;
931         final int mAudioSystemDevice;
932         final int mMusicDevice;
933         final boolean mIsDeviceSwitch;
934 
BtDeviceInfo(@onNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state, int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec)935         BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state,
936                     int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) {
937             mDevice = device;
938             mState = state;
939             mProfile = d.mInfo.getProfile();
940             mSupprNoisy = d.mInfo.isSuppressNoisyIntent();
941             mVolume = d.mInfo.getVolume();
942             mIsLeOutput = d.mInfo.isLeOutput();
943             mEventSource = d.mEventSource;
944             mAudioSystemDevice = audioDevice;
945             mMusicDevice = AudioSystem.DEVICE_NONE;
946             mIsDeviceSwitch = optimizeBtDeviceSwitch()
947                     && d.mNewDevice != null && d.mPreviousDevice != null;
948         }
949 
950         // constructor used by AudioDeviceBroker to search similar message
BtDeviceInfo(@onNull BluetoothDevice device, int profile)951         BtDeviceInfo(@NonNull BluetoothDevice device, int profile) {
952             mDevice = device;
953             mProfile = profile;
954             mEventSource = "";
955             mMusicDevice = AudioSystem.DEVICE_NONE;
956             mAudioSystemDevice = 0;
957             mState = 0;
958             mSupprNoisy = false;
959             mVolume = -1;
960             mIsLeOutput = false;
961             mIsDeviceSwitch = false;
962         }
963 
964         // constructor used by AudioDeviceInventory when config change failed
BtDeviceInfo(@onNull BluetoothDevice device, int profile, int state, int musicDevice, int audioSystemDevice)965         BtDeviceInfo(@NonNull BluetoothDevice device, int profile, int state, int musicDevice,
966                     int audioSystemDevice) {
967             mDevice = device;
968             mProfile = profile;
969             mEventSource = "";
970             mMusicDevice = musicDevice;
971             mAudioSystemDevice = audioSystemDevice;
972             mState = state;
973             mSupprNoisy = false;
974             mVolume = -1;
975             mIsLeOutput = false;
976             mIsDeviceSwitch = false;
977         }
978 
BtDeviceInfo(@onNull BtDeviceInfo src, int state)979         BtDeviceInfo(@NonNull BtDeviceInfo src, int state) {
980             mDevice = src.mDevice;
981             mState = state;
982             mProfile = src.mProfile;
983             mSupprNoisy = src.mSupprNoisy;
984             mVolume = src.mVolume;
985             mIsLeOutput = src.mIsLeOutput;
986             mEventSource = src.mEventSource;
987             mAudioSystemDevice = src.mAudioSystemDevice;
988             mMusicDevice = src.mMusicDevice;
989             mIsDeviceSwitch = false;
990         }
991 
992         // redefine equality op so we can match messages intended for this device
993         @Override
equals(Object o)994         public boolean equals(Object o) {
995             if (o == null) {
996                 return false;
997             }
998             if (this == o) {
999                 return true;
1000             }
1001             if (o instanceof BtDeviceInfo) {
1002                 return mProfile == ((BtDeviceInfo) o).mProfile
1003                     && mDevice.equals(((BtDeviceInfo) o).mDevice);
1004             }
1005             return false;
1006         }
1007 
1008         @Override
hashCode()1009         public int hashCode() {
1010             // only hashing on the fields used in equals()
1011             return Objects.hash(mProfile, mDevice);
1012         }
1013 
1014         @Override
toString()1015         public String toString() {
1016             return "BtDeviceInfo: device=" + mDevice.toString()
1017                             + " state=" + mState
1018                             + " prof=" + mProfile
1019                             + " supprNoisy=" + mSupprNoisy
1020                             + " volume=" + mVolume
1021                             + " isLeOutput=" + mIsLeOutput
1022                             + " eventSource=" + mEventSource
1023                             + " audioSystemDevice=" + mAudioSystemDevice
1024                             + " musicDevice=" + mMusicDevice
1025                             + " isDeviceSwitch=" + mIsDeviceSwitch;
1026         }
1027     }
1028 
createBtDeviceInfo(@onNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state)1029     /*package*/ static BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d,
1030             @NonNull BluetoothDevice device, int state) {
1031         int audioDevice = BtHelper.getTypeFromProfile(d.mInfo.getProfile(), d.mInfo.isLeOutput());
1032         return new BtDeviceInfo(d, device, state, audioDevice, AudioSystem.AUDIO_FORMAT_DEFAULT);
1033     }
1034 
btMediaMetricRecord(@onNull BluetoothDevice device, String state, @NonNull BtDeviceChangedData data)1035     private void btMediaMetricRecord(@NonNull BluetoothDevice device, String state,
1036             @NonNull BtDeviceChangedData data) {
1037         final String name = TextUtils.emptyIfNull(device.getName());
1038         new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
1039                 + "queueOnBluetoothActiveDeviceChanged")
1040             .set(MediaMetrics.Property.STATE, state)
1041             .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
1042             .set(MediaMetrics.Property.NAME, name)
1043             .record();
1044     }
1045 
1046     /**
1047      * will block on mDeviceStateLock, which is held during an A2DP (dis) connection
1048      * not just a simple message post
1049      * @param data struct with the (dis)connection information
1050      */
queueOnBluetoothActiveDeviceChanged(@onNull BtDeviceChangedData data)1051     /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) {
1052         if (data.mPreviousDevice != null
1053                 && data.mPreviousDevice.equals(data.mNewDevice)) {
1054             final String name = TextUtils.emptyIfNull(data.mNewDevice.getName());
1055             new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
1056                     + "queueOnBluetoothActiveDeviceChanged_update")
1057                     .set(MediaMetrics.Property.NAME, name)
1058                     .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
1059                     .record();
1060             synchronized (mDeviceStateLock) {
1061                 postBluetoothDeviceConfigChange(createBtDeviceInfo(data, data.mNewDevice,
1062                         BluetoothProfile.STATE_CONNECTED));
1063             }
1064         } else {
1065             synchronized (mDeviceStateLock) {
1066                 if (data.mPreviousDevice != null) {
1067                     btMediaMetricRecord(data.mPreviousDevice, MediaMetrics.Value.DISCONNECTED,
1068                             data);
1069                     sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE,
1070                             createBtDeviceInfo(data, data.mPreviousDevice,
1071                                     BluetoothProfile.STATE_DISCONNECTED));
1072                 }
1073                 if (data.mNewDevice != null) {
1074                     btMediaMetricRecord(data.mNewDevice, MediaMetrics.Value.CONNECTED, data);
1075                     sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE,
1076                             createBtDeviceInfo(data, data.mNewDevice,
1077                                     BluetoothProfile.STATE_CONNECTED));
1078                 }
1079             }
1080         }
1081     }
1082 
1083     // Lock protecting state variable related to Bluetooth audio state
1084     private final Object mBluetoothAudioStateLock = new Object();
1085 
1086     // Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
1087     @GuardedBy("mBluetoothAudioStateLock")
1088     private boolean mBluetoothScoOn;
1089     // value of BT_SCO parameter currently applied to audio HAL.
1090     @GuardedBy("mBluetoothAudioStateLock")
1091     private boolean mBluetoothScoOnApplied;
1092 
1093     // A2DP suspend state requested by AudioManager.setA2dpSuspended() API.
1094     @GuardedBy("mBluetoothAudioStateLock")
1095     private boolean mBluetoothA2dpSuspendedExt;
1096     // A2DP suspend state requested by AudioDeviceInventory.
1097     @GuardedBy("mBluetoothAudioStateLock")
1098     private boolean mBluetoothA2dpSuspendedInt;
1099     // value of BT_A2dpSuspendedSCO parameter currently applied to audio HAL.
1100 
1101     @GuardedBy("mBluetoothAudioStateLock")
1102     private boolean mBluetoothA2dpSuspendedApplied;
1103 
1104     // LE Audio suspend state requested by AudioManager.setLeAudioSuspended() API.
1105     @GuardedBy("mBluetoothAudioStateLock")
1106     private boolean mBluetoothLeSuspendedExt;
1107     // LE Audio suspend state requested by AudioDeviceInventory.
1108     @GuardedBy("mBluetoothAudioStateLock")
1109     private boolean mBluetoothLeSuspendedInt;
1110     // value of LeAudioSuspended parameter currently applied to audio HAL.
1111     @GuardedBy("mBluetoothAudioStateLock")
1112     private boolean mBluetoothLeSuspendedApplied;
1113 
initAudioHalBluetoothState()1114     private void initAudioHalBluetoothState() {
1115         synchronized (mBluetoothAudioStateLock) {
1116             mBluetoothScoOnApplied = false;
1117             mBluetoothA2dpSuspendedApplied = false;
1118             mBluetoothLeSuspendedApplied = false;
1119             reapplyAudioHalBluetoothState();
1120         }
1121     }
1122 
1123     @GuardedBy("mBluetoothAudioStateLock")
updateAudioHalBluetoothState()1124     private void updateAudioHalBluetoothState() {
1125         if (mBluetoothScoOn != mBluetoothScoOnApplied) {
1126             if (AudioService.DEBUG_COMM_RTE) {
1127                 Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothScoOn: "
1128                         + mBluetoothScoOn + ", mBluetoothScoOnApplied: " + mBluetoothScoOnApplied);
1129             }
1130             if (mBluetoothScoOn) {
1131                 if (!mBluetoothA2dpSuspendedApplied) {
1132                     AudioSystem.setParameters("A2dpSuspended=true");
1133                     mBluetoothA2dpSuspendedApplied = true;
1134                 }
1135                 if (!mBluetoothLeSuspendedApplied) {
1136                     AudioSystem.setParameters("LeAudioSuspended=true");
1137                     mBluetoothLeSuspendedApplied = true;
1138                 }
1139                 AudioSystem.setParameters("BT_SCO=on");
1140             } else {
1141                 AudioSystem.setParameters("BT_SCO=off");
1142             }
1143             mBluetoothScoOnApplied = mBluetoothScoOn;
1144         }
1145         if (!mBluetoothScoOnApplied) {
1146             if ((mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt)
1147                     != mBluetoothA2dpSuspendedApplied) {
1148                 if (AudioService.DEBUG_COMM_RTE) {
1149                     Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothA2dpSuspendedExt: "
1150                             + mBluetoothA2dpSuspendedExt
1151                             + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt
1152                             + ", mBluetoothA2dpSuspendedApplied: "
1153                             + mBluetoothA2dpSuspendedApplied);
1154                 }
1155                 mBluetoothA2dpSuspendedApplied =
1156                         mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt;
1157                 if (mBluetoothA2dpSuspendedApplied) {
1158                     AudioSystem.setParameters("A2dpSuspended=true");
1159                 } else {
1160                     AudioSystem.setParameters("A2dpSuspended=false");
1161                 }
1162             }
1163             if ((mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt)
1164                     != mBluetoothLeSuspendedApplied) {
1165                 if (AudioService.DEBUG_COMM_RTE) {
1166                     Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothLeSuspendedExt: "
1167                             + mBluetoothLeSuspendedExt
1168                             + ", mBluetoothLeSuspendedInt: " + mBluetoothLeSuspendedInt
1169                             + ", mBluetoothLeSuspendedApplied: " + mBluetoothLeSuspendedApplied);
1170                 }
1171                 mBluetoothLeSuspendedApplied =
1172                         mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt;
1173                 if (mBluetoothLeSuspendedApplied) {
1174                     AudioSystem.setParameters("LeAudioSuspended=true");
1175                 } else {
1176                     AudioSystem.setParameters("LeAudioSuspended=false");
1177                 }
1178             }
1179         }
1180     }
1181 
1182     @GuardedBy("mBluetoothAudioStateLock")
reapplyAudioHalBluetoothState()1183     private void reapplyAudioHalBluetoothState() {
1184         if (AudioService.DEBUG_COMM_RTE) {
1185             Log.v(TAG, "reapplyAudioHalBluetoothState() mBluetoothScoOnApplied: "
1186                     + mBluetoothScoOnApplied + ", mBluetoothA2dpSuspendedApplied: "
1187                     + mBluetoothA2dpSuspendedApplied + ", mBluetoothLeSuspendedApplied: "
1188                     + mBluetoothLeSuspendedApplied);
1189         }
1190         // Note: the order of parameters is important.
1191         if (mBluetoothScoOnApplied) {
1192             AudioSystem.setParameters("A2dpSuspended=true");
1193             AudioSystem.setParameters("LeAudioSuspended=true");
1194             AudioSystem.setParameters("BT_SCO=on");
1195             mBluetoothA2dpSuspendedApplied = true;
1196             mBluetoothLeSuspendedApplied = true;
1197         } else {
1198             AudioSystem.setParameters("BT_SCO=off");
1199             if (mBluetoothA2dpSuspendedApplied) {
1200                 AudioSystem.setParameters("A2dpSuspended=true");
1201             } else {
1202                 AudioSystem.setParameters("A2dpSuspended=false");
1203             }
1204             if (mBluetoothLeSuspendedApplied) {
1205                 AudioSystem.setParameters("LeAudioSuspended=true");
1206             } else {
1207                 AudioSystem.setParameters("LeAudioSuspended=false");
1208             }
1209         }
1210     }
1211 
1212     @GuardedBy("mDeviceStateLock")
setBluetoothScoOn(boolean on, String eventSource)1213     /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
1214         synchronized (mBluetoothAudioStateLock) {
1215             AttributionSource btScoRequesterAS = bluetoothScoRequestOwnerAttributionSource();
1216             Log.i(TAG, "setBluetoothScoOn: " + on + ", mBluetoothScoOn: "
1217                     + mBluetoothScoOn + ", btScoRequesterUId: "
1218                     + safeUidFromAttributionSource(btScoRequesterAS)
1219                     + ", from: " + eventSource);
1220             mBluetoothScoOn = on;
1221             updateAudioHalBluetoothState();
1222             if (!mScoManagedByAudio) {
1223                 postUpdateCommunicationRouteClient(btScoRequesterAS, eventSource);
1224             }
1225         }
1226     }
1227 
setA2dpSuspended(boolean enable, boolean internal, String eventSource)1228     /*package*/ void setA2dpSuspended(boolean enable, boolean internal, String eventSource) {
1229         synchronized (mBluetoothAudioStateLock) {
1230             if (AudioService.DEBUG_COMM_RTE) {
1231                 Log.v(TAG, "setA2dpSuspended source: " + eventSource + ", enable: "
1232                         + enable + ", internal: " + internal
1233                         + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt
1234                         + ", mBluetoothA2dpSuspendedExt: " + mBluetoothA2dpSuspendedExt);
1235             }
1236             if (internal) {
1237                 mBluetoothA2dpSuspendedInt = enable;
1238             } else {
1239                 mBluetoothA2dpSuspendedExt = enable;
1240             }
1241             updateAudioHalBluetoothState();
1242         }
1243     }
1244 
clearA2dpSuspended(boolean internalOnly)1245     /*package*/ void clearA2dpSuspended(boolean internalOnly) {
1246         if (AudioService.DEBUG_COMM_RTE) {
1247             Log.v(TAG, "clearA2dpSuspended, internalOnly: " + internalOnly);
1248         }
1249         synchronized (mBluetoothAudioStateLock) {
1250             mBluetoothA2dpSuspendedInt = false;
1251             if (!internalOnly) {
1252                 mBluetoothA2dpSuspendedExt = false;
1253             }
1254             updateAudioHalBluetoothState();
1255         }
1256     }
1257 
setLeAudioSuspended(boolean enable, boolean internal, String eventSource)1258     /*package*/ void setLeAudioSuspended(boolean enable, boolean internal, String eventSource) {
1259         synchronized (mBluetoothAudioStateLock) {
1260             if (AudioService.DEBUG_COMM_RTE) {
1261                 Log.v(TAG, "setLeAudioSuspended source: " + eventSource + ", enable: "
1262                         + enable + ", internal: " + internal
1263                         + ", mBluetoothLeSuspendedInt: " + mBluetoothA2dpSuspendedInt
1264                         + ", mBluetoothLeSuspendedExt: " + mBluetoothA2dpSuspendedExt);
1265             }
1266             if (internal) {
1267                 mBluetoothLeSuspendedInt = enable;
1268             } else {
1269                 mBluetoothLeSuspendedExt = enable;
1270             }
1271             updateAudioHalBluetoothState();
1272         }
1273     }
1274 
clearLeAudioSuspended(boolean internalOnly)1275     /*package*/ void clearLeAudioSuspended(boolean internalOnly) {
1276         if (AudioService.DEBUG_COMM_RTE) {
1277             Log.v(TAG, "clearLeAudioSuspended, internalOnly: " + internalOnly);
1278         }
1279         synchronized (mBluetoothAudioStateLock) {
1280             mBluetoothLeSuspendedInt = false;
1281             if (!internalOnly) {
1282                 mBluetoothLeSuspendedExt = false;
1283             }
1284             updateAudioHalBluetoothState();
1285         }
1286     }
1287 
startWatchingRoutes(IAudioRoutesObserver observer)1288     /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
1289         synchronized (mDeviceStateLock) {
1290             return mDeviceInventory.startWatchingRoutes(observer);
1291         }
1292     }
1293 
getCurAudioRoutes()1294     /*package*/ AudioRoutesInfo getCurAudioRoutes() {
1295         synchronized (mDeviceStateLock) {
1296             return mDeviceInventory.getCurAudioRoutes();
1297         }
1298     }
1299 
isBluetoothA2dpOn()1300     /*package*/ boolean isBluetoothA2dpOn() {
1301         return mBluetoothA2dpEnabled.get();
1302     }
1303 
postSetAvrcpAbsoluteVolumeIndex(int index)1304     /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) {
1305         sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index);
1306     }
1307 
postSetHearingAidVolumeIndex(int index, int streamType)1308     /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) {
1309         sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
1310     }
1311 
postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType)1312      /*package*/ void postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType) {
1313         BleVolumeInfo info = new BleVolumeInfo(index, maxIndex, streamType);
1314         sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
1315     }
1316 
postSetModeOwner(int mode, int pid, int uid, boolean signal)1317     /*package*/ void postSetModeOwner(int mode, int pid, int uid, boolean signal) {
1318         sendLMsgNoDelay(signal ? MSG_L_SET_MODE_OWNER_SIGNAL : MSG_L_SET_MODE_OWNER,
1319                 SENDMSG_REPLACE, new AudioModeInfo(mode, pid, uid));
1320     }
1321 
postBluetoothDeviceConfigChange(@onNull BtDeviceInfo info)1322     /*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
1323         sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
1324     }
1325 
startBluetoothScoForClient(IBinder cb, @NonNull AttributionSource attributionSource, int scoAudioMode, boolean isPrivileged, @NonNull String eventSource)1326     /*package*/ void startBluetoothScoForClient(IBinder cb,
1327             @NonNull AttributionSource attributionSource, int scoAudioMode, boolean isPrivileged,
1328             @NonNull String eventSource) {
1329         if (AudioService.DEBUG_COMM_RTE) {
1330             Log.v(TAG, "startBluetoothScoForClient, uid: " + attributionSource.getUid());
1331         }
1332         postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(cb, attributionSource,
1333                 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
1334                 true, scoAudioMode, eventSource, isPrivileged));
1335     }
1336 
stopBluetoothScoForClient(IBinder cb, @NonNull AttributionSource attributionSource, boolean isPrivileged, @NonNull String eventSource)1337     /*package*/ void stopBluetoothScoForClient(IBinder cb,
1338             @NonNull AttributionSource attributionSource, boolean isPrivileged,
1339             @NonNull String eventSource) {
1340         if (AudioService.DEBUG_COMM_RTE) {
1341             Log.v(TAG, "stopBluetoothScoForClient, uid: " + attributionSource.getUid());
1342         }
1343         postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
1344                 cb, attributionSource, new AudioDeviceAttributes(
1345                                               AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
1346                 false, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged));
1347     }
1348 
setPreferredDevicesForStrategySync(int strategy, @NonNull List<AudioDeviceAttributes> devices)1349     /*package*/ int setPreferredDevicesForStrategySync(int strategy,
1350             @NonNull List<AudioDeviceAttributes> devices) {
1351         return mDeviceInventory.setPreferredDevicesForStrategyAndSave(strategy, devices);
1352     }
1353 
removePreferredDevicesForStrategySync(int strategy)1354     /*package*/ int removePreferredDevicesForStrategySync(int strategy) {
1355         return mDeviceInventory.removePreferredDevicesForStrategyAndSave(strategy);
1356     }
1357 
setDeviceAsNonDefaultForStrategySync(int strategy, @NonNull AudioDeviceAttributes device)1358     /*package*/ int setDeviceAsNonDefaultForStrategySync(int strategy,
1359             @NonNull AudioDeviceAttributes device) {
1360         return mDeviceInventory.setDeviceAsNonDefaultForStrategyAndSave(strategy, device);
1361     }
1362 
removeDeviceAsNonDefaultForStrategySync(int strategy, @NonNull AudioDeviceAttributes device)1363     /*package*/ int removeDeviceAsNonDefaultForStrategySync(int strategy,
1364             @NonNull AudioDeviceAttributes device) {
1365         return mDeviceInventory.removeDeviceAsNonDefaultForStrategyAndSave(strategy, device);
1366     }
1367 
registerStrategyPreferredDevicesDispatcher( @onNull IStrategyPreferredDevicesDispatcher dispatcher, boolean isPrivileged)1368     /*package*/ void registerStrategyPreferredDevicesDispatcher(
1369             @NonNull IStrategyPreferredDevicesDispatcher dispatcher, boolean isPrivileged) {
1370         mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher, isPrivileged);
1371     }
1372 
unregisterStrategyPreferredDevicesDispatcher( @onNull IStrategyPreferredDevicesDispatcher dispatcher)1373     /*package*/ void unregisterStrategyPreferredDevicesDispatcher(
1374             @NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
1375         mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
1376     }
1377 
registerStrategyNonDefaultDevicesDispatcher( @onNull IStrategyNonDefaultDevicesDispatcher dispatcher, boolean isPrivileged)1378     /*package*/ void registerStrategyNonDefaultDevicesDispatcher(
1379             @NonNull IStrategyNonDefaultDevicesDispatcher dispatcher, boolean isPrivileged) {
1380         mDeviceInventory.registerStrategyNonDefaultDevicesDispatcher(dispatcher, isPrivileged);
1381     }
1382 
unregisterStrategyNonDefaultDevicesDispatcher( @onNull IStrategyNonDefaultDevicesDispatcher dispatcher)1383     /*package*/ void unregisterStrategyNonDefaultDevicesDispatcher(
1384             @NonNull IStrategyNonDefaultDevicesDispatcher dispatcher) {
1385         mDeviceInventory.unregisterStrategyNonDefaultDevicesDispatcher(dispatcher);
1386     }
1387 
setPreferredDevicesForCapturePresetSync(int capturePreset, @NonNull List<AudioDeviceAttributes> devices)1388     /*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset,
1389             @NonNull List<AudioDeviceAttributes> devices) {
1390         return mDeviceInventory.setPreferredDevicesForCapturePresetAndSave(capturePreset, devices);
1391     }
1392 
clearPreferredDevicesForCapturePresetSync(int capturePreset)1393     /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
1394         return mDeviceInventory.clearPreferredDevicesForCapturePresetAndSave(capturePreset);
1395     }
1396 
registerCapturePresetDevicesRoleDispatcher( @onNull ICapturePresetDevicesRoleDispatcher dispatcher, boolean isPrivileged)1397     /*package*/ void registerCapturePresetDevicesRoleDispatcher(
1398             @NonNull ICapturePresetDevicesRoleDispatcher dispatcher, boolean isPrivileged) {
1399         mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher, isPrivileged);
1400     }
1401 
unregisterCapturePresetDevicesRoleDispatcher( @onNull ICapturePresetDevicesRoleDispatcher dispatcher)1402     /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
1403             @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
1404         mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
1405     }
1406 
anonymizeAudioDeviceAttributesListUnchecked( List<AudioDeviceAttributes> devices)1407     /* package */ List<AudioDeviceAttributes> anonymizeAudioDeviceAttributesListUnchecked(
1408             List<AudioDeviceAttributes> devices) {
1409         return mAudioService.anonymizeAudioDeviceAttributesListUnchecked(devices);
1410     }
1411 
registerCommunicationDeviceDispatcher( @onNull ICommunicationDeviceDispatcher dispatcher)1412     /*package*/ void registerCommunicationDeviceDispatcher(
1413             @NonNull ICommunicationDeviceDispatcher dispatcher) {
1414         mCommDevDispatchers.register(dispatcher);
1415     }
1416 
unregisterCommunicationDeviceDispatcher( @onNull ICommunicationDeviceDispatcher dispatcher)1417     /*package*/ void unregisterCommunicationDeviceDispatcher(
1418             @NonNull ICommunicationDeviceDispatcher dispatcher) {
1419         mCommDevDispatchers.unregister(dispatcher);
1420     }
1421 
1422     // Monitoring of communication device
1423     final RemoteCallbackList<ICommunicationDeviceDispatcher> mCommDevDispatchers =
1424             new RemoteCallbackList<ICommunicationDeviceDispatcher>();
1425 
1426     // portId of the device currently selected for communication: avoids broadcasting changes
1427     // when same communication route is applied
1428     @GuardedBy("mDeviceStateLock")
1429     int mCurCommunicationPortId = -1;
1430 
1431     @GuardedBy("mDeviceStateLock")
dispatchCommunicationDevice()1432     private void dispatchCommunicationDevice() {
1433         AudioDeviceInfo device = getCommunicationDeviceInt();
1434         int portId = device != null ? device.getId() : 0;
1435         if (portId == mCurCommunicationPortId) {
1436             return;
1437         }
1438         mCurCommunicationPortId = portId;
1439 
1440         @BtCommDeviceActiveType int btCommDeviceActiveType = 0;
1441         if (equalScoLeaVcIndexRange()) {
1442             if (isBluetoothScoActive()) {
1443                 btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_SCO;
1444             } else if (isBluetoothBleHeadsetActive()) {
1445                 btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_BLE_HEADSET;
1446             } else if (isBluetoothBleSpeakerActive()) {
1447                 btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER;
1448             }
1449             mAudioService.postBtCommDeviceActive(btCommDeviceActiveType);
1450         } else {
1451             mAudioService.postBtCommDeviceActive(
1452                     isBluetoothScoActive() ? BT_COMM_DEVICE_ACTIVE_SCO : btCommDeviceActiveType);
1453         }
1454 
1455         final int nbDispatchers = mCommDevDispatchers.beginBroadcast();
1456         for (int i = 0; i < nbDispatchers; i++) {
1457             try {
1458                 mCommDevDispatchers.getBroadcastItem(i)
1459                         .dispatchCommunicationDeviceChanged(portId);
1460             } catch (RemoteException e) {
1461                 Log.e(TAG, "dispatchCommunicationDevice error", e);
1462             }
1463         }
1464         mCommDevDispatchers.finishBroadcast();
1465     }
1466 
1467 
1468     //---------------------------------------------------------------------
1469     // Communication with (to) AudioService
1470     //TODO check whether the AudioService methods are candidates to move here
postAccessoryPlugMediaUnmute(int device)1471     /*package*/ void postAccessoryPlugMediaUnmute(int device) {
1472         mAudioService.postAccessoryPlugMediaUnmute(device);
1473     }
1474 
getVolumeForDeviceIgnoreMute(int streamType, int device)1475     /*package*/ int getVolumeForDeviceIgnoreMute(int streamType, int device) {
1476         return mAudioService.getVolumeForDeviceIgnoreMute(streamType, device);
1477     }
1478 
getMaxVssVolumeForStream(int streamType)1479     /*package*/ int getMaxVssVolumeForStream(int streamType) {
1480         return mAudioService.getMaxVssVolumeForStream(streamType);
1481     }
1482 
getDeviceForStream(int streamType)1483     /*package*/ int getDeviceForStream(int streamType) {
1484         return mAudioService.getDeviceForStream(streamType);
1485     }
1486 
postApplyVolumeOnDevice(int streamType, int device, String caller)1487     /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) {
1488         mAudioService.postApplyVolumeOnDevice(streamType, device, caller);
1489     }
1490 
postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller)1491     /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
1492                                                 String caller) {
1493         mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller);
1494     }
1495 
postObserveDevicesForAllStreams()1496     /*packages*/ void postObserveDevicesForAllStreams() {
1497         mAudioService.postObserveDevicesForAllStreams();
1498     }
1499 
isInCommunication()1500     /*package*/ boolean isInCommunication() {
1501         return mAudioService.isInCommunication();
1502     }
1503 
hasMediaDynamicPolicy()1504     /*package*/ boolean hasMediaDynamicPolicy() {
1505         return mAudioService.hasMediaDynamicPolicy();
1506     }
1507 
getContentResolver()1508     /*package*/ ContentResolver getContentResolver() {
1509         return mAudioService.getContentResolver();
1510     }
1511 
checkMusicActive(int deviceType, String caller)1512     /*package*/ void checkMusicActive(int deviceType, String caller) {
1513         mAudioService.checkMusicActive(deviceType, caller);
1514     }
1515 
checkVolumeCecOnHdmiConnection( @udioService.ConnectionState int state, String caller)1516     /*package*/ void checkVolumeCecOnHdmiConnection(
1517             @AudioService.ConnectionState  int state, String caller) {
1518         mAudioService.postCheckVolumeCecOnHdmiConnection(state, caller);
1519     }
1520 
hasAudioFocusUsers()1521     /*package*/ boolean hasAudioFocusUsers() {
1522         return mAudioService.hasAudioFocusUsers();
1523     }
1524 
postInitSpatializerHeadTrackingSensors()1525     /*package*/ void postInitSpatializerHeadTrackingSensors() {
1526         mAudioService.postInitSpatializerHeadTrackingSensors();
1527     }
1528 
1529     //---------------------------------------------------------------------
1530     // Message handling on behalf of helper classes.
1531     // Each of these methods posts a message to mBrokerHandler message queue.
postBroadcastScoConnectionState(int state)1532     /*package*/ void postBroadcastScoConnectionState(int state) {
1533         sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
1534     }
1535 
postBroadcastBecomingNoisy()1536     /*package*/ void postBroadcastBecomingNoisy() {
1537         sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
1538     }
1539 
postBluetoothActiveDevice(BtDeviceInfo info, int delay)1540     /*package*/ void postBluetoothActiveDevice(BtDeviceInfo info, int delay) {
1541         sendLMsg(MSG_L_SET_BT_ACTIVE_DEVICE, SENDMSG_QUEUE, info, delay);
1542     }
1543 
postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay)1544     /*package*/ void postSetWiredDeviceConnectionState(
1545             AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) {
1546         sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
1547     }
1548 
postBtProfileDisconnected(int profile)1549     /*package*/ void postBtProfileDisconnected(int profile) {
1550         sendIMsgNoDelay(MSG_I_BT_SERVICE_DISCONNECTED_PROFILE, SENDMSG_QUEUE, profile);
1551     }
1552 
postBtProfileConnected(int profile, BluetoothProfile proxy)1553     /*package*/ void postBtProfileConnected(int profile, BluetoothProfile proxy) {
1554         sendILMsgNoDelay(MSG_IL_BT_SERVICE_CONNECTED_PROFILE, SENDMSG_QUEUE, profile, proxy);
1555     }
1556 
postCommunicationRouteClientDied(CommunicationRouteClient client)1557     /*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
1558         sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client);
1559     }
1560 
1561     private static final class UpdateCommRouteClientInfo {
1562         @NonNull public final AttributionSource attributionSource;
1563         @NonNull public final String eventSource;
1564 
UpdateCommRouteClientInfo(@onNull AttributionSource attributionSource, @NonNull String eventSource)1565         UpdateCommRouteClientInfo(@NonNull AttributionSource attributionSource,
1566                 @NonNull String eventSource) {
1567             this.attributionSource = attributionSource;
1568             this.eventSource = eventSource;
1569         }
1570     }
1571 
postUpdateCommunicationRouteClient( AttributionSource attributionSource, String eventSource)1572     /*package*/ void postUpdateCommunicationRouteClient(
1573             AttributionSource attributionSource, String eventSource) {
1574         sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
1575             new UpdateCommRouteClientInfo(attributionSource, eventSource));
1576     }
1577 
postSetCommunicationDeviceForClient(CommunicationDeviceInfo info)1578     /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
1579         sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT, SENDMSG_QUEUE, info);
1580     }
1581 
postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice)1582     /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
1583         sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice);
1584     }
1585 
postReceiveBtEvent(Intent intent)1586     /*package*/ void postReceiveBtEvent(Intent intent) {
1587         sendLMsgNoDelay(MSG_L_RECEIVED_BT_EVENT, SENDMSG_QUEUE, intent);
1588     }
1589 
postUpdateLeAudioGroupAddresses(int groupId)1590     /*package*/ void postUpdateLeAudioGroupAddresses(int groupId) {
1591         sendIMsgNoDelay(
1592                 MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES, SENDMSG_QUEUE, groupId);
1593     }
1594 
postSynchronizeAdiDevicesInInventory(AdiDeviceState deviceState)1595     /*package*/ void postSynchronizeAdiDevicesInInventory(AdiDeviceState deviceState) {
1596         sendLMsgNoDelay(MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY, SENDMSG_QUEUE, deviceState);
1597     }
1598 
postUpdatedAdiDeviceState(AdiDeviceState deviceState, boolean initSA)1599     /*package*/ void postUpdatedAdiDeviceState(AdiDeviceState deviceState, boolean initSA) {
1600         sendILMsgNoDelay(
1601                 MSG_IL_UPDATED_ADI_DEVICE_STATE, SENDMSG_QUEUE, initSA ? 1 : 0, deviceState);
1602     }
1603 
1604     /*package*/ static final class CommunicationDeviceInfo {
1605         final @NonNull IBinder mCb; // Identifies the requesting client for death handler
1606         final @NonNull AttributionSource mAttributionSource; // Requester attribution source
1607         final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset.
1608         final boolean mOn; // true if setting, false if resetting
1609         final int mScoAudioMode; // only used for SCO: requested audio mode
1610         final boolean mIsPrivileged; // true if the client app has MODIFY_PHONE_STATE permission
1611         final @NonNull String mEventSource; // caller identifier for logging
1612 
CommunicationDeviceInfo(@onNull IBinder cb, @NonNull AttributionSource attributionSource, @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode, @NonNull String eventSource, boolean isPrivileged)1613         CommunicationDeviceInfo(@NonNull IBinder cb, @NonNull AttributionSource attributionSource,
1614                 @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode,
1615                 @NonNull String eventSource, boolean isPrivileged) {
1616             mCb = cb;
1617             mAttributionSource = attributionSource;
1618             mDevice = device;
1619             mOn = on;
1620             mScoAudioMode = scoAudioMode;
1621             mIsPrivileged = isPrivileged;
1622             mEventSource = eventSource;
1623         }
1624 
1625         // redefine equality op so we can match messages intended for this client
1626         @Override
equals(Object o)1627         public boolean equals(Object o) {
1628             if (o == null) {
1629                 return false;
1630             }
1631             if (this == o) {
1632                 return true;
1633             }
1634             if (!(o instanceof CommunicationDeviceInfo)) {
1635                 return false;
1636             }
1637 
1638             return mCb.equals(((CommunicationDeviceInfo) o).mCb)
1639                     && mAttributionSource.equals(((CommunicationDeviceInfo) o).mAttributionSource);
1640         }
1641 
1642         @Override
hashCode()1643         public int hashCode() {
1644             // only hashing on the fields used in equals()
1645             return Objects.hash(mCb.hashCode(), mAttributionSource);
1646         }
1647 
1648         @Override
toString()1649         public String toString() {
1650             return "CommunicationDeviceInfo mCb=" + mCb.toString()
1651                     + " mAttributionSource=" + mAttributionSource.toString()
1652                     + " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]"
1653                     + " mOn=" + mOn
1654                     + " mScoAudioMode=" + mScoAudioMode
1655                     + " mIsPrivileged=" + mIsPrivileged
1656                     + " mEventSource=" + mEventSource;
1657         }
1658     }
1659 
1660     //---------------------------------------------------------------------
1661     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
1662     // only call from a "handle"* method or "on"* method
1663 
1664     // Handles request to override default use of A2DP for media.
1665     //@GuardedBy("mConnectedDevices")
setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source)1666     /*package*/ void setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source) {
1667         // for logging only
1668         final String eventSource = "setBluetoothA2dpOn(" + on
1669                 + ") from u/pid:" + Binder.getCallingUid() + "/"
1670                 + Binder.getCallingPid() + " src:" + source;
1671 
1672         mBluetoothA2dpEnabled.set(on);
1673         onSetForceUse(
1674                 AudioSystem.FOR_MEDIA,
1675                 on ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
1676                 fromA2dp,
1677                 eventSource);
1678     }
1679 
handleDeviceConnection(@onNull AudioDeviceAttributes attributes, boolean connect, @Nullable BluetoothDevice btDevice, boolean deviceSwitch)1680     /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
1681                                 boolean connect, @Nullable BluetoothDevice btDevice,
1682                                 boolean deviceSwitch) {
1683         synchronized (mDeviceStateLock) {
1684             boolean status =  mDeviceInventory.handleDeviceConnection(
1685                     attributes, connect, false /*for test*/, btDevice, deviceSwitch);
1686             if (isValidCommunicationDeviceType(attributes.getType())
1687                     || mDuplexCommunicationDevices.containsValue(attributes.getInternalType())) {
1688                 checkCommunicationRouteClientsDevices();
1689                 if (connect || !deviceSwitch) {
1690                     onUpdateCommunicationRouteClient(
1691                             bluetoothScoRequestOwnerAttributionSource(),
1692                             "handleDeviceConnection");
1693                 }
1694             }
1695             return status;
1696         }
1697     }
1698 
handleFailureToConnectToBtHeadsetService(int delay)1699     /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) {
1700         sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay);
1701     }
1702 
handleCancelFailureToConnectToBtHeadsetService()1703     /*package*/ void handleCancelFailureToConnectToBtHeadsetService() {
1704         mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
1705     }
1706 
postReportNewRoutes(boolean fromA2dp)1707     /*package*/ void postReportNewRoutes(boolean fromA2dp) {
1708         sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP);
1709     }
1710 
1711     // must be called synchronized on mConnectedDevices
hasScheduledA2dpConnection(BluetoothDevice btDevice, int profile)1712     /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice, int profile) {
1713         final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, profile);
1714         return mBrokerHandler.hasEqualMessages(MSG_L_SET_BT_ACTIVE_DEVICE, devInfoToCheck);
1715     }
1716 
setA2dpTimeout(String address, int a2dpCodec, int delayMs)1717     /*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) {
1718         sendILMsg(MSG_IL_BTA2DP_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs);
1719     }
1720 
setLeAudioTimeout(String address, int device, int codec, int delayMs)1721     /*package*/ void setLeAudioTimeout(String address, int device, int codec, int delayMs) {
1722         sendIILMsg(MSG_IIL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, codec, address, delayMs);
1723     }
1724 
setHearingAidTimeout(String address, int delayMs)1725     /*package*/ void setHearingAidTimeout(String address, int delayMs) {
1726         sendLMsg(MSG_IL_BT_HEARING_AID_TIMEOUT, SENDMSG_QUEUE, address, delayMs);
1727     }
1728 
setAvrcpAbsoluteVolumeSupported(boolean supported)1729     /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
1730         synchronized (mDeviceStateLock) {
1731             mBtHelper.setAvrcpAbsoluteVolumeSupported(supported);
1732         }
1733     }
1734 
clearAvrcpAbsoluteVolumeSupported()1735     /*package*/ void clearAvrcpAbsoluteVolumeSupported() {
1736         setAvrcpAbsoluteVolumeSupported(false);
1737         mAudioService.setAvrcpAbsoluteVolumeSupported(false);
1738     }
1739 
getBluetoothA2dpEnabled()1740     /*package*/ boolean getBluetoothA2dpEnabled() {
1741         return mBluetoothA2dpEnabled.get();
1742     }
1743 
getLeAudioDeviceGroupId(BluetoothDevice device)1744     /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) {
1745         return mBtHelper.getLeAudioDeviceGroupId(device);
1746     }
1747 
getLeAudioGroupAddresses(int groupId)1748     /*package*/ List<Pair<String, String>> getLeAudioGroupAddresses(int groupId) {
1749         return mBtHelper.getLeAudioGroupAddresses(groupId);
1750     }
1751 
broadcastStickyIntentToCurrentProfileGroup(Intent intent)1752     /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
1753         mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent);
1754     }
1755 
dump(PrintWriter pw, String prefix)1756     /*package*/ void dump(PrintWriter pw, String prefix) {
1757         if (mBrokerHandler != null) {
1758             pw.println(prefix + "Message handler (watch for unhandled messages):");
1759             mBrokerHandler.dump(new PrintWriterPrinter(pw), prefix + "  ");
1760         } else {
1761             pw.println("Message handler is null");
1762         }
1763 
1764         mDeviceInventory.dump(pw, prefix);
1765 
1766         pw.println("\n" + prefix + "Communication route clients:");
1767         mCommunicationRouteClients.forEach((cl) -> {
1768             pw.println("  " + prefix + cl.toString()); });
1769 
1770         pw.println("\n" + prefix + "Computed Preferred communication device: "
1771                 +  preferredCommunicationDevice());
1772         pw.println("\n" + prefix + "Applied Preferred communication device: "
1773                 +  mPreferredCommunicationDevice);
1774         pw.println(prefix + "Active communication device: "
1775                 +  ((mActiveCommunicationDevice == null) ? "None"
1776                         : new AudioDeviceAttributes(mActiveCommunicationDevice)));
1777 
1778         pw.println(prefix + "mCommunicationStrategyId: "
1779                 +  mCommunicationStrategyId);
1780 
1781         pw.println(prefix + "mAccessibilityStrategyId: "
1782                 +  mAccessibilityStrategyId);
1783 
1784         pw.println("\n" + prefix + "mAudioModeOwner: " + mAudioModeOwner);
1785 
1786         pw.println("\n" + prefix + "mScoManagedByAudio: " + mScoManagedByAudio);
1787 
1788         pw.println("\n" + prefix + "Bluetooth SCO on"
1789                 + ", requested: " + mBluetoothScoOn
1790                 + ", applied: " + mBluetoothScoOnApplied);
1791         pw.println("\n" + prefix +  "Bluetooth A2DP suspended"
1792                 + ", requested ext: " + mBluetoothA2dpSuspendedExt
1793                 + ", requested int: " + mBluetoothA2dpSuspendedInt
1794                 + ", applied " + mBluetoothA2dpSuspendedApplied);
1795         pw.println("\n" + prefix +  "Bluetooth LE Audio suspended"
1796                 + ", requested ext: " + mBluetoothLeSuspendedExt
1797                 + ", requested int: " + mBluetoothLeSuspendedInt
1798                 + ", applied " + mBluetoothLeSuspendedApplied);
1799 
1800         mBtHelper.dump(pw, prefix);
1801     }
1802 
1803     //---------------------------------------------------------------------
1804     // Internal handling of messages
1805     // These methods are ALL synchronous, in response to message handling in BrokerHandler
1806     // Blocking in any of those will block the message queue
1807 
onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource)1808     private void onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource) {
1809         if (useCase == AudioSystem.FOR_MEDIA) {
1810             postReportNewRoutes(fromA2dp);
1811         }
1812         AudioService.sForceUseLogger.enqueue(
1813                 new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource));
1814         new MediaMetrics.Item(MediaMetrics.Name.AUDIO_FORCE_USE + MediaMetrics.SEPARATOR
1815                 + AudioSystem.forceUseUsageToString(useCase))
1816                 .set(MediaMetrics.Property.EVENT, "onSetForceUse")
1817                 .set(MediaMetrics.Property.FORCE_USE_DUE_TO, eventSource)
1818                 .set(MediaMetrics.Property.FORCE_USE_MODE,
1819                         AudioSystem.forceUseConfigToString(config))
1820                 .record();
1821 
1822         if (AudioService.DEBUG_COMM_RTE) {
1823             Log.v(TAG, "onSetForceUse(useCase<" + useCase + ">, config<" + config + ">, fromA2dp<"
1824                     + fromA2dp + ">, eventSource<" + eventSource + ">)");
1825         }
1826         mAudioSystem.setForceUse(useCase, config);
1827     }
1828 
onSendBecomingNoisyIntent()1829     private void onSendBecomingNoisyIntent() {
1830         AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
1831                 "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));
1832         mSystemServer.sendDeviceBecomingNoisyIntent();
1833     }
1834 
1835     //---------------------------------------------------------------------
1836     // Message handling
1837     private BrokerHandler mBrokerHandler;
1838     private BrokerThread mBrokerThread;
1839     private PowerManager.WakeLock mBrokerEventWakeLock;
1840 
setupMessaging(Context ctxt)1841     private void setupMessaging(Context ctxt) {
1842         final PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE);
1843         mBrokerEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
1844                 "handleAudioDeviceEvent");
1845         mBrokerThread = new BrokerThread();
1846         mBrokerThread.start();
1847         waitForBrokerHandlerCreation();
1848     }
1849 
waitForBrokerHandlerCreation()1850     private void waitForBrokerHandlerCreation() {
1851         synchronized (this) {
1852             while (mBrokerHandler == null) {
1853                 try {
1854                     wait();
1855                 } catch (InterruptedException e) {
1856                     Log.e(TAG, "Interruption while waiting on BrokerHandler");
1857                 }
1858             }
1859         }
1860     }
1861 
1862     /** Class that handles the device broker's message queue */
1863     private class BrokerThread extends Thread {
BrokerThread()1864         BrokerThread() {
1865             super("AudioDeviceBroker");
1866         }
1867 
1868         @Override
run()1869         public void run() {
1870             // Set this thread up so the handler will work on it
1871             Looper.prepare();
1872 
1873             synchronized (AudioDeviceBroker.this) {
1874                 mBrokerHandler = new BrokerHandler();
1875 
1876                 // Notify that the handler has been created
1877                 AudioDeviceBroker.this.notify();
1878             }
1879 
1880             Looper.loop();
1881         }
1882     }
1883 
1884     /** Class that handles the message queue */
1885     private class BrokerHandler extends Handler {
1886 
1887         @Override
handleMessage(Message msg)1888         public void handleMessage(Message msg) {
1889             int muteCheckDelayMs = BTA2DP_MUTE_CHECK_DELAY_MS;
1890             switch (msg.what) {
1891                 case MSG_RESTORE_DEVICES:
1892                     synchronized (mSetModeLock) {
1893                         synchronized (mDeviceStateLock) {
1894                             initRoutingStrategyIds();
1895                             updateActiveCommunicationDevice();
1896                             mDeviceInventory.onRestoreDevices();
1897                             synchronized (mBluetoothAudioStateLock) {
1898                                 reapplyAudioHalBluetoothState();
1899                             }
1900                             final int forceForMedia = getBluetoothA2dpEnabled()
1901                                     ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
1902                             setForceUse_Async(
1903                                     AudioSystem.FOR_MEDIA, forceForMedia, "MSG_RESTORE_DEVICES");
1904                             updateCommunicationRoute("MSG_RESTORE_DEVICES");
1905                         }
1906                     }
1907                     break;
1908                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
1909                     synchronized (mDeviceStateLock) {
1910                         mDeviceInventory.onSetWiredDeviceConnectionState(
1911                                 (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj);
1912                     }
1913                     break;
1914                 case MSG_I_BROADCAST_BT_CONNECTION_STATE:
1915                     synchronized (mDeviceStateLock) {
1916                         mBtHelper.onBroadcastScoConnectionState(msg.arg1);
1917                     }
1918                     break;
1919                 case MSG_IIL_SET_FORCE_USE: // intended fall-through
1920                     onSetForceUse(msg.arg1, msg.arg2, false, (String) msg.obj);
1921                     break;
1922                 case MSG_L_SET_FORCE_BT_A2DP_USE:
1923                 case MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE:
1924                     int forcedUsage = mBluetoothA2dpEnabled.get()
1925                             ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
1926                     onSetForceUse(AudioSystem.FOR_MEDIA, forcedUsage, true, (String) msg.obj);
1927                     break;
1928                 case MSG_REPORT_NEW_ROUTES:
1929                 case MSG_REPORT_NEW_ROUTES_A2DP:
1930                     synchronized (mDeviceStateLock) {
1931                         mDeviceInventory.onReportNewRoutes();
1932                     }
1933                     break;
1934                 case MSG_L_SET_BT_ACTIVE_DEVICE: {
1935                     final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
1936                     if (btInfo.mState == BluetoothProfile.STATE_CONNECTED
1937                             && !mBtHelper.isProfilePoxyConnected(btInfo.mProfile)) {
1938                         AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
1939                                 "msg: MSG_L_SET_BT_ACTIVE_DEVICE "
1940                                         + "received with null profile proxy: "
1941                                         + btInfo)).printLog(TAG));
1942                     } else {
1943                         final Pair<Integer, Boolean> codecAndChanged =
1944                                 mBtHelper.getCodecWithFallback(btInfo.mDevice,
1945                                         btInfo.mProfile, btInfo.mIsLeOutput,
1946                                         "MSG_L_SET_BT_ACTIVE_DEVICE");
1947                         synchronized (mSetModeLock) {
1948                             synchronized (mDeviceStateLock) {
1949                                 mDeviceInventory.onSetBtActiveDevice(btInfo, codecAndChanged.first,
1950                                         (btInfo.mProfile != BluetoothProfile.LE_AUDIO
1951                                                 || btInfo.mIsLeOutput)
1952                                             ? mAudioService.getBluetoothContextualVolumeStream()
1953                                             : AudioSystem.STREAM_DEFAULT);
1954                                 if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
1955                                         || btInfo.mProfile == BluetoothProfile.HEARING_AID
1956                                         || (mScoManagedByAudio
1957                                             && btInfo.mProfile == BluetoothProfile.HEADSET)) {
1958                                     checkCommunicationRouteClientsDevices();
1959                                     if (btInfo.mState == BluetoothProfile.STATE_CONNECTED
1960                                             || !btInfo.mIsDeviceSwitch) {
1961                                         onUpdateCommunicationRouteClient(
1962                                             bluetoothScoRequestOwnerAttributionSource(),
1963                                             "setBluetoothActiveDevice");
1964                                     }
1965                                 }
1966                             }
1967                         }
1968                     }
1969                 } break;
1970                 case MSG_BT_HEADSET_CNCT_FAILED:
1971                     synchronized (mSetModeLock) {
1972                         synchronized (mDeviceStateLock) {
1973                             mBtHelper.resetBluetoothSco();
1974                         }
1975                     }
1976                     break;
1977                 case MSG_IL_BTA2DP_TIMEOUT:
1978                     // msg.obj  == address of BTA2DP device
1979                     synchronized (mDeviceStateLock) {
1980                         mDeviceInventory.onMakeA2dpDeviceUnavailableNow(
1981                                 (String) msg.obj, msg.arg1);
1982                     }
1983                     break;
1984                 case MSG_IIL_BTLEAUDIO_TIMEOUT:
1985                     // msg.obj  == address of LE Audio device
1986                     synchronized (mDeviceStateLock) {
1987                         mDeviceInventory.onMakeLeAudioDeviceUnavailableNow(
1988                                 (String) msg.obj, msg.arg1, msg.arg2);
1989                     }
1990                     break;
1991                 case MSG_IL_BT_HEARING_AID_TIMEOUT:
1992                     // msg.obj  == address of Hearing Aid device
1993                     synchronized (mDeviceStateLock) {
1994                         mDeviceInventory.onMakeHearingAidDeviceUnavailableNow(
1995                                 (String) msg.obj);
1996                     }
1997                     break;
1998                 case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: {
1999                     final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
2000                     final Pair<Integer, Boolean> codecAndChanged = mBtHelper.getCodecWithFallback(
2001                             btInfo.mDevice, btInfo.mProfile, btInfo.mIsLeOutput,
2002                             "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE");
2003                     synchronized (mDeviceStateLock) {
2004                         muteCheckDelayMs += mDeviceInventory.onBluetoothDeviceConfigChange(btInfo,
2005                                 codecAndChanged.first, codecAndChanged.second,
2006                                 BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
2007                     }
2008                 } break;
2009                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
2010                     onSendBecomingNoisyIntent();
2011                     break;
2012                 case MSG_II_SET_HEARING_AID_VOLUME:
2013                     synchronized (mDeviceStateLock) {
2014                         mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2,
2015                                 mDeviceInventory.isHearingAidConnected());
2016                     }
2017                     break;
2018                 case MSG_II_SET_LE_AUDIO_OUT_VOLUME: {
2019                     final BleVolumeInfo info = (BleVolumeInfo) msg.obj;
2020                     synchronized (mDeviceStateLock) {
2021                         mBtHelper.setLeAudioVolume(info.mIndex, info.mMaxIndex, info.mStreamType);
2022                     }
2023                 } break;
2024                 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
2025                     synchronized (mDeviceStateLock) {
2026                         mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
2027                     }
2028                     break;
2029                 case MSG_L_SET_MODE_OWNER:
2030                 case MSG_L_SET_MODE_OWNER_SIGNAL:
2031                     synchronized (mSetModeLock) {
2032                         synchronized (mDeviceStateLock) {
2033                             mAudioModeOwner = (AudioModeInfo) msg.obj;
2034                             if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
2035                                 onUpdateCommunicationRouteClient(
2036                                         bluetoothScoRequestOwnerAttributionSource(),
2037                                         "setNewModeOwner");
2038                             }
2039                         }
2040                     }
2041                     if (msg.what == MSG_L_SET_MODE_OWNER_SIGNAL) {
2042                         mAudioService.decrementAudioModeResetCount();
2043                     }
2044                     break;
2045 
2046                 case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT:
2047                     CommunicationDeviceInfo deviceInfo = (CommunicationDeviceInfo) msg.obj;
2048                     synchronized (mSetModeLock) {
2049                         synchronized (mDeviceStateLock) {
2050                             onSetCommunicationDeviceForClient(deviceInfo);
2051                         }
2052                     }
2053                     synchronized (mCommunicationDeviceLock) {
2054                         if (mCommunicationDeviceUpdateCount > 0) {
2055                             mCommunicationDeviceUpdateCount--;
2056                         } else {
2057                             Log.e(TAG, "mCommunicationDeviceUpdateCount already 0 in"
2058                                     + " MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT");
2059                         }
2060                         mCommunicationDeviceLock.notify();
2061                     }
2062                     break;
2063 
2064                 case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
2065                     synchronized (mSetModeLock) {
2066                         synchronized (mDeviceStateLock) {
2067                             UpdateCommRouteClientInfo info = (UpdateCommRouteClientInfo) msg.obj;
2068                             onUpdateCommunicationRouteClient(
2069                                     info.attributionSource, info.eventSource);
2070                         }
2071                     }
2072                     break;
2073 
2074                 case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
2075                     synchronized (mSetModeLock) {
2076                         synchronized (mDeviceStateLock) {
2077                             onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
2078                         }
2079                     }
2080                     break;
2081 
2082                 case MSG_L_RECEIVED_BT_EVENT:
2083                     synchronized (mSetModeLock) {
2084                         synchronized (mDeviceStateLock) {
2085                             onReceiveBtEvent((Intent) msg.obj);
2086                         }
2087                     }
2088                     break;
2089 
2090                 case MSG_TOGGLE_HDMI:
2091                     synchronized (mDeviceStateLock) {
2092                         mDeviceInventory.onToggleHdmi();
2093                     }
2094                     break;
2095                 case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE:
2096                     synchronized (mSetModeLock) {
2097                         synchronized (mDeviceStateLock) {
2098                             mBtHelper.onBtProfileDisconnected(msg.arg1);
2099                             mDeviceInventory.onBtProfileDisconnected(msg.arg1);
2100                         }
2101                     }
2102                     break;
2103                 case MSG_IL_BT_SERVICE_CONNECTED_PROFILE:
2104                     synchronized (mSetModeLock) {
2105                         synchronized (mDeviceStateLock) {
2106                             mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj);
2107                         }
2108                     }
2109                     break;
2110                 case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: {
2111                     final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
2112                     if (btInfo.mDevice == null) break;
2113                     AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
2114                             "msg: MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT " + btInfo)).printLog(TAG));
2115                     synchronized (mDeviceStateLock) {
2116                         mDeviceInventory.setBluetoothActiveDevice(btInfo);
2117                     }
2118                 } break;
2119                 case MSG_CHECK_MUTE_MUSIC:
2120                     checkMessagesMuteMusic(0);
2121                     break;
2122                 case MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED: {
2123                     final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
2124                     BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
2125                 } break;
2126                 case MSG_PERSIST_AUDIO_DEVICE_SETTINGS:
2127                     onPersistAudioDeviceSettings();
2128                     break;
2129 
2130                 case MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE: {
2131                     synchronized (mDeviceStateLock) {
2132                         onCheckCommunicationRouteClientState(msg.arg1, msg.arg2 == 1);
2133                     }
2134                 } break;
2135 
2136                 case MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES:
2137                     synchronized (mSetModeLock) {
2138                         synchronized (mDeviceStateLock) {
2139                             mDeviceInventory.onUpdateLeAudioGroupAddresses(msg.arg1);
2140                         }
2141                     } break;
2142 
2143                 case MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY:
2144                     synchronized (mSetModeLock) {
2145                         synchronized (mDeviceStateLock) {
2146                             mDeviceInventory.onSynchronizeAdiDevicesInInventory(
2147                                     (AdiDeviceState) msg.obj);
2148                         }
2149                     } break;
2150 
2151                 case MSG_IL_UPDATED_ADI_DEVICE_STATE:
2152                     mAudioService.onUpdatedAdiDeviceState((AdiDeviceState) msg.obj, msg.arg1 == 1);
2153                     break;
2154 
2155                 default:
2156                     Log.wtf(TAG, "Invalid message " + msg.what);
2157             }
2158 
2159             // Give some time to Bluetooth service to post a connection message
2160             // in case of active device switch
2161             if (MESSAGES_MUTE_MUSIC.contains(msg.what)) {
2162                 sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, muteCheckDelayMs);
2163             }
2164 
2165             if (isMessageHandledUnderWakelock(msg.what)) {
2166                 try {
2167                     mBrokerEventWakeLock.release();
2168                 } catch (Exception e) {
2169                     Log.e(TAG, "Exception releasing wakelock", e);
2170                 }
2171             }
2172         }
2173     }
2174 
2175     // List of all messages. If a message has be handled under wakelock, add it to
2176     //    the isMessageHandledUnderWakelock(int) method
2177     // Naming of msg indicates arguments, using JNI argument grammar
2178     // (e.g. II indicates two int args, IL indicates int and Obj arg)
2179     private static final int MSG_RESTORE_DEVICES = 1;
2180     private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2;
2181     private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3;
2182     private static final int MSG_IIL_SET_FORCE_USE = 4;
2183     private static final int MSG_L_SET_FORCE_BT_A2DP_USE = 5;
2184     private static final int MSG_TOGGLE_HDMI = 6;
2185     private static final int MSG_L_SET_BT_ACTIVE_DEVICE = 7;
2186     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
2187     private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
2188 
2189     // process change of A2DP device configuration, obj is BluetoothDevice
2190     private static final int MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE = 11;
2191 
2192     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12;
2193     private static final int MSG_REPORT_NEW_ROUTES = 13;
2194     private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
2195     private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
2196     private static final int MSG_L_SET_MODE_OWNER = 16;
2197     private static final int MSG_L_SET_MODE_OWNER_SIGNAL = 17;
2198 
2199     private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
2200     private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
2201 
2202     // process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo
2203     private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 29;
2204 
2205     // process external command to (dis)connect a hearing aid device
2206     private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
2207 
2208     private static final int MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED = 34;
2209     private static final int MSG_CHECK_MUTE_MUSIC = 35;
2210     private static final int MSG_REPORT_NEW_ROUTES_A2DP = 36;
2211 
2212     private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
2213     private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
2214 
2215     private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
2216     //
2217     // process set volume for Le Audio, obj is BleVolumeInfo
2218     private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46;
2219 
2220     private static final int MSG_IIL_BTLEAUDIO_TIMEOUT = 49;
2221 
2222     private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
2223 
2224     private static final int MSG_PERSIST_AUDIO_DEVICE_SETTINGS = 54;
2225 
2226     private static final int MSG_L_RECEIVED_BT_EVENT = 55;
2227 
2228     private static final int MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE = 56;
2229     private static final int MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES = 57;
2230     private static final int MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY = 58;
2231     private static final int MSG_IL_UPDATED_ADI_DEVICE_STATE = 59;
2232     private static final int MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE = 60;
2233     private static final int MSG_IL_BT_HEARING_AID_TIMEOUT = 61;
2234 
isMessageHandledUnderWakelock(int msgId)2235     private static boolean isMessageHandledUnderWakelock(int msgId) {
2236         switch(msgId) {
2237             case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
2238             case MSG_L_SET_BT_ACTIVE_DEVICE:
2239             case MSG_IL_BTA2DP_TIMEOUT:
2240             case MSG_IIL_BTLEAUDIO_TIMEOUT:
2241             case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
2242             case MSG_TOGGLE_HDMI:
2243             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
2244             case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
2245             case MSG_CHECK_MUTE_MUSIC:
2246             case MSG_IL_BT_HEARING_AID_TIMEOUT:
2247                 return true;
2248             default:
2249                 return false;
2250         }
2251     }
2252 
2253     // Message helper methods
2254 
2255     // sendMsg() flags
2256     /** If the msg is already queued, replace it with this one. */
2257     private static final int SENDMSG_REPLACE = 0;
2258     /** If the msg is already queued, ignore this one and leave the old. */
2259     private static final int SENDMSG_NOOP = 1;
2260     /** If the msg is already queued, queue this one and leave the old. */
2261     private static final int SENDMSG_QUEUE = 2;
2262 
sendMsg(int msg, int existingMsgPolicy, int delay)2263     private void sendMsg(int msg, int existingMsgPolicy, int delay) {
2264         sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay);
2265     }
2266 
sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay)2267     private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) {
2268         sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay);
2269     }
2270 
sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay)2271     private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) {
2272         sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay);
2273     }
2274 
sendMsgNoDelay(int msg, int existingMsgPolicy)2275     private void sendMsgNoDelay(int msg, int existingMsgPolicy) {
2276         sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0);
2277     }
2278 
sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg)2279     private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) {
2280         sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0);
2281     }
2282 
sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2)2283     private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) {
2284         sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0);
2285     }
2286 
sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj)2287     private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) {
2288         sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0);
2289     }
2290 
sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj)2291     private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) {
2292         sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0);
2293     }
2294 
sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj)2295     private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) {
2296         sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0);
2297     }
2298 
sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)2299     private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj,
2300                             int delay) {
2301         if (existingMsgPolicy == SENDMSG_REPLACE) {
2302             mBrokerHandler.removeMessages(msg);
2303         } else if (existingMsgPolicy == SENDMSG_NOOP && mBrokerHandler.hasMessages(msg)) {
2304             return;
2305         }
2306 
2307         if (isMessageHandledUnderWakelock(msg)) {
2308             final long identity = Binder.clearCallingIdentity();
2309             try {
2310                 mBrokerEventWakeLock.acquire(BROKER_WAKELOCK_TIMEOUT_MS);
2311             } catch (Exception e) {
2312                 Log.e(TAG, "Exception acquiring wakelock", e);
2313             } finally {
2314                 Binder.restoreCallingIdentity(identity);
2315             }
2316         }
2317 
2318         if (MESSAGES_MUTE_MUSIC.contains(msg)) {
2319             checkMessagesMuteMusic(msg);
2320         }
2321 
2322         synchronized (sLastDeviceConnectionMsgTimeLock) {
2323             long time = SystemClock.uptimeMillis() + delay;
2324 
2325             switch (msg) {
2326                 case MSG_L_SET_BT_ACTIVE_DEVICE:
2327                 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
2328                 case MSG_IL_BTA2DP_TIMEOUT:
2329                 case MSG_IIL_BTLEAUDIO_TIMEOUT:
2330                 case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
2331                 case MSG_IL_BT_HEARING_AID_TIMEOUT:
2332                     if (sLastDeviceConnectMsgTime >= time) {
2333                         // add a little delay to make sure messages are ordered as expected
2334                         time = sLastDeviceConnectMsgTime + 30;
2335                     }
2336                     sLastDeviceConnectMsgTime = time;
2337                     break;
2338                 default:
2339                     break;
2340             }
2341             mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj),
2342                     time);
2343         }
2344     }
2345 
removeMsgForCheckClientState(int uid)2346     private void removeMsgForCheckClientState(int uid) {
2347         CommunicationRouteClient crc = getCommunicationRouteClientForUid(uid);
2348         if (crc != null) {
2349             mBrokerHandler.removeEqualMessages(MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE, crc);
2350         }
2351     }
2352 
sendMsgForCheckClientState(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)2353     private void sendMsgForCheckClientState(int msg, int existingMsgPolicy,
2354                                             int arg1, int arg2, Object obj, int delay) {
2355         if ((existingMsgPolicy == SENDMSG_REPLACE) && (obj != null)) {
2356             mBrokerHandler.removeEqualMessages(msg, obj);
2357         }
2358 
2359         long time = SystemClock.uptimeMillis() + delay;
2360         mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), time);
2361     }
2362 
2363     /** List of messages for which music is muted while processing is pending */
2364     private static final Set<Integer> MESSAGES_MUTE_MUSIC;
2365     static {
2366         MESSAGES_MUTE_MUSIC = new HashSet<>();
2367         MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE);
2368         MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE);
2369         MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT);
2370         MESSAGES_MUTE_MUSIC.add(MSG_L_SET_FORCE_BT_A2DP_USE);
2371     }
2372 
2373     private AtomicBoolean mMusicMuted = new AtomicBoolean(false);
2374 
hasIntersection(Set<T> a, Set<T> b)2375     private static <T> boolean hasIntersection(Set<T> a, Set<T> b) {
2376         for (T e : a) {
2377             if (b.contains(e)) return true;
2378         }
2379         return false;
2380     }
2381 
messageMutesMusic(int message)2382     boolean messageMutesMusic(int message) {
2383         if (message == 0) {
2384             return false;
2385         }
2386         // Do not mute on bluetooth event if music is playing on a wired headset.
2387         if ((message == MSG_L_SET_BT_ACTIVE_DEVICE
2388                 || message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT
2389                 || message == MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE)
2390                 && AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
2391                 && hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET,
2392                         mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) {
2393             return false;
2394         }
2395         return true;
2396     }
2397 
2398     /** Mutes or unmutes music according to pending A2DP messages */
checkMessagesMuteMusic(int message)2399     private void checkMessagesMuteMusic(int message) {
2400         boolean mute = messageMutesMusic(message);
2401         if (!mute) {
2402             for (int msg : MESSAGES_MUTE_MUSIC) {
2403                 if (mBrokerHandler.hasMessages(msg)) {
2404                     if (messageMutesMusic(msg)) {
2405                         mute = true;
2406                         break;
2407                     }
2408                 }
2409             }
2410         }
2411 
2412         if (mute != mMusicMuted.getAndSet(mute)) {
2413             mAudioService.setMusicMute(mute);
2414         }
2415     }
2416 
2417     // List of applications requesting a specific route for communication.
2418     @GuardedBy("mDeviceStateLock")
2419     private final @NonNull LinkedList<CommunicationRouteClient> mCommunicationRouteClients =
2420             new LinkedList<CommunicationRouteClient>();
2421 
2422     private class CommunicationRouteClient implements IBinder.DeathRecipient {
2423         private final IBinder mCb;
2424         @NonNull private final AttributionSource mAttributionSource;
2425         private final boolean mIsPrivileged;
2426         @NonNull private AudioDeviceAttributes mDevice;
2427         private boolean mPlaybackActive;
2428         private boolean mRecordingActive;
2429 
2430         private boolean mDisabled;
2431 
CommunicationRouteClient(IBinder cb, @NonNull AttributionSource attributionSource, @NonNull AudioDeviceAttributes device, boolean isPrivileged)2432         CommunicationRouteClient(IBinder cb, @NonNull AttributionSource attributionSource,
2433                 @NonNull AudioDeviceAttributes device, boolean isPrivileged) {
2434             mCb = cb;
2435             mAttributionSource = attributionSource;
2436             mDevice = device;
2437             mIsPrivileged = isPrivileged;
2438             mPlaybackActive = mAudioService.isPlaybackActiveForUid(attributionSource.getUid());
2439             mRecordingActive = mAudioService.isRecordingActiveForUid(attributionSource.getUid());
2440             mDisabled = false;
2441         }
2442 
registerDeathRecipient()2443         public boolean registerDeathRecipient() {
2444             boolean status = false;
2445             try {
2446                 mCb.linkToDeath(this, 0);
2447                 status = true;
2448             } catch (RemoteException e) {
2449                 Log.w(TAG, "CommunicationRouteClient could not link to " + mCb + " binder death");
2450             }
2451             return status;
2452         }
2453 
unregisterDeathRecipient()2454         public void unregisterDeathRecipient() {
2455             try {
2456                 mCb.unlinkToDeath(this, 0);
2457             } catch (NoSuchElementException e) {
2458                 Log.w(TAG, "CommunicationRouteClient could not unlink to " + mCb + " binder death");
2459             }
2460         }
2461 
2462         @Override
binderDied()2463         public void binderDied() {
2464             postCommunicationRouteClientDied(this);
2465         }
2466 
getBinder()2467         IBinder getBinder() {
2468             return mCb;
2469         }
2470 
getAttributionSource()2471         @NonNull AttributionSource getAttributionSource() {
2472             return mAttributionSource;
2473         }
2474 
getUid()2475         int getUid() {
2476             return mAttributionSource.getUid();
2477         }
2478 
isPrivileged()2479         boolean isPrivileged() {
2480             return mIsPrivileged;
2481         }
2482 
setDevice(@onNull AudioDeviceAttributes device)2483         void setDevice(@NonNull AudioDeviceAttributes device) {
2484             mDevice = device;
2485         }
getDevice()2486         @NonNull AudioDeviceAttributes getDevice() {
2487             return mDevice;
2488         }
2489 
setPlaybackActive(boolean active)2490         public void setPlaybackActive(boolean active) {
2491             mPlaybackActive = active;
2492         }
2493 
setRecordingActive(boolean active)2494         public void setRecordingActive(boolean active) {
2495             mRecordingActive = active;
2496         }
2497 
isActive()2498         public boolean isActive() {
2499             return !mDisabled && (mIsPrivileged || mRecordingActive || mPlaybackActive);
2500         }
2501 
setDisabled(boolean disabled)2502         public void setDisabled(boolean disabled) {
2503             mDisabled = disabled;
2504         }
isDisabled()2505         public boolean isDisabled() {
2506             return mDisabled;
2507         }
2508 
2509         @Override
toString()2510         public String toString() {
2511             return "[CommunicationRouteClient: mAttributionSource: " + mAttributionSource
2512                     + " mDevice: " + mDevice.toString()
2513                     + " mIsPrivileged: " + mIsPrivileged
2514                     + " mPlaybackActive: " + mPlaybackActive
2515                     + " mRecordingActive: " + mRecordingActive
2516                     + " mDisabled: " + mDisabled + "]";
2517         }
2518     }
2519 
2520     // @GuardedBy("mSetModeLock")
2521     @GuardedBy("mDeviceStateLock")
onCommunicationRouteClientDied(CommunicationRouteClient client)2522     private void onCommunicationRouteClientDied(CommunicationRouteClient client) {
2523         if (client == null) {
2524             return;
2525         }
2526         Log.w(TAG, "Communication client died");
2527         setCommunicationRouteForClient(client.getBinder(), client.getAttributionSource(),
2528                 null, BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(),
2529                 "onCommunicationRouteClientDied");
2530     }
2531 
2532     /**
2533      * Determines which preferred device for phone strategy should be sent to audio policy manager
2534      * as a function of current SCO audio activation state and active communication route requests.
2535      * SCO audio state has the highest priority as it can result from external activation by
2536      * telephony service.
2537      * @return selected forced usage for communication.
2538      */
2539     @GuardedBy("mDeviceStateLock")
preferredCommunicationDevice()2540     @Nullable private AudioDeviceAttributes preferredCommunicationDevice() {
2541         boolean btSCoOn = mBtHelper.isBluetoothScoOn();
2542         synchronized (mBluetoothAudioStateLock) {
2543             btSCoOn = (btSCoOn || mScoManagedByAudio) && mBluetoothScoOn;
2544         }
2545 
2546         if (btSCoOn) {
2547             // Use the SCO device known to BtHelper so that it matches exactly
2548             // what has been communicated to audio policy manager. The device
2549             // returned by requestedCommunicationDevice() can be a placeholder SCO device if legacy
2550             // APIs are used to start SCO audio.
2551             AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice();
2552             if (device != null) {
2553                 return device;
2554             }
2555         }
2556         AudioDeviceAttributes device = requestedCommunicationDevice();
2557         if (device == null || device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
2558             // Do not indicate BT SCO selection if SCO is requested but SCO is not ON
2559             return null;
2560         }
2561         return device;
2562     }
2563 
2564     /**
2565      * Configures audio policy manager and audio HAL according to active communication route.
2566      * Always called from message Handler.
2567      */
2568     // @GuardedBy("mSetModeLock")
2569     @GuardedBy("mDeviceStateLock")
updateCommunicationRoute(String eventSource)2570     private void updateCommunicationRoute(String eventSource) {
2571         AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice();
2572         if (AudioService.DEBUG_COMM_RTE) {
2573             Log.v(TAG, "updateCommunicationRoute, preferredCommunicationDevice: "
2574                     + preferredCommunicationDevice + " eventSource: " + eventSource);
2575         }
2576         AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
2577                 "updateCommunicationRoute, preferredCommunicationDevice: "
2578                 + preferredCommunicationDevice + " eventSource: " + eventSource)));
2579 
2580         if (preferredCommunicationDevice == null) {
2581             AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
2582             if (defaultDevice != null) {
2583                 mDeviceInventory.setPreferredDevicesForStrategyInt(
2584                         mCommunicationStrategyId, Arrays.asList(defaultDevice));
2585                 mDeviceInventory.setPreferredDevicesForStrategyInt(
2586                         mAccessibilityStrategyId, Arrays.asList(defaultDevice));
2587             } else {
2588                 mDeviceInventory.removePreferredDevicesForStrategyInt(mCommunicationStrategyId);
2589                 mDeviceInventory.removePreferredDevicesForStrategyInt(mAccessibilityStrategyId);
2590             }
2591             mDeviceInventory.applyConnectedDevicesRoles();
2592             mDeviceInventory.reapplyExternalDevicesRoles();
2593         } else {
2594             mDeviceInventory.setPreferredDevicesForStrategyInt(
2595                     mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
2596             mDeviceInventory.setPreferredDevicesForStrategyInt(
2597                     mAccessibilityStrategyId, Arrays.asList(preferredCommunicationDevice));
2598         }
2599         onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
2600     }
2601 
2602     // Pairs of input and output devices for duplex communication devices (headsets)
2603     private final HashMap<Integer, Integer> mDuplexCommunicationDevices = new HashMap<>(
2604             Map.of(DEVICE_OUT_BLE_HEADSET, DEVICE_IN_BLE_HEADSET,
2605                 DEVICE_OUT_WIRED_HEADSET, DEVICE_IN_WIRED_HEADSET,
2606                 DEVICE_OUT_USB_HEADSET, DEVICE_IN_USB_HEADSET,
2607                 DEVICE_OUT_BLUETOOTH_SCO, DEVICE_IN_BLUETOOTH_SCO_HEADSET,
2608                 DEVICE_OUT_BLUETOOTH_SCO_HEADSET, DEVICE_IN_BLUETOOTH_SCO_HEADSET,
2609                 DEVICE_OUT_BLUETOOTH_SCO_CARKIT, DEVICE_IN_BLUETOOTH_SCO_HEADSET
2610             ));
2611     /**
2612      * Scan communication route clients and disable them if their selected device is not connected
2613      * or re-enable them if a device of the same type as their connected device is connected
2614      */
2615     // @GuardedBy("mSetModeLock")
2616     @GuardedBy("mDeviceStateLock")
checkCommunicationRouteClientsDevices()2617     private void checkCommunicationRouteClientsDevices() {
2618         for (CommunicationRouteClient crc : mCommunicationRouteClients) {
2619             int deviceType = crc.getDevice().getInternalType();
2620             // Skip non detachable devices
2621             if (deviceType == DEVICE_OUT_EARPIECE || deviceType == DEVICE_OUT_SPEAKER
2622                     || deviceType == DEVICE_OUT_BUS) {
2623                 continue;
2624             }
2625 
2626             // outDeviceSet is the expected connected output device types for the requested device
2627             Set<Integer> outDeviceSet = null;
2628             // inDeviceSet is the expected input device for outDeviceSet. Null for non
2629             // duplex devices
2630             Set<Integer> inDeviceSet = null;
2631             // Special case for SCO because several device types are equivalent
2632             if (isBluetoothScoOutDevice(deviceType)) {
2633                 outDeviceSet = DEVICE_OUT_ALL_SCO_SET;
2634                 inDeviceSet = DEVICE_IN_ALL_SCO_SET;
2635             } else {
2636                 outDeviceSet = new HashSet<>();
2637                 outDeviceSet.add(deviceType);
2638                 if (mDuplexCommunicationDevices.containsKey(deviceType)) {
2639                     inDeviceSet = new HashSet<>();
2640                     inDeviceSet.add(mDuplexCommunicationDevices.get(deviceType));
2641                 }
2642             }
2643 
2644             AudioDeviceAttributes outAda =
2645                     mDeviceInventory.getFirstConnectedDeviceAttributesOfTypes(outDeviceSet);
2646             AudioDeviceAttributes inAda = (inDeviceSet == null) ? null
2647                     : mDeviceInventory.getFirstConnectedDeviceAttributesOfTypes(inDeviceSet);
2648 
2649             // A device is fully connected if the output device is connect and if not duplex
2650             // or an input device with the same address is connected
2651             boolean fullyConnected = outAda != null && (inDeviceSet == null
2652                     || (inAda != null && inAda.getAddress().equals(outAda.getAddress())));
2653 
2654             if (fullyConnected) {
2655                 crc.setDevice(outAda);
2656                 if (crc.isDisabled()) {
2657                     crc.setDisabled(false);
2658                     if (AudioService.DEBUG_COMM_RTE) {
2659                         Log.v(TAG,
2660                                 "checkCommunicationRouteClientsDevices, enabling client: " + crc);
2661                     }
2662                 }
2663             } else if (!crc.isDisabled()) {
2664                 crc.setDisabled(true);
2665                 if (AudioService.DEBUG_COMM_RTE) {
2666                     Log.v(TAG, "checkCommunicationRouteClientsDevices, disabling client: " + crc);
2667                 }
2668             }
2669         }
2670     }
2671 
2672     /**
2673      * Select new communication device from communication route client at the top of the stack
2674      * and restore communication route including restarting SCO audio if needed.
2675      */
2676     // @GuardedBy("mSetModeLock")
2677     @GuardedBy("mDeviceStateLock")
onUpdateCommunicationRouteClient( @ullable AttributionSource previousBtScoRequesterAS, String eventSource)2678     private void onUpdateCommunicationRouteClient(
2679             @Nullable AttributionSource previousBtScoRequesterAS, String eventSource) {
2680 
2681         CommunicationRouteClient crc = topCommunicationRouteClient();
2682         if (AudioService.DEBUG_COMM_RTE) {
2683             Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
2684                     + " previous BT SCO Requester UID: "
2685                     + safeUidFromAttributionSource(previousBtScoRequesterAS)
2686                     + " eventSource: " + eventSource);
2687         }
2688         if (crc != null) {
2689             setCommunicationRouteForClient(crc.getBinder(), crc.getAttributionSource(),
2690                     crc.getDevice(), BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
2691         } else {
2692             boolean wasScoRequested = previousBtScoRequesterAS != null;
2693             if (!isBluetoothScoRequested() && wasScoRequested) {
2694                 if (mScoManagedByAudio) {
2695                     if (shouldStartScoForAttributionSource(previousBtScoRequesterAS)) {
2696                         mBtHelper.stopBluetoothSco(eventSource);
2697                     }
2698                     setBluetoothScoOn(false, eventSource);
2699                 } else {
2700                     mBtHelper.stopBluetoothSco(eventSource);
2701                 }
2702             }
2703             updateCommunicationRoute(eventSource);
2704         }
2705     }
2706 
2707     // @GuardedBy("mSetModeLock")
2708     @GuardedBy("mDeviceStateLock")
onUpdatePhoneStrategyDevice(AudioDeviceAttributes device)2709     private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
2710         boolean wasSpeakerphoneActive = isSpeakerphoneActive();
2711         mPreferredCommunicationDevice = device;
2712         updateActiveCommunicationDevice();
2713         if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
2714             try {
2715                 mContext.sendBroadcastAsUser(
2716                         new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
2717                                 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2718                                           UserHandle.ALL);
2719             } catch (Exception e) {
2720                 Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
2721             }
2722         }
2723         dispatchCommunicationDevice();
2724         mAudioService.postUpdateRingerModeServiceInt();
2725     }
2726 
2727     @GuardedBy("mDeviceStateLock")
removeCommunicationRouteClient( IBinder cb, boolean unregister)2728     private CommunicationRouteClient removeCommunicationRouteClient(
2729                     IBinder cb, boolean unregister) {
2730         for (CommunicationRouteClient cl : mCommunicationRouteClients) {
2731             if (cl.getBinder() == cb) {
2732                 if (unregister) {
2733                     cl.unregisterDeathRecipient();
2734                 }
2735                 removeMsgForCheckClientState(cl.getUid());
2736                 mCommunicationRouteClients.remove(cl);
2737                 return cl;
2738             }
2739         }
2740         return null;
2741     }
2742 
2743     @GuardedBy("mDeviceStateLock")
addCommunicationRouteClient( IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device, boolean isPrivileged)2744     private CommunicationRouteClient addCommunicationRouteClient(
2745             IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device,
2746             boolean isPrivileged) {
2747         // always insert new request at first position
2748         removeCommunicationRouteClient(cb, true);
2749         CommunicationRouteClient client =
2750                 new CommunicationRouteClient(cb, attributionSource, device, isPrivileged);
2751         if (client.registerDeathRecipient()) {
2752             mCommunicationRouteClients.add(0, client);
2753             if (!client.isActive()) {
2754                 // initialize the inactive client's state as active and check it after 6 seconds
2755                 setForceCommunicationClientStateAndDelayedCheck(
2756                         client,
2757                         !mAudioService.isPlaybackActiveForUid(client.getUid()),
2758                         !mAudioService.isRecordingActiveForUid(client.getUid()));
2759             }
2760             return client;
2761         }
2762         return null;
2763     }
2764 
2765     @GuardedBy("mDeviceStateLock")
getCommunicationRouteClientForUid(int uid)2766     private CommunicationRouteClient getCommunicationRouteClientForUid(int uid) {
2767         for (CommunicationRouteClient cl : mCommunicationRouteClients) {
2768             if (cl.getUid() == uid) {
2769                 return cl;
2770             }
2771         }
2772         return null;
2773     }
2774 
2775     @GuardedBy("mDeviceStateLock")
2776     // LE Audio: For system server (Telecom) and APKs targeting S and above, we let the audio
2777     // policy routing rules select the default communication device.
2778     // For older APKs, we force LE Audio headset when connected as those APKs cannot select a LE
2779     // Audiodevice explicitly.
communnicationDeviceLeAudioCompatOn()2780     private boolean communnicationDeviceLeAudioCompatOn() {
2781         return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
2782                 && !(CompatChanges.isChangeEnabled(
2783                         USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
2784                      || mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
2785     }
2786 
2787     @GuardedBy("mDeviceStateLock")
2788     // Hearing Aid: For system server (Telecom) and IN_CALL mode we let the audio
2789     // policy routing rules select the default communication device.
2790     // For 3p apps and IN_COMMUNICATION mode we force Hearing aid when connected to maintain
2791     // backwards compatibility
communnicationDeviceHaCompatOn()2792     private boolean communnicationDeviceHaCompatOn() {
2793         return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
2794                 && !(mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
2795     }
2796 
2797     @GuardedBy("mDeviceStateLock")
getDefaultCommunicationDevice()2798     AudioDeviceAttributes getDefaultCommunicationDevice() {
2799         AudioDeviceAttributes device = null;
2800         // If both LE and Hearing Aid are active (thie should not happen),
2801         // priority to Hearing Aid.
2802         if (communnicationDeviceHaCompatOn()) {
2803             device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
2804         }
2805         if (device == null && communnicationDeviceLeAudioCompatOn()) {
2806             device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
2807         }
2808         return device;
2809     }
2810 
updateCommunicationRouteClientsActivity( List<AudioPlaybackConfiguration> playbackConfigs, List<AudioRecordingConfiguration> recordConfigs)2811     void updateCommunicationRouteClientsActivity(
2812             List<AudioPlaybackConfiguration> playbackConfigs,
2813             List<AudioRecordingConfiguration> recordConfigs) {
2814         synchronized (mSetModeLock) {
2815             synchronized (mDeviceStateLock) {
2816                 for (CommunicationRouteClient crc : mCommunicationRouteClients) {
2817                     boolean wasActive = crc.isActive();
2818                     boolean updateClientState = false;
2819                     if (playbackConfigs != null) {
2820                         crc.setPlaybackActive(false);
2821                         for (AudioPlaybackConfiguration config : playbackConfigs) {
2822                             if (config.getClientUid() == crc.getUid()
2823                                     && config.isActive()) {
2824                                 crc.setPlaybackActive(true);
2825                                 updateClientState = true;
2826                                 break;
2827                             }
2828                         }
2829                     }
2830                     if (recordConfigs != null) {
2831                         crc.setRecordingActive(false);
2832                         for (AudioRecordingConfiguration config : recordConfigs) {
2833                             if (config.getClientUid() == crc.getUid()
2834                                     && !config.isClientSilenced()) {
2835                                 crc.setRecordingActive(true);
2836                                 updateClientState = true;
2837                                 break;
2838                             }
2839                         }
2840                     }
2841                     if (updateClientState) {
2842                         removeMsgForCheckClientState(crc.getUid());
2843                         updateCommunicationRouteClientState(crc, wasActive);
2844                     } else {
2845                         if (wasActive) {
2846                             setForceCommunicationClientStateAndDelayedCheck(
2847                                     crc,
2848                                     playbackConfigs != null /* forcePlaybackActive */,
2849                                     recordConfigs != null /* forceRecordingActive */);
2850                         }
2851                     }
2852                 }
2853             }
2854         }
2855     }
2856 
getDeviceIdentityAddresses(AudioDeviceAttributes device)2857     List<String> getDeviceIdentityAddresses(AudioDeviceAttributes device) {
2858         synchronized (mDeviceStateLock) {
2859             return mDeviceInventory.getDeviceIdentityAddresses(device);
2860         }
2861     }
2862 
dispatchPreferredMixerAttributesChangedCausedByDeviceRemoved(AudioDeviceInfo info)2863     void dispatchPreferredMixerAttributesChangedCausedByDeviceRemoved(AudioDeviceInfo info) {
2864         // Currently, only media usage will be allowed to set preferred mixer attributes
2865         mAudioService.dispatchPreferredMixerAttributesChanged(
2866                 new AudioAttributes.Builder()
2867                         .setUsage(AudioAttributes.USAGE_MEDIA).build(),
2868                 info.getId(),
2869                 null /*mixerAttributes*/);
2870     }
2871 
2872     /**
2873      * post a message to persist the audio device settings.
2874      * Message is delayed by 1s on purpose in case of successive changes in quick succession (at
2875      * init time for instance)
2876      * Note this method is made public to work around a Mockito bug where it needs to be public
2877      * in order to be mocked by a test a the same package
2878      * (see https://code.google.com/archive/p/mockito/issues/127)
2879      */
postPersistAudioDeviceSettings()2880     public void postPersistAudioDeviceSettings() {
2881         sendMsg(MSG_PERSIST_AUDIO_DEVICE_SETTINGS, SENDMSG_REPLACE, /*delay*/ 1000);
2882     }
2883 
onPersistAudioDeviceSettings()2884     void onPersistAudioDeviceSettings() {
2885         final String deviceSettings = mDeviceInventory.getDeviceSettings();
2886         Log.v(TAG, "onPersistAudioDeviceSettings AdiDeviceState: " + deviceSettings);
2887         String currentSettings = readDeviceSettings();
2888         if (deviceSettings.equals(currentSettings)) {
2889             return;
2890         }
2891         final SettingsAdapter settingsAdapter = mAudioService.getSettings();
2892         if (settingsAdapter == null) {
2893             Log.e(TAG, "No settings adapter when saving AdiDeviceState: " + deviceSettings);
2894             return;
2895         }
2896         try {
2897             boolean res = settingsAdapter.putSecureStringForUser(mAudioService.getContentResolver(),
2898                     Settings.Secure.AUDIO_DEVICE_INVENTORY,
2899                     deviceSettings, UserHandle.USER_CURRENT);
2900             if (!res) {
2901                 Log.e(TAG, "error saving AdiDeviceState: " + deviceSettings);
2902             }
2903         } catch (IllegalArgumentException e) {
2904             Log.e(TAG, "error saving AdiDeviceState: " + deviceSettings, e);
2905         }
2906     }
2907 
readDeviceSettings()2908     private String readDeviceSettings() {
2909         final SettingsAdapter settingsAdapter = mAudioService.getSettings();
2910         final ContentResolver contentResolver = mAudioService.getContentResolver();
2911         if (settingsAdapter == null || contentResolver == null) {
2912             // should not happen, throw Exception for stack trace
2913             Log.e(TAG, "No settings adapter or content resolver to read device settings",
2914                     new Exception("readDeviceSettings_NPE"));
2915             return "";
2916         }
2917         return settingsAdapter.getSecureStringForUser(contentResolver,
2918                 Settings.Secure.AUDIO_DEVICE_INVENTORY, UserHandle.USER_CURRENT);
2919     }
2920 
onReadAudioDeviceSettings()2921     void onReadAudioDeviceSettings() {
2922         final SettingsAdapter settingsAdapter = mAudioService.getSettings();
2923         final ContentResolver contentResolver = mAudioService.getContentResolver();
2924         String settings = readDeviceSettings();
2925         if (settings == null) {
2926             Log.i(TAG, "reading AdiDeviceState from legacy key"
2927                     + Settings.Secure.SPATIAL_AUDIO_ENABLED);
2928             // legacy string format for key SPATIAL_AUDIO_ENABLED has the same order of fields like
2929             // the strings for key AUDIO_DEVICE_INVENTORY. This will ensure to construct valid
2930             // device settings when calling {@link #setDeviceSettings()}
2931             settings = settingsAdapter.getSecureStringForUser(contentResolver,
2932                     Settings.Secure.SPATIAL_AUDIO_ENABLED, UserHandle.USER_CURRENT);
2933             if (settings == null) {
2934                 Log.i(TAG, "no AdiDeviceState stored with legacy key");
2935             } else if (!settings.equals("")) {
2936                 // Delete old key value and update the new key
2937                 if (!settingsAdapter.putSecureStringForUser(contentResolver,
2938                         Settings.Secure.SPATIAL_AUDIO_ENABLED,
2939                         /*value=*/"",
2940                         UserHandle.USER_CURRENT)) {
2941                     Log.w(TAG, "cannot erase the legacy AdiDeviceState with key "
2942                             + Settings.Secure.SPATIAL_AUDIO_ENABLED);
2943                 }
2944                 if (!settingsAdapter.putSecureStringForUser(contentResolver,
2945                         Settings.Secure.AUDIO_DEVICE_INVENTORY,
2946                         settings,
2947                         UserHandle.USER_CURRENT)) {
2948                     Log.e(TAG, "error updating the new AdiDeviceState with key "
2949                             + Settings.Secure.AUDIO_DEVICE_INVENTORY);
2950                 }
2951             }
2952         }
2953 
2954         if (settings != null && !settings.equals("")) {
2955             setDeviceSettings(settings);
2956         }
2957     }
2958 
setDeviceSettings(String settings)2959     void setDeviceSettings(String settings) {
2960         mDeviceInventory.setDeviceSettings(settings);
2961     }
2962 
2963     /** Test only method. */
getDeviceSettings()2964     String getDeviceSettings() {
2965         return mDeviceInventory.getDeviceSettings();
2966     }
2967 
getImmutableDeviceInventory()2968     Collection<AdiDeviceState> getImmutableDeviceInventory() {
2969         return mDeviceInventory.getImmutableDeviceInventory();
2970     }
2971 
addOrUpdateDeviceSAStateInInventory(AdiDeviceState deviceState, boolean syncInventory)2972     void addOrUpdateDeviceSAStateInInventory(AdiDeviceState deviceState, boolean syncInventory) {
2973         mDeviceInventory.addOrUpdateDeviceSAStateInInventory(deviceState, syncInventory);
2974     }
2975 
addOrUpdateBtAudioDeviceCategoryInInventory( AdiDeviceState deviceState, boolean syncInventory)2976     void addOrUpdateBtAudioDeviceCategoryInInventory(
2977             AdiDeviceState deviceState, boolean syncInventory) {
2978         mDeviceInventory.addOrUpdateAudioDeviceCategoryInInventory(deviceState, syncInventory);
2979     }
2980 
2981     @Nullable
findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada, int canonicalType)2982     AdiDeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada,
2983             int canonicalType) {
2984         return mDeviceInventory.findDeviceStateForAudioDeviceAttributes(ada, canonicalType);
2985     }
2986 
2987     @Nullable
findBtDeviceStateForAddress(String address, int deviceType)2988     AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) {
2989         return mDeviceInventory.findBtDeviceStateForAddress(address, deviceType);
2990     }
2991 
addAudioDeviceWithCategoryInInventoryIfNeeded(@onNull String address, @AudioDeviceCategory int btAudioDeviceCategory)2992     void addAudioDeviceWithCategoryInInventoryIfNeeded(@NonNull String address,
2993             @AudioDeviceCategory int btAudioDeviceCategory) {
2994         mDeviceInventory.addAudioDeviceWithCategoryInInventoryIfNeeded(address,
2995                 btAudioDeviceCategory);
2996     }
2997 
2998     @AudioDeviceCategory
getAndUpdateBtAdiDeviceStateCategoryForAddress(@onNull String address)2999     int getAndUpdateBtAdiDeviceStateCategoryForAddress(@NonNull String address) {
3000         return mDeviceInventory.getAndUpdateBtAdiDeviceStateCategoryForAddress(address);
3001     }
3002 
isBluetoothAudioDeviceCategoryFixed(@onNull String address)3003     boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) {
3004         return mDeviceInventory.isBluetoothAudioDeviceCategoryFixed(address);
3005     }
3006 
isSADevice(AdiDeviceState deviceState)3007     /*package*/ boolean isSADevice(AdiDeviceState deviceState) {
3008         return mAudioService.isSADevice(deviceState);
3009     }
3010 
3011     //------------------------------------------------
3012     // for testing purposes only
clearDeviceInventory()3013     void clearDeviceInventory() {
3014         mDeviceInventory.clearDeviceInventory();
3015     }
3016 
3017 }
3018