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

Commit cbdb8a3e authored by Zach Johnson's avatar Zach Johnson Committed by Automerger Merge Worker
Browse files

Special case & sanitize exposure notification results am: 584ce99e

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Bluetooth/+/12222704

Change-Id: I15a9a9ab5c05b48cf13649f067850497247198d7
parents 89289c46 584ce99e
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -114,4 +114,7 @@
    <!-- Flag whether or not to keep polling AG with CLCC for call information every 2 seconds -->
    <!-- Flag whether or not to keep polling AG with CLCC for call information every 2 seconds -->
    <bool name="hfp_clcc_poll_during_call">true</bool>
    <bool name="hfp_clcc_poll_during_call">true</bool>


    <!-- Package that is providing the exposure notification service -->
    <string name="exposure_notification_package">com.google.android.gms</string>

</resources>
</resources>
+2 −0
Original line number Original line Diff line number Diff line
@@ -107,6 +107,8 @@ import java.util.UUID;
        /** Whether the calling app has the network setup wizard permission */
        /** Whether the calling app has the network setup wizard permission */
        boolean mHasScanWithoutLocationPermission;
        boolean mHasScanWithoutLocationPermission;


        boolean mEligibleForSanitizedExposureNotification;

        public List<String> mAssociatedDevices;
        public List<String> mAssociatedDevices;


        /** Internal callback info queue, waiting to be send on congestion clear */
        /** Internal callback info queue, waiting to be send on congestion clear */
+68 −0
Original line number Original line Diff line number Diff line
@@ -56,6 +56,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.Log;
import android.util.Log;


import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.BluetoothMetricsProto;
@@ -185,6 +186,7 @@ public class GattService extends ProfileService {
    private ScanManager mScanManager;
    private ScanManager mScanManager;
    private AppOpsManager mAppOps;
    private AppOpsManager mAppOps;
    private ICompanionDeviceManager mCompanionManager;
    private ICompanionDeviceManager mCompanionManager;
    private String mExposureNotificationPackage;


    private static GattService sGattService;
    private static GattService sGattService;


@@ -207,6 +209,9 @@ public class GattService extends ProfileService {
        if (DBG) {
        if (DBG) {
            Log.d(TAG, "start()");
            Log.d(TAG, "start()");
        }
        }
        mExposureNotificationPackage = getString(R.string.exposure_notification_package);
        Settings.Global.putInt(
                getContentResolver(), "bluetooth_sanitized_exposure_notification_supported", 1);
        initializeNative();
        initializeNative();
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
        mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
@@ -960,6 +965,56 @@ public class GattService extends ProfileService {
     * Callback functions - CLIENT
     * Callback functions - CLIENT
     *************************************************************************/
     *************************************************************************/


    // EN format defined here:
    // https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf
    private static final byte[] EXPOSURE_NOTIFICATION_FLAGS_PREAMBLE = new byte[] {
        // size 2, flag field, flags byte (value is not important)
        (byte) 0x02, (byte) 0x01
    };
    private static final int EXPOSURE_NOTIFICATION_FLAGS_LENGTH = 0x2 + 1;
    private static final byte[] EXPOSURE_NOTIFICATION_PAYLOAD_PREAMBLE = new byte[] {
        // size 3, complete 16 bit UUID, EN UUID
        (byte) 0x03, (byte) 0x03, (byte) 0x6F, (byte) 0xFD,
        // size 23, data for 16 bit UUID, EN UUID
        (byte) 0x17, (byte) 0x16, (byte) 0x6F, (byte) 0xFD,
        // ...payload
    };
    private static final int EXPOSURE_NOTIFICATION_PAYLOAD_LENGTH = 0x03 + 0x17 + 2;

    private static boolean arrayStartsWith(byte[] array, byte[] prefix) {
        if (array.length < prefix.length) {
            return false;
        }
        for (int i = 0; i < prefix.length; i++) {
            if (prefix[i] != array[i]) {
                return false;
            }
        }
        return true;
    }

    ScanResult getSanitizedExposureNotification(ScanResult result) {
        ScanRecord record = result.getScanRecord();
        // Remove the flags part of the payload, if present
        if (record.getBytes().length > EXPOSURE_NOTIFICATION_FLAGS_LENGTH
                && arrayStartsWith(record.getBytes(), EXPOSURE_NOTIFICATION_FLAGS_PREAMBLE)) {
            record = ScanRecord.parseFromBytes(
                    Arrays.copyOfRange(
                            record.getBytes(),
                            EXPOSURE_NOTIFICATION_FLAGS_LENGTH,
                            record.getBytes().length));
        }

        if (record.getBytes().length != EXPOSURE_NOTIFICATION_PAYLOAD_LENGTH) {
            return null;
        }
        if (!arrayStartsWith(record.getBytes(), EXPOSURE_NOTIFICATION_PAYLOAD_PREAMBLE)) {
            return null;
        }

        return new ScanResult(null, 0, 0, 0, 0, 0, result.getRssi(), 0, record, 0);
    }

    void onScanResult(int eventType, int addressType, String address, int primaryPhy,
    void onScanResult(int eventType, int addressType, String address, int primaryPhy,
            int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt,
            int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt,
            byte[] advData) {
            byte[] advData) {
@@ -1027,6 +1082,13 @@ public class GattService extends ProfileService {
                    }
                    }
                }
                }
            }
            }
            if (!hasPermission && client.eligibleForSanitizedExposureNotification) {
                ScanResult sanitized = getSanitizedExposureNotification(result);
                if (sanitized != null) {
                    hasPermission = true;
                    result = sanitized;
                }
            }
            if (!hasPermission || !matchesFilters(client, result)) {
            if (!hasPermission || !matchesFilters(client, result)) {
                continue;
                continue;
            }
            }
@@ -1986,6 +2048,8 @@ public class GattService extends ProfileService {
        final ScanClient scanClient = new ScanClient(scannerId, settings, filters, storages);
        final ScanClient scanClient = new ScanClient(scannerId, settings, filters, storages);
        scanClient.userHandle = UserHandle.of(UserHandle.getCallingUserId());
        scanClient.userHandle = UserHandle.of(UserHandle.getCallingUserId());
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
        scanClient.eligibleForSanitizedExposureNotification =
                callingPackage.equals(mExposureNotificationPackage);
        scanClient.isQApp = Utils.isQApp(this, callingPackage);
        scanClient.isQApp = Utils.isQApp(this, callingPackage);
        if (scanClient.isQApp) {
        if (scanClient.isQApp) {
            scanClient.hasLocationPermission = Utils.checkCallerHasFineLocation(this, mAppOps,
            scanClient.hasLocationPermission = Utils.checkCallerHasFineLocation(this, mAppOps,
@@ -2046,6 +2110,8 @@ public class GattService extends ProfileService {
        ScannerMap.App app = mScannerMap.add(uuid, null, null, piInfo, this);
        ScannerMap.App app = mScannerMap.add(uuid, null, null, piInfo, this);
        app.mUserHandle = UserHandle.of(UserHandle.getCallingUserId());
        app.mUserHandle = UserHandle.of(UserHandle.getCallingUserId());
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
        app.mEligibleForSanitizedExposureNotification =
                callingPackage.equals(mExposureNotificationPackage);
        app.mIsQApp = Utils.isQApp(this, callingPackage);
        app.mIsQApp = Utils.isQApp(this, callingPackage);
        try {
        try {
            if (app.mIsQApp) {
            if (app.mIsQApp) {
@@ -2076,6 +2142,8 @@ public class GattService extends ProfileService {
        scanClient.hasLocationPermission = app.hasLocationPermission;
        scanClient.hasLocationPermission = app.hasLocationPermission;
        scanClient.userHandle = app.mUserHandle;
        scanClient.userHandle = app.mUserHandle;
        scanClient.isQApp = app.mIsQApp;
        scanClient.isQApp = app.mIsQApp;
        scanClient.eligibleForSanitizedExposureNotification =
                app.mEligibleForSanitizedExposureNotification;
        scanClient.hasNetworkSettingsPermission = app.mHasNetworkSettingsPermission;
        scanClient.hasNetworkSettingsPermission = app.mHasNetworkSettingsPermission;
        scanClient.hasNetworkSetupWizardPermission = app.mHasNetworkSetupWizardPermission;
        scanClient.hasNetworkSetupWizardPermission = app.mHasNetworkSetupWizardPermission;
        scanClient.hasScanWithoutLocationPermission = app.mHasScanWithoutLocationPermission;
        scanClient.hasScanWithoutLocationPermission = app.mHasScanWithoutLocationPermission;
+1 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@ import java.util.UUID;
    public boolean hasLocationPermission;
    public boolean hasLocationPermission;
    public UserHandle userHandle;
    public UserHandle userHandle;
    public boolean isQApp;
    public boolean isQApp;
    public boolean eligibleForSanitizedExposureNotification;
    public boolean hasNetworkSettingsPermission;
    public boolean hasNetworkSettingsPermission;
    public boolean hasNetworkSetupWizardPermission;
    public boolean hasNetworkSetupWizardPermission;
    public boolean hasScanWithoutLocationPermission;
    public boolean hasScanWithoutLocationPermission;