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

Commit c038399d authored by Andrew Cheng's avatar Andrew Cheng Committed by Andrew Cheng
Browse files

Fix HFP client JNI NPE and concurrency issues in JNI and service

1.) There is a JNI NPE during shutdown of HeadsetClientService. In JNI,
{@code mCallbacksObj} is shared between {@code cleanupNative()} and
native upcalls, e.g., {@code connection_state_cb}. To protect against
this, a null check for {@code mCallbacksObj} is added to each of the
upcalls, and a mutex for {@code mCallbacksObj} is also added. For good
measure, a separate mutex was also added to guard {@code
sBluetoothHfpClientInterface}. This is the approach in CL 405014,
which solved the same problem for the phone-side/AG of HFP.

2.) The mutex in the JNI guarding {@code mCallbacksObj} (c.f. #1)
introduces a deadlock scenario in the java code. In
HeadsetClientService, {@code stop} (which calls {@code cleanupNative} in
the JNI) and {@code getStateMachine} (which is called by {@code
messageFromNative}, which is called by various native upcalls, e.g.,
{@code connection_state_cb}) are synchronized methods. This CL removes
the synchronized label from the methods and instead guard on the HashMap
of state machines. This is the approach taken on the phone-side/AG of
HFP (c.f. CL 548206). This CL also adds some additional guards around
{@code sHeadsetClientService}.

3. Guarding {@code mStateMachineMap} with itself (c.f. #2) should also
resolve a {@code ConcurrentModificationException} in the
BroadcastReceiver of HeadsetClientService.

4. {@code getStateMachine} currently creates a new state machine if one
doesn't already exist in the map (i.e., as long as a {@code device} is
non-null and the maximum number of state machines hasn't been exceeded).
However, the only times a new state machine should be created and added
is when a device connects. This CL adds checks to make it so.

5. When a state machine is allocated, this CL adds a check to verify the
service is non-null, i.e., the service has not begun stopping or has
completed startup. This protects against situations such as: {@code
stop} is called and starts removing state machines. At the same time,
something else calls {@code allocateStateMachine}, which creates and
adds one to the map -- after the service shut down and cleared out the
state machines. {@code NativeInterface} provides some protection already
(i.e., they check the service is non-null before calling {@code
messageFromNative}, which is one of the potential paths to calling
{@code allocateStateMachine}, but adding this null-check directly inside
of {@code allocateStateMachine} should make things more robust.

Tag: #stability
Bug: 177882643
Bug: 193867157
Test: atest BluetoothInstrumentationTests
Change-Id: Ia6b447764f0c11b579b82cb7ab87a083ab0ac274
parent 1767bad7
Loading
Loading
Loading
Loading
+71 −21
Original line number Diff line number Diff line
@@ -22,10 +22,15 @@
#include "hardware/bt_hf_client.h"
#include "utils/Log.h"

#include <shared_mutex>

namespace android {

static bthf_client_interface_t* sBluetoothHfpClientInterface = NULL;
static std::shared_mutex interface_mutex;

static jobject mCallbacksObj = NULL;
static std::shared_mutex callbacks_mutex;

static jmethodID method_onConnectionStateChanged;
static jmethodID method_onAudioStateChanged;
@@ -68,8 +73,9 @@ static void connection_state_cb(const RawAddress* bd_addr,
                                bthf_client_connection_state_t state,
                                unsigned int peer_feat,
                                unsigned int chld_feat) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -82,8 +88,9 @@ static void connection_state_cb(const RawAddress* bd_addr,

static void audio_state_cb(const RawAddress* bd_addr,
                           bthf_client_audio_state_t state) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -93,8 +100,9 @@ static void audio_state_cb(const RawAddress* bd_addr,
}

static void vr_cmd_cb(const RawAddress* bd_addr, bthf_client_vr_state_t state) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -105,8 +113,9 @@ static void vr_cmd_cb(const RawAddress* bd_addr, bthf_client_vr_state_t state) {

static void network_state_cb(const RawAddress* bd_addr,
                             bthf_client_network_state_t state) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -117,7 +126,9 @@ static void network_state_cb(const RawAddress* bd_addr,

static void network_roaming_cb(const RawAddress* bd_addr,
                               bthf_client_service_type_t type) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -127,8 +138,9 @@ static void network_roaming_cb(const RawAddress* bd_addr,
}

static void network_signal_cb(const RawAddress* bd_addr, int signal) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -138,8 +150,9 @@ static void network_signal_cb(const RawAddress* bd_addr, int signal) {
}

static void battery_level_cb(const RawAddress* bd_addr, int level) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -149,8 +162,9 @@ static void battery_level_cb(const RawAddress* bd_addr, int level) {
}

static void current_operator_cb(const RawAddress* bd_addr, const char* name) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -169,8 +183,9 @@ static void current_operator_cb(const RawAddress* bd_addr, const char* name) {
}

static void call_cb(const RawAddress* bd_addr, bthf_client_call_t call) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -181,8 +196,9 @@ static void call_cb(const RawAddress* bd_addr, bthf_client_call_t call) {

static void callsetup_cb(const RawAddress* bd_addr,
                         bthf_client_callsetup_t callsetup) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -197,8 +213,9 @@ static void callsetup_cb(const RawAddress* bd_addr,

static void callheld_cb(const RawAddress* bd_addr,
                        bthf_client_callheld_t callheld) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -209,8 +226,9 @@ static void callheld_cb(const RawAddress* bd_addr,

static void resp_and_hold_cb(const RawAddress* bd_addr,
                             bthf_client_resp_and_hold_t resp_and_hold) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -220,8 +238,9 @@ static void resp_and_hold_cb(const RawAddress* bd_addr,
}

static void clip_cb(const RawAddress* bd_addr, const char* number) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -240,8 +259,9 @@ static void clip_cb(const RawAddress* bd_addr, const char* number) {
}

static void call_waiting_cb(const RawAddress* bd_addr, const char* number) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -264,8 +284,9 @@ static void current_calls_cb(const RawAddress* bd_addr, int index,
                             bthf_client_call_state_t state,
                             bthf_client_call_mpty_type_t mpty,
                             const char* number) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -285,8 +306,9 @@ static void current_calls_cb(const RawAddress* bd_addr, int index,

static void volume_change_cb(const RawAddress* bd_addr,
                             bthf_client_volume_type_t type, int volume) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -296,8 +318,9 @@ static void volume_change_cb(const RawAddress* bd_addr,

static void cmd_complete_cb(const RawAddress* bd_addr,
                            bthf_client_cmd_complete_t type, int cme) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -307,8 +330,9 @@ static void cmd_complete_cb(const RawAddress* bd_addr,

static void subscriber_info_cb(const RawAddress* bd_addr, const char* name,
                               bthf_client_subscriber_service_type_t type) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -328,8 +352,9 @@ static void subscriber_info_cb(const RawAddress* bd_addr, const char* name,

static void in_band_ring_cb(const RawAddress* bd_addr,
                            bthf_client_in_band_ring_state_t in_band) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -339,8 +364,9 @@ static void in_band_ring_cb(const RawAddress* bd_addr,

static void last_voice_tag_number_cb(const RawAddress* bd_addr,
                                     const char* number) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -359,8 +385,9 @@ static void last_voice_tag_number_cb(const RawAddress* bd_addr,
}

static void ring_indication_cb(const RawAddress* bd_addr) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -370,8 +397,9 @@ static void ring_indication_cb(const RawAddress* bd_addr) {

static void unknown_event_cb(const RawAddress* bd_addr,
                             const char* eventString) {
  std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbackEnv.valid() || mCallbacksObj == NULL) return;

  ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
  if (!addr.get()) return;
@@ -446,6 +474,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {

static void initializeNative(JNIEnv* env, jobject object) {
  ALOGD("%s: HfpClient", __func__);
  std::unique_lock<std::shared_mutex> interface_lock(interface_mutex);
  std::unique_lock<std::shared_mutex> callbacks_lock(callbacks_mutex);

  const bt_interface_t* btInf = getBluetoothInterface();
  if (btInf == NULL) {
    ALOGE("Bluetooth module is not loaded");
@@ -484,6 +515,9 @@ static void initializeNative(JNIEnv* env, jobject object) {
}

static void cleanupNative(JNIEnv* env, jobject object) {
  std::unique_lock<std::shared_mutex> interface_lock(interface_mutex);
  std::unique_lock<std::shared_mutex> callbacks_lock(callbacks_mutex);

  const bt_interface_t* btInf = getBluetoothInterface();
  if (btInf == NULL) {
    ALOGE("Bluetooth module is not loaded");
@@ -504,6 +538,7 @@ static void cleanupNative(JNIEnv* env, jobject object) {
}

static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -522,6 +557,7 @@ static jboolean connectNative(JNIEnv* env, jobject object, jbyteArray address) {

static jboolean disconnectNative(JNIEnv* env, jobject object,
                                 jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -541,6 +577,7 @@ static jboolean disconnectNative(JNIEnv* env, jobject object,

static jboolean connectAudioNative(JNIEnv* env, jobject object,
                                   jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -560,6 +597,7 @@ static jboolean connectAudioNative(JNIEnv* env, jobject object,

static jboolean disconnectAudioNative(JNIEnv* env, jobject object,
                                      jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -579,6 +617,7 @@ static jboolean disconnectAudioNative(JNIEnv* env, jobject object,

static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object,
                                            jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -598,6 +637,7 @@ static jboolean startVoiceRecognitionNative(JNIEnv* env, jobject object,

static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object,
                                           jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -617,6 +657,7 @@ static jboolean stopVoiceRecognitionNative(JNIEnv* env, jobject object,

static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address,
                                jint volume_type, jint volume) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -636,6 +677,7 @@ static jboolean setVolumeNative(JNIEnv* env, jobject object, jbyteArray address,

static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address,
                           jstring number_str) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -664,6 +706,7 @@ static jboolean dialNative(JNIEnv* env, jobject object, jbyteArray address,

static jboolean dialMemoryNative(JNIEnv* env, jobject object,
                                 jbyteArray address, jint location) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -685,6 +728,7 @@ static jboolean dialMemoryNative(JNIEnv* env, jobject object,
static jboolean handleCallActionNative(JNIEnv* env, jobject object,
                                       jbyteArray address, jint action,
                                       jint index) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -705,6 +749,7 @@ static jboolean handleCallActionNative(JNIEnv* env, jobject object,

static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object,
                                        jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -725,6 +770,7 @@ static jboolean queryCurrentCallsNative(JNIEnv* env, jobject object,

static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object,
                                               jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -746,6 +792,7 @@ static jboolean queryCurrentOperatorNameNative(JNIEnv* env, jobject object,

static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object,
                                             jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -766,6 +813,7 @@ static jboolean retrieveSubscriberInfoNative(JNIEnv* env, jobject object,

static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address,
                               jbyte code) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -786,6 +834,7 @@ static jboolean sendDtmfNative(JNIEnv* env, jobject object, jbyteArray address,

static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object,
                                                jbyteArray address) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
@@ -809,6 +858,7 @@ static jboolean requestLastVoiceTagNumberNative(JNIEnv* env, jobject object,
static jboolean sendATCmdNative(JNIEnv* env, jobject object, jbyteArray address,
                                jint cmd, jint val1, jint val2,
                                jstring arg_str) {
  std::shared_lock<std::shared_mutex> lock(interface_mutex);
  if (!sBluetoothHfpClientInterface) return JNI_FALSE;

  jbyte* addr = env->GetByteArrayElements(address, NULL);
+221 −134

File changed.

Preview size limit exceeded, changes collapsed.