Merge "Add locking to AVRCP Target JNI"
diff --git a/jni/com_android_bluetooth_avrcp_target.cpp b/jni/com_android_bluetooth_avrcp_target.cpp
index d17137f..a83bfa2 100644
--- a/jni/com_android_bluetooth_avrcp_target.cpp
+++ b/jni/com_android_bluetooth_avrcp_target.cpp
@@ -18,6 +18,8 @@
 
 #include <base/bind.h>
 #include <map>
+#include <mutex>
+#include <shared_mutex>
 #include <vector>
 
 #include "android_runtime/AndroidRuntime.h"
@@ -33,6 +35,8 @@
 static MediaCallbacks* mServiceCallbacks;
 static ServiceInterface* sServiceInterface;
 static jobject mJavaInterface;
+static std::shared_timed_mutex interface_mutex;
+static std::shared_timed_mutex callbacks_mutex;
 
 // Forward Declarations
 static void sendMediaKeyEvent(int, int);
@@ -204,6 +208,8 @@
 
 static void initNative(JNIEnv* env, jobject object) {
   ALOGD("%s", __func__);
+  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
+  std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
   mJavaInterface = env->NewGlobalRef(object);
 
   sServiceInterface = getBluetoothInterface()->get_avrcp_service();
@@ -214,7 +220,12 @@
                                   jboolean metadata, jboolean state,
                                   jboolean queue) {
   ALOGD("%s", __func__);
-  CHECK(mServiceCallbacks);
+  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
+  if (mServiceCallbacks == nullptr) {
+    ALOGW("%s: Service not loaded.", __func__);
+    return;
+  }
+
   mServiceCallbacks->SendMediaUpdate(metadata == JNI_TRUE, state == JNI_TRUE,
                                      queue == JNI_TRUE);
 }
@@ -223,13 +234,21 @@
                                    jboolean available_players,
                                    jboolean addressed_player, jboolean uids) {
   ALOGD("%s", __func__);
-  CHECK(mServiceCallbacks);
+  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
+  if (mServiceCallbacks == nullptr) {
+    ALOGW("%s: Service not loaded.", __func__);
+    return;
+  }
+
   mServiceCallbacks->SendFolderUpdate(available_players == JNI_TRUE,
                                       addressed_player == JNI_TRUE,
                                       uids == JNI_TRUE);
 }
 
 static void cleanupNative(JNIEnv* env, jobject object) {
+  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
+  std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
+
   sServiceInterface->Cleanup();
   env->DeleteGlobalRef(mJavaInterface);
   mJavaInterface = nullptr;
@@ -239,7 +258,11 @@
 
 jboolean connectDeviceNative(JNIEnv* env, jobject object, jstring address) {
   ALOGD("%s", __func__);
-  if (!sServiceInterface) return JNI_FALSE;
+  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
+  if (mServiceCallbacks == nullptr) {
+    ALOGW("%s: Service not loaded.", __func__);
+    return JNI_FALSE;
+  }
 
   const char* tmp_addr = env->GetStringUTFChars(address, 0);
   RawAddress bdaddr;
@@ -254,7 +277,11 @@
 
 jboolean disconnectDeviceNative(JNIEnv* env, jobject object, jstring address) {
   ALOGD("%s", __func__);
-  if (!sServiceInterface) return JNI_FALSE;
+  std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
+  if (mServiceCallbacks == nullptr) {
+    ALOGW("%s: Service not loaded.", __func__);
+    return JNI_FALSE;
+  }
 
   const char* tmp_addr = env->GetStringUTFChars(address, 0);
   RawAddress bdaddr;
@@ -269,8 +296,9 @@
 
 static void sendMediaKeyEvent(int key, int state) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
-  if (!sCallbackEnv.valid()) return;
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
   sCallbackEnv->CallVoidMethod(mJavaInterface, method_sendMediaKeyEvent, key,
                                state);
 }
@@ -393,7 +421,10 @@
 
 static SongInfo getSongInfo() {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return SongInfo();
+
   jobject metadata =
       sCallbackEnv->CallObjectMethod(mJavaInterface, method_getCurrentSongInfo);
   return getSongInfoFromJavaObj(sCallbackEnv.get(), metadata);
@@ -401,11 +432,11 @@
 
 static PlayStatus getCurrentPlayStatus() {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
+  CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return PlayStatus();
 
   PlayStatus status;
-  CallbackEnv sCallbackEnv(__func__);
-  if (!sCallbackEnv.valid()) return status;
-
   jobject playStatus =
       sCallbackEnv->CallObjectMethod(mJavaInterface, method_getPlaybackStatus);
   jclass class_playStatus = sCallbackEnv->GetObjectClass(playStatus);
@@ -425,8 +456,9 @@
 
 static std::string getCurrentMediaId() {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
-  if (!sCallbackEnv.valid()) return "";
+  if (!sCallbackEnv.valid() || !mJavaInterface) return "";
 
   jstring media_id = (jstring)sCallbackEnv->CallObjectMethod(
       mJavaInterface, method_getCurrentMediaId);
@@ -440,8 +472,9 @@
 
 static std::vector<SongInfo> getNowPlayingList() {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
-  if (!sCallbackEnv.valid()) return std::vector<SongInfo>();
+  if (!sCallbackEnv.valid() || !mJavaInterface) return std::vector<SongInfo>();
 
   jobject song_list =
       sCallbackEnv->CallObjectMethod(mJavaInterface, method_getNowPlayingList);
@@ -468,9 +501,9 @@
 
 static uint16_t getCurrentPlayerId() {
   ALOGD("%s", __func__);
-
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
-  if (!sCallbackEnv.valid()) return 0u;
+  if (!sCallbackEnv.valid() || !mJavaInterface) return 0u;
 
   jint id =
       sCallbackEnv->CallIntMethod(mJavaInterface, method_getCurrentPlayerId);
@@ -480,7 +513,10 @@
 
 static std::vector<MediaPlayerInfo> getMediaPlayerList() {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface)
+    return std::vector<MediaPlayerInfo>();
 
   jobject player_list = (jobject)sCallbackEnv->CallObjectMethod(
       mJavaInterface, method_getMediaPlayerList);
@@ -535,7 +571,9 @@
 
 static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb cb) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   set_browsed_player_cb = cb;
   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setBrowsedPlayer,
@@ -631,7 +669,9 @@
 static void getFolderItems(uint16_t player_id, std::string media_id,
                            GetFolderItemsCb cb) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   // TODO (apanicke): Fix a potential media_id collision if two media players
   // use the same media_id scheme or two devices browse the same content.
@@ -645,7 +685,9 @@
 static void playItem(uint16_t player_id, bool now_playing,
                      std::string media_id) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   jstring j_media_id = sCallbackEnv->NewStringUTF(media_id.c_str());
   sCallbackEnv->CallVoidMethod(mJavaInterface, method_playItem, player_id,
@@ -654,7 +696,9 @@
 
 static void setActiveDevice(const RawAddress& address) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setActiveDevice,
@@ -663,7 +707,9 @@
 
 static void volumeDeviceConnected(const RawAddress& address) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
   sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceConnected,
@@ -677,7 +723,9 @@
     const RawAddress& address,
     ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   volumeCallbackMap.emplace(address, cb);
 
@@ -688,7 +736,9 @@
 
 static void volumeDeviceDisconnected(const RawAddress& address) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   volumeCallbackMap.erase(address);
 
@@ -706,7 +756,9 @@
 
 static void setVolume(int8_t volume) {
   ALOGD("%s", __func__);
+  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
   CallbackEnv sCallbackEnv(__func__);
+  if (!sCallbackEnv.valid() || !mJavaInterface) return;
 
   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setVolume, volume);
 }