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

Commit 660cbe74 authored by William Escande's avatar William Escande Committed by Automerger Merge Worker
Browse files

Merge "Bt: Add support for interop conf feature" am: fca42b8f

parents 1d7367bc fca42b8f
Loading
Loading
Loading
Loading
+193 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016-2017 The Linux Foundation
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
@@ -1854,6 +1855,186 @@ static jboolean isLogRedactionEnabled(JNIEnv* env, jobject obj) {
  return bluetooth::os::should_log_be_redacted();
}

static jboolean interopMatchAddrNative(JNIEnv* env, jclass clazz,
                                       jstring feature_name, jstring address) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) {
    ALOGW("%s: sBluetoothInterface is null.", __func__);
    return JNI_FALSE;
  }

  const char* tmp_addr = env->GetStringUTFChars(address, NULL);
  if (!tmp_addr) {
    ALOGW("%s: address is null.", __func__);
    return JNI_FALSE;
  }
  RawAddress bdaddr;
  bool success = RawAddress::FromString(tmp_addr, bdaddr);

  env->ReleaseStringUTFChars(address, tmp_addr);

  if (!success) {
    ALOGW("%s: address is invalid.", __func__);
    return JNI_FALSE;
  }

  const char* feature_name_str = env->GetStringUTFChars(feature_name, NULL);
  if (!feature_name_str) {
    ALOGW("%s: feature name is null.", __func__);
    return JNI_FALSE;
  }

  bool matched =
      sBluetoothInterface->interop_match_addr(feature_name_str, &bdaddr);
  env->ReleaseStringUTFChars(feature_name, feature_name_str);

  return matched ? JNI_TRUE : JNI_FALSE;
}

static jboolean interopMatchNameNative(JNIEnv* env, jclass clazz,
                                       jstring feature_name, jstring name) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) {
    ALOGW("%s: sBluetoothInterface is null.", __func__);
    return JNI_FALSE;
  }

  const char* feature_name_str = env->GetStringUTFChars(feature_name, NULL);
  if (!feature_name_str) {
    ALOGW("%s: feature name is null.", __func__);
    return JNI_FALSE;
  }

  const char* name_str = env->GetStringUTFChars(name, NULL);
  if (!name_str) {
    ALOGW("%s: name is null.", __func__);
    env->ReleaseStringUTFChars(feature_name, feature_name_str);
    return JNI_FALSE;
  }

  bool matched =
      sBluetoothInterface->interop_match_name(feature_name_str, name_str);
  env->ReleaseStringUTFChars(feature_name, feature_name_str);
  env->ReleaseStringUTFChars(name, name_str);

  return matched ? JNI_TRUE : JNI_FALSE;
}

static jboolean interopMatchAddrOrNameNative(JNIEnv* env, jclass clazz,
                                             jstring feature_name,
                                             jstring address) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) {
    ALOGW("%s: sBluetoothInterface is null.", __func__);
    return JNI_FALSE;
  }

  const char* tmp_addr = env->GetStringUTFChars(address, NULL);
  if (!tmp_addr) {
    ALOGW("%s: address is null.", __func__);
    return JNI_FALSE;
  }
  RawAddress bdaddr;
  bool success = RawAddress::FromString(tmp_addr, bdaddr);

  env->ReleaseStringUTFChars(address, tmp_addr);

  if (!success) {
    ALOGW("%s: address is invalid.", __func__);
    return JNI_FALSE;
  }

  const char* feature_name_str = env->GetStringUTFChars(feature_name, NULL);
  if (!feature_name_str) {
    ALOGW("%s: feature name is null.", __func__);
    return JNI_FALSE;
  }

  bool matched = sBluetoothInterface->interop_match_addr_or_name(
      feature_name_str, &bdaddr);
  env->ReleaseStringUTFChars(feature_name, feature_name_str);

  return matched ? JNI_TRUE : JNI_FALSE;
}

static void interopDatabaseAddRemoveAddrNative(JNIEnv* env, jclass clazz,
                                               jboolean do_add,
                                               jstring feature_name,
                                               jstring address, jint length) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) {
    ALOGW("%s: sBluetoothInterface is null.", __func__);
    return;
  }

  if ((do_add == JNI_TRUE) && (length <= 0 || length > 6)) {
    ALOGE("%s: address length %d is invalid, valid length is [1,6]", __func__,
          length);
    return;
  }

  const char* tmp_addr = env->GetStringUTFChars(address, NULL);
  if (!tmp_addr) {
    ALOGW("%s: address is null.", __func__);
    return;
  }
  RawAddress bdaddr;
  bool success = RawAddress::FromString(tmp_addr, bdaddr);

  env->ReleaseStringUTFChars(address, tmp_addr);

  if (!success) {
    ALOGW("%s: address is invalid.", __func__);
    return;
  }

  const char* feature_name_str = env->GetStringUTFChars(feature_name, NULL);
  if (!feature_name_str) {
    ALOGW("%s: feature name is null.", __func__);
    return;
  }

  sBluetoothInterface->interop_database_add_remove_addr(
      (do_add == JNI_TRUE), feature_name_str, &bdaddr, (int)length);

  env->ReleaseStringUTFChars(feature_name, feature_name_str);
}

static void interopDatabaseAddRemoveNameNative(JNIEnv* env, jclass clazz,
                                               jboolean do_add,
                                               jstring feature_name,
                                               jstring name) {
  ALOGV("%s", __func__);

  if (!sBluetoothInterface) {
    ALOGW("%s: sBluetoothInterface is null.", __func__);
    return;
  }

  const char* feature_name_str = env->GetStringUTFChars(feature_name, NULL);
  if (!feature_name_str) {
    ALOGW("%s: feature name is null.", __func__);
    return;
  }

  const char* name_str = env->GetStringUTFChars(name, NULL);
  if (!name_str) {
    ALOGW("%s: name is null.", __func__);
    env->ReleaseStringUTFChars(feature_name, feature_name_str);
    return;
  }

  sBluetoothInterface->interop_database_add_remove_name(
      (do_add == JNI_TRUE), feature_name_str, name_str);

  env->ReleaseStringUTFChars(feature_name, feature_name_str);
  env->ReleaseStringUTFChars(name, name_str);
}

static JNINativeMethod sMethods[] = {
    /* name, signature, funcPtr */
    {"classInitNative", "()V", (void*)classInitNative},
@@ -1898,6 +2079,18 @@ static JNINativeMethod sMethods[] = {
    {"allowLowLatencyAudioNative", "(Z[B)Z", (void*)allowLowLatencyAudioNative},
    {"metadataChangedNative", "([BI[B)V", (void*)metadataChangedNative},
    {"isLogRedactionEnabled", "()Z", (void*)isLogRedactionEnabled},
    {"interopMatchAddrNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
     (void*)interopMatchAddrNative},
    {"interopMatchNameNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
     (void*)interopMatchNameNative},
    {"interopMatchAddrOrNameNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
     (void*)interopMatchAddrOrNameNative},
    {"interopDatabaseAddRemoveAddrNative",
     "(ZLjava/lang/String;Ljava/lang/String;I)V",
     (void*)interopDatabaseAddRemoveAddrNative},
    {"interopDatabaseAddRemoveNameNative",
     "(ZLjava/lang/String;Ljava/lang/String;)V",
     (void*)interopDatabaseAddRemoveNameNative},
};

int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ public final class AbstractionLayer {

    static final int BT_PROPERTY_DYNAMIC_AUDIO_BUFFER = 0x10;
    static final int BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER = 0x11;
    static final int BT_PROPERTY_WL_MEDIA_PLAYERS_LIST = 0x14;

    public static final int BT_DEVICE_TYPE_BREDR = 0x01;
    public static final int BT_DEVICE_TYPE_BLE = 0x02;
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 * Copyright (C) 2016-2017 The Linux Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -96,6 +97,8 @@ class AdapterProperties {

    private static final int SCAN_MODE_CHANGES_MAX_SIZE = 10;
    private EvictingQueue<String> mScanModeChanges;
    private CopyOnWriteArrayList<String> mAllowlistedPlayers =
            new CopyOnWriteArrayList<String>();

    private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
    private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState =
@@ -263,6 +266,7 @@ class AdapterProperties {
        mBondedDevices.clear();
        mScanModeChanges.clear();
        invalidateBluetoothCaches();
        mAllowlistedPlayers.clear();
    }

    private static void invalidateGetProfileConnectionStateCache() {
@@ -700,6 +704,24 @@ class AdapterProperties {
        }
    }

     /**
     * @return the mAllowlistedPlayers
     */
    String[] getAllowlistedMediaPlayers() {
        String[] AllowlistedPlayersList = new String[0];
        try {
            AllowlistedPlayersList = mAllowlistedPlayers.toArray(AllowlistedPlayersList);
        } catch (ArrayStoreException ee) {
            errorLog("Error retrieving Allowlisted Players array");
        }
        Log.d(TAG, "getAllowlistedMediaPlayers: numAllowlistedPlayers = "
                                        + AllowlistedPlayersList.length);
        for (int i = 0; i < AllowlistedPlayersList.length; i++) {
            Log.d(TAG, "players :" + AllowlistedPlayersList[i]);
        }
        return AllowlistedPlayersList;
    }

    long discoveryEndMillis() {
        return mDiscoveryEndMs;
    }
@@ -911,6 +933,15 @@ class AdapterProperties {
        }
    }

    void updateAllowlistedMediaPlayers(String playername) {
        Log.d(TAG, "updateAllowlistedMediaPlayers ");

        if (!mAllowlistedPlayers.contains(playername)) {
            Log.d(TAG, "Adding to Allowlisted Players list:" + playername);
            mAllowlistedPlayers.add(playername);
        }
    }

    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
    void adapterPropertyChangedCallback(int[] types, byte[][] values) {
        Intent intent;
@@ -999,6 +1030,23 @@ class AdapterProperties {
                        debugLog("mLocalIOCapabilityBLE set to " + mLocalIOCapabilityBLE);
                        break;

                    case AbstractionLayer.BT_PROPERTY_WL_MEDIA_PLAYERS_LIST:
                        int pos = 0;
                        for (int j = 0; j < val.length; j++) {
                            if (val[j] != 0) {
                                continue;
                            }
                            int name_len = j - pos;

                            byte[] buf = new byte[name_len];
                            System.arraycopy(val, pos, buf, 0, name_len);
                            String player_name = new String(buf, 0, name_len);
                            Log.d(TAG, "player_name: "  +  player_name);
                            updateAllowlistedMediaPlayers(player_name);
                            pos += (name_len + 1);
                        }
                        break;

                    default:
                        errorLog("Property change not handled in Java land:" + type);
                }
+43 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 * Copyright (C) 2016-2017 The Linux Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -108,6 +109,7 @@ import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.a2dpsink.A2dpSinkService;
import com.android.bluetooth.bas.BatteryService;
import com.android.bluetooth.bass_client.BassClientService;
import com.android.bluetooth.btservice.InteropUtil.InteropFeature;
import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties;
import com.android.bluetooth.btservice.activityattribution.ActivityAttributionService;
import com.android.bluetooth.btservice.bluetoothkeystore.BluetoothKeystoreService;
@@ -5468,6 +5470,10 @@ public class AdapterService extends Service {
        return mAdapterProperties.isA2dpOffloadEnabled();
    }

    public String[] getAllowlistedMediaPlayers() {
        return mAdapterProperties.getAllowlistedMediaPlayers();
    }

    @VisibleForTesting
    BluetoothActivityEnergyInfo reportActivityInfo() {
        if (mAdapterProperties.getState() != BluetoothAdapter.STATE_ON
@@ -6246,6 +6252,35 @@ public class AdapterService extends Service {
        mRemoteDevices.updateBatteryLevel(device, batteryLevel);
    }

    public boolean interopMatchAddr(InteropFeature feature, String address) {
        return interopMatchAddrNative(feature.name(), address);
    }

    public boolean interopMatchName(InteropFeature feature, String name) {
        return interopMatchNameNative(feature.name(), name);
    }

    public boolean interopMatchAddrOrName(InteropFeature feature, String address) {
        return interopMatchAddrOrNameNative(feature.name(), address);
    }

    public void interopDatabaseAddAddr(InteropFeature feature,
            String address, int length) {
        interopDatabaseAddRemoveAddrNative(true, feature.name(), address, length);
    }

    public void interopDatabaseRemoveAddr(InteropFeature feature, String address) {
        interopDatabaseAddRemoveAddrNative(false, feature.name(), address, 0);
    }

    public void interopDatabaseAddName(InteropFeature feature, String name) {
        interopDatabaseAddRemoveNameNative(true, feature.name(), name);
    }

    public void interopDatabaseRemoveName(InteropFeature feature, String name) {
        interopDatabaseAddRemoveNameNative(false, feature.name(), name);
    }

    static native void classInitNative();

    native boolean initNative(boolean startRestricted, boolean isCommonCriteriaMode,
@@ -6343,6 +6378,14 @@ public class AdapterService extends Service {

    private native void metadataChangedNative(byte[] address, int key, byte[] value);

    private native boolean interopMatchAddrNative(String featureName, String address);
    private native boolean interopMatchNameNative(String featureName, String name);
    private native boolean interopMatchAddrOrNameNative(String featureName, String address);
    private native void interopDatabaseAddRemoveAddrNative(boolean doAdd,
            String featureName, String address, int length);
    private native void interopDatabaseAddRemoveNameNative(boolean doAdd,
            String featureBame, String name);

    // Returns if this is a mock object. This is currently used in testing so that we may not call
    // System.exit() while finalizing the object. Otherwise GC of mock objects unfortunately ends up
    // calling finalize() which in turn calls System.exit() and the process crashes.
+218 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2022 The Android Open Source Project
 * Copyright (c) 2020 The Linux Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.bluetooth.btservice;

import android.util.Log;

/**
 * APIs of interoperability workaround utilities.
 * These APIs will call stack layer's interop APIs of interop.cc to do matching
 * or entry adding/removing.
 */
public class InteropUtil {
    private static final String TAG = "InteropUtil";

    /**
     * Add interop feature from device/include/interop.h to below InteropFeature if
     * this feature needs to be matched at java layer. Feature's name will be passed to
     * stack layer to do matching, so make sure that the added feature's name is exactly
     * same as that in device/include/interop.h.
     */
    public enum InteropFeature {
        INTEROP_NOT_UPDATE_AVRCP_PAUSED_TO_REMOTE,
        INTEROP_PHONE_POLICY_INCREASED_DELAY_CONNECT_OTHER_PROFILES,
        INTEROP_PHONE_POLICY_REDUCED_DELAY_CONNECT_OTHER_PROFILES,
        INTEROP_HFP_FAKE_INCOMING_CALL_INDICATOR,
        INTEROP_HFP_SEND_CALL_INDICATORS_BACK_TO_BACK,
        INTEROP_SETUP_SCO_WITH_NO_DELAY_AFTER_SLC_DURING_CALL,
        INTEROP_RETRY_SCO_AFTER_REMOTE_REJECT_SCO;
    }

    /**
     * Check if a given address matches a known interoperability workaround
     * identified by the interop feature.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param address a given address to be matched.
     * @return true if matched, false otherwise.
     */
    public static boolean interopMatchAddr(InteropFeature feature, String address) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopMatchAddr: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return false;
        }

        Log.d(TAG, "interopMatchAddr: feature=" + feature.name() + ", address=" + address);
        if (address == null) {
            return false;
        }

        boolean matched = adapterService.interopMatchAddr(feature, address);
        Log.d(TAG, "interopMatchAddr: matched=" + matched);
        return matched;
    }

    /**
     * Check if a given name matches a known interoperability workaround
     * identified by the interop feature.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param name a given name to be matched.
     * @return true if matched, false otherwise.
     */
    public static boolean interopMatchName(InteropFeature feature, String name) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopMatchName: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return false;
        }

        Log.d(TAG, "interopMatchName: feature=" + feature.name() + ", name=" + name);
        if (name == null) {
            return false;
        }

        boolean matched = adapterService.interopMatchName(feature, name);
        Log.d(TAG, "interopMatchName: matched=" + matched);
        return matched;
    }

    /**
     * Check if a given address or remote device name matches a known interoperability workaround
     * identified by the interop feature. remote device name will be fetched internally based on
     * the given address at stack layer.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param address a given address to be matched.
     * @return true if matched, false otherwise
     */
    public static boolean interopMatchAddrOrName(InteropFeature feature, String address) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopMatchAddrOrName: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return false;
        }

        Log.d(TAG, "interopMatchAddrOrName: feature=" + feature.name() + ", address=" + address);
        if (address == null) {
            return false;
        }

        boolean matched = adapterService.interopMatchAddrOrName(feature, address);
        Log.d(TAG, "interopMatchAddrOrName: matched=" + matched);
        return matched;
    }

    /**
     * Add a dynamic address interop database entry identified by the interop feature
     * for a device matching the first length bytes of addr.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param address a given address to be added.
     * @param length the number of bytes of address to be stored,
     * length must be in [1,6], and usually it is 3.
     */
    public static void interopDatabaseAddAddr(InteropFeature feature,
            String address, int length) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopDatabaseAddAddr: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return;
        }

        Log.d(TAG, "interopDatabaseAddAddr: feature=" + feature.name()
                + ", address=" + address + ", length=" + length);
        if (address == null || (length <= 0 || length > 6)) {
            return;
        }

        adapterService.interopDatabaseAddAddr(feature, address, length);
    }

    /**
     * Remove a dynamic address interop database entry identified by the interop feature
     * for a device matching the addr.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param address a given address to be removed.
     */
    public static void interopDatabaseRemoveAddr(InteropFeature feature, String address) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopDatabaseRemoveAddr: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return;
        }

        Log.d(TAG, "interopDatabaseRemoveAddr: feature=" + feature.name() + ", address=" + address);
        if (address == null) {
            return;
        }

        adapterService.interopDatabaseRemoveAddr(feature, address);
    }

    /**
     * Add a dynamic name interop database entry identified by the interop feature for the name.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param name a given name to be added.
     */
    public static void interopDatabaseAddName(InteropFeature feature, String name) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopDatabaseAddName: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return;
        }

        Log.d(TAG, "interopDatabaseAddName: feature=" + feature.name() + ", name=" + name);
        if (name == null) {
            return;
        }

        adapterService.interopDatabaseAddName(feature, name);
    }

    /**
     * Remove a dynamic name interop database entry identified by the interop feature for the name.
     *
     * @param feature a given interop feature defined in {@link InteropFeature}.
     * @param name a given name to be removed.
     */
    public static void interopDatabaseRemoveName(InteropFeature feature, String name) {
        AdapterService adapterService = AdapterService.getAdapterService();
        if (adapterService == null) {
            Log.d(TAG, "interopDatabaseRemoveName: feature=" + feature.name()
                    + ", adapterService is null or vendor intf is not enabled");
            return;
        }

        Log.d(TAG, "interopDatabaseRemoveName: feature=" + feature.name() + ", name=" + name);
        if (name == null) {
            return;
        }

        adapterService.interopDatabaseRemoveName(feature, name);
    }
}
Loading