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

Commit a47312d9 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 4db8abcc
Loading
Loading
Loading
Loading
+25 −1
Original line number 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.
     */
    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.
     * Should not be used as a unique identifier for a device.
@@ -186,6 +186,21 @@ public final class AudioDeviceAttributes implements Parcelable {
        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
     * Returns the role of a device
@@ -216,6 +231,15 @@ public final class AudioDeviceAttributes implements Parcelable {
        return mAddress;
    }

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

    /**
     * @hide
     * Returns the name of the audio device, or an empty string for devices without one
+2 −1
Original line number Diff line number Diff line
@@ -165,7 +165,8 @@ import java.util.Objects;

    @Override
    public String toString() {
        return "type: " + mDeviceType + "internal type: " + mInternalDeviceType
        return "type: " + mDeviceType
                + " internal type: 0x" + Integer.toHexString(mInternalDeviceType)
                + " addr: " + mDeviceAddress + " bt audio type: "
                + AudioManager.audioDeviceCategoryToString(mAudioDeviceCategory)
                + " enabled: " + mSAEnabled + " HT: " + mHasHeadTracker
+11 −6
Original line number Diff line number Diff line
@@ -1250,8 +1250,8 @@ public class AudioDeviceBroker {
    }

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

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

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

    /*package*/ void unregisterStrategyNonDefaultDevicesDispatcher(
@@ -1279,8 +1279,8 @@ public class AudioDeviceBroker {
    }

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

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

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

    /*package*/ void registerCommunicationDeviceDispatcher(
            @NonNull ICommunicationDeviceDispatcher dispatcher) {
        mCommDevDispatchers.register(dispatcher);
+43 −9
Original line number Diff line number Diff line
@@ -120,6 +120,26 @@ public class AudioDeviceInventory {
        }
    }

    /**
     * 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();
    }

    /**
     * Adds a new AdiDeviceState or updates the audio device cateogory of the matching
     * AdiDeviceState in the {@link AudioDeviceInventory#mDeviceInventory} list.
@@ -992,8 +1012,8 @@ public class AudioDeviceInventory {


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

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

    /*package*/ void registerStrategyNonDefaultDevicesDispatcher(
            @NonNull IStrategyNonDefaultDevicesDispatcher dispatcher) {
        mNonDefDevDispatchers.register(dispatcher);
            @NonNull IStrategyNonDefaultDevicesDispatcher dispatcher, boolean isPrivileged) {
        mNonDefDevDispatchers.register(dispatcher, isPrivileged);
    }

    /*package*/ void unregisterStrategyNonDefaultDevicesDispatcher(
@@ -1084,8 +1104,8 @@ public class AudioDeviceInventory {
    }

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

    /*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
@@ -1414,6 +1434,8 @@ public class AudioDeviceInventory {
                    updateBluetoothPreferredModes_l(connect ? btDevice : null /*connectedDevice*/);
                    if (!connect) {
                        purgeDevicesRoles_l();
                    } else {
                        addAudioDeviceInInventoryIfNeeded(attributes);
                    }
                }
                mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -1702,6 +1724,7 @@ public class AudioDeviceInventory {
        setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);

        updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
        addAudioDeviceInInventoryIfNeeded(ada);
    }

    static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER,
@@ -2006,9 +2029,9 @@ public class AudioDeviceInventory {
        final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
                AudioSystem.DEVICE_OUT_HEARING_AID);
        mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);

        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
                AudioSystem.DEVICE_OUT_HEARING_AID, address, name),
        AudioDeviceAttributes ada = new AudioDeviceAttributes(
                AudioSystem.DEVICE_OUT_HEARING_AID, address, name);
        mAudioSystem.setDeviceConnectionState(ada,
                AudioSystem.DEVICE_STATE_AVAILABLE,
                AudioSystem.AUDIO_FORMAT_DEFAULT);
        mConnectedDevices.put(
@@ -2018,6 +2041,7 @@ public class AudioDeviceInventory {
        mDeviceBroker.postApplyVolumeOnDevice(streamType,
                AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
        setCurrentAudioRouteNameIfPossible(name, false /*fromA2dp*/);
        addAudioDeviceInInventoryIfNeeded(ada);
        new MediaMetrics.Item(mMetricsId + "makeHearingAidDeviceAvailable")
                .set(MediaMetrics.Property.ADDRESS, address != null ? address : "")
                .set(MediaMetrics.Property.DEVICE,
@@ -2128,6 +2152,7 @@ public class AudioDeviceInventory {
                            sensorUuid));
            mDeviceBroker.postAccessoryPlugMediaUnmute(device);
            setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
            addAudioDeviceInInventoryIfNeeded(ada);
        }

        if (streamType == AudioSystem.STREAM_DEFAULT) {
@@ -2462,6 +2487,9 @@ public class AudioDeviceInventory {
        final int nbDispatchers = mPrefDevDispatchers.beginBroadcast();
        for (int i = 0; i < nbDispatchers; i++) {
            try {
                if (!((Boolean) mPrefDevDispatchers.getBroadcastCookie(i))) {
                    devices = mDeviceBroker.anonymizeAudioDeviceAttributesListUnchecked(devices);
                }
                mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDevicesChanged(
                        strategy, devices);
            } catch (RemoteException e) {
@@ -2475,6 +2503,9 @@ public class AudioDeviceInventory {
        final int nbDispatchers = mNonDefDevDispatchers.beginBroadcast();
        for (int i = 0; i < nbDispatchers; i++) {
            try {
                if (!((Boolean) mNonDefDevDispatchers.getBroadcastCookie(i))) {
                    devices = mDeviceBroker.anonymizeAudioDeviceAttributesListUnchecked(devices);
                }
                mNonDefDevDispatchers.getBroadcastItem(i).dispatchNonDefDevicesChanged(
                        strategy, devices);
            } catch (RemoteException e) {
@@ -2488,6 +2519,9 @@ public class AudioDeviceInventory {
        final int nbDispatchers = mDevRoleCapturePresetDispatchers.beginBroadcast();
        for (int i = 0; i < nbDispatchers; ++i) {
            try {
                if (!((Boolean) mDevRoleCapturePresetDispatchers.getBroadcastCookie(i))) {
                    devices = mDeviceBroker.anonymizeAudioDeviceAttributesListUnchecked(devices);
                }
                mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged(
                        capturePreset, role, devices);
            } catch (RemoteException e) {
+183 −26

File changed.

Preview size limit exceeded, changes collapsed.