Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 665342c5 authored by Eric Laurent's avatar Eric Laurent
Browse files

AudioService: anonymize Bluetooth MAC addresses

Make sure APIs returning AudioDeviceAttributes from AudioService
anonymize the Bluetooth MAC addresses because those are considered
privacy sensitive.
Only expose the full MAC address to system and apps with BLUETOOTH_CONNECT
permission.

setters, getters and listeners for preferred device for strategy,
preferred device for capture preset and mute await connection are
modified:
- when entering AudioService, full MAC addresses are retrieved based on the
  known Bluetooth devices stored in AudioDeviceInventory.mDeviceInventory
- when exiting AudioService, MAC addresses are anonymized if the client
  app does not have BLUETOOTH_CONNECT permission or is not a system component

APIs based on AudioDeviceInfo do not need to be modified as the
AudioDeviceInfo MAC address is for the AudioPort cached in the app
process and AudioPorts are anonymized by the native audioserver before
being returned to client apps.

Bug: 285588444

Test: atest AudioManagerTest
Test: atest RoutingTest
Test: atest AudioCommunicationDeviceTest
Change-Id: I67bbba2ba941c97138a068d640079b17650e3d86
Merged-In: I67bbba2ba941c97138a068d640079b17650e3d86
parent ada3f604
Loading
Loading
Loading
Loading
+25 −1
Original line number Original line Diff line number Diff line
@@ -68,7 +68,7 @@ public final class AudioDeviceAttributes implements Parcelable {
    /**
    /**
     * The unique address of the device. Some devices don't have addresses, only an empty string.
     * The unique address of the device. Some devices don't have addresses, only an empty string.
     */
     */
    private final @NonNull String mAddress;
    private @NonNull String mAddress;
    /**
    /**
     * The non-unique name of the device. Some devices don't have names, only an empty string.
     * The non-unique name of the device. Some devices don't have names, only an empty string.
     * Should not be used as a unique identifier for a device.
     * Should not be used as a unique identifier for a device.
@@ -186,6 +186,21 @@ public final class AudioDeviceAttributes implements Parcelable {
        mAudioDescriptors = new ArrayList<>();
        mAudioDescriptors = new ArrayList<>();
    }
    }


    /**
     * @hide
     * Copy Constructor.
     * @param ada the copied AudioDeviceAttributes
     */
    public AudioDeviceAttributes(AudioDeviceAttributes ada) {
        mRole = ada.getRole();
        mType = ada.getType();
        mAddress = ada.getAddress();
        mName = ada.getName();
        mNativeType = ada.getInternalType();
        mAudioProfiles = ada.getAudioProfiles();
        mAudioDescriptors = ada.getAudioDescriptors();
    }

    /**
    /**
     * @hide
     * @hide
     * Returns the role of a device
     * Returns the role of a device
@@ -216,6 +231,15 @@ public final class AudioDeviceAttributes implements Parcelable {
        return mAddress;
        return mAddress;
    }
    }


    /**
     * @hide
     * Sets the device address. Only used by audio service.
     */
    public void setAddress(@NonNull String address) {
        Objects.requireNonNull(address);
        mAddress = address;
    }

    /**
    /**
     * @hide
     * @hide
     * Returns the name of the audio device, or an empty string for devices without one
     * Returns the name of the audio device, or an empty string for devices without one
+10 −1
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioDeviceInfo;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;
import android.util.Pair;


import java.util.Objects;
import java.util.Objects;


@@ -43,6 +44,8 @@ import java.util.Objects;
    private final int mInternalDeviceType;
    private final int mInternalDeviceType;
    @NonNull
    @NonNull
    private final String mDeviceAddress;
    private final String mDeviceAddress;
    /** Unique device id from internal device type and address. */
    private final Pair<Integer, String> mDeviceId;
    private boolean mSAEnabled;
    private boolean mSAEnabled;
    private boolean mHasHeadTracker = false;
    private boolean mHasHeadTracker = false;
    private boolean mHeadTrackerEnabled;
    private boolean mHeadTrackerEnabled;
@@ -68,6 +71,11 @@ import java.util.Objects;
        }
        }
        mDeviceAddress = isBluetoothDevice(mInternalDeviceType) ? Objects.requireNonNull(
        mDeviceAddress = isBluetoothDevice(mInternalDeviceType) ? Objects.requireNonNull(
                address) : "";
                address) : "";
        mDeviceId = new Pair<>(mInternalDeviceType, mDeviceAddress);
    }

    public Pair<Integer, String> getDeviceId() {
        return mDeviceId;
    }
    }


    @AudioDeviceInfo.AudioDeviceType
    @AudioDeviceInfo.AudioDeviceType
@@ -138,7 +146,8 @@ import java.util.Objects;


    @Override
    @Override
    public String toString() {
    public String toString() {
        return "type: " + mDeviceType + "internal type: " + mInternalDeviceType
        return "type: " + mDeviceType
                + " internal type: 0x" + Integer.toHexString(mInternalDeviceType)
                + " addr: " + mDeviceAddress + " enabled: " + mSAEnabled
                + " addr: " + mDeviceAddress + " enabled: " + mSAEnabled
                + " HT: " + mHasHeadTracker + " HTenabled: " + mHeadTrackerEnabled;
                + " HT: " + mHasHeadTracker + " HTenabled: " + mHeadTrackerEnabled;
    }
    }
+10 −4
Original line number Original line Diff line number Diff line
@@ -938,8 +938,8 @@ public class AudioDeviceBroker {
    }
    }


    /*package*/ void registerStrategyPreferredDevicesDispatcher(
    /*package*/ void registerStrategyPreferredDevicesDispatcher(
            @NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
            @NonNull IStrategyPreferredDevicesDispatcher dispatcher, boolean isPrivileged) {
        mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher);
        mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher, isPrivileged);
    }
    }


    /*package*/ void unregisterStrategyPreferredDevicesDispatcher(
    /*package*/ void unregisterStrategyPreferredDevicesDispatcher(
@@ -957,8 +957,8 @@ public class AudioDeviceBroker {
    }
    }


    /*package*/ void registerCapturePresetDevicesRoleDispatcher(
    /*package*/ void registerCapturePresetDevicesRoleDispatcher(
            @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
            @NonNull ICapturePresetDevicesRoleDispatcher dispatcher, boolean isPrivileged) {
        mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher);
        mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher, isPrivileged);
    }
    }


    /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
    /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
@@ -966,6 +966,11 @@ public class AudioDeviceBroker {
        mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
        mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
    }
    }


    /* package */ List<AudioDeviceAttributes> anonymizeAudioDeviceAttributesListUnchecked(
            List<AudioDeviceAttributes> devices) {
        return mAudioService.anonymizeAudioDeviceAttributesListUnchecked(devices);
    }

    /*package*/ void registerCommunicationDeviceDispatcher(
    /*package*/ void registerCommunicationDeviceDispatcher(
            @NonNull ICommunicationDeviceDispatcher dispatcher) {
            @NonNull ICommunicationDeviceDispatcher dispatcher) {
        mCommDevDispatchers.register(dispatcher);
        mCommDevDispatchers.register(dispatcher);
@@ -2181,4 +2186,5 @@ public class AudioDeviceBroker {
    void clearDeviceInventory() {
    void clearDeviceInventory() {
        mDeviceInventory.clearDeviceInventory();
        mDeviceInventory.clearDeviceInventory();
    }
    }

}
}
+78 −34
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
@@ -48,7 +49,9 @@ import com.android.internal.annotations.VisibleForTesting;


import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
@@ -75,31 +78,59 @@ public class AudioDeviceInventory {


    private final Object mDeviceInventoryLock = new Object();
    private final Object mDeviceInventoryLock = new Object();
    @GuardedBy("mDeviceInventoryLock")
    @GuardedBy("mDeviceInventoryLock")
    private final ArrayList<AdiDeviceState> mDeviceInventory = new ArrayList<>(0);
    private final HashMap<Pair<Integer, String>, AdiDeviceState> mDeviceInventory = new HashMap<>();



    List<AdiDeviceState> getImmutableDeviceInventory() {
    List<AdiDeviceState> getImmutableDeviceInventory() {
        synchronized (mDeviceInventoryLock) {
        synchronized (mDeviceInventoryLock) {
            return List.copyOf(mDeviceInventory);
            return new ArrayList<AdiDeviceState>(mDeviceInventory.values());
        }
        }
    }
    }


    void addDeviceStateToInventory(AdiDeviceState deviceState) {
    void addDeviceStateToInventory(AdiDeviceState deviceState) {
        synchronized (mDeviceInventoryLock) {
        synchronized (mDeviceInventoryLock) {
            mDeviceInventory.add(deviceState);
            mDeviceInventory.put(deviceState.getDeviceId(), deviceState);
        }
        }
    }
    }


    /**
     * Adds a new entry in mDeviceInventory if the AudioDeviceAttributes passed is an sink
     * Bluetooth device and no corresponding entry already exists.
     * @param ada the device to add if needed
     */
    void addAudioDeviceInInventoryIfNeeded(AudioDeviceAttributes ada) {
        if (!AudioSystem.isBluetoothOutDevice(ada.getInternalType())) {
            return;
        }
        synchronized (mDeviceInventoryLock) {
            if (findDeviceStateForAudioDeviceAttributes(ada, ada.getType()) != null) {
                return;
            }
            AdiDeviceState ads = new AdiDeviceState(
                    ada.getType(), ada.getInternalType(), ada.getAddress());
            mDeviceInventory.put(ads.getDeviceId(), ads);
        }
        mDeviceBroker.persistAudioDeviceSettings();
    }

    /**
     * Finds the device state that matches the passed {@link AudioDeviceAttributes} and device
     * type. Note: currently this method only returns a valid device for A2DP and BLE devices.
     *
     * @param ada attributes of device to match
     * @param canonicalDeviceType external device type to match
     * @return the found {@link AdiDeviceState} matching a cached A2DP or BLE device or
     *         {@code null} otherwise.
     */
    @Nullable
    AdiDeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada,
    AdiDeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada,
            int canonicalDeviceType) {
            int canonicalDeviceType) {
        final boolean isWireless = isBluetoothDevice(ada.getInternalType());
        final boolean isWireless = isBluetoothDevice(ada.getInternalType());

        synchronized (mDeviceInventoryLock) {
        synchronized (mDeviceInventoryLock) {
            for (AdiDeviceState deviceSetting : mDeviceInventory) {
            for (AdiDeviceState deviceState : mDeviceInventory.values()) {
                if (deviceSetting.getDeviceType() == canonicalDeviceType
                if (deviceState.getDeviceType() == canonicalDeviceType
                        && (!isWireless || ada.getAddress().equals(
                        && (!isWireless || ada.getAddress().equals(
                        deviceSetting.getDeviceAddress()))) {
                        deviceState.getDeviceAddress()))) {
                    return deviceSetting;
                    return deviceState;
                }
                }
            }
            }
        }
        }
@@ -309,7 +340,7 @@ public class AudioDeviceInventory {
                    + " devices:" + devices); });
                    + " devices:" + devices); });
        pw.println("\ndevices:\n");
        pw.println("\ndevices:\n");
        synchronized (mDeviceInventoryLock) {
        synchronized (mDeviceInventoryLock) {
            for (AdiDeviceState device : mDeviceInventory) {
            for (AdiDeviceState device : mDeviceInventory.values()) {
                pw.println("\t" + device + "\n");
                pw.println("\t" + device + "\n");
            }
            }
        }
        }
@@ -705,8 +736,8 @@ public class AudioDeviceInventory {
    }
    }


    /*package*/ void registerStrategyPreferredDevicesDispatcher(
    /*package*/ void registerStrategyPreferredDevicesDispatcher(
            @NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
            @NonNull IStrategyPreferredDevicesDispatcher dispatcher, boolean isPrivileged) {
        mPrefDevDispatchers.register(dispatcher);
        mPrefDevDispatchers.register(dispatcher, isPrivileged);
    }
    }


    /*package*/ void unregisterStrategyPreferredDevicesDispatcher(
    /*package*/ void unregisterStrategyPreferredDevicesDispatcher(
@@ -740,8 +771,8 @@ public class AudioDeviceInventory {
    }
    }


    /*package*/ void registerCapturePresetDevicesRoleDispatcher(
    /*package*/ void registerCapturePresetDevicesRoleDispatcher(
            @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
            @NonNull ICapturePresetDevicesRoleDispatcher dispatcher, boolean isPrivileged) {
        mDevRoleCapturePresetDispatchers.register(dispatcher);
        mDevRoleCapturePresetDispatchers.register(dispatcher, isPrivileged);
    }
    }


    /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
    /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
@@ -819,6 +850,10 @@ public class AudioDeviceInventory {
                mConnectedDevices.put(deviceKey, new DeviceInfo(
                mConnectedDevices.put(deviceKey, new DeviceInfo(
                        device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
                        device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
                mDeviceBroker.postAccessoryPlugMediaUnmute(device);
                mDeviceBroker.postAccessoryPlugMediaUnmute(device);

                if (AudioSystem.isBluetoothScoDevice(device)) {
                    addAudioDeviceInInventoryIfNeeded(attributes);
                }
                mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
                mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
                return true;
                return true;
            } else if (!connect && isConnected) {
            } else if (!connect && isConnected) {
@@ -1049,8 +1084,9 @@ public class AudioDeviceInventory {
        mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
        mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
        // at this point there could be another A2DP device already connected in APM, but it
        // at this point there could be another A2DP device already connected in APM, but it
        // doesn't matter as this new one will overwrite the previous one
        // doesn't matter as this new one will overwrite the previous one
        final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
        AudioDeviceAttributes ada = new AudioDeviceAttributes(
                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name);
        final int res = mAudioSystem.setDeviceConnectionState(ada,
                AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
                AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);


        // TODO: log in MediaMetrics once distinction between connection failure and
        // TODO: log in MediaMetrics once distinction between connection failure and
@@ -1072,8 +1108,7 @@ public class AudioDeviceInventory {
        // The convention for head tracking sensors associated with A2DP devices is to
        // The convention for head tracking sensors associated with A2DP devices is to
        // use a UUID derived from the MAC address as follows:
        // use a UUID derived from the MAC address as follows:
        //   time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
        //   time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
        UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(
        UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
        final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
        final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
                address, a2dpCodec, sensorUuid);
                address, a2dpCodec, sensorUuid);
        final String diKey = di.getKey();
        final String diKey = di.getKey();
@@ -1084,6 +1119,7 @@ public class AudioDeviceInventory {


        mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
        mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
        setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
        setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
        addAudioDeviceInInventoryIfNeeded(ada);
    }
    }


    @GuardedBy("mDevicesLock")
    @GuardedBy("mDevicesLock")
@@ -1179,9 +1215,9 @@ public class AudioDeviceInventory {
        final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
        final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
                AudioSystem.DEVICE_OUT_HEARING_AID);
                AudioSystem.DEVICE_OUT_HEARING_AID);
        mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
        mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);

        AudioDeviceAttributes ada = new AudioDeviceAttributes(
        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
                AudioSystem.DEVICE_OUT_HEARING_AID, address, name);
                AudioSystem.DEVICE_OUT_HEARING_AID, address, name),
        mAudioSystem.setDeviceConnectionState(ada,
                AudioSystem.DEVICE_STATE_AVAILABLE,
                AudioSystem.DEVICE_STATE_AVAILABLE,
                AudioSystem.AUDIO_FORMAT_DEFAULT);
                AudioSystem.AUDIO_FORMAT_DEFAULT);
        mConnectedDevices.put(
        mConnectedDevices.put(
@@ -1192,6 +1228,7 @@ public class AudioDeviceInventory {
        mDeviceBroker.postApplyVolumeOnDevice(streamType,
        mDeviceBroker.postApplyVolumeOnDevice(streamType,
                AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
                AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
        setCurrentAudioRouteNameIfPossible(name, false /*fromA2dp*/);
        setCurrentAudioRouteNameIfPossible(name, false /*fromA2dp*/);
        addAudioDeviceInInventoryIfNeeded(ada);
        new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceAvailable")
        new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceAvailable")
                .set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
                .set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
                .set(MediaMetrics.Property.DEVICE,
                .set(MediaMetrics.Property.DEVICE,
@@ -1243,9 +1280,8 @@ public class AudioDeviceInventory {
             * AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
             * AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
             */
             */
            mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
            mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);

            AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
            final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
            final int res = AudioSystem.setDeviceConnectionState(ada,
                    device, address, name),
                    AudioSystem.DEVICE_STATE_AVAILABLE,
                    AudioSystem.DEVICE_STATE_AVAILABLE,
                    AudioSystem.AUDIO_FORMAT_DEFAULT);
                    AudioSystem.AUDIO_FORMAT_DEFAULT);
            if (res != AudioSystem.AUDIO_STATUS_OK) {
            if (res != AudioSystem.AUDIO_STATUS_OK) {
@@ -1263,6 +1299,7 @@ public class AudioDeviceInventory {
                    new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
                    new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
            mDeviceBroker.postAccessoryPlugMediaUnmute(device);
            mDeviceBroker.postAccessoryPlugMediaUnmute(device);
            setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
            setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
            addAudioDeviceInInventoryIfNeeded(ada);
        }
        }


        if (streamType == AudioSystem.STREAM_DEFAULT) {
        if (streamType == AudioSystem.STREAM_DEFAULT) {
@@ -1585,6 +1622,9 @@ public class AudioDeviceInventory {
        final int nbDispatchers = mPrefDevDispatchers.beginBroadcast();
        final int nbDispatchers = mPrefDevDispatchers.beginBroadcast();
        for (int i = 0; i < nbDispatchers; i++) {
        for (int i = 0; i < nbDispatchers; i++) {
            try {
            try {
                if (!((Boolean) mPrefDevDispatchers.getBroadcastCookie(i))) {
                    devices = mDeviceBroker.anonymizeAudioDeviceAttributesListUnchecked(devices);
                }
                mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDevicesChanged(
                mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDevicesChanged(
                        strategy, devices);
                        strategy, devices);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
@@ -1598,6 +1638,9 @@ public class AudioDeviceInventory {
        final int nbDispatchers = mDevRoleCapturePresetDispatchers.beginBroadcast();
        final int nbDispatchers = mDevRoleCapturePresetDispatchers.beginBroadcast();
        for (int i = 0; i < nbDispatchers; ++i) {
        for (int i = 0; i < nbDispatchers; ++i) {
            try {
            try {
                if (!((Boolean) mDevRoleCapturePresetDispatchers.getBroadcastCookie(i))) {
                    devices = mDeviceBroker.anonymizeAudioDeviceAttributesListUnchecked(devices);
                }
                mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged(
                mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged(
                        capturePreset, role, devices);
                        capturePreset, role, devices);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
@@ -1634,20 +1677,21 @@ public class AudioDeviceInventory {
        int deviceCatalogSize = 0;
        int deviceCatalogSize = 0;
        synchronized (mDeviceInventoryLock) {
        synchronized (mDeviceInventoryLock) {
            deviceCatalogSize = mDeviceInventory.size();
            deviceCatalogSize = mDeviceInventory.size();
        }

            final StringBuilder settingsBuilder = new StringBuilder(
            final StringBuilder settingsBuilder = new StringBuilder(
                    deviceCatalogSize * AdiDeviceState.getPeristedMaxSize());
                    deviceCatalogSize * AdiDeviceState.getPeristedMaxSize());


        synchronized (mDeviceInventoryLock) {
            Iterator<AdiDeviceState> iterator = mDeviceInventory.values().iterator();
            for (int i = 0; i < mDeviceInventory.size(); i++) {
            if (iterator.hasNext()) {
                settingsBuilder.append(mDeviceInventory.get(i).toPersistableString());
                settingsBuilder.append(iterator.next().toPersistableString());
                if (i != mDeviceInventory.size() - 1) {
                    settingsBuilder.append(SETTING_DEVICE_SEPARATOR_CHAR);
                }
            }
            }
            while (iterator.hasNext()) {
                settingsBuilder.append(SETTING_DEVICE_SEPARATOR_CHAR);
                settingsBuilder.append(iterator.next().toPersistableString());
            }
            }
            return settingsBuilder.toString();
            return settingsBuilder.toString();
        }
        }
    }


    /*package*/ void setDeviceSettings(String settings) {
    /*package*/ void setDeviceSettings(String settings) {
        clearDeviceInventory();
        clearDeviceInventory();
+176 −24

File changed.

Preview size limit exceeded, changes collapsed.