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
*/