Merge "BLE: Don't start scan if the same Pi scan is running."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d51a9b9..92ecae6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -317,6 +317,16 @@
                 <action android:name="android.media.browse.MediaBrowserService" />
             </intent-filter>
         </service>
+
+        <activity
+            android:name=".BluetoothPrefs"
+            android:exported="@bool/profile_supported_a2dp_sink"
+            android:enabled="@bool/profile_supported_a2dp_sink">
+            <intent-filter>
+                <action android:name="android.intent.action.APPLICATION_PREFERENCES"/>
+            </intent-filter>
+        </activity>
+
         <service
             android:process="@string/process"
             android:name = ".avrcp.AvrcpTargetService"
diff --git a/jni/Android.bp b/jni/Android.bp
index ec72acf..39b9f3f 100644
--- a/jni/Android.bp
+++ b/jni/Android.bp
@@ -2,7 +2,6 @@
     name: "libbluetooth_jni",
     compile_multilib: "first",
     srcs: [
-        "bluetooth_socket_manager.cc",
         "com_android_bluetooth_btservice_AdapterService.cpp",
         "com_android_bluetooth_hfp.cpp",
         "com_android_bluetooth_hfpclient.cpp",
@@ -16,18 +15,13 @@
         "com_android_bluetooth_pan.cpp",
         "com_android_bluetooth_gatt.cpp",
         "com_android_bluetooth_sdp.cpp",
-        "IUserManager.cc",
-        "permission_helpers.cc",
     ],
     header_libs: ["libbluetooth_headers"],
     include_dirs: [
         "system/bt/types",
     ],
     shared_libs: [
-        "libandroid_runtime",
         "libbase",
-        "libbinder",
-        "libbluetooth-binder",
         "libchrome",
         "libnativehelper",
         "liblog",
diff --git a/jni/IUserManager.cc b/jni/IUserManager.cc
deleted file mode 100644
index 0e36292..0000000
--- a/jni/IUserManager.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * 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.
- */
-
-#define LOG_TAG "IUserManager"
-#include <binder/Parcel.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Log.h>
-
-#include "IUserManager.h"
-
-namespace android {
-
-class BpUserManager : public BpInterface<IUserManager> {
- public:
-  explicit BpUserManager(const sp<IBinder>& impl)
-      : BpInterface<IUserManager>(impl) {}
-  virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
-    Parcel data, reply;
-    data.writeInterfaceToken(IUserManager::getInterfaceDescriptor());
-    data.writeInt32(user_id);
-    status_t rc =
-        remote()->transact(GET_CREDENTIAL_OWNER_PROFILE, data, &reply, 0);
-    if (rc != NO_ERROR) {
-      ALOGE("%s: failed (%d)\n", __func__, rc);
-      return -1;
-    }
-
-    int32_t exception = reply.readExceptionCode();
-    if (exception != 0) {
-      ALOGE("%s: got exception (%d)\n", __func__, exception);
-      return -1;
-    }
-
-    return reply.readInt32();
-  }
-
-  virtual int32_t getProfileParentId(int32_t user_handle) {
-    Parcel data, reply;
-    data.writeInterfaceToken(IUserManager::getInterfaceDescriptor());
-    data.writeInt32(user_handle);
-    status_t rc = remote()->transact(GET_PROFILE_PARENT_ID, data, &reply, 0);
-    if (rc != NO_ERROR) {
-      ALOGE("%s: failed (%d)\n", __func__, rc);
-      return -1;
-    }
-
-    int32_t exception = reply.readExceptionCode();
-    if (exception != 0) {
-      ALOGE("%s: got exception (%d)\n", __func__, exception);
-      return -1;
-    }
-
-    return reply.readInt32();
-  }
-};
-
-IMPLEMENT_META_INTERFACE(UserManager, "android.os.IUserManager");
-
-};  // namespace android
diff --git a/jni/IUserManager.h b/jni/IUserManager.h
deleted file mode 100644
index 2164d9a..0000000
--- a/jni/IUserManager.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef IUSERMANAGER_H_
-#define IUSERMANAGER_H_
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <inttypes.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-/*
- * Communication channel to UserManager
- */
-class IUserManager : public IInterface {
- public:
-  // must be kept in sync with IUserManager.aidl
-  enum {
-    GET_CREDENTIAL_OWNER_PROFILE = IBinder::FIRST_CALL_TRANSACTION + 0,
-    GET_PROFILE_PARENT_ID,
-  };
-
-  virtual int32_t getCredentialOwnerProfile(int32_t user_id) = 0;
-  virtual int32_t getProfileParentId(int32_t user_handle) = 0;
-
-  DECLARE_META_INTERFACE(UserManager);
-};
-
-};  // namespace android
-
-#endif  // IUSERMANAGER_H_
diff --git a/jni/bluetooth_socket_manager.cc b/jni/bluetooth_socket_manager.cc
deleted file mode 100644
index ba45aa5..0000000
--- a/jni/bluetooth_socket_manager.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * 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.
- */
-
-#include "bluetooth_socket_manager.h"
-#include "permission_helpers.h"
-
-#include <base/logging.h>
-#include <binder/IPCThreadState.h>
-
-using ::android::String8;
-using ::android::binder::Status;
-using ::android::os::ParcelFileDescriptor;
-using ::android::os::ParcelUuid;
-
-namespace android {
-namespace bluetooth {
-
-Status BluetoothSocketManagerBinderServer::connectSocket(
-    const BluetoothDevice& device, int32_t type,
-    const std::unique_ptr<ParcelUuid>& uuid, int32_t port, int32_t flag,
-    std::unique_ptr<ParcelFileDescriptor>* _aidl_return) {
-  if (!isCallerActiveUserOrManagedProfile()) {
-    LOG(WARNING) << "connectSocket() - Not allowed for non-active users";
-    return Status::fromExceptionCode(
-        Status::EX_SECURITY, String8("Not allowed for non-active users"));
-  }
-
-  ENFORCE_PERMISSION(PERMISSION_BLUETOOTH);
-
-  IPCThreadState* ipc = IPCThreadState::self();
-
-  int socket_fd = -1;
-  bt_status_t status = socketInterface->connect(
-      &device.address, (btsock_type_t)type, uuid ? &uuid->uuid : nullptr, port,
-      &socket_fd, flag, ipc->getCallingUid());
-  if (status != BT_STATUS_SUCCESS) {
-    LOG(ERROR) << "Socket connection failed: " << +status;
-    socket_fd = -1;
-  }
-
-  if (socket_fd < 0) {
-    LOG(ERROR) << "Fail to create file descriptor on socket fd";
-    return Status::ok();
-  }
-
-  _aidl_return->reset(
-      new ParcelFileDescriptor(android::base::unique_fd(socket_fd)));
-  return Status::ok();
-}
-
-Status BluetoothSocketManagerBinderServer::createSocketChannel(
-    int32_t type, const std::unique_ptr<::android::String16>& serviceName,
-    const std::unique_ptr<ParcelUuid>& uuid, int32_t port, int32_t flag,
-    std::unique_ptr<ParcelFileDescriptor>* _aidl_return) {
-  if (!isCallerActiveUserOrManagedProfile()) {
-    LOG(WARNING) << "createSocketChannel() - Not allowed for non-active users";
-    return Status::fromExceptionCode(
-        Status::EX_SECURITY, String8("Not allowed for non-active users"));
-  }
-
-  ENFORCE_PERMISSION(PERMISSION_BLUETOOTH);
-
-  VLOG(1) << __func__ << ": SOCK FLAG=" << flag;
-
-  IPCThreadState* ipc = IPCThreadState::self();
-  int socket_fd = -1;
-
-  const std::string payload_url{};
-
-  bt_status_t status = socketInterface->listen(
-      (btsock_type_t)type,
-      serviceName ? String8{*serviceName}.c_str() : nullptr,
-      uuid ? &uuid->uuid : nullptr, port, &socket_fd, flag,
-      ipc->getCallingUid());
-
-  if (status != BT_STATUS_SUCCESS) {
-    LOG(ERROR) << "Socket listen failed: " << +status;
-    socket_fd = -1;
-  }
-
-  if (socket_fd < 0) {
-    LOG(ERROR) << "Failed to create file descriptor on socket fd";
-    return Status::ok();
-  }
-
-  _aidl_return->reset(
-      new ParcelFileDescriptor(android::base::unique_fd(socket_fd)));
-  return Status::ok();
-}
-
-Status BluetoothSocketManagerBinderServer::requestMaximumTxDataLength(
-    const BluetoothDevice& device) {
-  if (!isCallerActiveUserOrManagedProfile()) {
-    LOG(WARNING) << __func__ << ": Not allowed for non-active users";
-    return Status::fromExceptionCode(
-        Status::EX_SECURITY, String8("Not allowed for non-active users"));
-  }
-
-  ENFORCE_PERMISSION(PERMISSION_BLUETOOTH);
-
-  VLOG(1) << __func__;
-
-  socketInterface->request_max_tx_data_length(device.address);
-  return Status::ok();
-}
-
-}  // namespace bluetooth
-}  // namespace android
diff --git a/jni/bluetooth_socket_manager.h b/jni/bluetooth_socket_manager.h
deleted file mode 100644
index e732dcc..0000000
--- a/jni/bluetooth_socket_manager.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * 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.
- */
-
-#include <android/bluetooth/BnBluetoothSocketManager.h>
-#include <android/bluetooth/IBluetoothSocketManager.h>
-#include <base/macros.h>
-#include <binder/IBinder.h>
-#include <binder/IInterface.h>
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sock.h>
-
-namespace android {
-namespace bluetooth {
-
-using ::android::binder::Status;
-
-class BluetoothSocketManagerBinderServer : public BnBluetoothSocketManager {
- public:
-  explicit BluetoothSocketManagerBinderServer(
-      const btsock_interface_t* socketInterface)
-      : socketInterface(socketInterface) {}
-  ~BluetoothSocketManagerBinderServer() override = default;
-
-  Status connectSocket(
-      const BluetoothDevice& device, int32_t type,
-      const std::unique_ptr<::android::os::ParcelUuid>& uuid, int32_t port,
-      int32_t flag,
-      std::unique_ptr<::android::os::ParcelFileDescriptor>* _aidl_return);
-
-  Status createSocketChannel(
-      int32_t type, const std::unique_ptr<::android::String16>& serviceName,
-      const std::unique_ptr<::android::os::ParcelUuid>& uuid, int32_t port,
-      int32_t flag,
-      std::unique_ptr<::android::os::ParcelFileDescriptor>* _aidl_return)
-      override;
-
-  Status requestMaximumTxDataLength(const BluetoothDevice& device);
-
- private:
-  const btsock_interface_t* socketInterface;
-  DISALLOW_COPY_AND_ASSIGN(BluetoothSocketManagerBinderServer);
-};
-}  // namespace bluetooth
-}  // namespace android
\ No newline at end of file
diff --git a/jni/com_android_bluetooth.h b/jni/com_android_bluetooth.h
index 2076779..ac3c220 100644
--- a/jni/com_android_bluetooth.h
+++ b/jni/com_android_bluetooth.h
@@ -18,18 +18,17 @@
 #ifndef COM_ANDROID_BLUETOOTH_H
 #define COM_ANDROID_BLUETOOTH_H
 
-#include <nativehelper/JNIHelp.h>
-#include "android_runtime/AndroidRuntime.h"
-#include "android_runtime/Log.h"
 #include "hardware/bluetooth.h"
 #include "hardware/hardware.h"
 #include "jni.h"
+#include "jni_logging.h"
 #include "nativehelper/ScopedLocalRef.h"
 #include "utils/Log.h"
 
 namespace android {
 
 JNIEnv* getCallbackEnv();
+bool isCallbackThread();
 
 class CallbackEnv {
 public:
@@ -46,10 +45,9 @@
     }
 
     bool valid() const {
-      JNIEnv *env = AndroidRuntime::getJNIEnv();
-      if (!mCallbackEnv || (mCallbackEnv != env)) {
-          ALOGE("%s: Callback env fail: env: %p, callback: %p", mName, env, mCallbackEnv);
-          return false;
+      if (!mCallbackEnv || !isCallbackThread()) {
+        ALOGE("%s: Callback env fail", mName);
+        return false;
       }
       return true;
     }
diff --git a/jni/com_android_bluetooth_a2dp.cpp b/jni/com_android_bluetooth_a2dp.cpp
index af125bd..7ca0aa5 100644
--- a/jni/com_android_bluetooth_a2dp.cpp
+++ b/jni/com_android_bluetooth_a2dp.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_av.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_a2dp_sink.cpp b/jni/com_android_bluetooth_a2dp_sink.cpp
index 91de5af..8518944 100644
--- a/jni/com_android_bluetooth_a2dp_sink.cpp
+++ b/jni/com_android_bluetooth_a2dp_sink.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_av.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_avrcp_controller.cpp b/jni/com_android_bluetooth_avrcp_controller.cpp
index 2d9e87b..112e826 100644
--- a/jni/com_android_bluetooth_avrcp_controller.cpp
+++ b/jni/com_android_bluetooth_avrcp_controller.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_rc.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_avrcp_target.cpp b/jni/com_android_bluetooth_avrcp_target.cpp
index a6c8d28..22c954c 100644
--- a/jni/com_android_bluetooth_avrcp_target.cpp
+++ b/jni/com_android_bluetooth_avrcp_target.cpp
@@ -23,7 +23,6 @@
 #include <shared_mutex>
 #include <vector>
 
-#include "android_runtime/AndroidRuntime.h"
 #include "avrcp.h"
 #include "com_android_bluetooth.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 0ac85f4..34eb2bb 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -15,18 +15,11 @@
  */
 
 #define LOG_TAG "BluetoothServiceJni"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_runtime/Log.h"
-#include "bluetooth_socket_manager.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_sock.h"
-#include "permission_helpers.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
 
-#include <android_util_Binder.h>
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
 #include <cutils/properties.h>
 #include <dlfcn.h>
 #include <errno.h>
@@ -40,7 +33,9 @@
 #include <hardware/bluetooth.h>
 #include <mutex>
 
-using android::bluetooth::BluetoothSocketManagerBinderServer;
+#include <pthread.h>
+
+using bluetooth::Uuid;
 
 namespace android {
 // OOB_LE_BD_ADDR_SIZE is 6 bytes addres + 1 byte address type
@@ -49,6 +44,8 @@
 #define OOB_LE_SC_C_SIZE 16
 #define OOB_LE_SC_R_SIZE 16
 
+const jint INVALID_FD = -1;
+
 static jmethodID method_stateChangeCallback;
 static jmethodID method_adapterPropertyChangedCallback;
 static jmethodID method_devicePropertyChangedCallback;
@@ -70,21 +67,23 @@
 
 static const bt_interface_t* sBluetoothInterface = NULL;
 static const btsock_interface_t* sBluetoothSocketInterface = NULL;
+static JavaVM* vm = NULL;
 static JNIEnv* callbackEnv = NULL;
+static pthread_t sCallbackThread;
+static bool sHaveCallbackThread;
 
 static jobject sJniAdapterServiceObj;
 static jobject sJniCallbacksObj;
 static jfieldID sJniCallbacksField;
 
-namespace {
-android::sp<BluetoothSocketManagerBinderServer> sSocketManager = NULL;
-std::mutex sSocketManagerMutex;
-}
-
 const bt_interface_t* getBluetoothInterface() { return sBluetoothInterface; }
 
 JNIEnv* getCallbackEnv() { return callbackEnv; }
 
+bool isCallbackThread() {
+  return sHaveCallbackThread && pthread_equal(sCallbackThread, pthread_self());
+}
+
 static void adapter_state_change_callback(bt_state_t status) {
   CallbackEnv sCallbackEnv(__func__);
   if (!sCallbackEnv.valid()) return;
@@ -389,7 +388,6 @@
 }
 
 static void callback_thread_event(bt_cb_thread_evt event) {
-  JavaVM* vm = AndroidRuntime::getJavaVM();
   if (event == ASSOCIATE_JVM) {
     JavaVMAttachArgs args;
     char name[] = "BT Service Callback Thread";
@@ -397,13 +395,16 @@
     args.name = name;
     args.group = NULL;
     vm->AttachCurrentThread(&callbackEnv, &args);
+    sHaveCallbackThread = true;
+    sCallbackThread = pthread_self();
     ALOGV("Callback thread attached: %p", callbackEnv);
   } else if (event == DISASSOCIATE_JVM) {
-    if (callbackEnv != AndroidRuntime::getJNIEnv()) {
+    if (!isCallbackThread()) {
       ALOGE("Callback: '%s' is not called on the correct thread", __func__);
       return;
     }
     vm->DetachCurrentThread();
+    sHaveCallbackThread = false;
   }
 }
 
@@ -463,8 +464,7 @@
 
 class JNIThreadAttacher {
  public:
-  JNIThreadAttacher() : vm_(nullptr), env_(nullptr) {
-    vm_ = AndroidRuntime::getJavaVM();
+  JNIThreadAttacher(JavaVM* vm) : vm_(vm), env_(nullptr) {
     status_ = vm_->GetEnv((void**)&env_, JNI_VERSION_1_6);
 
     if (status_ != JNI_OK && status_ != JNI_EDETACHED) {
@@ -510,7 +510,7 @@
 
 static bool set_wake_alarm_callout(uint64_t delay_millis, bool should_wake,
                                    alarm_cb cb, void* data) {
-  JNIThreadAttacher attacher;
+  JNIThreadAttacher attacher(vm);
   JNIEnv* env = attacher.getEnv();
 
   if (env == nullptr) {
@@ -534,7 +534,7 @@
 }
 
 static int acquire_wake_lock_callout(const char* lock_name) {
-  JNIThreadAttacher attacher;
+  JNIThreadAttacher attacher(vm);
   JNIEnv* env = attacher.getEnv();
 
   if (env == nullptr) {
@@ -559,7 +559,7 @@
 }
 
 static int release_wake_lock_callout(const char* lock_name) {
-  JNIThreadAttacher attacher;
+  JNIThreadAttacher attacher(vm);
   JNIEnv* env = attacher.getEnv();
 
   if (env == nullptr) {
@@ -611,22 +611,20 @@
   void* handle = dlopen(path, RTLD_NOW);
   if (!handle) {
     const char* err_str = dlerror();
-    LOG(ERROR) << __func__ << ": failed to load Bluetooth library, error="
-               << (err_str ? err_str : "error unknown");
+    ALOGE("%s: failed to load Bluetooth library, error=%s", __func__,
+          err_str ? err_str : "error unknown");
     goto error;
   }
 
   // Get the address of the bt_interface_t.
   itf = (bt_interface_t*)dlsym(handle, sym);
   if (!itf) {
-    LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library "
-               << sym;
+    ALOGE("%s: failed to load symbol from Bluetooth library %s", __func__, sym);
     goto error;
   }
 
   // Success.
-  LOG(INFO) << __func__ << " loaded HAL: btinterface=" << itf
-            << ", handle=" << handle;
+  ALOGI("%s: loaded Bluetooth library successfully", __func__);
   *interface = itf;
   return 0;
 
@@ -678,6 +676,10 @@
   method_energyInfo = env->GetMethodID(
       clazz, "energyInfoCallback", "(IIJJJJ[Landroid/bluetooth/UidTraffic;)V");
 
+  if (env->GetJavaVM(&vm) != JNI_OK) {
+    ALOGE("Could not get JavaVM");
+  }
+
   if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) {
     ALOGE("No Bluetooth Library found");
   }
@@ -746,10 +748,6 @@
     env->DeleteGlobalRef(android_bluetooth_UidTraffic.clazz);
     android_bluetooth_UidTraffic.clazz = NULL;
   }
-  {
-    std::lock_guard<std::mutex> lock(sSocketManagerMutex);
-    sSocketManager = nullptr;
-  }
   return JNI_TRUE;
 }
 
@@ -1123,23 +1121,6 @@
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jobject getSocketManagerNative(JNIEnv* env) {
-  std::lock_guard<std::mutex> lock(sSocketManagerMutex);
-  if (!sSocketManager.get()) {
-    sSocketManager =
-        new BluetoothSocketManagerBinderServer(sBluetoothSocketInterface);
-  }
-  return javaObjectForIBinder(env, IInterface::asBinder(sSocketManager));
-}
-
-static void setSystemUiUidNative(JNIEnv* env, jobject obj, jint uid) {
-  android::bluetooth::systemUiUid = uid;
-}
-
-static void setForegroundUserIdNative(JNIEnv* env, jclass clazz, jint id) {
-  android::bluetooth::foregroundUserId = id;
-}
-
 static int readEnergyInfo() {
   ALOGV("%s", __func__);
 
@@ -1237,6 +1218,85 @@
   return output_bytes;
 }
 
+static jint connectSocketNative(JNIEnv* env, jobject obj, jbyteArray address,
+                                jint type, jbyteArray uuid, jint port,
+                                jint flag, jint callingUid) {
+  int socket_fd = INVALID_FD;
+  jbyte* addr = nullptr;
+  jbyte* uuidBytes = nullptr;
+  Uuid btUuid;
+
+  if (!sBluetoothSocketInterface) {
+    goto done;
+  }
+  addr = env->GetByteArrayElements(address, nullptr);
+  uuidBytes = env->GetByteArrayElements(uuid, nullptr);
+  if (addr == nullptr || uuidBytes == nullptr) {
+    jniThrowIOException(env, EINVAL);
+    goto done;
+  }
+
+  btUuid = Uuid::From128BitBE((uint8_t*)uuidBytes);
+  if (sBluetoothSocketInterface->connect((RawAddress*)addr, (btsock_type_t)type,
+                                         &btUuid, port, &socket_fd, flag,
+                                         callingUid) != BT_STATUS_SUCCESS) {
+    socket_fd = INVALID_FD;
+  }
+
+done:
+  if (addr) env->ReleaseByteArrayElements(address, addr, 0);
+  if (uuidBytes) env->ReleaseByteArrayElements(uuid, uuidBytes, 0);
+  return socket_fd;
+}
+
+static jint createSocketChannelNative(JNIEnv* env, jobject obj, jint type,
+                                      jstring serviceName, jbyteArray uuid,
+                                      jint port, jint flag, jint callingUid) {
+  int socket_fd = INVALID_FD;
+  jbyte* uuidBytes = nullptr;
+  Uuid btUuid;
+  const char* nativeServiceName = nullptr;
+
+  if (!sBluetoothSocketInterface) {
+    goto done;
+  }
+  uuidBytes = env->GetByteArrayElements(uuid, nullptr);
+  nativeServiceName = env->GetStringUTFChars(serviceName, nullptr);
+  if (uuidBytes == nullptr) {
+    jniThrowIOException(env, EINVAL);
+    goto done;
+  }
+  btUuid = Uuid::From128BitBE((uint8_t*)uuidBytes);
+
+  if (sBluetoothSocketInterface->listen((btsock_type_t)type, nativeServiceName,
+                                        &btUuid, port, &socket_fd, flag,
+                                        callingUid) != BT_STATUS_SUCCESS) {
+    socket_fd = INVALID_FD;
+  }
+
+done:
+  if (uuidBytes) env->ReleaseByteArrayElements(uuid, uuidBytes, 0);
+  if (nativeServiceName)
+    env->ReleaseStringUTFChars(serviceName, nativeServiceName);
+  return socket_fd;
+}
+
+static void requestMaximumTxDataLengthNative(JNIEnv* env, jobject obj,
+                                             jbyteArray address) {
+  if (!sBluetoothSocketInterface) {
+    return;
+  }
+  jbyte* addr = env->GetByteArrayElements(address, nullptr);
+  if (addr == nullptr) {
+    jniThrowIOException(env, EINVAL);
+    return;
+  }
+
+  RawAddress addressVar = *(RawAddress*)addr;
+  sBluetoothSocketInterface->request_max_tx_data_length(addressVar);
+  env->ReleaseByteArrayElements(address, addr, 1);
+}
+
 static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     {"classInitNative", "()V", (void*)classInitNative},
@@ -1260,10 +1320,6 @@
     {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative},
     {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative},
     {"getRemoteServicesNative", "([B)Z", (void*)getRemoteServicesNative},
-    {"getSocketManagerNative", "()Landroid/os/IBinder;",
-     (void*)getSocketManagerNative},
-    {"setSystemUiUidNative", "(I)V", (void*)setSystemUiUidNative},
-    {"setForegroundUserIdNative", "(I)V", (void*)setForegroundUserIdNative},
     {"alarmFiredNative", "()V", (void*)alarmFiredNative},
     {"readEnergyInfo", "()I", (void*)readEnergyInfo},
     {"dumpNative", "(Ljava/io/FileDescriptor;[Ljava/lang/String;)V",
@@ -1272,7 +1328,12 @@
     {"factoryResetNative", "()Z", (void*)factoryResetNative},
     {"interopDatabaseClearNative", "()V", (void*)interopDatabaseClearNative},
     {"interopDatabaseAddNative", "(I[BI)V", (void*)interopDatabaseAddNative},
-    {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative}};
+    {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative},
+    {"connectSocketNative", "([BI[BIII)I", (void*)connectSocketNative},
+    {"createSocketChannelNative", "(ILjava/lang/String;[BIII)I",
+     (void*)createSocketChannelNative},
+    {"requestMaximumTxDataLengthNative", "([B)V",
+     (void*)requestMaximumTxDataLengthNative}};
 
 int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
   return jniRegisterNativeMethods(
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp
index 4521515..64db277 100644
--- a/jni/com_android_bluetooth_gatt.cpp
+++ b/jni/com_android_bluetooth_gatt.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_gatt.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_hearing_aid.cpp b/jni/com_android_bluetooth_hearing_aid.cpp
index f93a42a..b459ae2 100644
--- a/jni/com_android_bluetooth_hearing_aid.cpp
+++ b/jni/com_android_bluetooth_hearing_aid.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "base/logging.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_hearing_aid.h"
diff --git a/jni/com_android_bluetooth_hfp.cpp b/jni/com_android_bluetooth_hfp.cpp
index 16bf961..9918c87 100644
--- a/jni/com_android_bluetooth_hfp.cpp
+++ b/jni/com_android_bluetooth_hfp.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bluetooth_headset_callbacks.h"
 #include "hardware/bluetooth_headset_interface.h"
diff --git a/jni/com_android_bluetooth_hfpclient.cpp b/jni/com_android_bluetooth_hfpclient.cpp
index 7acf402..83c6b20 100644
--- a/jni/com_android_bluetooth_hfpclient.cpp
+++ b/jni/com_android_bluetooth_hfpclient.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "BluetoothHeadsetClientServiceJni"
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_hf_client.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_hid_device.cpp b/jni/com_android_bluetooth_hid_device.cpp
index 403e904..17b6e97 100644
--- a/jni/com_android_bluetooth_hid_device.cpp
+++ b/jni/com_android_bluetooth_hid_device.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_hd.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_hid_host.cpp b/jni/com_android_bluetooth_hid_host.cpp
index b8f4d65..cab5e33 100644
--- a/jni/com_android_bluetooth_hid_host.cpp
+++ b/jni/com_android_bluetooth_hid_host.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 1
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_hh.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_pan.cpp b/jni/com_android_bluetooth_pan.cpp
index 85107a0..d423eab 100644
--- a/jni/com_android_bluetooth_pan.cpp
+++ b/jni/com_android_bluetooth_pan.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_pan.h"
 #include "utils/Log.h"
diff --git a/jni/com_android_bluetooth_sdp.cpp b/jni/com_android_bluetooth_sdp.cpp
index 827db71..90e3fc1 100644
--- a/jni/com_android_bluetooth_sdp.cpp
+++ b/jni/com_android_bluetooth_sdp.cpp
@@ -18,7 +18,6 @@
 
 #define LOG_NDEBUG 0
 
-#include "android_runtime/AndroidRuntime.h"
 #include "com_android_bluetooth.h"
 #include "hardware/bt_sdp.h"
 #include "utils/Log.h"
diff --git a/jni/jni_logging.h b/jni/jni_logging.h
new file mode 100644
index 0000000..c2b9bd9
--- /dev/null
+++ b/jni/jni_logging.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * 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.
+ */
+#pragma once
+
+#include <nativehelper/JNIHelp.h>
+
+/* Logging macros imported from android_runtime/Log.h
+ *
+ * Logs an exception.  If the exception is omitted or NULL, logs the current
+ * exception from the JNI environment, if any.
+ */
+#define LOG_EX(env, priority, tag, ...) \
+  jniLogException(env, ANDROID_##priority, tag, ##__VA_ARGS__)
+#define LOGV_EX(env, ...) LOG_EX(env, LOG_VERBOSE, LOG_TAG, ##__VA_ARGS__)
+#define LOGD_EX(env, ...) LOG_EX(env, LOG_DEBUG, LOG_TAG, ##__VA_ARGS__)
+#define LOGI_EX(env, ...) LOG_EX(env, LOG_INFO, LOG_TAG, ##__VA_ARGS__)
+#define LOGW_EX(env, ...) LOG_EX(env, LOG_WARN, LOG_TAG, ##__VA_ARGS__)
+#define LOGE_EX(env, ...) LOG_EX(env, LOG_ERROR, LOG_TAG, ##__VA_ARGS__)
diff --git a/jni/permission_helpers.cc b/jni/permission_helpers.cc
deleted file mode 100644
index 26a8a89..0000000
--- a/jni/permission_helpers.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * 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.
- */
-
-#include "permission_helpers.h"
-
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include "IUserManager.h"
-
-using ::android::binder::Status;
-
-namespace android {
-namespace bluetooth {
-
-uid_t foregroundUserId;
-uid_t systemUiUid;
-static uid_t SYSTEM_UID = 1000;
-constexpr int PER_USER_RANGE = 100000;
-
-Status checkPermission(const char* permission) {
-  int32_t pid;
-  int32_t uid;
-
-  if (android::checkCallingPermission(String16(permission), &pid, &uid)) {
-    return Status::ok();
-  }
-
-  auto err = ::base::StringPrintf("UID %d / PID %d lacks permission %s", uid,
-                                  pid, permission);
-  return Status::fromExceptionCode(Status::EX_SECURITY, String8(err.c_str()));
-}
-
-bool isCallerActiveUser() {
-  IPCThreadState* ipcState = IPCThreadState::selfOrNull();
-  if (!ipcState) return true;  // It's a local call
-
-  uid_t callingUid = ipcState->getCallingUid();
-  uid_t callingUser = callingUid / PER_USER_RANGE;
-  if (callingUid == getuid()) return true;  // It's a local call
-
-  return (foregroundUserId == callingUser) || (systemUiUid == callingUid) ||
-         (SYSTEM_UID == callingUid);
-}
-
-bool isCallerActiveUserOrManagedProfile() {
-  IPCThreadState* ipcState = IPCThreadState::selfOrNull();
-  if (!ipcState) return true;  // It's a local call
-
-  uid_t callingUid = ipcState->getCallingUid();
-  uid_t callingUser = callingUid / PER_USER_RANGE;
-  if (callingUid == getuid()) return true;  // It's a local call
-
-  if ((foregroundUserId == callingUser) || (systemUiUid == callingUid) ||
-      (SYSTEM_UID == callingUid))
-    return true;
-
-  uid_t parentUser = callingUser;
-
-  sp<IServiceManager> sm = defaultServiceManager();
-  sp<IBinder> binder = sm->getService(String16("user"));
-  sp<IUserManager> um = interface_cast<IUserManager>(binder);
-  if (um != NULL) {
-    // Must use Bluetooth process identity when making call to get parent user
-    int64_t ident = ipcState->clearCallingIdentity();
-    parentUser = um->getProfileParentId(callingUser);
-    ipcState->restoreCallingIdentity(ident);
-  }
-
-  return foregroundUserId == parentUser;
-}
-
-}  // namespace bluetooth
-}  // namespace android
diff --git a/jni/permission_helpers.h b/jni/permission_helpers.h
deleted file mode 100644
index 952281f..0000000
--- a/jni/permission_helpers.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * 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.
- */
-#pragma once
-
-#include <binder/Status.h>
-
-namespace android {
-namespace bluetooth {
-
-const char PERMISSION_BLUETOOTH[] = "android.permission.BLUETOOTH";
-const char PERMISSION_BLUETOOTH_ADMIN[] = "android.permission.BLUETOOTH_ADMIN";
-const char PERMISSION_BLUETOOTH_PRIVILEGED[] =
-    "android.permission.BLUETOOTH_PRIVILEGED";
-
-extern uid_t foregroundUserId;
-extern uid_t systemUiUid;
-
-android::binder::Status checkPermission(const char* permission);
-bool isCallerActiveUser();
-bool isCallerActiveUserOrManagedProfile();
-
-}  // namespace bluetooth
-}  // namespace android
-
-#define ENFORCE_PERMISSION(permission)                     \
-  {                                                        \
-    android::binder::Status status =                       \
-        android::bluetooth::checkPermission((permission)); \
-    if (!status.isOk()) {                                  \
-      return status;                                       \
-    }                                                      \
-  }
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1389e0d..0204f98 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -249,4 +249,5 @@
     <string name="bluetooth_disconnected">Bluetooth audio disconnected"</string>
     <string name="a2dp_sink_mbs_label">Bluetooth Audio</string>
     <string name="bluetooth_opp_file_limit_exceeded">Files bigger than 4GB cannot be transferred</string>
+    <string name="bluetooth_connect_action">Connect to Bluetooth</string>
 </resources>
diff --git a/src/com/android/bluetooth/BluetoothPrefs.java b/src/com/android/bluetooth/BluetoothPrefs.java
new file mode 100644
index 0000000..2c7c87a
--- /dev/null
+++ b/src/com/android/bluetooth/BluetoothPrefs.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Activity that routes to Bluetooth settings when launched
+ */
+public class BluetoothPrefs extends Activity {
+
+    public static final String BLUETOOTH_SETTING_ACTION = "android.settings.BLUETOOTH_SETTINGS";
+    public static final String BLUETOOTH_SETTING_CATEGORY = "android.intent.category.DEFAULT";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent launchIntent = new Intent();
+        launchIntent.setAction(BLUETOOTH_SETTING_ACTION);
+        launchIntent.addCategory(BLUETOOTH_SETTING_CATEGORY);
+        startActivity(launchIntent);
+        finish();
+    }
+}
diff --git a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index 23f1ce7..ae94a4d 100644
--- a/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -233,11 +233,7 @@
         mAddressedPlayer.updateCurrentTrack(null);
         mBrowseTree.mNowPlayingNode.setCached(false);
         BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
-        PlaybackStateCompat.Builder pbb = new PlaybackStateCompat.Builder();
-        pbb.setState(PlaybackStateCompat.STATE_ERROR, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN,
-                1.0f).setActions(0);
-        pbb.setErrorMessage(mService.getString(R.string.bluetooth_disconnected));
-        BluetoothMediaBrowserService.notifyChanged(pbb.build());
+        BluetoothMediaBrowserService.addressedPlayerChanged(null);
         mService.sBrowseTree.mRootNode.removeChild(
                 mBrowseTree.mRootNode);
         BluetoothMediaBrowserService.notifyChanged(mService
diff --git a/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java b/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
index b8a3337..a0b1224 100644
--- a/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
+++ b/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
@@ -16,6 +16,8 @@
 
 package com.android.bluetooth.avrcpcontroller;
 
+import android.app.PendingIntent;
+import android.content.Intent;
 import android.media.MediaMetadata;
 import android.media.browse.MediaBrowser.MediaItem;
 import android.os.Bundle;
@@ -29,6 +31,7 @@
 
 import androidx.media.MediaBrowserServiceCompat;
 
+import com.android.bluetooth.BluetoothPrefs;
 import com.android.bluetooth.R;
 
 import java.util.ArrayList;
@@ -60,6 +63,12 @@
     // Browsing related structures.
     private List<MediaSessionCompat.QueueItem> mMediaQueue = new ArrayList<>();
 
+    // Error messaging extras
+    public static final String ERROR_RESOLUTION_ACTION_INTENT =
+            "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+    public static final String ERROR_RESOLUTION_ACTION_LABEL =
+            "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
+
     /**
      * Initialize this BluetoothMediaBrowserService, creating our MediaSessionCompat, MediaPlayer
      * and MediaMetaData, and setting up mechanisms to talk with the AvrcpControllerService.
@@ -76,11 +85,7 @@
                 | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
         mSession.setQueueTitle(getString(R.string.bluetooth_a2dp_sink_queue_name));
         mSession.setQueue(mMediaQueue);
-        PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder();
-        playbackStateBuilder.setState(PlaybackStateCompat.STATE_ERROR,
-                PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 1.0f).setActions(0);
-        playbackStateBuilder.setErrorMessage(getString(R.string.bluetooth_disconnected));
-        mSession.setPlaybackState(playbackStateBuilder.build());
+        setErrorPlaybackState();
         sBluetoothMediaBrowserService = this;
     }
 
@@ -94,6 +99,24 @@
         }
     }
 
+    private void setErrorPlaybackState() {
+        Bundle extras = new Bundle();
+        extras.putString(ERROR_RESOLUTION_ACTION_LABEL,
+                getString(R.string.bluetooth_connect_action));
+        Intent launchIntent = new Intent();
+        launchIntent.setAction(BluetoothPrefs.BLUETOOTH_SETTING_ACTION);
+        launchIntent.addCategory(BluetoothPrefs.BLUETOOTH_SETTING_CATEGORY);
+        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0,
+                launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+        extras.putParcelable(ERROR_RESOLUTION_ACTION_INTENT, pendingIntent);
+        PlaybackStateCompat errorState = new PlaybackStateCompat.Builder()
+                .setErrorMessage(getString(R.string.bluetooth_disconnected))
+                .setExtras(extras)
+                .setState(PlaybackStateCompat.STATE_ERROR, 0, 0)
+                .build();
+        mSession.setPlaybackState(errorState);
+    }
+
     @Override
     public synchronized void onLoadChildren(final String parentMediaId,
             final Result<List<MediaBrowserCompat.MediaItem>> result) {
@@ -138,6 +161,9 @@
 
     static synchronized void addressedPlayerChanged(MediaSessionCompat.Callback callback) {
         if (sBluetoothMediaBrowserService != null) {
+            if (callback == null) {
+                sBluetoothMediaBrowserService.setErrorPlaybackState();
+            }
             sBluetoothMediaBrowserService.mSession.setCallback(callback);
         } else {
             Log.w(TAG, "addressedPlayerChanged Unavailable");
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 508eacf..e0452bf 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -198,6 +198,8 @@
     private SilenceDeviceManager mSilenceDeviceManager;
     private AppOpsManager mAppOps;
 
+    private BluetoothSocketManagerBinder mBluetoothSocketManagerBinder;
+
     /**
      * Register a {@link ProfileService} with AdapterService.
      *
@@ -432,6 +434,8 @@
                 Looper.getMainLooper());
         mSilenceDeviceManager.start();
 
+        mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);
+
         setAdapterService(this);
 
         // First call to getSharedPreferences will result in a file read into
@@ -454,7 +458,6 @@
                     "com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY,
                     UserHandle.USER_SYSTEM);
             Utils.setSystemUiUid(systemUiUid);
-            setSystemUiUidNative(systemUiUid);
         } catch (PackageManager.NameNotFoundException e) {
             // Some platforms, such as wearables do not have a system ui.
             Log.w(TAG, "Unable to resolve SystemUI's UID.", e);
@@ -465,7 +468,6 @@
                 filter, null, null);
         int fuid = ActivityManager.getCurrentUser();
         Utils.setForegroundUserId(fuid);
-        setForegroundUserIdNative(fuid);
     }
 
     @Override
@@ -498,7 +500,6 @@
             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
                 int fuid = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 Utils.setForegroundUserId(fuid);
-                setForegroundUserIdNative(fuid);
             }
         }
     };
@@ -737,6 +738,11 @@
             mProfileServicesState.clear();
         }
 
+        if (mBluetoothSocketManagerBinder != null) {
+            mBluetoothSocketManagerBinder.cleanUp();
+            mBluetoothSocketManagerBinder = null;
+        }
+
         if (mBinder != null) {
             mBinder.cleanup();
             mBinder = null;  //Do not remove. Otherwise Binder leak!
@@ -2378,12 +2384,7 @@
     }
 
     IBluetoothSocketManager getSocketManager() {
-        android.os.IBinder obj = getSocketManagerNative();
-        if (obj == null) {
-            return null;
-        }
-
-        return IBluetoothSocketManager.Stub.asInterface(obj);
+        return IBluetoothSocketManager.Stub.asInterface(mBluetoothSocketManagerBinder);
     }
 
     boolean factoryReset() {
@@ -2939,12 +2940,6 @@
 
     private native int readEnergyInfo();
 
-    private native IBinder getSocketManagerNative();
-
-    private native void setSystemUiUidNative(int systemUiUid);
-
-    private static native void setForegroundUserIdNative(int foregroundUserId);
-
     /*package*/
     native boolean factoryResetNative();
 
@@ -2960,6 +2955,14 @@
 
     private native byte[] obfuscateAddressNative(byte[] address);
 
+    /*package*/ native int connectSocketNative(
+            byte[] address, int type, byte[] uuid, int port, int flag, int callingUid);
+
+    /*package*/ native int createSocketChannelNative(
+            int type, String serviceName, byte[] uuid, int port, int flag, int callingUid);
+
+    /*package*/ native void requestMaximumTxDataLengthNative(byte[] address);
+
     // 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.
diff --git a/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java b/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
new file mode 100644
index 0000000..42595ab
--- /dev/null
+++ b/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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.bluetooth.BluetoothDevice;
+import android.bluetooth.IBluetoothSocketManager;
+import android.os.Binder;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelUuid;
+import com.android.bluetooth.Utils;
+
+class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub {
+    private static final String TAG = "BluetoothSocketManagerBinder";
+
+    private static final int INVALID_FD = -1;
+    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+    private AdapterService mService;
+
+    BluetoothSocketManagerBinder(AdapterService service) {
+        mService = service;
+    }
+
+    void cleanUp() {
+        mService = null;
+    }
+
+    @Override
+    public ParcelFileDescriptor connectSocket(
+            BluetoothDevice device, int type, ParcelUuid uuid, int port, int flag) {
+
+        enforceBluetoothAndActiveUser();
+
+        return marshalFd(mService.connectSocketNative(
+            Utils.getBytesFromAddress(device.getAddress()),
+            type,
+            Utils.uuidToByteArray(uuid),
+            port,
+            flag,
+            Binder.getCallingUid()));
+    }
+
+    @Override
+    public ParcelFileDescriptor createSocketChannel(
+            int type, String serviceName, ParcelUuid uuid, int port, int flag) {
+
+        enforceBluetoothAndActiveUser();
+
+        return marshalFd(mService.createSocketChannelNative(
+            type,
+            serviceName,
+            Utils.uuidToByteArray(uuid),
+            port,
+            flag,
+            Binder.getCallingUid()));
+
+    }
+
+    @Override
+    public void requestMaximumTxDataLength(BluetoothDevice device) {
+        enforceBluetoothAndActiveUser();
+
+        mService.requestMaximumTxDataLengthNative(Utils.getBytesFromAddress(device.getAddress()));
+    }
+
+    private void enforceBluetoothAndActiveUser() {
+        if (!Utils.checkCallerAllowManagedProfiles(mService)) {
+            throw new SecurityException("Not allowed for non-active user");
+        }
+        mService.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+    }
+
+    private static ParcelFileDescriptor marshalFd(int fd) {
+        if (fd == INVALID_FD) {
+            return null;
+        }
+        return ParcelFileDescriptor.adoptFd(fd);
+    }
+}
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 34543d6..203d271 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -340,25 +340,25 @@
                 Log.d(TAG, "Binder is dead - unregistering scanner (" + mScannerId + ")!");
             }
 
-            if (isScanClient(mScannerId)) {
-                ScanClient client = new ScanClient(mScannerId);
+            ScanClient client = getScanClient(mScannerId);
+            if (client != null) {
                 client.appDied = true;
                 stopScan(client.scannerId);
             }
         }
 
-        private boolean isScanClient(int clientIf) {
+        private ScanClient getScanClient(int clientIf) {
             for (ScanClient client : mScanManager.getRegularScanQueue()) {
                 if (client.scannerId == clientIf) {
-                    return true;
+                    return client;
                 }
             }
             for (ScanClient client : mScanManager.getBatchScanQueue()) {
                 if (client.scannerId == clientIf) {
-                    return true;
+                    return client;
                 }
             }
-            return false;
+            return null;
         }
     }
 
diff --git a/src/com/android/bluetooth/mapclient/MceStateMachine.java b/src/com/android/bluetooth/mapclient/MceStateMachine.java
index 867ab18..9b86aae 100644
--- a/src/com/android/bluetooth/mapclient/MceStateMachine.java
+++ b/src/com/android/bluetooth/mapclient/MceStateMachine.java
@@ -58,6 +58,7 @@
 import com.android.bluetooth.BluetoothMetricsProto;
 import com.android.bluetooth.btservice.MetricsLogger;
 import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.map.BluetoothMapbMessageMime;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IState;
 import com.android.internal.util.State;
@@ -345,7 +346,9 @@
     void setDefaultMessageType(SdpMasRecord sdpMasRecord) {
         int supportedMessageTypes = sdpMasRecord.getSupportedMessageTypes();
         synchronized (mDefaultMessageType) {
-            if ((supportedMessageTypes & SdpMasRecord.MessageType.SMS_CDMA) > 0) {
+            if ((supportedMessageTypes & SdpMasRecord.MessageType.MMS) > 0) {
+                mDefaultMessageType = Bmessage.Type.MMS;
+            } else if ((supportedMessageTypes & SdpMasRecord.MessageType.SMS_CDMA) > 0) {
                 mDefaultMessageType = Bmessage.Type.SMS_CDMA;
             } else if ((supportedMessageTypes & SdpMasRecord.MessageType.SMS_GSM) > 0) {
                 mDefaultMessageType = Bmessage.Type.SMS_GSM;
@@ -471,6 +474,11 @@
                     }
                     break;
 
+                case MSG_MAS_DISCONNECTED:
+                    deferMessage(message);
+                    transitionTo(mDisconnecting);
+                    break;
+
                 case MSG_OUTBOUND_MESSAGE:
                     mMasClient.makeRequest(
                             new RequestPushMessage(FOLDER_OUTBOX, (Bmessage) message.obj, null,
@@ -666,6 +674,7 @@
             switch (message.getType()) {
                 case SMS_CDMA:
                 case SMS_GSM:
+                case MMS:
                     if (DBG) {
                         Log.d(TAG, "Body: " + message.getBodyContent());
                     }
@@ -706,6 +715,12 @@
                         intent.putExtra(BluetoothMapClient.EXTRA_SENDER_CONTACT_NAME,
                                 originator.getDisplayName());
                     }
+                    if (message.getType() == Bmessage.Type.MMS) {
+                        BluetoothMapbMessageMime mmsBmessage = new BluetoothMapbMessageMime();
+                        mmsBmessage.parseMsgPart(message.getBodyContent());
+                        intent.putExtra(android.content.Intent.EXTRA_TEXT,
+                                mmsBmessage.getMessageAsText());
+                    }
                     // Only send to the current default SMS app if one exists
                     String defaultMessagingPackage = Telephony.Sms.getDefaultSmsPackage(mService);
                     if (defaultMessagingPackage != null) {
@@ -713,8 +728,6 @@
                     }
                     mService.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS);
                     break;
-
-                case MMS:
                 case EMAIL:
                 default:
                     Log.e(TAG, "Received unhandled type" + message.getType().toString());
diff --git a/src/com/android/bluetooth/mapclient/MnsObexServer.java b/src/com/android/bluetooth/mapclient/MnsObexServer.java
index 53cd79b..33ba1ea 100644
--- a/src/com/android/bluetooth/mapclient/MnsObexServer.java
+++ b/src/com/android/bluetooth/mapclient/MnsObexServer.java
@@ -90,6 +90,10 @@
         if (VDBG) {
             Log.v(TAG, "onDisconnect");
         }
+        MceStateMachine currentStateMachine = mStateMachineReference.get();
+        if (currentStateMachine != null) {
+            currentStateMachine.disconnect();
+        }
     }
 
     @Override
diff --git a/src/com/android/bluetooth/mapclient/MnsService.java b/src/com/android/bluetooth/mapclient/MnsService.java
index c1ab39e..b3317df 100644
--- a/src/com/android/bluetooth/mapclient/MnsService.java
+++ b/src/com/android/bluetooth/mapclient/MnsService.java
@@ -17,6 +17,7 @@
 package com.android.bluetooth.mapclient;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothServerSocket;
 import android.bluetooth.BluetoothSocket;
 import android.os.Handler;
@@ -129,6 +130,11 @@
                 Log.e(TAG, "Error: NO statemachine for device: " + device.getAddress()
                         + " (name: " + device.getName());
                 return false;
+            } else if (stateMachine.getState() != BluetoothProfile.STATE_CONNECTED) {
+                Log.e(TAG, "Error: statemachine for device: " + device.getAddress()
+                        + " (name: " + device.getName() + ") is not currently CONNECTED : "
+                        + stateMachine.getCurrentState());
+                return false;
             }
             MnsObexServer srv = new MnsObexServer(stateMachine, sServerSockets);
             BluetoothObexTransport transport = new BluetoothObexTransport(socket);
diff --git a/src/com/android/bluetooth/mapclient/obex/BmessageParser.java b/src/com/android/bluetooth/mapclient/obex/BmessageParser.java
index 2705e34..5b844dc 100644
--- a/src/com/android/bluetooth/mapclient/obex/BmessageParser.java
+++ b/src/com/android/bluetooth/mapclient/obex/BmessageParser.java
@@ -309,6 +309,12 @@
         String remng = mParser.remaining();
         byte[] data = remng.getBytes();
 
+        if (offset < 0 || offset > data.length) {
+            /* Handle possible exception for incorrect LENGTH value
+             * from MSE while parsing end of props */
+            throw new ParseException("Invalid LENGTH value", mParser.pos());
+        }
+
         /* restart parsing from after 'message'<CRLF> */
         mParser = new BmsgTokenizer(new String(data, offset, data.length - offset), restartPos);
 
diff --git a/src/com/android/bluetooth/opp/BluetoothOppManager.java b/src/com/android/bluetooth/opp/BluetoothOppManager.java
index 129d110..01b9209 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppManager.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java
@@ -337,7 +337,7 @@
         String deviceName = null;
 
         if (device != null) {
-            deviceName = device.getAliasName();
+            deviceName = device.getAlias();
             if (deviceName == null) {
                 deviceName = BluetoothOppPreference.getInstance(mContext).getName(device);
             }
diff --git a/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java b/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
new file mode 100644
index 0000000..acd05ed
--- /dev/null
+++ b/tests/unit/src/com/android/bluetooth/mapclient/BmessageTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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.mapclient;
+
+import static org.mockito.Mockito.*;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BmessageTest {
+    private static final String TAG = BmessageTest.class.getSimpleName();
+    private static final String SIMPLE_MMS_MESSAGE =
+            "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+            + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+            + "BEGIN:BBODY\r\nLENGTH:39\r\nBEGIN:MSG\r\nThis is a new msg\r\nEND:MSG\r\n"
+            + "END:BBODY\r\nEND:BENV\r\nEND:BMSG\r\n";
+
+    private static final String NO_END_MESSAGE =
+            "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+            + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+            + "BEGIN:BBODY\r\nLENGTH:39\r\nBEGIN:MSG\r\nThis is a new msg\r\n";
+
+    private static final String WRONG_LENGTH_MESSAGE =
+            "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+            + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+            + "BEGIN:BBODY\r\nLENGTH:200\r\nBEGIN:MSG\r\nThis is a new msg\r\nEND:MSG\r\n"
+            + "END:BBODY\r\nEND:BENV\r\nEND:BMSG\r\n";
+
+    private static final String NO_BODY_MESSAGE =
+            "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+            + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+            + "BEGIN:BBODY\r\nLENGTH:\r\n";
+
+    private static final String NEGATIVE_LENGTH_MESSAGE =
+            "BEGIN:BMSG\r\nVERSION:1.0\r\nSTATUS:READ\r\nTYPE:MMS\r\nFOLDER:null\r\nBEGIN:BENV\r\n"
+            + "BEGIN:VCARD\r\nVERSION:2.1\r\nN:null;;;;\r\nTEL:555-5555\r\nEND:VCARD\r\n"
+            + "BEGIN:BBODY\r\nLENGTH:-1\r\nBEGIN:MSG\r\nThis is a new msg\r\nEND:MSG\r\n"
+            + "END:BBODY\r\nEND:BENV\r\nEND:BMSG\r\n";
+
+    @Test
+    public void testNormalMessages() {
+        Bmessage message = BmessageParser.createBmessage(SIMPLE_MMS_MESSAGE);
+        Assert.assertNotNull(message);
+    }
+
+    @Test
+    public void testParseWrongLengthMessage() {
+        Bmessage message = BmessageParser.createBmessage(WRONG_LENGTH_MESSAGE);
+        Assert.assertNull(message);
+    }
+
+    @Test
+    public void testParseNoEndMessage() {
+        Bmessage message = BmessageParser.createBmessage(NO_END_MESSAGE);
+        Assert.assertNull(message);
+    }
+
+    @Test
+    public void testParseReallyLongMessage() {
+        String testMessage = new String(new char[68048]).replace('\0', 'A');
+        Bmessage message = BmessageParser.createBmessage(testMessage);
+        Assert.assertNull(message);
+    }
+
+    @Test
+    public void testNoBodyMessage() {
+        Bmessage message = BmessageParser.createBmessage(NO_BODY_MESSAGE);
+        Assert.assertNull(message);
+    }
+
+    @Test
+    public void testNegativeLengthMessage() {
+        Bmessage message = BmessageParser.createBmessage(NEGATIVE_LENGTH_MESSAGE);
+        Assert.assertNull(message);
+    }
+}
diff --git a/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java b/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
index 70854d8..ccfd9f8 100644
--- a/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java
@@ -150,6 +150,36 @@
         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
     }
 
+     /**
+     * Test transition from STATE_CONNECTING --> (receive MSG_MAS_CONNECTED) --> STATE_CONNECTED
+     * --> (receive MSG_MAS_DISCONNECTED) --> STATE_DISCONNECTED
+     */
+    @Test
+    public void testStateTransitionFromConnectedWithMasDisconnected() {
+        Log.i(TAG, "in testStateTransitionFromConnectedWithMasDisconnected");
+
+        setupSdpRecordReceipt();
+        Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED);
+        mMceStateMachine.sendMessage(msg);
+
+        // Wait until the message is processed and a broadcast request is sent to
+        // to MapClientService to change
+        // state from STATE_CONNECTING to STATE_CONNECTED
+        verify(mMockMapClientService,
+                timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast(
+                mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
+        Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState());
+
+        msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED);
+        mMceStateMachine.sendMessage(msg);
+        verify(mMockMapClientService,
+                timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(4)).sendBroadcast(
+                mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM));
+
+        Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mMceStateMachine.getState());
+    }
+
+
     /**
      * Test receiving an empty event report
      */