Loading android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +95 −8 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ namespace android { const jint INVALID_FD = -1; static jmethodID method_oobDataReceivedCallback; static jmethodID method_stateChangeCallback; static jmethodID method_adapterPropertyChangedCallback; static jmethodID method_devicePropertyChangedCallback; Loading Loading @@ -401,6 +402,73 @@ static void ssp_request_callback(RawAddress* bd_addr, bt_bdname_t* bdname, (jint)pairing_variant, pass_key); } static jobject createClassicOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { jclass oobDataClass = env->FindClass("android/bluetooth/OobData"); jmethodID staticCreatorMethod = env->GetStaticMethodID( oobDataClass, "createClassicBuilder", "([B[B[B)Landroid/bluetooth/OobData$ClassicBuilder;"); jbyteArray confirmationHash = env->NewByteArray(OOB_C_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_C_SIZE, reinterpret_cast<jbyte*>(oob_data.c)); jbyteArray oobDataLength = env->NewByteArray(OOB_DATA_LEN_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_DATA_LEN_SIZE, reinterpret_cast<jbyte*>(oob_data.oob_data_length)); jbyteArray address = env->NewByteArray(OOB_ADDRESS_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_ADDRESS_SIZE, reinterpret_cast<jbyte*>(oob_data.address)); jobject oobDataClassicBuilder = env->CallStaticObjectMethod(oobDataClass, staticCreatorMethod, confirmationHash, oobDataLength, address); jclass oobDataClassicBuilderClass = env->FindClass("android/bluetooth/OobData$ClassicBuilder"); jmethodID setRMethod = env->GetMethodID(oobDataClassicBuilderClass, "setRandomizerHash", "([B)Landroid/bluetooth/OobData$ClassicBuilder;"); jbyteArray randomizerHash = env->NewByteArray(OOB_R_SIZE); env->SetByteArrayRegion(randomizerHash, 0, OOB_R_SIZE, reinterpret_cast<jbyte*>(oob_data.r)); oobDataClassicBuilder = env->CallObjectMethod(oobDataClassicBuilder, setRMethod, randomizerHash); jmethodID buildMethod = env->GetMethodID(oobDataClassicBuilderClass, "build", "()Landroid/bluetooth/OobData;"); return env->CallObjectMethod(oobDataClassicBuilder, buildMethod); } static jobject createLeOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { // TODO(184377951): Connect dots for LE generateLocalOobData() ALOGE("%s: unimplemented", __func__); return nullptr; } static void generate_local_oob_data_callback(tBT_TRANSPORT transport, bt_oob_data_t oob_data) { CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid()) return; if (transport == TRANSPORT_BREDR) { sCallbackEnv->CallVoidMethod( sJniCallbacksObj, method_oobDataReceivedCallback, (jint)transport, ((oob_data.is_valid) ? createClassicOobDataObject(sCallbackEnv.get(), oob_data) : nullptr)); } else { sCallbackEnv->CallVoidMethod( sJniCallbacksObj, method_oobDataReceivedCallback, (jint)transport, ((oob_data.is_valid) ? createLeOobDataObject(sCallbackEnv.get(), oob_data) : nullptr)); } } static void link_quality_report_callback( uint64_t timestamp, int report_id, int rssi, int snr, int retransmission_count, int packets_not_receive_count, Loading Loading @@ -487,7 +555,7 @@ static bt_callbacks_t sBluetoothCallbacks = { bond_state_changed_callback, acl_state_changed_callback, callback_thread_event, dut_mode_recv_callback, le_test_mode_recv_callback, energy_info_recv_callback, link_quality_report_callback}; link_quality_report_callback, generate_local_oob_data_callback}; // The callback to call when the wake alarm fires. static alarm_cb sAlarmCallback; Loading Loading @@ -673,6 +741,10 @@ static void classInitNative(JNIEnv* env, jclass clazz) { sJniCallbacksField = env->GetFieldID( clazz, "mJniCallbacks", "Lcom/android/bluetooth/btservice/JniCallbacks;"); method_oobDataReceivedCallback = env->GetMethodID(jniCallbackClass, "oobDataReceivedCallback", "(ILandroid/bluetooth/OobData;)V"); method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V"); Loading Loading @@ -1057,6 +1129,20 @@ static jboolean set_data(JNIEnv* env, bt_oob_data_t& oob_data, jobject oobData, return JNI_TRUE; } static void generateLocalOobDataNative(JNIEnv* env, jobject obj, jint transport) { // No BT interface? Can't do anything. if (!sBluetoothInterface) return; if (sBluetoothInterface->generate_local_oob_data(transport) != BT_STATUS_SUCCESS) { ALOGE("%s: Call to generate_local_oob_data failed!", __func__); bt_oob_data_t oob_data; oob_data.is_valid = false; generate_local_oob_data_callback(transport, oob_data); } } static jboolean createBondOutOfBandNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport, jobject p192Data, jobject p256Data) { Loading Loading @@ -1536,6 +1622,7 @@ static JNINativeMethod sMethods[] = { (void*)createBondOutOfBandNative}, {"removeBondNative", "([B)Z", (void*)removeBondNative}, {"cancelBondNative", "([B)Z", (void*)cancelBondNative}, {"generateLocalOobDataNative", "(I)V", (void*)generateLocalOobDataNative}, {"getConnectionStateNative", "([B)I", (void*)getConnectionStateNative}, {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative}, {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative}, Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +75 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothConnectionCallback; import android.bluetooth.IBluetoothMetadataListener; import android.bluetooth.IBluetoothOobDataCallback; import android.bluetooth.IBluetoothSocketManager; import android.bluetooth.OobData; import android.bluetooth.UidTraffic; Loading Loading @@ -115,6 +116,7 @@ import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; Loading Loading @@ -1590,6 +1592,26 @@ public class AdapterService extends Service { return deviceProp != null && deviceProp.isBondingInitiatedLocally(); } @Override public void generateLocalOobData(int transport, IBluetoothOobDataCallback callback) { AdapterService service = getService(); if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "generateLocalOobData")) { return; } enforceBluetoothPrivilegedPermission(service); if (transport == BluetoothDevice.TRANSPORT_LE) { // TODO(184377951): LE isn't yet supported, coming soon try { callback.onError(BluetoothAdapter.OOB_ERROR_UNKNOWN); } catch (RemoteException e) { Log.e(TAG, "Failed to call callback"); } return; } service.generateLocalOobData(transport, callback); } @Override public long getSupportedProfiles() { AdapterService service = getService(); Loading Loading @@ -2443,6 +2465,56 @@ public class AdapterService extends Service { return true; } private final ArrayDeque<IBluetoothOobDataCallback> mOobDataCallbackQueue = new ArrayDeque<>(); /** * Fetches the local OOB data to give out to remote. * * @param transport - specify data transport. * @param callback - callback used to receive the requested {@link Oobdata}; null will be * ignored silently. * * @hide */ public synchronized void generateLocalOobData(int transport, IBluetoothOobDataCallback callback) { if (callback == null) { Log.e(TAG, "'callback' argument must not be null!"); return; } if (mOobDataCallbackQueue.peek() != null) { try { callback.onError(BluetoothAdapter.OOB_ERROR_ANOTHER_ACTIVE_REQUEST); return; } catch (RemoteException e) { Log.e(TAG, "Failed to make callback", e); } } mOobDataCallbackQueue.offer(callback); generateLocalOobDataNative(transport); } /* package */ synchronized void notifyOobDataCallback(int transport, OobData oobData) { if (mOobDataCallbackQueue.peek() == null) { Log.e(TAG, "Failed to make callback, no callback exists"); return; } if (oobData == null) { try { mOobDataCallbackQueue.poll().onError(BluetoothAdapter.OOB_ERROR_UNKNOWN); } catch (RemoteException e) { Log.e(TAG, "Failed to make callback", e); } } else { try { mOobDataCallbackQueue.poll().onOobData(transport, oobData); } catch (RemoteException e) { Log.e(TAG, "Failed to make callback", e); } } } public boolean isQuietModeEnabled() { debugLog("isQuetModeEnabled() - Enabled = " + mQuietmode); return mQuietmode; Loading Loading @@ -3469,6 +3541,9 @@ public class AdapterService extends Service { /*package*/ native boolean cancelBondNative(byte[] address); /*package*/ native void generateLocalOobDataNative(int transport); /*package*/ native boolean sdpSearchNative(byte[] address, byte[] uuid); Loading android/app/src/com/android/bluetooth/btservice/JniCallbacks.java +6 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.btservice; import android.bluetooth.OobData; final class JniCallbacks { private RemoteDevices mRemoteDevices; Loading Loading @@ -81,6 +83,10 @@ final class JniCallbacks { mAdapterProperties.adapterPropertyChangedCallback(types, val); } void oobDataReceivedCallback(int transport, OobData oobData) { mAdapterService.notifyOobDataCallback(transport, oobData); } void linkQualityReportCallback( long timestamp, int report_id, Loading Loading
android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp +95 −8 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ namespace android { const jint INVALID_FD = -1; static jmethodID method_oobDataReceivedCallback; static jmethodID method_stateChangeCallback; static jmethodID method_adapterPropertyChangedCallback; static jmethodID method_devicePropertyChangedCallback; Loading Loading @@ -401,6 +402,73 @@ static void ssp_request_callback(RawAddress* bd_addr, bt_bdname_t* bdname, (jint)pairing_variant, pass_key); } static jobject createClassicOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { jclass oobDataClass = env->FindClass("android/bluetooth/OobData"); jmethodID staticCreatorMethod = env->GetStaticMethodID( oobDataClass, "createClassicBuilder", "([B[B[B)Landroid/bluetooth/OobData$ClassicBuilder;"); jbyteArray confirmationHash = env->NewByteArray(OOB_C_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_C_SIZE, reinterpret_cast<jbyte*>(oob_data.c)); jbyteArray oobDataLength = env->NewByteArray(OOB_DATA_LEN_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_DATA_LEN_SIZE, reinterpret_cast<jbyte*>(oob_data.oob_data_length)); jbyteArray address = env->NewByteArray(OOB_ADDRESS_SIZE); env->SetByteArrayRegion(confirmationHash, 0, OOB_ADDRESS_SIZE, reinterpret_cast<jbyte*>(oob_data.address)); jobject oobDataClassicBuilder = env->CallStaticObjectMethod(oobDataClass, staticCreatorMethod, confirmationHash, oobDataLength, address); jclass oobDataClassicBuilderClass = env->FindClass("android/bluetooth/OobData$ClassicBuilder"); jmethodID setRMethod = env->GetMethodID(oobDataClassicBuilderClass, "setRandomizerHash", "([B)Landroid/bluetooth/OobData$ClassicBuilder;"); jbyteArray randomizerHash = env->NewByteArray(OOB_R_SIZE); env->SetByteArrayRegion(randomizerHash, 0, OOB_R_SIZE, reinterpret_cast<jbyte*>(oob_data.r)); oobDataClassicBuilder = env->CallObjectMethod(oobDataClassicBuilder, setRMethod, randomizerHash); jmethodID buildMethod = env->GetMethodID(oobDataClassicBuilderClass, "build", "()Landroid/bluetooth/OobData;"); return env->CallObjectMethod(oobDataClassicBuilder, buildMethod); } static jobject createLeOobDataObject(JNIEnv* env, bt_oob_data_t oob_data) { // TODO(184377951): Connect dots for LE generateLocalOobData() ALOGE("%s: unimplemented", __func__); return nullptr; } static void generate_local_oob_data_callback(tBT_TRANSPORT transport, bt_oob_data_t oob_data) { CallbackEnv sCallbackEnv(__func__); if (!sCallbackEnv.valid()) return; if (transport == TRANSPORT_BREDR) { sCallbackEnv->CallVoidMethod( sJniCallbacksObj, method_oobDataReceivedCallback, (jint)transport, ((oob_data.is_valid) ? createClassicOobDataObject(sCallbackEnv.get(), oob_data) : nullptr)); } else { sCallbackEnv->CallVoidMethod( sJniCallbacksObj, method_oobDataReceivedCallback, (jint)transport, ((oob_data.is_valid) ? createLeOobDataObject(sCallbackEnv.get(), oob_data) : nullptr)); } } static void link_quality_report_callback( uint64_t timestamp, int report_id, int rssi, int snr, int retransmission_count, int packets_not_receive_count, Loading Loading @@ -487,7 +555,7 @@ static bt_callbacks_t sBluetoothCallbacks = { bond_state_changed_callback, acl_state_changed_callback, callback_thread_event, dut_mode_recv_callback, le_test_mode_recv_callback, energy_info_recv_callback, link_quality_report_callback}; link_quality_report_callback, generate_local_oob_data_callback}; // The callback to call when the wake alarm fires. static alarm_cb sAlarmCallback; Loading Loading @@ -673,6 +741,10 @@ static void classInitNative(JNIEnv* env, jclass clazz) { sJniCallbacksField = env->GetFieldID( clazz, "mJniCallbacks", "Lcom/android/bluetooth/btservice/JniCallbacks;"); method_oobDataReceivedCallback = env->GetMethodID(jniCallbackClass, "oobDataReceivedCallback", "(ILandroid/bluetooth/OobData;)V"); method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V"); Loading Loading @@ -1057,6 +1129,20 @@ static jboolean set_data(JNIEnv* env, bt_oob_data_t& oob_data, jobject oobData, return JNI_TRUE; } static void generateLocalOobDataNative(JNIEnv* env, jobject obj, jint transport) { // No BT interface? Can't do anything. if (!sBluetoothInterface) return; if (sBluetoothInterface->generate_local_oob_data(transport) != BT_STATUS_SUCCESS) { ALOGE("%s: Call to generate_local_oob_data failed!", __func__); bt_oob_data_t oob_data; oob_data.is_valid = false; generate_local_oob_data_callback(transport, oob_data); } } static jboolean createBondOutOfBandNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport, jobject p192Data, jobject p256Data) { Loading Loading @@ -1536,6 +1622,7 @@ static JNINativeMethod sMethods[] = { (void*)createBondOutOfBandNative}, {"removeBondNative", "([B)Z", (void*)removeBondNative}, {"cancelBondNative", "([B)Z", (void*)cancelBondNative}, {"generateLocalOobDataNative", "(I)V", (void*)generateLocalOobDataNative}, {"getConnectionStateNative", "([B)I", (void*)getConnectionStateNative}, {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative}, {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative}, Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +75 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothConnectionCallback; import android.bluetooth.IBluetoothMetadataListener; import android.bluetooth.IBluetoothOobDataCallback; import android.bluetooth.IBluetoothSocketManager; import android.bluetooth.OobData; import android.bluetooth.UidTraffic; Loading Loading @@ -115,6 +116,7 @@ import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; Loading Loading @@ -1590,6 +1592,26 @@ public class AdapterService extends Service { return deviceProp != null && deviceProp.isBondingInitiatedLocally(); } @Override public void generateLocalOobData(int transport, IBluetoothOobDataCallback callback) { AdapterService service = getService(); if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "generateLocalOobData")) { return; } enforceBluetoothPrivilegedPermission(service); if (transport == BluetoothDevice.TRANSPORT_LE) { // TODO(184377951): LE isn't yet supported, coming soon try { callback.onError(BluetoothAdapter.OOB_ERROR_UNKNOWN); } catch (RemoteException e) { Log.e(TAG, "Failed to call callback"); } return; } service.generateLocalOobData(transport, callback); } @Override public long getSupportedProfiles() { AdapterService service = getService(); Loading Loading @@ -2443,6 +2465,56 @@ public class AdapterService extends Service { return true; } private final ArrayDeque<IBluetoothOobDataCallback> mOobDataCallbackQueue = new ArrayDeque<>(); /** * Fetches the local OOB data to give out to remote. * * @param transport - specify data transport. * @param callback - callback used to receive the requested {@link Oobdata}; null will be * ignored silently. * * @hide */ public synchronized void generateLocalOobData(int transport, IBluetoothOobDataCallback callback) { if (callback == null) { Log.e(TAG, "'callback' argument must not be null!"); return; } if (mOobDataCallbackQueue.peek() != null) { try { callback.onError(BluetoothAdapter.OOB_ERROR_ANOTHER_ACTIVE_REQUEST); return; } catch (RemoteException e) { Log.e(TAG, "Failed to make callback", e); } } mOobDataCallbackQueue.offer(callback); generateLocalOobDataNative(transport); } /* package */ synchronized void notifyOobDataCallback(int transport, OobData oobData) { if (mOobDataCallbackQueue.peek() == null) { Log.e(TAG, "Failed to make callback, no callback exists"); return; } if (oobData == null) { try { mOobDataCallbackQueue.poll().onError(BluetoothAdapter.OOB_ERROR_UNKNOWN); } catch (RemoteException e) { Log.e(TAG, "Failed to make callback", e); } } else { try { mOobDataCallbackQueue.poll().onOobData(transport, oobData); } catch (RemoteException e) { Log.e(TAG, "Failed to make callback", e); } } } public boolean isQuietModeEnabled() { debugLog("isQuetModeEnabled() - Enabled = " + mQuietmode); return mQuietmode; Loading Loading @@ -3469,6 +3541,9 @@ public class AdapterService extends Service { /*package*/ native boolean cancelBondNative(byte[] address); /*package*/ native void generateLocalOobDataNative(int transport); /*package*/ native boolean sdpSearchNative(byte[] address, byte[] uuid); Loading
android/app/src/com/android/bluetooth/btservice/JniCallbacks.java +6 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.btservice; import android.bluetooth.OobData; final class JniCallbacks { private RemoteDevices mRemoteDevices; Loading Loading @@ -81,6 +83,10 @@ final class JniCallbacks { mAdapterProperties.adapterPropertyChangedCallback(types, val); } void oobDataReceivedCallback(int transport, OobData oobData) { mAdapterService.notifyOobDataCallback(transport, oobData); } void linkQualityReportCallback( long timestamp, int report_id, Loading