diff options
Diffstat (limited to 'core/jni')
28 files changed, 1777 insertions, 2418 deletions
diff --git a/core/jni/ActivityManager.cpp b/core/jni/ActivityManager.cpp index 9017827..8950dfb 100644 --- a/core/jni/ActivityManager.cpp +++ b/core/jni/ActivityManager.cpp @@ -16,9 +16,9 @@ #include <unistd.h> #include <android_runtime/ActivityManager.h> -#include <utils/IBinder.h> -#include <utils/IServiceManager.h> -#include <utils/Parcel.h> +#include <binder/IBinder.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> #include <utils/String8.h> namespace android { diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 80c2489..0ecf678 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -11,6 +11,10 @@ else LOCAL_CFLAGS += -DPACKED="" endif +ifeq ($(WITH_JIT),true) + LOCAL_CFLAGS += -DWITH_JIT +endif + ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),) LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX) endif @@ -38,7 +42,6 @@ LOCAL_SRC_FILES:= \ android_text_AndroidCharacter.cpp \ android_text_KeyCharacterMap.cpp \ android_os_Debug.cpp \ - android_os_Exec.cpp \ android_os_FileUtils.cpp \ android_os_MemoryFile.cpp \ android_os_ParcelFileDescriptor.cpp \ @@ -103,11 +106,10 @@ LOCAL_SRC_FILES:= \ android_util_FileObserver.cpp \ android/opengl/poly_clip.cpp.arm \ android/opengl/util.cpp.arm \ - android_bluetooth_Database.cpp \ android_bluetooth_HeadsetBase.cpp \ android_bluetooth_common.cpp \ android_bluetooth_BluetoothAudioGateway.cpp \ - android_bluetooth_RfcommSocket.cpp \ + android_bluetooth_BluetoothSocket.cpp \ android_bluetooth_ScoSocket.cpp \ android_server_BluetoothDeviceService.cpp \ android_server_BluetoothEventLoop.cpp \ @@ -148,6 +150,7 @@ LOCAL_SHARED_LIBRARIES := \ libnativehelper \ libcutils \ libutils \ + libbinder \ libnetutils \ libui \ libskiagl \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 7350348..f8a4df0 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -19,12 +19,12 @@ //#define LOG_NDEBUG 0 #include <android_runtime/AndroidRuntime.h> -#include <utils/IBinder.h> -#include <utils/IServiceManager.h> +#include <binder/IBinder.h> +#include <binder/IServiceManager.h> #include <utils/Log.h> #include <utils/misc.h> -#include <utils/Parcel.h> -#include <utils/string_array.h> +#include <binder/Parcel.h> +#include <utils/StringArray.h> #include <utils/threads.h> #include <cutils/properties.h> @@ -130,7 +130,6 @@ extern int register_android_os_Power(JNIEnv *env); extern int register_android_os_StatFs(JNIEnv *env); extern int register_android_os_SystemProperties(JNIEnv *env); extern int register_android_os_Hardware(JNIEnv* env); -extern int register_android_os_Exec(JNIEnv *env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_FileObserver(JNIEnv *env); extern int register_android_os_FileUtils(JNIEnv *env); @@ -143,10 +142,9 @@ extern int register_android_security_Md5MessageDigest(JNIEnv *env); extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_KeyCharacterMap(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env); -extern int register_android_bluetooth_Database(JNIEnv* env); extern int register_android_bluetooth_HeadsetBase(JNIEnv* env); extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env); -extern int register_android_bluetooth_RfcommSocket(JNIEnv *env); +extern int register_android_bluetooth_BluetoothSocket(JNIEnv *env); extern int register_android_bluetooth_ScoSocket(JNIEnv *env); extern int register_android_server_BluetoothDeviceService(JNIEnv* env); extern int register_android_server_BluetoothEventLoop(JNIEnv *env); @@ -508,11 +506,17 @@ static void readLocale(char* language, char* region) //LOGD("language=%s region=%s\n", language, region); } -void AndroidRuntime::start(const char* className, const bool startSystemServer) +/* + * Start the Dalvik Virtual Machine. + * + * Various arguments, most determined by system properties, are passed in. + * The "mOptions" vector is updated. + * + * Returns 0 on success. + */ +int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) { - LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n"); - - JNIEnv* env; + int result = -1; JavaVMInitArgs initArgs; JavaVMOption opt; char propBuf[PROPERTY_VALUE_MAX]; @@ -521,24 +525,18 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX]; char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; char* stackTraceFile = NULL; - char* slashClassName = NULL; - char* cp; bool checkJni = false; + bool checkDexSum = false; bool logStdio = false; - enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault; + enum { + kEMDefault, + kEMIntPortable, + kEMIntFast, +#if defined(WITH_JIT) + kEMJitCompiler, +#endif + } executionMode = kEMDefault; - blockSigpipe(); - - /* - * 'startSystemServer == true' means runtime is obslete and not run from - * init.rc anymore, so we print out the boot start event here. - */ - if (startSystemServer) { - /* track our progress through the boot sequence */ - const int LOG_BOOT_PROGRESS_START = 3000; - LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, - ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); - } property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { @@ -556,10 +554,19 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) executionMode = kEMIntPortable; } else if (strcmp(propBuf, "int:fast") == 0) { executionMode = kEMIntFast; +#if defined(WITH_JIT) + } else if (strcmp(propBuf, "int:jit") == 0) { + executionMode = kEMJitCompiler; +#endif } property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, ""); + property_get("dalvik.vm.check-dex-sum", propBuf, ""); + if (strcmp(propBuf, "true") == 0) { + checkDexSum = true; + } + property_get("log.redirect-stdio", propBuf, ""); if (strcmp(propBuf, "true") == 0) { logStdio = true; @@ -571,19 +578,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) strcpy(jniOptsBuf, "-Xjniopts:"); property_get("dalvik.vm.jniopts", jniOptsBuf+10, ""); - const char* rootDir = getenv("ANDROID_ROOT"); - if (rootDir == NULL) { - rootDir = "/system"; - if (!hasDir("/system")) { - LOG_FATAL("No root directory specified, and /android does not exist."); - return; - } - setenv("ANDROID_ROOT", rootDir, 1); - } - - const char* kernelHack = getenv("LD_ASSUME_KERNEL"); - //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); - /* route exit() to our handler */ opt.extraInfo = (void*) runtime_exit; opt.optionString = "exit"; @@ -657,6 +651,10 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) if (opc != NULL) { opt.optionString = "-Xgenregmap"; mOptions.add(opt); + + /* turn on precise GC while we're at it */ + opt.optionString = "-Xgc:precise"; + mOptions.add(opt); } } @@ -696,13 +694,78 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) //opt.optionString = "-verbose:jni"; //mOptions.add(opt); } + +#if defined(WITH_JIT) + /* Minimal profile threshold to trigger JIT compilation */ + char jitThresholdBuf[sizeof("-Xthreshold:") + PROPERTY_VALUE_MAX]; + property_get("dalvik.vm.jit.threshold", propBuf, ""); + if (strlen(propBuf) > 0) { + strcpy(jitThresholdBuf, "-Xthreshold:"); + strcat(jitThresholdBuf, propBuf); + opt.optionString = jitThresholdBuf; + mOptions.add(opt); + } + + /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */ + char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX]; + property_get("dalvik.vm.jit.op", propBuf, ""); + if (strlen(propBuf) > 0) { + strcpy(jitOpBuf, "-Xjitop:"); + strcat(jitOpBuf, propBuf); + opt.optionString = jitOpBuf; + mOptions.add(opt); + } + + /* + * Reverse the polarity of dalvik.vm.jit.op and force interpreter-only + * for non-selected opcodes. + */ + property_get("dalvik.vm.jit.includeop", propBuf, ""); + if (strlen(propBuf) > 0) { + opt.optionString = "-Xincludeselectedop"; + mOptions.add(opt); + } + + /* Force interpreter-only mode for selected methods */ + char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX]; + property_get("dalvik.vm.jit.method", propBuf, ""); + if (strlen(propBuf) > 0) { + strcpy(jitMethodBuf, "-Xjitmethod:"); + strcat(jitMethodBuf, propBuf); + opt.optionString = jitMethodBuf; + mOptions.add(opt); + } + + /* + * Reverse the polarity of dalvik.vm.jit.method and force interpreter-only + * for non-selected methods. + */ + property_get("dalvik.vm.jit.includemethod", propBuf, ""); + if (strlen(propBuf) > 0) { + opt.optionString = "-Xincludeselectedmethod"; + mOptions.add(opt); + } +#endif + if (executionMode == kEMIntPortable) { opt.optionString = "-Xint:portable"; mOptions.add(opt); } else if (executionMode == kEMIntFast) { opt.optionString = "-Xint:fast"; mOptions.add(opt); +#if defined(WITH_JIT) + } else if (executionMode == kEMJitCompiler) { + opt.optionString = "-Xint:jit"; + mOptions.add(opt); +#endif } + + if (checkDexSum) { + /* perform additional DEX checksum tests */ + opt.optionString = "-Xcheckdexsum"; + mOptions.add(opt); + } + if (logStdio) { /* convert stdout/stderr to log messages */ opt.optionString = "-Xlog-stdio"; @@ -770,11 +833,61 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ - if (JNI_CreateJavaVM(&mJavaVM, &env, &initArgs) < 0) { + if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { LOGE("JNI_CreateJavaVM failed\n"); goto bail; } + result = 0; + +bail: + free(stackTraceFile); + return result; +} + +/* + * Start the Android runtime. This involves starting the virtual machine + * and calling the "static void main(String[] args)" method in the class + * named by "className". + */ +void AndroidRuntime::start(const char* className, const bool startSystemServer) +{ + LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n"); + + char* slashClassName = NULL; + char* cp; + JNIEnv* env; + + blockSigpipe(); + + /* + * 'startSystemServer == true' means runtime is obslete and not run from + * init.rc anymore, so we print out the boot start event here. + */ + if (startSystemServer) { + /* track our progress through the boot sequence */ + const int LOG_BOOT_PROGRESS_START = 3000; + LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, + ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); + } + + const char* rootDir = getenv("ANDROID_ROOT"); + if (rootDir == NULL) { + rootDir = "/system"; + if (!hasDir("/system")) { + LOG_FATAL("No root directory specified, and /android does not exist."); + goto bail; + } + setenv("ANDROID_ROOT", rootDir, 1); + } + + //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); + //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); + + /* start the virtual machine */ + if (startVm(&mJavaVM, &env) != 0) + goto bail; + /* * Register android functions. */ @@ -844,7 +957,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) bail: free(slashClassName); - free(stackTraceFile); } void AndroidRuntime::start() @@ -1094,7 +1206,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_database_SQLiteQuery), REG_JNI(register_android_database_SQLiteStatement), REG_JNI(register_android_os_Debug), - REG_JNI(register_android_os_Exec), REG_JNI(register_android_os_FileObserver), REG_JNI(register_android_os_FileUtils), REG_JNI(register_android_os_ParcelFileDescriptor), @@ -1116,10 +1227,9 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_opengl_classes), - REG_JNI(register_android_bluetooth_Database), REG_JNI(register_android_bluetooth_HeadsetBase), REG_JNI(register_android_bluetooth_BluetoothAudioGateway), - REG_JNI(register_android_bluetooth_RfcommSocket), + REG_JNI(register_android_bluetooth_BluetoothSocket), REG_JNI(register_android_bluetooth_ScoSocket), REG_JNI(register_android_server_BluetoothDeviceService), REG_JNI(register_android_server_BluetoothEventLoop), diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp index fb891c9..7864189 100644 --- a/core/jni/CursorWindow.cpp +++ b/core/jni/CursorWindow.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "CursorWindow" #include <utils/Log.h> -#include <utils/MemoryDealer.h> +#include <binder/MemoryDealer.h> #include <assert.h> #include <string.h> diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h index 0fb074f..e98b009 100644 --- a/core/jni/CursorWindow.h +++ b/core/jni/CursorWindow.h @@ -21,7 +21,7 @@ #include <stddef.h> #include <stdint.h> -#include <utils/MemoryDealer.h> +#include <binder/MemoryDealer.h> #include <utils/RefBase.h> #include <jni.h> diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index af8ecf5..957b825 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -5,7 +5,7 @@ #include "SkDither.h"
#include "SkUnPreMultiply.h"
-#include "Parcel.h"
+#include <binder/Parcel.h>
#include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 93d68cb..c61b2ed 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -23,6 +23,7 @@ #include "SkGLCanvas.h" #include "SkGraphics.h" #include "SkImageRef_GlobalPool.h" +#include "SkPorterDuff.h" #include "SkShader.h" #include "SkTemplates.h" @@ -324,7 +325,7 @@ public: static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas, jint color, SkPorterDuff::Mode mode) { - canvas->drawColor(color, mode); + canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); } static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas, diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index b6ec4a2..ebfb209 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -21,6 +21,7 @@ #include "SkColorFilter.h" #include "SkColorMatrixFilter.h" +#include "SkPorterDuff.h" namespace android { @@ -32,8 +33,9 @@ public: } static SkColorFilter* CreatePorterDuffFilter(JNIEnv* env, jobject, - jint srcColor, SkPorterDuff::Mode porterDuffMode) { - return SkColorFilter::CreatePorterDuffFilter(srcColor, porterDuffMode); + jint srcColor, SkPorterDuff::Mode mode) { + return SkColorFilter::CreateModeFilter(srcColor, + SkPorterDuff::ToXfermodeMode(mode)); } static SkColorFilter* CreateLightingFilter(JNIEnv* env, jobject, diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index effb1c8..11c608c 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -75,9 +75,8 @@ public: return result; } - static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, SkPath::BoundsType btype) { - SkRect bounds_; - obj->computeBounds(&bounds_, btype); + static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, int boundstype) { + const SkRect& bounds_ = obj->getBounds(); GraphicsJNI::rect_to_jrectf(bounds_, env, bounds); } diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index 1dc0314..723cd37 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -134,7 +134,7 @@ static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) //////////////////////////////////////////////////////////////////////////////////////////////////////////// -#include "Parcel.h" +#include <binder/Parcel.h> #include "android_util_Binder.h" static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp new file mode 100644 index 0000000..9c4f7c7 --- /dev/null +++ b/core/jni/android_bluetooth_BluetoothSocket.cpp @@ -0,0 +1,517 @@ +/* + * Copyright 2009, 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 "BluetoothSocket.cpp" + +#include "android_bluetooth_common.h" +#include "android_runtime/AndroidRuntime.h" +#include "JNIHelp.h" +#include "utils/Log.h" +#include "cutils/abort_socket.h" + +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#ifdef HAVE_BLUETOOTH +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> +#include <bluetooth/l2cap.h> +#include <bluetooth/sco.h> +#endif + +#define TYPE_AS_STR(t) \ + ((t) == TYPE_RFCOMM ? "RFCOMM" : ((t) == TYPE_SCO ? "SCO" : "L2CAP")) + +namespace android { + +static jfieldID field_mAuth; /* read-only */ +static jfieldID field_mEncrypt; /* read-only */ +static jfieldID field_mType; /* read-only */ +static jfieldID field_mAddress; /* read-only */ +static jfieldID field_mPort; /* read-only */ +static jfieldID field_mSocketData; +static jmethodID method_BluetoothSocket_ctor; +static jclass class_BluetoothSocket; + +/* Keep TYPE_RFCOMM etc in sync with BluetoothSocket.java */ +static const int TYPE_RFCOMM = 1; +static const int TYPE_SCO = 2; +static const int TYPE_L2CAP = 3; // TODO: Test l2cap code paths + +static struct asocket *get_socketData(JNIEnv *env, jobject obj) { + struct asocket *s = + (struct asocket *) env->GetIntField(obj, field_mSocketData); + if (!s) + jniThrowException(env, "java/io/IOException", "null socketData"); + return s; +} + +static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + struct asocket *s = asocket_init(fd); + + if (!s) { + LOGV("asocket_init() failed, throwing"); + jniThrowIOException(env, errno); + return; + } + + env->SetIntField(obj, field_mSocketData, (jint)s); + + return; +#endif + jniThrowIOException(env, ENOSYS); +} + +static void initSocketNative(JNIEnv *env, jobject obj) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + int fd; + int lm = 0; + jboolean auth; + jboolean encrypt; + jint type; + + type = env->GetIntField(obj, field_mType); + + switch (type) { + case TYPE_RFCOMM: + fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + break; + case TYPE_SCO: + fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); + break; + case TYPE_L2CAP: + fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + break; + default: + jniThrowIOException(env, ENOSYS); + return; + } + + if (fd < 0) { + LOGV("socket() failed, throwing"); + jniThrowIOException(env, errno); + return; + } + + auth = env->GetBooleanField(obj, field_mAuth); + encrypt = env->GetBooleanField(obj, field_mEncrypt); + + /* kernel does not yet support LM for SCO */ + switch (type) { + case TYPE_RFCOMM: + lm |= auth ? RFCOMM_LM_AUTH : 0; + lm |= encrypt? RFCOMM_LM_ENCRYPT : 0; + break; + case TYPE_L2CAP: + lm |= auth ? L2CAP_LM_AUTH : 0; + lm |= encrypt? L2CAP_LM_ENCRYPT : 0; + break; + } + + if (lm) { + if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) { + LOGV("setsockopt() failed, throwing"); + jniThrowIOException(env, errno); + return; + } + } + + LOGV("...fd %d created (%s, lm = %x)", fd, TYPE_AS_STR(type), lm); + + initSocketFromFdNative(env, obj, fd); + return; +#endif + jniThrowIOException(env, ENOSYS); +} + +static void connectNative(JNIEnv *env, jobject obj) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + int ret; + jint type; + const char *c_address; + jstring address; + bdaddr_t bdaddress; + socklen_t addr_sz; + struct sockaddr *addr; + struct asocket *s = get_socketData(env, obj); + + if (!s) + return; + + type = env->GetIntField(obj, field_mType); + + /* parse address into bdaddress */ + address = (jstring) env->GetObjectField(obj, field_mAddress); + c_address = env->GetStringUTFChars(address, NULL); + if (get_bdaddr(c_address, &bdaddress)) { + env->ReleaseStringUTFChars(address, c_address); + jniThrowIOException(env, EINVAL); + return; + } + env->ReleaseStringUTFChars(address, c_address); + + switch (type) { + case TYPE_RFCOMM: + struct sockaddr_rc addr_rc; + addr = (struct sockaddr *)&addr_rc; + addr_sz = sizeof(addr_rc); + + memset(addr, 0, addr_sz); + addr_rc.rc_family = AF_BLUETOOTH; + addr_rc.rc_channel = env->GetIntField(obj, field_mPort); + memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t)); + + break; + case TYPE_SCO: + struct sockaddr_sco addr_sco; + addr = (struct sockaddr *)&addr_sco; + addr_sz = sizeof(addr_sco); + + memset(addr, 0, addr_sz); + addr_sco.sco_family = AF_BLUETOOTH; + memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t)); + + break; + case TYPE_L2CAP: + struct sockaddr_l2 addr_l2; + addr = (struct sockaddr *)&addr_l2; + addr_sz = sizeof(addr_l2); + + memset(addr, 0, addr_sz); + addr_l2.l2_family = AF_BLUETOOTH; + addr_l2.l2_psm = env->GetIntField(obj, field_mPort); + memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t)); + + break; + default: + jniThrowIOException(env, ENOSYS); + return; + } + + ret = asocket_connect(s, addr, addr_sz, -1); + LOGV("...connect(%d, %s) = %d (errno %d)", + s->fd, TYPE_AS_STR(type), ret, errno); + + if (ret) + jniThrowIOException(env, errno); + + return; +#endif + jniThrowIOException(env, ENOSYS); +} + +static void bindListenNative(JNIEnv *env, jobject obj) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + jint type; + socklen_t addr_sz; + struct sockaddr *addr; + bdaddr_t bdaddr = *BDADDR_ANY; + struct asocket *s = get_socketData(env, obj); + + if (!s) + return; + + type = env->GetIntField(obj, field_mType); + + switch (type) { + case TYPE_RFCOMM: + struct sockaddr_rc addr_rc; + addr = (struct sockaddr *)&addr_rc; + addr_sz = sizeof(addr_rc); + + memset(addr, 0, addr_sz); + addr_rc.rc_family = AF_BLUETOOTH; + addr_rc.rc_channel = env->GetIntField(obj, field_mPort); + memcpy(&addr_rc.rc_bdaddr, &bdaddr, sizeof(bdaddr_t)); + break; + case TYPE_SCO: + struct sockaddr_sco addr_sco; + addr = (struct sockaddr *)&addr_sco; + addr_sz = sizeof(addr_sco); + + memset(addr, 0, addr_sz); + addr_sco.sco_family = AF_BLUETOOTH; + memcpy(&addr_sco.sco_bdaddr, &bdaddr, sizeof(bdaddr_t)); + break; + case TYPE_L2CAP: + struct sockaddr_l2 addr_l2; + addr = (struct sockaddr *)&addr_l2; + addr_sz = sizeof(addr_l2); + + memset(addr, 0, addr_sz); + addr_l2.l2_family = AF_BLUETOOTH; + addr_l2.l2_psm = env->GetIntField(obj, field_mPort); + memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t)); + break; + default: + jniThrowIOException(env, ENOSYS); + return; + } + + if (bind(s->fd, addr, addr_sz)) { + jniThrowIOException(env, errno); + return; + } + + if (listen(s->fd, 1)) { + jniThrowIOException(env, errno); + return; + } + + return; +#endif + jniThrowIOException(env, ENOSYS); +} + +static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + int fd; + jint type; + struct sockaddr *addr; + socklen_t addr_sz; + jstring addr_jstr; + char addr_cstr[BTADDR_SIZE]; + bdaddr_t *bdaddr; + jboolean auth; + jboolean encrypt; + + struct asocket *s = get_socketData(env, obj); + + if (!s) + return NULL; + + type = env->GetIntField(obj, field_mType); + + switch (type) { + case TYPE_RFCOMM: + struct sockaddr_rc addr_rc; + addr = (struct sockaddr *)&addr_rc; + addr_sz = sizeof(addr_rc); + bdaddr = &addr_rc.rc_bdaddr; + memset(addr, 0, addr_sz); + break; + case TYPE_SCO: + struct sockaddr_sco addr_sco; + addr = (struct sockaddr *)&addr_sco; + addr_sz = sizeof(addr_sco); + bdaddr = &addr_sco.sco_bdaddr; + memset(addr, 0, addr_sz); + break; + case TYPE_L2CAP: + struct sockaddr_l2 addr_l2; + addr = (struct sockaddr *)&addr_l2; + addr_sz = sizeof(addr_l2); + bdaddr = &addr_l2.l2_bdaddr; + memset(addr, 0, addr_sz); + break; + default: + jniThrowIOException(env, ENOSYS); + return NULL; + } + + fd = asocket_accept(s, addr, &addr_sz, timeout); + + LOGV("...accept(%d, %s) = %d (errno %d)", + s->fd, TYPE_AS_STR(type), fd, errno); + + if (fd < 0) { + jniThrowIOException(env, errno); + return NULL; + } + + /* Connected - return new BluetoothSocket */ + auth = env->GetBooleanField(obj, field_mAuth); + encrypt = env->GetBooleanField(obj, field_mEncrypt); + + get_bdaddr_as_string(bdaddr, addr_cstr); + + addr_jstr = env->NewStringUTF(addr_cstr); + return env->NewObject(class_BluetoothSocket, method_BluetoothSocket_ctor, + type, fd, auth, encrypt, addr_jstr, -1); + +#endif + jniThrowIOException(env, ENOSYS); + return NULL; +} + +static jint availableNative(JNIEnv *env, jobject obj) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + int available; + struct asocket *s = get_socketData(env, obj); + + if (!s) + return -1; + + if (ioctl(s->fd, FIONREAD, &available) < 0) { + jniThrowIOException(env, errno); + return -1; + } + + return available; + +#endif + jniThrowIOException(env, ENOSYS); + return -1; +} + +/** jb must not be null. offset and offset+length must be within array */ +static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset, + jint length) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + int ret; + jbyte *b; + struct asocket *s = get_socketData(env, obj); + + if (!s) + return -1; + + b = env->GetByteArrayElements(jb, NULL); + if (b == NULL) { + jniThrowIOException(env, EINVAL); + return -1; + } + + ret = asocket_read(s, &b[offset], length, -1); + if (ret < 0) { + jniThrowIOException(env, errno); + env->ReleaseByteArrayElements(jb, b, JNI_ABORT); + return -1; + } + + env->ReleaseByteArrayElements(jb, b, 0); + return (jint)ret; + +#endif + jniThrowIOException(env, ENOSYS); + return -1; +} + +/** jb must not be null. offset and offset+length must be within array */ +static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset, + jint length) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + + int ret; + jbyte *b; + struct asocket *s = get_socketData(env, obj); + + if (!s) + return -1; + + b = env->GetByteArrayElements(jb, NULL); + if (b == NULL) { + jniThrowIOException(env, EINVAL); + return -1; + } + + ret = asocket_write(s, &b[offset], length, -1); + if (ret < 0) { + jniThrowIOException(env, errno); + env->ReleaseByteArrayElements(jb, b, JNI_ABORT); + return -1; + } + + env->ReleaseByteArrayElements(jb, b, JNI_ABORT); // no need to commit + return (jint)ret; + +#endif + jniThrowIOException(env, ENOSYS); + return -1; +} + +static void closeNative(JNIEnv *env, jobject obj) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + struct asocket *s = get_socketData(env, obj); + + if (!s) + return; + + asocket_abort(s); + + LOGV("...asocket_abort(%d) complete", s->fd); + return; +#endif + jniThrowIOException(env, ENOSYS); +} + +static void destroyNative(JNIEnv *env, jobject obj) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + struct asocket *s = get_socketData(env, obj); + int fd = s->fd; + + if (!s) + return; + + asocket_destroy(s); + + LOGV("...asocket_destroy(%d) complete", fd); + return; +#endif + jniThrowIOException(env, ENOSYS); +} + +static JNINativeMethod sMethods[] = { + {"initSocketNative", "()V", (void*) initSocketNative}, + {"initSocketFromFdNative", "(I)V", (void*) initSocketFromFdNative}, + {"connectNative", "()V", (void *) connectNative}, + {"bindListenNative", "()V", (void *) bindListenNative}, + {"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative}, + {"availableNative", "()I", (void *) availableNative}, + {"readNative", "([BII)I", (void *) readNative}, + {"writeNative", "([BII)I", (void *) writeNative}, + {"closeNative", "()V", (void *) closeNative}, + {"destroyNative", "()V", (void *) destroyNative}, +}; + +int register_android_bluetooth_BluetoothSocket(JNIEnv *env) { + jclass clazz = env->FindClass("android/bluetooth/BluetoothSocket"); + if (clazz == NULL) + return -1; + class_BluetoothSocket = (jclass) env->NewGlobalRef(clazz); + field_mType = env->GetFieldID(clazz, "mType", "I"); + field_mAddress = env->GetFieldID(clazz, "mAddress", "Ljava/lang/String;"); + field_mPort = env->GetFieldID(clazz, "mPort", "I"); + field_mAuth = env->GetFieldID(clazz, "mAuth", "Z"); + field_mEncrypt = env->GetFieldID(clazz, "mEncrypt", "Z"); + field_mSocketData = env->GetFieldID(clazz, "mSocketData", "I"); + method_BluetoothSocket_ctor = env->GetMethodID(clazz, "<init>", "(IIZZLjava/lang/String;I)V"); + return AndroidRuntime::registerNativeMethods(env, + "android/bluetooth/BluetoothSocket", sMethods, NELEM(sMethods)); +} + +} /* namespace android */ + diff --git a/core/jni/android_bluetooth_Database.cpp b/core/jni/android_bluetooth_Database.cpp deleted file mode 100644 index 73b8efd..0000000 --- a/core/jni/android_bluetooth_Database.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 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 DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Database" -#define LOG_TAG "bluetooth_Database.cpp" - -#include "android_bluetooth_common.h" -#include "android_runtime/AndroidRuntime.h" -#include "JNIHelp.h" -#include "jni.h" -#include "utils/Log.h" - -#ifdef HAVE_BLUETOOTH -#include <dbus/dbus.h> -#endif - -namespace android { - -#ifdef HAVE_BLUETOOTH -static DBusConnection* conn = NULL; // Singleton thread-safe connection -#endif - -static void classInitNative(JNIEnv* env, jclass clazz) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - conn = NULL; -#endif -} - -static void initializeNativeDataNative(JNIEnv* env, jobject object) { - LOGV(__FUNCTION__); - -#ifdef HAVE_BLUETOOTH - if (conn == NULL) { - DBusError err; - dbus_error_init(&err); - dbus_threads_init_default(); - conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); - if (dbus_error_is_set(&err)) { - LOGE("Could not get onto the system bus!"); - dbus_error_free(&err); - } - dbus_connection_set_exit_on_disconnect(conn, FALSE); - } -#endif -} - -static void cleanupNativeDataNative(JNIEnv* env, jobject object) { - LOGV(__FUNCTION__); -} - -static jint addServiceRecordNative(JNIEnv *env, jobject object, - jbyteArray record) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - if (conn != NULL) { - jbyte* c_record = env->GetByteArrayElements(record, NULL); - DBusMessage *reply = dbus_func_args(env, - conn, - BLUEZ_DBUS_BASE_PATH, - DBUS_CLASS_NAME, - "AddServiceRecord", - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &c_record, - env->GetArrayLength(record), - DBUS_TYPE_INVALID); - env->ReleaseByteArrayElements(record, c_record, JNI_ABORT); - return reply ? dbus_returns_uint32(env, reply) : -1; - } -#endif - return -1; -} - -static jint addServiceRecordFromXmlNative(JNIEnv *env, jobject object, - jstring record) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - if (conn != NULL) { - const char *c_record = env->GetStringUTFChars(record, NULL); - DBusMessage *reply = dbus_func_args(env, - conn, - BLUEZ_DBUS_BASE_PATH, - DBUS_CLASS_NAME, - "AddServiceRecordFromXML", - DBUS_TYPE_STRING, &c_record, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(record, c_record); - return reply ? dbus_returns_uint32(env, reply) : -1; - } -#endif - return -1; -} - -static void updateServiceRecordNative(JNIEnv *env, jobject object, - jint handle, - jbyteArray record) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - if (conn != NULL) { - jbyte* c_record = env->GetByteArrayElements(record, NULL); - DBusMessage *reply = dbus_func_args(env, - conn, - BLUEZ_DBUS_BASE_PATH, - DBUS_CLASS_NAME, - "UpdateServiceRecord", - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &c_record, - env->GetArrayLength(record), - DBUS_TYPE_INVALID); - env->ReleaseByteArrayElements(record, c_record, JNI_ABORT); - } -#endif -} - -static void updateServiceRecordFromXmlNative(JNIEnv *env, jobject object, - jint handle, - jstring record) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - if (conn != NULL) { - const char *c_record = env->GetStringUTFChars(record, NULL); - DBusMessage *reply = dbus_func_args(env, - conn, - BLUEZ_DBUS_BASE_PATH, - DBUS_CLASS_NAME, - "UpdateServiceRecordFromXML", - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_STRING, &c_record, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(record, c_record); - } -#endif -} - -/* private static native void removeServiceRecordNative(int handle); */ -static void removeServiceRecordNative(JNIEnv *env, jobject object, - jint handle) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - if (conn != NULL) { - DBusMessage *reply = dbus_func_args(env, - conn, - BLUEZ_DBUS_BASE_PATH, - DBUS_CLASS_NAME, - "RemoveServiceRecord", - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - } -#endif -} - - -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, - {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, - {"addServiceRecordNative", "([B)I", (void*)addServiceRecordNative}, - {"addServiceRecordFromXmlNative", "(Ljava/lang/String;)I", (void*)addServiceRecordFromXmlNative}, - {"updateServiceRecordNative", "(I[B)V", (void*)updateServiceRecordNative}, - {"updateServiceRecordFromXmlNative", "(ILjava/lang/String;)V", (void*)updateServiceRecordFromXmlNative}, - {"removeServiceRecordNative", "(I)V", (void*)removeServiceRecordNative}, -}; - -int register_android_bluetooth_Database(JNIEnv *env) { - return AndroidRuntime::registerNativeMethods(env, - "android/bluetooth/Database", sMethods, NELEM(sMethods)); -} - -} /* namespace android */ diff --git a/core/jni/android_bluetooth_RfcommSocket.cpp b/core/jni/android_bluetooth_RfcommSocket.cpp deleted file mode 100644 index 3ed35d9..0000000 --- a/core/jni/android_bluetooth_RfcommSocket.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/* -** Copyright 2006, 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 "bluetooth_RfcommSocket.cpp" - -#include "android_bluetooth_common.h" -#include "android_runtime/AndroidRuntime.h" -#include "JNIHelp.h" -#include "jni.h" -#include "utils/Log.h" -#include "utils/misc.h" - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <sys/uio.h> -#include <sys/poll.h> - -#ifdef HAVE_BLUETOOTH -#include <bluetooth/bluetooth.h> -#include <bluetooth/rfcomm.h> -#include <bluetooth/sco.h> -#endif - -namespace android { - -#ifdef HAVE_BLUETOOTH -static jfieldID field_mNativeData; -static jfieldID field_mTimeoutRemainingMs; -static jfieldID field_mAcceptTimeoutRemainingMs; -static jfieldID field_mAddress; -static jfieldID field_mPort; - -typedef struct { - jstring address; - const char *c_address; - int rfcomm_channel; - int last_read_err; - int rfcomm_sock; - // < 0 -- in progress, - // 0 -- not connected - // > 0 connected - // 1 input is open - // 2 output is open - // 3 both input and output are open - int rfcomm_connected; - int rfcomm_sock_flags; -} native_data_t; - -static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { - return (native_data_t *)(env->GetIntField(object, field_mNativeData)); -} - -static inline void init_socket_info( - JNIEnv *env, jobject object, - native_data_t *nat, - jstring address, - jint rfcomm_channel) { - nat->address = (jstring)env->NewGlobalRef(address); - nat->c_address = env->GetStringUTFChars(nat->address, NULL); - nat->rfcomm_channel = (int)rfcomm_channel; -} - -static inline void cleanup_socket_info(JNIEnv *env, native_data_t *nat) { - if (nat->c_address != NULL) { - env->ReleaseStringUTFChars(nat->address, nat->c_address); - env->DeleteGlobalRef(nat->address); - nat->c_address = NULL; - } -} -#endif - -static void classInitNative(JNIEnv* env, jclass clazz) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - field_mNativeData = get_field(env, clazz, "mNativeData", "I"); - field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I"); - field_mAcceptTimeoutRemainingMs = get_field(env, clazz, "mAcceptTimeoutRemainingMs", "I"); - field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;"); - field_mPort = get_field(env, clazz, "mPort", "I"); -#endif -} - -static void initializeNativeDataNative(JNIEnv* env, jobject object) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - - native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); - if (nat == NULL) { - LOGE("%s: out of memory!", __FUNCTION__); - return; - } - - env->SetIntField(object, field_mNativeData, (jint)nat); - nat->rfcomm_sock = -1; - nat->rfcomm_connected = 0; -#endif -} - -static void cleanupNativeDataNative(JNIEnv* env, jobject object) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, object); - if (nat) { - free(nat); - } -#endif -} - -static jobject createNative(JNIEnv *env, jobject obj) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - int lm; - native_data_t *nat = get_native_data(env, obj); - nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - - if (nat->rfcomm_sock < 0) { - LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__, - strerror(errno)); - return NULL; - } - - lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT; - - if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, - sizeof(lm)) < 0) { - LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__); - close(nat->rfcomm_sock); - return NULL; - } - - return jniCreateFileDescriptor(env, nat->rfcomm_sock); -#else - return NULL; -#endif -} - -static void destroyNative(JNIEnv *env, jobject obj) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - cleanup_socket_info(env, nat); - if (nat->rfcomm_sock >= 0) { - close(nat->rfcomm_sock); - nat->rfcomm_sock = -1; - } -#endif -} - - -static jboolean connectNative(JNIEnv *env, jobject obj, - jstring address, jint port) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - - if (nat->rfcomm_sock >= 0) { - if (nat->rfcomm_connected) { - LOGI("RFCOMM socket: %s.", - (nat->rfcomm_connected > 0) ? "already connected" : "connection is in progress"); - return JNI_TRUE; - } - - init_socket_info(env, obj, nat, address, port); - - struct sockaddr_rc addr; - memset(&addr, 0, sizeof(struct sockaddr_rc)); - get_bdaddr(nat->c_address, &addr.rc_bdaddr); - addr.rc_channel = nat->rfcomm_channel; - addr.rc_family = AF_BLUETOOTH; - nat->rfcomm_connected = 0; - - while (nat->rfcomm_connected == 0) { - if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr, - sizeof(addr)) < 0) { - if (errno == EINTR) continue; - LOGE("connect error: %s (%d)\n", strerror(errno), errno); - break; - } else { - nat->rfcomm_connected = 3; // input and output - } - } - } else { - LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__); - } - - if (nat->rfcomm_connected > 0) { - env->SetIntField(obj, field_mPort, port); - return JNI_TRUE; - } -#endif - return JNI_FALSE; -} - -static jboolean connectAsyncNative(JNIEnv *env, jobject obj, - jstring address, jint port) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - - if (nat->rfcomm_sock < 0) { - LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__); - return JNI_FALSE; - } - - if (nat->rfcomm_connected) { - LOGI("RFCOMM socket: %s.", - (nat->rfcomm_connected > 0) ? - "already connected" : "connection is in progress"); - return JNI_TRUE; - } - - init_socket_info(env, obj, nat, address, port); - - struct sockaddr_rc addr; - memset(&addr, 0, sizeof(struct sockaddr_rc)); - get_bdaddr(nat->c_address, &addr.rc_bdaddr); - addr.rc_channel = nat->rfcomm_channel; - addr.rc_family = AF_BLUETOOTH; - - nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0); - if (fcntl(nat->rfcomm_sock, - F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) { - int rc; - nat->rfcomm_connected = 0; - errno = 0; - rc = connect(nat->rfcomm_sock, - (struct sockaddr *)&addr, - sizeof(addr)); - - if (rc >= 0) { - nat->rfcomm_connected = 3; - LOGI("RFCOMM async connect immediately successful"); - env->SetIntField(obj, field_mPort, port); - return JNI_TRUE; - } - else if (rc < 0) { - if (errno == EINPROGRESS || errno == EAGAIN) - { - LOGI("RFCOMM async connect is in progress (%s)", - strerror(errno)); - nat->rfcomm_connected = -1; - env->SetIntField(obj, field_mPort, port); - return JNI_TRUE; - } - else - { - LOGE("RFCOMM async connect error (%d): %s (%d)", - nat->rfcomm_sock, strerror(errno), errno); - return JNI_FALSE; - } - } - } // fcntl(nat->rfcomm_sock ...) -#endif - return JNI_FALSE; -} - -static jboolean interruptAsyncConnectNative(JNIEnv *env, jobject obj) { - //WRITEME - return JNI_TRUE; -} - -static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj, - jint timeout_ms) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - struct sockaddr_rc addr; - native_data_t *nat = get_native_data(env, obj); - - env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms); - - if (nat->rfcomm_sock < 0) { - LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__); - return -1; - } - - if (nat->rfcomm_connected > 0) { - LOGI("%s: RFCOMM is already connected!", __FUNCTION__); - return 1; - } - - /* Do an asynchronous select() */ - int n; - fd_set rset, wset; - struct timeval to; - - FD_ZERO(&rset); - FD_ZERO(&wset); - FD_SET(nat->rfcomm_sock, &rset); - FD_SET(nat->rfcomm_sock, &wset); - if (timeout_ms >= 0) { - to.tv_sec = timeout_ms / 1000; - to.tv_usec = 1000 * (timeout_ms % 1000); - } - n = select(nat->rfcomm_sock + 1, - &rset, - &wset, - NULL, - (timeout_ms < 0 ? NULL : &to)); - - if (timeout_ms > 0) { - jint remaining = to.tv_sec*1000 + to.tv_usec/1000; - LOGI("Remaining time %ldms", (long)remaining); - env->SetIntField(obj, field_mTimeoutRemainingMs, - remaining); - } - - if (n <= 0) { - if (n < 0) { - LOGE("select() on RFCOMM socket: %s (%d)", - strerror(errno), - errno); - return -1; - } - return 0; - } - /* n must be equal to 1 and either rset or wset must have the - file descriptor set. */ - LOGI("select() returned %d.", n); - if (FD_ISSET(nat->rfcomm_sock, &rset) || - FD_ISSET(nat->rfcomm_sock, &wset)) { - /* A trial async read() will tell us if everything is OK. */ - char ch; - errno = 0; - int nr = read(nat->rfcomm_sock, &ch, 1); - /* It should be that nr != 1 because we just opened a socket - and we haven't sent anything over it for the other side to - respond... but one can't be paranoid enough. - */ - if (nr >= 0 || errno != EAGAIN) { - LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n", - strerror(errno), - errno, - nr); - /* Clear the rfcomm_connected flag to cause this function - to re-create the socket and re-attempt the connect() - the next time it is called. - */ - nat->rfcomm_connected = 0; - /* Restore the blocking properties of the socket. */ - fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags); - return -1; - } - /* Restore the blocking properties of the socket. */ - fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags); - LOGI("Successful RFCOMM socket connect."); - nat->rfcomm_connected = 3; // input and output - return 1; - } -#endif - return -1; -} - -static jboolean shutdownNative(JNIEnv *env, jobject obj, - jboolean shutdownInput) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - /* NOTE: If you change the bcode to modify nat, make sure you - add synchronize(this) to the method calling this native - method. - */ - native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - int rc = shutdown(nat->rfcomm_sock, - shutdownInput ? SHUT_RD : SHUT_WR); - if (!rc) { - nat->rfcomm_connected &= - shutdownInput ? ~1 : ~2; - return JNI_TRUE; - } -#endif - return JNI_FALSE; -} - -static jint isConnectedNative(JNIEnv *env, jobject obj) { - LOGI(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - const native_data_t *nat = get_native_data(env, obj); - return nat->rfcomm_connected; -#endif - return 0; -} - -//@@@@@@@@@ bind to device??? -static jboolean bindNative(JNIEnv *env, jobject obj, jstring device, - jint port) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - - /* NOTE: If you change the code to modify nat, make sure you - add synchronize(this) to the method calling this native - method. - */ - const native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - - struct sockaddr_rc laddr; - int lm; - - lm = 0; -/* - lm |= RFCOMM_LM_MASTER; - lm |= RFCOMM_LM_AUTH; - lm |= RFCOMM_LM_ENCRYPT; - lm |= RFCOMM_LM_SECURE; -*/ - - if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) { - LOGE("Can't set RFCOMM link mode"); - return JNI_FALSE; - } - - laddr.rc_family = AF_BLUETOOTH; - bacpy(&laddr.rc_bdaddr, BDADDR_ANY); - laddr.rc_channel = port; - - if (bind(nat->rfcomm_sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) { - LOGE("Can't bind RFCOMM socket"); - return JNI_FALSE; - } - - env->SetIntField(obj, field_mPort, port); - - return JNI_TRUE; -#endif - return JNI_FALSE; -} - -static jboolean listenNative(JNIEnv *env, jobject obj, jint backlog) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - /* NOTE: If you change the code to modify nat, make sure you - add synchronize(this) to the method calling this native - method. - */ - const native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - return listen(nat->rfcomm_sock, backlog) < 0 ? JNI_FALSE : JNI_TRUE; -#else - return JNI_FALSE; -#endif -} - -static int set_nb(int sk, bool nb) { - int flags = fcntl(sk, F_GETFL); - if (flags < 0) { - LOGE("Can't get socket flags with fcntl(): %s (%d)", - strerror(errno), errno); - close(sk); - return -1; - } - flags &= ~O_NONBLOCK; - if (nb) flags |= O_NONBLOCK; - int status = fcntl(sk, F_SETFL, flags); - if (status < 0) { - LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)", - strerror(errno), errno); - close(sk); - return -1; - } - return 0; -} - -// Note: the code should check at a higher level to see whether -// listen() has been called. -#ifdef HAVE_BLUETOOTH -static int do_accept(JNIEnv* env, jobject object, int sock, - jobject newsock, - jfieldID out_address, - bool must_succeed) { - - if (must_succeed && set_nb(sock, true) < 0) - return -1; - - struct sockaddr_rc raddr; - int alen = sizeof(raddr); - int nsk = accept(sock, (struct sockaddr *) &raddr, &alen); - if (nsk < 0) { - LOGE("Error on accept from socket fd %d: %s (%d).", - sock, - strerror(errno), - errno); - if (must_succeed) set_nb(sock, false); - return -1; - } - - char addr[BTADDR_SIZE]; - get_bdaddr_as_string(&raddr.rc_bdaddr, addr); - env->SetObjectField(newsock, out_address, env->NewStringUTF(addr)); - - LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d", - sock, - nsk, - addr, - raddr.rc_channel); - if (must_succeed) set_nb(sock, false); - return nsk; -} -#endif /*HAVE_BLUETOOTH*/ - -static jobject acceptNative(JNIEnv *env, jobject obj, - jobject newsock, jint timeoutMs) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, obj); - if (nat->rfcomm_sock < 0) { - LOGE("socket(RFCOMM) error: socket not created"); - return JNI_FALSE; - } - - if (newsock == NULL) { - LOGE("%s: newsock = NULL\n", __FUNCTION__); - return JNI_FALSE; - } - - int nsk = -1; - if (timeoutMs < 0) { - /* block until accept() succeeds */ - nsk = do_accept(env, obj, nat->rfcomm_sock, - newsock, field_mAddress, false); - if (nsk < 0) { - return NULL; - } - } - else { - /* wait with a timeout */ - - struct pollfd fds; - fds.fd = nat->rfcomm_sock; - fds.events = POLLIN | POLLPRI | POLLOUT | POLLERR; - - env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, 0); - int n = poll(&fds, 1, timeoutMs); - if (n <= 0) { - if (n < 0) { - LOGE("listening poll() on RFCOMM socket: %s (%d)", - strerror(errno), - errno); - env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, timeoutMs); - } - else { - LOGI("listening poll() on RFCOMM socket timed out"); - } - return NULL; - } - - LOGI("listening poll() on RFCOMM socket returned %d", n); - if (fds.fd == nat->rfcomm_sock) { - if (fds.revents & (POLLIN | POLLPRI | POLLOUT)) { - LOGI("Accepting connection.\n"); - nsk = do_accept(env, obj, nat->rfcomm_sock, - newsock, field_mAddress, true); - if (nsk < 0) { - return NULL; - } - } - } - } - - LOGI("Connection accepted, new socket fd = %d.", nsk); - native_data_t *newnat = get_native_data(env, newsock); - newnat->rfcomm_sock = nsk; - newnat->rfcomm_connected = 3; - return jniCreateFileDescriptor(env, nsk); -#else - return NULL; -#endif -} - -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"classInitNative", "()V", (void*)classInitNative}, - {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, - {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, - - {"createNative", "()Ljava/io/FileDescriptor;", (void *)createNative}, - {"destroyNative", "()V", (void *)destroyNative}, - {"connectNative", "(Ljava/lang/String;I)Z", (void *)connectNative}, - {"connectAsyncNative", "(Ljava/lang/String;I)Z", (void *)connectAsyncNative}, - {"interruptAsyncConnectNative", "()Z", (void *)interruptAsyncConnectNative}, - {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative}, - {"shutdownNative", "(Z)Z", (void *)shutdownNative}, - {"isConnectedNative", "()I", (void *)isConnectedNative}, - - {"bindNative", "(Ljava/lang/String;I)Z", (void*)bindNative}, - {"listenNative", "(I)Z", (void*)listenNative}, - {"acceptNative", "(Landroid/bluetooth/RfcommSocket;I)Ljava/io/FileDescriptor;", (void*)acceptNative}, -}; - -int register_android_bluetooth_RfcommSocket(JNIEnv *env) { - return AndroidRuntime::registerNativeMethods(env, - "android/bluetooth/RfcommSocket", sMethods, NELEM(sMethods)); -} - -} /* namespace android */ diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp index 0b8a604..8361212 100644 --- a/core/jni/android_bluetooth_common.cpp +++ b/core/jni/android_bluetooth_common.cpp @@ -36,6 +36,38 @@ namespace android { #ifdef HAVE_BLUETOOTH + +static Properties remote_device_properties[] = { + {"Address", DBUS_TYPE_STRING}, + {"Name", DBUS_TYPE_STRING}, + {"Icon", DBUS_TYPE_STRING}, + {"Class", DBUS_TYPE_UINT32}, + {"UUIDs", DBUS_TYPE_ARRAY}, + {"Paired", DBUS_TYPE_BOOLEAN}, + {"Connected", DBUS_TYPE_BOOLEAN}, + {"Trusted", DBUS_TYPE_BOOLEAN}, + {"Alias", DBUS_TYPE_STRING}, + {"Nodes", DBUS_TYPE_ARRAY}, + {"Adapter", DBUS_TYPE_OBJECT_PATH}, + {"LegacyPairing", DBUS_TYPE_BOOLEAN}, + {"RSSI", DBUS_TYPE_INT16}, + {"TX", DBUS_TYPE_UINT32} +}; + +static Properties adapter_properties[] = { + {"Address", DBUS_TYPE_STRING}, + {"Name", DBUS_TYPE_STRING}, + {"Class", DBUS_TYPE_UINT32}, + {"Powered", DBUS_TYPE_BOOLEAN}, + {"Discoverable", DBUS_TYPE_BOOLEAN}, + {"DiscoverableTimeout", DBUS_TYPE_UINT32}, + {"Pairable", DBUS_TYPE_BOOLEAN}, + {"PairableTimeout", DBUS_TYPE_UINT32}, + {"Discovering", DBUS_TYPE_BOOLEAN}, + {"Devices", DBUS_TYPE_ARRAY}, +}; + + jfieldID get_field(JNIEnv *env, jclass clazz, const char *member, const char *mtype) { jfieldID field = env->GetFieldID(clazz, member, mtype); @@ -332,6 +364,44 @@ jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) { return ret; } +static void set_object_array_element(JNIEnv *env, jobjectArray strArray, + const char *value, int index) { + jstring obj; + obj = env->NewStringUTF(value); + env->SetObjectArrayElement(strArray, index, obj); + env->DeleteLocalRef(obj); +} + +jobjectArray dbus_returns_array_of_object_path(JNIEnv *env, + DBusMessage *reply) { + + DBusError err; + char **list; + int i, len; + jobjectArray strArray = NULL; + + dbus_error_init(&err); + if (dbus_message_get_args (reply, + &err, + DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, + &list, &len, + DBUS_TYPE_INVALID)) { + jclass stringClass; + jstring classNameStr; + + stringClass = env->FindClass("java/lang/String"); + strArray = env->NewObjectArray(len, stringClass, NULL); + + for (i = 0; i < len; i++) + set_object_array_element(env, strArray, list[i], i); + } else { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); + } + + dbus_message_unref(reply); + return strArray; +} + jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) { DBusError err; @@ -353,11 +423,8 @@ jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) { stringClass = env->FindClass("java/lang/String"); strArray = env->NewObjectArray(len, stringClass, NULL); - for (i = 0; i < len; i++) { - //LOGV("%s: array[%d] = [%s]", __FUNCTION__, i, list[i]); - env->SetObjectArrayElement(strArray, i, - env->NewStringUTF(list[i])); - } + for (i = 0; i < len; i++) + set_object_array_element(env, strArray, list[i], i); } else { LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); } @@ -390,17 +457,304 @@ jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) { return byteArray; } -void get_bdaddr(const char *str, bdaddr_t *ba) { +void append_variant(DBusMessageIter *iter, int type, void *val) +{ + DBusMessageIter value_iter; + char var_type[2] = { type, '\0'}; + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter); + dbus_message_iter_append_basic(&value_iter, type, val); + dbus_message_iter_close_container(iter, &value_iter); +} + + +//TODO(): Remove code duplication between parse_properties and +//parse_property_change +jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties, + const int max_num_properties) { + DBusMessageIter dict_entry, dict, prop_val, device_val, array_val_iter; + jobjectArray strArray = NULL; + char * property; + char values[max_num_properties][256]; + char **uuid_array = NULL; + char **device_path = NULL; + char **array_elements = NULL; + char *string_val; + uint32_t int_val, bool_val; + int i, j, k, type, array_type, num_array_elements = 0; + int ret, num_properties = 0, num_uuids = 0, num_devices = 0; + + + jclass stringClass = env->FindClass("java/lang/String"); + DBusError err; + dbus_error_init(&err); + + for (i = 0; i < max_num_properties; i++) + memset(values[i], '\0', 128 * sizeof(char)); + + if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + goto failure; + dbus_message_iter_recurse(iter, &dict); + do { + if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY) + goto failure; + dbus_message_iter_recurse(&dict, &dict_entry); + if (dbus_message_iter_get_arg_type(&dict_entry) != DBUS_TYPE_STRING) + goto failure; + dbus_message_iter_get_basic(&dict_entry, &property); + if (!dbus_message_iter_next(&dict_entry)) + goto failure; + if (dbus_message_iter_get_arg_type(&dict_entry) != DBUS_TYPE_VARIANT) + goto failure; + + for (i = 0; i < max_num_properties; i++) { + if (!strncmp(properties[i].name, property, strlen(property))) { + num_properties ++; + break; + } + } + if (i == max_num_properties) + goto failure; + + type = properties[i].type; + dbus_message_iter_recurse(&dict_entry, &prop_val); + if(dbus_message_iter_get_arg_type(&prop_val) != type) { + LOGE("Property type mismatch in parse_properties: %d, expected:%d", + dbus_message_iter_get_arg_type(&prop_val), type); + goto failure; + } + + switch(type) { + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + dbus_message_iter_get_basic(&prop_val, &string_val); + strcpy(values[i], string_val); + break; + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT16: + dbus_message_iter_get_basic(&prop_val, &int_val); + sprintf(values[i], "%d", int_val); + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_basic(&prop_val, &bool_val); + sprintf(values[i], "%s", bool_val ? "true" : "false"); + break; + case DBUS_TYPE_ARRAY: + dbus_message_iter_recurse(&prop_val, &array_val_iter); + array_type = dbus_message_iter_get_arg_type(&array_val_iter); + num_array_elements = 0; + if (array_type == DBUS_TYPE_OBJECT_PATH || + array_type == DBUS_TYPE_STRING){ + do { + num_array_elements++; + } while(dbus_message_iter_next(&array_val_iter)); + dbus_message_iter_recurse(&prop_val, &array_val_iter); + // Allocate an array + array_elements = (char **)malloc(sizeof(char *) * + num_array_elements); + if (!array_elements) + goto failure; + + j = 0; + do { + dbus_message_iter_get_basic(&array_val_iter, &array_elements[j]); + j++; + } while(dbus_message_iter_next(&array_val_iter)); + if (!strncmp(property, "UUIDs", strlen("UUIDs"))) { + num_uuids = num_array_elements; + uuid_array = array_elements; + } else { + num_devices = num_array_elements; + device_path = array_elements; + } + } + break; + default: + goto failure; + } + } while(dbus_message_iter_next(&dict)); + + // Convert it to a array of strings. + strArray = env->NewObjectArray((num_properties + num_array_elements) * 2, + stringClass, NULL); + + j = 0; + for (i = 0; i < max_num_properties; i++) { + if (properties[i].type == DBUS_TYPE_ARRAY) { + if (!strncmp(properties[i].name, "UUIDs", strlen("UUIDs"))) { + num_array_elements = num_uuids; + array_elements = uuid_array; + } else { + num_array_elements = num_devices; + array_elements = device_path; + } + + for (k = 0; k < num_array_elements; k++) { + set_object_array_element(env, strArray, properties[i].name, j++); + set_object_array_element(env, strArray, array_elements[k], j++); + } + } else if (values[i][0] != '\0') { + set_object_array_element(env, strArray, properties[i].name, j++); + set_object_array_element(env, strArray, values[i], j++); + } + } + + if (uuid_array) + free(uuid_array); + if (device_path) + free(device_path); + return strArray; + +failure: + if (dbus_error_is_set(&err)) + LOG_AND_FREE_DBUS_ERROR(&err); + if (uuid_array) + free(uuid_array); + if (device_path) + free(device_path); + return NULL; +} + +jobjectArray create_prop_array(JNIEnv *env, Properties *properties, + int prop_index, void *value, int len ) { + jclass stringClass= env->FindClass("java/lang/String"); + char **prop_val = NULL; + char buf[32] = {'\0'}; + int i, j; + + jobjectArray strArray = env->NewObjectArray(1 + len, stringClass, NULL); + j = 0; + set_object_array_element(env, strArray, properties[prop_index].name, j++); + + if (properties[prop_index].type == DBUS_TYPE_UINT32) { + sprintf(buf, "%d", *(int *) value); + set_object_array_element(env, strArray, buf, j++); + } else if (properties[prop_index].type == DBUS_TYPE_BOOLEAN) { + sprintf(buf, "%s", *(int *) value ? "true" : "false"); + set_object_array_element(env, strArray, buf, j++); + } else if (properties[prop_index].type == DBUS_TYPE_ARRAY) { + prop_val = (char **) value; + for (i = 0; i < len; i++) + set_object_array_element(env, strArray, prop_val[i], j++); + } else { + set_object_array_element(env, strArray, (const char *) value, j++); + } + if (prop_val) + free (prop_val); + return strArray; +} + +jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg, + Properties *properties, int max_num_properties) { + DBusMessageIter iter, prop_val, array_val_iter; + DBusError err; + void *value; + char *property; + uint32_t array_type; + int i, j, type, len, prop_index; + + dbus_error_init(&err); + if (!dbus_message_iter_init(msg, &iter)) + goto failure; + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + goto failure; + dbus_message_iter_get_basic(&iter, &property); + if (!dbus_message_iter_next(&iter)) + goto failure; + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + goto failure; + for (i = 0; i < max_num_properties; i++) { + if (!strncmp(property, properties[i].name, strlen(properties[i].name))) + break; + } + prop_index = i; + if (i == max_num_properties) + goto failure; + + dbus_message_iter_recurse(&iter, &prop_val); + type = properties[prop_index].type; + if (dbus_message_iter_get_arg_type(&prop_val) != type) { + LOGE("Property type mismatch in parse_properties: %d, expected:%d", + dbus_message_iter_get_arg_type(&prop_val), type); + goto failure; + } + + switch(type) { + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + dbus_message_iter_get_basic(&prop_val, &value); + len = 1; + break; + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT16: + case DBUS_TYPE_BOOLEAN: + uint32_t int_val; + dbus_message_iter_get_basic(&prop_val, &int_val); + value = &int_val; + len = 1; + break; + case DBUS_TYPE_ARRAY: + dbus_message_iter_recurse(&prop_val, &array_val_iter); + array_type = dbus_message_iter_get_arg_type(&array_val_iter); + len = 0; + if (array_type == DBUS_TYPE_OBJECT_PATH || + array_type == DBUS_TYPE_STRING){ + do { + len ++; + } while(dbus_message_iter_next(&array_val_iter)); + dbus_message_iter_recurse(&prop_val, &array_val_iter); + // Allocate an array of char * + char **tmp = (char **)malloc(sizeof(char *) * len); + if (!tmp) + goto failure; + j = 0; + do { + dbus_message_iter_get_basic(&array_val_iter, &tmp[j]); + j ++; + } while(dbus_message_iter_next(&array_val_iter)); + value = (char **) tmp; + } + break; + default: + goto failure; + } + return create_prop_array(env, properties, prop_index, value, len); +failure: + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + return NULL; +} + +jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) { + return parse_property_change(env, msg, (Properties *) &adapter_properties, + sizeof(adapter_properties) / sizeof(Properties)); +} + +jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) { + return parse_property_change(env, msg, (Properties *) &remote_device_properties, + sizeof(remote_device_properties) / sizeof(Properties)); +} + +jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) { + return parse_properties(env, iter, (Properties *) &adapter_properties, + sizeof(adapter_properties) / sizeof(Properties)); +} + +jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) { + return parse_properties(env, iter, (Properties *) &remote_device_properties, + sizeof(remote_device_properties) / sizeof(Properties)); +} + +int get_bdaddr(const char *str, bdaddr_t *ba) { char *d = ((char *)ba) + 5, *endp; int i; for(i = 0; i < 6; i++) { *d-- = strtol(str, &endp, 16); if (*endp != ':' && i != 5) { memset(ba, 0, sizeof(bdaddr_t)); - return; + return -1; } str = endp + 1; } + return 0; } void get_bdaddr_as_string(const bdaddr_t *ba, char *str) { diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h index 69092dd..ef9b66b 100644 --- a/core/jni/android_bluetooth_common.h +++ b/core/jni/android_bluetooth_common.h @@ -68,6 +68,7 @@ jfieldID get_field(JNIEnv *env, struct event_loop_native_data_t { DBusConnection *conn; + const char *adapter; /* protects the thread */ pthread_mutex_t thread_mutex; @@ -89,6 +90,12 @@ struct event_loop_native_data_t { jobject me; }; +struct _Properties { + char name[32]; + int type; +}; +typedef struct _Properties Properties; + dbus_bool_t dbus_func_args_async(JNIEnv *env, DBusConnection *conn, int timeout_ms, @@ -142,9 +149,19 @@ jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply); jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply); jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply); jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply); +jobjectArray dbus_returns_array_of_object_path(JNIEnv *env, DBusMessage *reply); jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply); -void get_bdaddr(const char *str, bdaddr_t *ba); +jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties, + const int max_num_properties); +jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg, + Properties *properties, int max_num_properties); +jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter); +jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter); +jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg); +jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg); +void append_variant(DBusMessageIter *iter, int type, void *val); +int get_bdaddr(const char *str, bdaddr_t *ba); void get_bdaddr_as_string(const bdaddr_t *ba, char *str); bool debug_no_encrypt(); diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index f19fbbf..91449bc 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -229,7 +229,7 @@ static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column { int32_t err; CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window); +LOG_WINDOW("Checking if column is a blob or null for %d,%d from %p", row, column, window); field_slot_t field; err = window->read_field_slot(row, column, &field); @@ -241,6 +241,54 @@ LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL; } +static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column) +{ + int32_t err; + CursorWindow * window = GET_WINDOW(env, object); +LOG_WINDOW("Checking if column is a string or null for %d,%d from %p", row, column, window); + + field_slot_t field; + err = window->read_field_slot(row, column, &field); + if (err != 0) { + throwExceptionWithRowCol(env, row, column); + return NULL; + } + + return field.type == FIELD_TYPE_STRING || field.type == FIELD_TYPE_NULL; +} + +static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column) +{ + int32_t err; + CursorWindow * window = GET_WINDOW(env, object); +LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, window); + + field_slot_t field; + err = window->read_field_slot(row, column, &field); + if (err != 0) { + throwExceptionWithRowCol(env, row, column); + return NULL; + } + + return field.type == FIELD_TYPE_INTEGER; +} + +static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column) +{ + int32_t err; + CursorWindow * window = GET_WINDOW(env, object); +LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window); + + field_slot_t field; + err = window->read_field_slot(row, column, &field); + if (err != 0) { + throwExceptionWithRowCol(env, row, column); + return NULL; + } + + return field.type == FIELD_TYPE_FLOAT; +} + static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; @@ -326,11 +374,11 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot"); return NULL; } - + jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField); if (buffer == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null"); - return NULL; + return NULL; } jchar* dst = env->GetCharArrayElements(buffer, NULL); uint8_t type = field.type; @@ -338,7 +386,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); jcharArray newArray = NULL; if (type == FIELD_TYPE_STRING) { uint32_t size = field.data.buffer.size; - if (size > 0) { + if (size > 0) { #if WINDOW_STORAGE_UTF8 // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1); @@ -346,7 +394,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); if (strSize > bufferSize || dst == NULL) { newArray = env->NewCharArray(strSize); env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string()); - } else { + } else { memcpy(dst, (jchar const *)utf16.string(), strSize * 2); } sizeCopied = strSize; @@ -359,7 +407,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size); } #endif - } + } } else if (type == FIELD_TYPE_INTEGER) { int64_t value; if (window->getLong(row, column, &value)) { @@ -628,6 +676,9 @@ static JNINativeMethod sMethods[] = {"putDouble_native", "(DII)Z", (void *)putDouble_native}, {"freeLastRow_native", "()V", (void *)freeLastRow}, {"putNull_native", "(II)Z", (void *)putNull_native}, + {"isString_native", "(II)Z", (void *)isString_native}, + {"isFloat_native", "(II)Z", (void *)isFloat_native}, + {"isInteger_native", "(II)Z", (void *)isInteger_native}, }; int register_android_database_CursorWindow(JNIEnv * env) @@ -646,7 +697,7 @@ int register_android_database_CursorWindow(JNIEnv * env) LOGE("Error locating fields"); return -1; } - + clazz = env->FindClass("android/database/CharArrayBuffer"); if (clazz == NULL) { LOGE("Can't find android/database/CharArrayBuffer"); diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp index 66858f9..020aff4 100644 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ b/core/jni/android_database_SQLiteDatabase.cpp @@ -28,7 +28,10 @@ #include <sqlite3.h> #include <sqlite3_android.h> #include <string.h> -#include <utils.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include <utils/List.h> +#include <utils/Errors.h> #include <ctype.h> #include <stdio.h> diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 9b92bc5..217e649 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -25,7 +25,7 @@ #include <ui/Surface.h> #include <ui/Camera.h> -#include <utils/IMemory.h> +#include <binder/IMemory.h> using namespace android; diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 42ada54..0cce3a6 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -30,8 +30,8 @@ #include "media/AudioSystem.h" #include "media/AudioTrack.h" -#include <utils/MemoryHeapBase.h> -#include <utils/MemoryBase.h> +#include <binder/MemoryHeapBase.h> +#include <binder/MemoryBase.h> // ---------------------------------------------------------------------------- diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 9f93e2f..75ae4d9 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -307,14 +307,15 @@ static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz) return result; } -static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz) +static jint android_net_wifi_getRssiHelper(const char *cmd) { char reply[256]; int rssi = -200; - if (doCommand("DRIVER RSSI", reply, sizeof(reply)) != 0) { + if (doCommand(cmd, reply, sizeof(reply)) != 0) { return (jint)-1; } + // reply comes back in the form "<SSID> rssi XX" where XX is the // number we're interested in. if we're associating, it returns "OK". // beware - <SSID> can contain spaces. @@ -328,6 +329,16 @@ static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz) return (jint)rssi; } +static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz) +{ + return android_net_wifi_getRssiHelper("DRIVER RSSI"); +} + +static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject clazz) +{ + return android_net_wifi_getRssiHelper("DRIVER RSSI-APPROX"); +} + static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz) { char reply[256]; @@ -523,6 +534,8 @@ static JNINativeMethod gWifiMethods[] = { { "setBluetoothCoexistenceScanModeCommand", "(Z)Z", (void*) android_net_wifi_setBluetoothCoexistenceScanModeCommand }, { "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand }, + { "getRssiApproxCommand", "()I", + (void*) android_net_wifi_getRssiApproxCommand}, { "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand }, { "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand }, { "saveConfigCommand", "()Z", (void*) android_net_wifi_saveConfigCommand }, diff --git a/core/jni/android_os_Exec.cpp b/core/jni/android_os_Exec.cpp deleted file mode 100644 index ca5e695..0000000 --- a/core/jni/android_os_Exec.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2007 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 "Exec" - -#include "JNIHelp.h" -#include "jni.h" -#include "utils/Log.h" -#include "utils/misc.h" -#include "android_runtime/AndroidRuntime.h" - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <termios.h> - -namespace android -{ - -static jclass class_fileDescriptor; -static jfieldID field_fileDescriptor_descriptor; -static jmethodID method_fileDescriptor_init; - - -static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, - int* pProcessId) -{ - char *devname; - int ptm; - pid_t pid; - - ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY); - if(ptm < 0){ - LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno)); - return -1; - } - fcntl(ptm, F_SETFD, FD_CLOEXEC); - - if(grantpt(ptm) || unlockpt(ptm) || - ((devname = (char*) ptsname(ptm)) == 0)){ - LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno)); - return -1; - } - - pid = fork(); - if(pid < 0) { - LOGE("- fork failed: %s -\n", strerror(errno)); - return -1; - } - - if(pid == 0){ - int pts; - - setsid(); - - pts = open(devname, O_RDWR); - if(pts < 0) exit(-1); - - dup2(pts, 0); - dup2(pts, 1); - dup2(pts, 2); - - close(ptm); - - execl(cmd, cmd, arg0, arg1, NULL); - exit(-1); - } else { - *pProcessId = (int) pid; - return ptm; - } -} - - -static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz, - jstring cmd, jstring arg0, jstring arg1, jintArray processIdArray) -{ - const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0; - String8 cmd_8; - if (str) { - cmd_8 = String8(str, env->GetStringLength(cmd)); - env->ReleaseStringCritical(cmd, str); - } - - str = arg0 ? env->GetStringCritical(arg0, 0) : 0; - const char* arg0Str = 0; - String8 arg0_8; - if (str) { - arg0_8 = String8(str, env->GetStringLength(arg0)); - env->ReleaseStringCritical(arg0, str); - arg0Str = arg0_8.string(); - } - - str = arg1 ? env->GetStringCritical(arg1, 0) : 0; - const char* arg1Str = 0; - String8 arg1_8; - if (str) { - arg1_8 = String8(str, env->GetStringLength(arg1)); - env->ReleaseStringCritical(arg1, str); - arg1Str = arg1_8.string(); - } - - int procId; - int ptm = create_subprocess(cmd_8.string(), arg0Str, arg1Str, &procId); - - if (processIdArray) { - int procIdLen = env->GetArrayLength(processIdArray); - if (procIdLen > 0) { - jboolean isCopy; - - int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy); - if (pProcId) { - *pProcId = procId; - env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0); - } - } - } - - jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init); - - if (!result) { - LOGE("Couldn't create a FileDescriptor."); - } - else { - env->SetIntField(result, field_fileDescriptor_descriptor, ptm); - } - - return result; -} - - -static void android_os_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz, - jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel) -{ - int fd; - struct winsize sz; - - fd = jniGetFDFromFileDescriptor(env, fileDescriptor); - - if (env->ExceptionOccurred() != NULL) { - return; - } - - sz.ws_row = row; - sz.ws_col = col; - sz.ws_xpixel = xpixel; - sz.ws_ypixel = ypixel; - - ioctl(fd, TIOCSWINSZ, &sz); -} - -static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz, - jint procId) { - int status; - waitpid(procId, &status, 0); - int result = 0; - if (WIFEXITED(status)) { - result = WEXITSTATUS(status); - } - return result; -} - -static JNINativeMethod method_table[] = { - { "createSubprocess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;", - (void*) android_os_Exec_createSubProcess }, - { "setPtyWindowSize", "(Ljava/io/FileDescriptor;IIII)V", - (void*) android_os_Exec_setPtyWindowSize}, - { "waitFor", "(I)I", - (void*) android_os_Exec_waitFor} -}; - -int register_android_os_Exec(JNIEnv *env) -{ - class_fileDescriptor = env->FindClass("java/io/FileDescriptor"); - - if (class_fileDescriptor == NULL) { - LOGE("Can't find java/io/FileDescriptor"); - return -1; - } - - field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I"); - - if (field_fileDescriptor_descriptor == NULL) { - LOGE("Can't find FileDescriptor.descriptor"); - return -1; - } - - method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "<init>", "()V"); - if (method_fileDescriptor_init == NULL) { - LOGE("Can't find FileDescriptor.init"); - return -1; - } - - return AndroidRuntime::registerNativeMethods( - env, "android/os/Exec", - method_table, NELEM(method_table)); -} - -}; diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp index 8643393..1ae3ec7 100644 --- a/core/jni/android_os_MemoryFile.cpp +++ b/core/jni/android_os_MemoryFile.cpp @@ -118,7 +118,7 @@ static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDe } } -static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject clazz, +static jint android_os_MemoryFile_get_mapped_size(JNIEnv* env, jobject clazz, jobject fileDescriptor) { int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); // Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region. @@ -129,13 +129,13 @@ static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject claz if (errno == ENOTTY) { // ENOTTY means that the ioctl does not apply to this object, // i.e., it is not an ashmem region. - return JNI_FALSE; + return (jint) -1; } // Some other error, throw exception jniThrowIOException(env, errno); - return JNI_FALSE; + return (jint) -1; } - return JNI_TRUE; + return (jint) result; } static const JNINativeMethod methods[] = { @@ -146,8 +146,8 @@ static const JNINativeMethod methods[] = { {"native_read", "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read}, {"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write}, {"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin}, - {"native_is_ashmem_region", "(Ljava/io/FileDescriptor;)Z", - (void*)android_os_MemoryFile_is_ashmem_region} + {"native_get_mapped_size", "(Ljava/io/FileDescriptor;)I", + (void*)android_os_MemoryFile_get_mapped_size} }; static const char* const kClassPathName = "android/os/MemoryFile"; diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp index 91a8e8e..14da1fd 100644 --- a/core/jni/android_server_BluetoothA2dpService.cpp +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -37,12 +37,7 @@ namespace android { #ifdef HAVE_BLUETOOTH -static jmethodID method_onHeadsetCreated; -static jmethodID method_onHeadsetRemoved; -static jmethodID method_onSinkConnected; -static jmethodID method_onSinkDisconnected; -static jmethodID method_onSinkPlaying; -static jmethodID method_onSinkStopped; +static jmethodID method_onSinkPropertyChanged; typedef struct { JavaVM *vm; @@ -53,11 +48,11 @@ typedef struct { static native_data_t *nat = NULL; // global native data -#endif - -#ifdef HAVE_BLUETOOTH -static void onConnectSinkResult(DBusMessage *msg, void *user, void *nat); -static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *nat); +static Properties sink_properties[] = { + {"State", DBUS_TYPE_STRING}, + {"Connected", DBUS_TYPE_BOOLEAN}, + {"Playing", DBUS_TYPE_BOOLEAN}, + }; #endif /* Returns true on success (even if adapter is present but disabled). @@ -100,91 +95,58 @@ static void cleanupNative(JNIEnv* env, jobject object) { } #endif } -static jobjectArray listHeadsetsNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, "/org/bluez/audio", - "org.bluez.audio.Manager", "ListHeadsets", - DBUS_TYPE_INVALID); - return reply ? dbus_returns_array_of_strings(env, reply) : NULL; - } -#endif - return NULL; -} -static jstring createHeadsetNative(JNIEnv *env, jobject object, - jstring address) { +static jobjectArray getSinkPropertiesNative(JNIEnv *env, jobject object, + jstring path) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - LOGV("... address = %s\n", c_address); - DBusMessage *reply = - dbus_func_args(env, nat->conn, "/org/bluez/audio", - "org.bluez.audio.Manager", "CreateHeadset", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - return reply ? dbus_returns_string(env, reply) : NULL; - } -#endif - return NULL; -} + DBusMessage *msg, *reply; + DBusError err; + dbus_error_init(&err); -static jstring removeHeadsetNative(JNIEnv *env, jobject object, jstring path) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - if (nat) { const char *c_path = env->GetStringUTFChars(path, NULL); - DBusMessage *reply = - dbus_func_args(env, nat->conn, "/org/bluez/audio", - "org.bluez.audio.Manager", "RemoveHeadset", - DBUS_TYPE_STRING, &c_path, - DBUS_TYPE_INVALID); + reply = dbus_func_args_timeout(env, + nat->conn, -1, c_path, + "org.bluez.AudioSink", "GetProperties", + DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(path, c_path); - return reply ? dbus_returns_string(env, reply) : NULL; + if (!reply && dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); + return NULL; + } else if (!reply) { + LOGE("DBus reply is NULL in function %s", __FUNCTION__); + return NULL; + } + DBusMessageIter iter; + if (dbus_message_iter_init(reply, &iter)) + return parse_properties(env, &iter, (Properties *)&sink_properties, + sizeof(sink_properties) / sizeof(Properties)); } #endif return NULL; } -static jstring getAddressNative(JNIEnv *env, jobject object, jstring path) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - if (nat) { - const char *c_path = env->GetStringUTFChars(path, NULL); - DBusMessage *reply = - dbus_func_args(env, nat->conn, c_path, - "org.bluez.audio.Device", "GetAddress", - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(path, c_path); - return reply ? dbus_returns_string(env, reply) : NULL; - } -#endif - return NULL; -} static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); if (nat) { const char *c_path = env->GetStringUTFChars(path, NULL); - size_t path_sz = env->GetStringUTFLength(path) + 1; - char *c_path_copy = (char *)malloc(path_sz); // callback data - strncpy(c_path_copy, c_path, path_sz); - - bool ret = - dbus_func_args_async(env, nat->conn, -1, - onConnectSinkResult, (void *)c_path_copy, nat, - c_path, - "org.bluez.audio.Sink", "Connect", - DBUS_TYPE_INVALID); + DBusError err; + dbus_error_init(&err); + DBusMessage *reply = + dbus_func_args_timeout(env, nat->conn, -1, c_path, + "org.bluez.AudioSink", "Connect", + DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(path, c_path); - if (!ret) { - free(c_path_copy); + + if (!reply && dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); + return JNI_FALSE; + } else if (!reply) { + LOGE("DBus reply is NULL in function %s", __FUNCTION__); return JNI_FALSE; } return JNI_TRUE; @@ -199,19 +161,20 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object, LOGV(__FUNCTION__); if (nat) { const char *c_path = env->GetStringUTFChars(path, NULL); - size_t path_sz = env->GetStringUTFLength(path) + 1; - char *c_path_copy = (char *)malloc(path_sz); // callback data - strncpy(c_path_copy, c_path, path_sz); - - bool ret = - dbus_func_args_async(env, nat->conn, -1, - onDisconnectSinkResult, (void *)c_path_copy, nat, - c_path, - "org.bluez.audio.Sink", "Disconnect", - DBUS_TYPE_INVALID); + DBusError err; + dbus_error_init(&err); + + DBusMessage *reply = + dbus_func_args_timeout(env, nat->conn, -1, c_path, + "org.bluez.AudioSink", "Disconnect", + DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(path, c_path); - if (!ret) { - free(c_path_copy); + + if (!reply && dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); + return JNI_FALSE; + } else if (!reply) { + LOGE("DBus reply is NULL in function %s", __FUNCTION__); return JNI_FALSE; } return JNI_TRUE; @@ -220,93 +183,7 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object, return JNI_FALSE; } -static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - if (nat) { - const char *c_path = env->GetStringUTFChars(path, NULL); - DBusMessage *reply = - dbus_func_args(env, nat->conn, c_path, - "org.bluez.audio.Sink", "IsConnected", - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(path, c_path); - return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE; - } -#endif - return JNI_FALSE; -} - #ifdef HAVE_BLUETOOTH -static void onConnectSinkResult(DBusMessage *msg, void *user, void *natData) { - LOGV(__FUNCTION__); - - char *c_path = (char *)user; - DBusError err; - JNIEnv *env; - - if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) { - LOGE("%s: error finding Env for our VM\n", __FUNCTION__); - return; - } - - dbus_error_init(&err); - - LOGV("... path = %s", c_path); - if (dbus_set_error_from_message(&err, msg)) { - /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */ - LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); - dbus_error_free(&err); - env->CallVoidMethod(nat->me, - method_onSinkDisconnected, - env->NewStringUTF(c_path)); - if (env->ExceptionCheck()) { - LOGE("VM Exception occurred in native function %s (%s:%d)", - __FUNCTION__, __FILE__, __LINE__); - } - } // else Java callback is triggered by signal in a2dp_event_filter - - free(c_path); -} - -static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *natData) { - LOGV(__FUNCTION__); - - char *c_path = (char *)user; - DBusError err; - JNIEnv *env; - - if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) { - LOGE("%s: error finding Env for our VM\n", __FUNCTION__); - return; - } - - dbus_error_init(&err); - - LOGV("... path = %s", c_path); - if (dbus_set_error_from_message(&err, msg)) { - /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */ - LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); - if (strcmp(err.name, "org.bluez.Error.NotConnected") == 0) { - // we were already disconnected, so report disconnect - env->CallVoidMethod(nat->me, - method_onSinkDisconnected, - env->NewStringUTF(c_path)); - } else { - // Assume it is still connected - env->CallVoidMethod(nat->me, - method_onSinkConnected, - env->NewStringUTF(c_path)); - } - dbus_error_free(&err); - if (env->ExceptionCheck()) { - LOGE("VM Exception occurred in native function %s (%s:%d)", - __FUNCTION__, __FILE__, __LINE__); - } - } // else Java callback is triggered by signal in a2dp_event_filter - - free(c_path); -} - DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) { DBusError err; @@ -324,71 +201,23 @@ DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) { DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (dbus_message_is_signal(msg, - "org.bluez.audio.Manager", - "HeadsetCreated")) { - char *c_path; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_path, - DBUS_TYPE_INVALID)) { - LOGV("... path = %s", c_path); - env->CallVoidMethod(nat->me, - method_onHeadsetCreated, - env->NewStringUTF(c_path)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - result = DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.audio.Manager", - "HeadsetRemoved")) { - char *c_path; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_path, - DBUS_TYPE_INVALID)) { - LOGV("... path = %s", c_path); - env->CallVoidMethod(nat->me, - method_onHeadsetRemoved, - env->NewStringUTF(c_path)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - result = DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.audio.Sink", - "Connected")) { + if (dbus_message_is_signal(msg, "org.bluez.AudioSink", + "PropertyChanged")) { + jobjectArray str_array = + parse_property_change(env, msg, (Properties *)&sink_properties, + sizeof(sink_properties) / sizeof(Properties)); const char *c_path = dbus_message_get_path(msg); - LOGV("... path = %s", c_path); env->CallVoidMethod(nat->me, - method_onSinkConnected, - env->NewStringUTF(c_path)); - result = DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.audio.Sink", - "Disconnected")) { - const char *c_path = dbus_message_get_path(msg); - LOGV("... path = %s", c_path); - env->CallVoidMethod(nat->me, - method_onSinkDisconnected, - env->NewStringUTF(c_path)); - result = DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.audio.Sink", - "Playing")) { - const char *c_path = dbus_message_get_path(msg); - LOGV("... path = %s", c_path); - env->CallVoidMethod(nat->me, - method_onSinkPlaying, - env->NewStringUTF(c_path)); - result = DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.audio.Sink", - "Stopped")) { - const char *c_path = dbus_message_get_path(msg); - LOGV("... path = %s", c_path); - env->CallVoidMethod(nat->me, - method_onSinkStopped, - env->NewStringUTF(c_path)); + method_onSinkPropertyChanged, + env->NewStringUTF(c_path), + str_array); + for (int i = 0; i < env->GetArrayLength(str_array); i++) { + env->DeleteLocalRef(env->GetObjectArrayElement(str_array, i)); + } + env->DeleteLocalRef(str_array); result = DBUS_HANDLER_RESULT_HANDLED; - } - - if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) { + return result; + } else { LOGV("... ignored"); } if (env->ExceptionCheck()) { @@ -407,14 +236,11 @@ static JNINativeMethod sMethods[] = { {"initNative", "()Z", (void *)initNative}, {"cleanupNative", "()V", (void *)cleanupNative}, - /* Bluez audio 3.36 API */ - {"listHeadsetsNative", "()[Ljava/lang/String;", (void*)listHeadsetsNative}, - {"createHeadsetNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)createHeadsetNative}, - {"removeHeadsetNative", "(Ljava/lang/String;)Z", (void*)removeHeadsetNative}, - {"getAddressNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAddressNative}, - {"connectSinkNative", "(Ljava/lang/String;)Z", (void*)connectSinkNative}, - {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void*)disconnectSinkNative}, - {"isSinkConnectedNative", "(Ljava/lang/String;)Z", (void*)isSinkConnectedNative}, + /* Bluez audio 4.40 API */ + {"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative}, + {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative}, + {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", + (void *)getSinkPropertiesNative}, }; int register_android_server_BluetoothA2dpService(JNIEnv *env) { @@ -425,12 +251,8 @@ int register_android_server_BluetoothA2dpService(JNIEnv *env) { } #ifdef HAVE_BLUETOOTH - method_onHeadsetCreated = env->GetMethodID(clazz, "onHeadsetCreated", "(Ljava/lang/String;)V"); - method_onHeadsetRemoved = env->GetMethodID(clazz, "onHeadsetRemoved", "(Ljava/lang/String;)V"); - method_onSinkConnected = env->GetMethodID(clazz, "onSinkConnected", "(Ljava/lang/String;)V"); - method_onSinkDisconnected = env->GetMethodID(clazz, "onSinkDisconnected", "(Ljava/lang/String;)V"); - method_onSinkPlaying = env->GetMethodID(clazz, "onSinkPlaying", "(Ljava/lang/String;)V"); - method_onSinkStopped = env->GetMethodID(clazz, "onSinkStopped", "(Ljava/lang/String;)V"); + method_onSinkPropertyChanged = env->GetMethodID(clazz, "onSinkPropertyChanged", + "(Ljava/lang/String;[Ljava/lang/String;)V"); #endif return AndroidRuntime::registerNativeMethods(env, diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp index 58ae4f6..b02a19b 100644 --- a/core/jni/android_server_BluetoothDeviceService.cpp +++ b/core/jni/android_server_BluetoothDeviceService.cpp @@ -14,7 +14,8 @@ ** limitations under the License. */ -#define DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Adapter" +#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter" +#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device" #define LOG_TAG "BluetoothDeviceService.cpp" #include "android_bluetooth_common.h" @@ -60,8 +61,11 @@ typedef struct { extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *, jobject); -void onCreateBondingResult(DBusMessage *msg, void *user, void *nat); -void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *nat); +extern DBusHandlerResult agent_event_filter(DBusConnection *conn, + DBusMessage *msg, + void *data); +void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat); + /** Get native data stored in the opaque (Java code maintained) pointer mNativeData * Perform quick sanity check, if there are any problems return NULL @@ -110,36 +114,71 @@ static bool initializeNativeDataNative(JNIEnv* env, jobject object) { return false; } dbus_connection_set_exit_on_disconnect(nat->conn, FALSE); - - nat->adapter = BLUEZ_ADAPTER_OBJECT_NAME; #endif /*HAVE_BLUETOOTH*/ return true; } -static void cleanupNativeDataNative(JNIEnv* env, jobject object) { +static const char *get_adapter_path(JNIEnv* env, jobject object) { +#ifdef HAVE_BLUETOOTH + event_loop_native_data_t *event_nat = + get_EventLoop_native_data(env, env->GetObjectField(object, + field_mEventLoop)); + if (event_nat == NULL) + return NULL; + return event_nat->adapter; +#else + return NULL; +#endif +} + +// This function is called when the adapter is enabled. +static jboolean setupNativeDataNative(JNIEnv* env, jobject object) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH native_data_t *nat = (native_data_t *)env->GetIntField(object, field_mNativeData); - if (nat) { - free(nat); - nat = NULL; + event_loop_native_data_t *event_nat = + get_EventLoop_native_data(env, env->GetObjectField(object, + field_mEventLoop)); + // Register agent for remote devices. + const char *device_agent_path = "/android/bluetooth/remote_device_agent"; + static const DBusObjectPathVTable agent_vtable = { + NULL, agent_event_filter, NULL, NULL, NULL, NULL }; + + if (!dbus_connection_register_object_path(nat->conn, device_agent_path, + &agent_vtable, event_nat)) { + LOGE("%s: Can't register object path %s for remote device agent!", + __FUNCTION__, device_agent_path); + return JNI_FALSE; } -#endif +#endif /*HAVE_BLUETOOTH*/ + return JNI_TRUE; } -static jstring getNameNative(JNIEnv *env, jobject object){ +static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, object); + native_data_t *nat = + (native_data_t *)env->GetIntField(object, field_mNativeData); + if (nat != NULL) { + const char *device_agent_path = + "/android/bluetooth/remote_device_agent"; + dbus_connection_unregister_object_path (nat->conn, device_agent_path); + } +#endif /*HAVE_BLUETOOTH*/ + return JNI_TRUE; +} + +static void cleanupNativeDataNative(JNIEnv* env, jobject object) { + LOGV(__FUNCTION__); +#ifdef HAVE_BLUETOOTH + native_data_t *nat = + (native_data_t *)env->GetIntField(object, field_mNativeData); if (nat) { - DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetName", - DBUS_TYPE_INVALID); - return reply ? dbus_returns_string(env, reply) : NULL; + free(nat); + nat = NULL; } #endif - return NULL; } static jstring getAdapterPathNative(JNIEnv *env, jobject object) { @@ -147,7 +186,7 @@ static jstring getAdapterPathNative(JNIEnv *env, jobject object) { #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); if (nat) { - return (env->NewStringUTF(nat->adapter)); + return (env->NewStringUTF(get_adapter_path(env, object))); } #endif return NULL; @@ -171,28 +210,23 @@ static jboolean startDiscoveryNative(JNIEnv *env, jobject object) { dbus_error_init(&err); /* Compose the command */ - msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, - DBUS_CLASS_NAME, "DiscoverDevices"); + msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "StartDiscovery"); if (msg == NULL) { - LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__); + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + } goto done; } /* Send the command. */ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); if (dbus_error_is_set(&err)) { - /* We treat the in-progress error code as success. */ - if(strcmp(err.message, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) { - LOGW("%s: D-Bus error: %s, treating as startDiscoveryNative success\n", - __FUNCTION__, err.message); - ret = JNI_TRUE; - goto done; - } else { - LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); - ret = JNI_FALSE; - goto done; - } + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + ret = JNI_FALSE; + goto done; } ret = JNI_TRUE; @@ -205,7 +239,7 @@ done: #endif } -static void cancelDiscoveryNative(JNIEnv *env, jobject object) { +static void stopDiscoveryNative(JNIEnv *env, jobject object) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH DBusMessage *msg = NULL; @@ -223,18 +257,20 @@ static void cancelDiscoveryNative(JNIEnv *env, jobject object) { } /* Compose the command */ - msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, - DBUS_CLASS_NAME, "CancelDiscovery"); - + msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "StopDiscovery"); if (msg == NULL) { - LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__); + if (dbus_error_is_set(&err)) + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); goto done; } /* Send the command. */ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); if (dbus_error_is_set(&err)) { - if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized") == 0) { + if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized", + strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) { // hcid sends this if there is no active discovery to cancel LOGV("%s: There was no active discovery to cancel", __FUNCTION__); dbus_error_free(&err); @@ -249,232 +285,8 @@ done: #endif } -static jboolean startPeriodicDiscoveryNative(JNIEnv *env, jobject object) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - DBusMessage *msg = NULL; - DBusMessage *reply = NULL; - DBusError err; - jboolean ret = JNI_FALSE; - - native_data_t *nat = get_native_data(env, object); - if (nat == NULL) { - goto done; - } - - dbus_error_init(&err); - msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, - DBUS_CLASS_NAME, "StartPeriodicDiscovery"); - if (msg == NULL) { - LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__); - goto done; - } - - /* Send the command. */ - reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); - if (dbus_error_is_set(&err)) { - /* We treat the in-progress error code as success. */ - if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) { - LOGW("%s: D-Bus error: %s (%s), treating as " - "startPeriodicDiscoveryNative success\n", - __FUNCTION__, err.name, err.message); - } else { - LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); - ret = JNI_FALSE; - goto done; - } - } - - ret = JNI_TRUE; -done: - if (reply) dbus_message_unref(reply); - if (msg) dbus_message_unref(msg); - return ret; -#else - return JNI_FALSE; -#endif -} - -static jboolean stopPeriodicDiscoveryNative(JNIEnv *env, jobject object) { - LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - DBusMessage *msg = NULL; - DBusMessage *reply = NULL; - DBusError err; - const char *name; - jboolean ret = JNI_FALSE; - - native_data_t *nat = get_native_data(env, object); - if (nat == NULL) { - goto done; - } - - dbus_error_init(&err); - msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, - DBUS_CLASS_NAME, "StopPeriodicDiscovery"); - if (msg == NULL) { - LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__); - goto done; - } - - /* Send the command. */ - reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); - if (dbus_error_is_set(&err)) { - /* We treat the in-progress error code as success. */ - if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) { - LOGW("%s: D-Bus error: %s (%s), treating as " - "stopPeriodicDiscoveryNative success\n", - __FUNCTION__, err.name, err.message); - } else { - LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); - ret = JNI_FALSE; - goto done; - } - } - - ret = JNI_TRUE; -done: - if (reply) dbus_message_unref(reply); - if (msg) dbus_message_unref(msg); - return ret; -#else - return JNI_FALSE; -#endif -} - -static jboolean isPeriodicDiscoveryNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "IsPeriodicDiscovery", - DBUS_TYPE_INVALID); - return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE; - } -#endif - return JNI_FALSE; -} - -static jboolean setDiscoverableTimeoutNative(JNIEnv *env, jobject object, jint timeout_s) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - - if (timeout_s < 0) { - return JNI_FALSE; - } - - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "SetDiscoverableTimeout", - DBUS_TYPE_UINT32, &timeout_s, - DBUS_TYPE_INVALID); - if (reply != NULL) { - dbus_message_unref(reply); - return JNI_TRUE; - } - } -#endif - return JNI_FALSE; -} - -static jint getDiscoverableTimeoutNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetDiscoverableTimeout", - DBUS_TYPE_INVALID); - return reply ? dbus_returns_uint32(env, reply) : -1; - } -#endif - return -1; -} - -static jboolean isConnectedNative(JNIEnv *env, jobject object, jstring address) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "IsConnected", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE; - } -#endif - return JNI_FALSE; -} - -static void disconnectRemoteDeviceNative(JNIEnv *env, jobject object, jstring address) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - // Set a timeout of 5 seconds. Specifying the default timeout is - // not long enough, as a remote-device disconnect results in - // signal RemoteDisconnectRequested being sent, followed by a - // delay of 2 seconds, after which the actual disconnect takes - // place. - DBusMessage *reply = - dbus_func_args_timeout(env, nat->conn, 60000, nat->adapter, - DBUS_CLASS_NAME, "DisconnectRemoteDevice", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - if (reply) dbus_message_unref(reply); - } -#endif -} - -static jstring getModeNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetMode", - DBUS_TYPE_INVALID); - return reply ? dbus_returns_string(env, reply) : NULL; - } -#endif - return NULL; -} - -static jboolean setModeNative(JNIEnv *env, jobject object, jstring mode) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - const char *c_mode = env->GetStringUTFChars(mode, NULL); - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "SetMode", - DBUS_TYPE_STRING, &c_mode, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(mode, c_mode); - if (reply) { - dbus_message_unref(reply); - return JNI_TRUE; - } - return JNI_FALSE; - } -#endif - return JNI_FALSE; -} - -static jboolean createBondingNative(JNIEnv *env, jobject object, - jstring address, jint timeout_ms) { +static jboolean createPairedDeviceNative(JNIEnv *env, jobject object, + jstring address, jint timeout_ms) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); @@ -486,14 +298,20 @@ static jboolean createBondingNative(JNIEnv *env, jobject object, const char *c_address = env->GetStringUTFChars(address, NULL); LOGV("... address = %s", c_address); char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); + const char *capabilities = "DisplayYesNo"; + const char *agent_path = "/android/bluetooth/remote_device_agent"; + strlcpy(context_address, c_address, BTADDR_SIZE); // for callback bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, - onCreateBondingResult, // callback + onCreatePairedDeviceResult, // callback context_address, eventLoopNat, - nat->adapter, - DBUS_CLASS_NAME, "CreateBonding", + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, + "CreatePairedDevice", DBUS_TYPE_STRING, &c_address, + DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_STRING, &capabilities, DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(address, c_address); return ret ? JNI_TRUE : JNI_FALSE; @@ -503,479 +321,324 @@ static jboolean createBondingNative(JNIEnv *env, jobject object, return JNI_FALSE; } -static jboolean cancelBondingProcessNative(JNIEnv *env, jobject object, - jstring address) { +static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object, + jstring path, + jstring pattern, jint attr_id) { +#ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); + native_data_t *nat = get_native_data(env, object); + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); + if (nat && eventLoopNat) { + const char *c_pattern = env->GetStringUTFChars(pattern, NULL); + const char *c_path = env->GetStringUTFChars(path, NULL); + LOGV("... pattern = %s", c_pattern); + LOGV("... attr_id = %#X", attr_id); + DBusMessage *reply = + dbus_func_args(env, nat->conn, c_path, + DBUS_DEVICE_IFACE, "GetServiceAttributeValue", + DBUS_TYPE_STRING, &c_pattern, + DBUS_TYPE_UINT16, &attr_id, + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(pattern, c_pattern); + env->ReleaseStringUTFChars(path, c_path); + return reply ? dbus_returns_int32(env, reply) : -1; + } +#endif + return -1; +} + +static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object, + jstring address) { + LOGV(__FUNCTION__); + jboolean result = JNI_FALSE; #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); if (nat) { const char *c_address = env->GetStringUTFChars(address, NULL); + DBusError err; + dbus_error_init(&err); LOGV("... address = %s", c_address); DBusMessage *reply = - dbus_func_args_timeout(env, nat->conn, -1, nat->adapter, - DBUS_CLASS_NAME, "CancelBondingProcess", + dbus_func_args_timeout(env, nat->conn, -1, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "CancelDeviceCreation", DBUS_TYPE_STRING, &c_address, DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(address, c_address); - if (reply) { - dbus_message_unref(reply); + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } else + LOGE("DBus reply is NULL in function %s", __FUNCTION__); + return JNI_FALSE; + } else { + result = JNI_TRUE; } - return JNI_TRUE; + dbus_message_unref(reply); } #endif return JNI_FALSE; } -static jboolean removeBondingNative(JNIEnv *env, jobject object, jstring address) { +static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) { LOGV(__FUNCTION__); jboolean result = JNI_FALSE; #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - LOGV("... address = %s", c_address); + const char *c_object_path = env->GetStringUTFChars(object_path, NULL); DBusError err; dbus_error_init(&err); DBusMessage *reply = - dbus_func_args_error(env, nat->conn, &err, nat->adapter, - DBUS_CLASS_NAME, "RemoveBonding", - DBUS_TYPE_STRING, &c_address, + dbus_func_args_error(env, nat->conn, &err, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "RemoveDevice", + DBUS_TYPE_OBJECT_PATH, &c_object_path, DBUS_TYPE_INVALID); - if (dbus_error_is_set(&err)) { - if (dbus_error_has_name(&err, - BLUEZ_DBUS_BASE_IFC ".Error.DoesNotExist")) { - LOGW("%s: Warning: %s (%s)", __FUNCTION__, err.message, - c_address); - result = JNI_TRUE; - } else { - LOGE("%s: D-Bus error %s (%s)", __FUNCTION__, err.name, - err.message); - } + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } else + LOGE("DBus reply is NULL in function %s", __FUNCTION__); + result = JNI_FALSE; } else { result = JNI_TRUE; } - - env->ReleaseStringUTFChars(address, c_address); - dbus_error_free(&err); + env->ReleaseStringUTFChars(object_path, c_object_path); if (reply) dbus_message_unref(reply); } #endif return result; } -static jobjectArray listBondingsNative(JNIEnv *env, jobject object) { +static jint enableNative(JNIEnv *env, jobject object) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "ListBondings", - DBUS_TYPE_INVALID); - // return String[] - return reply ? dbus_returns_array_of_strings(env, reply) : NULL; - } + return bt_enable(); #endif - return NULL; + return -1; } -static jobjectArray listConnectionsNative(JNIEnv *env, jobject object) { +static jint disableNative(JNIEnv *env, jobject object) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "ListConnections", - DBUS_TYPE_INVALID); - // return String[] - return reply ? dbus_returns_array_of_strings(env, reply) : NULL; - } + return bt_disable(); #endif - return NULL; + return -1; } -static jobjectArray listRemoteDevicesNative(JNIEnv *env, jobject object) { +static jint isEnabledNative(JNIEnv *env, jobject object) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "ListRemoteDevices", - DBUS_TYPE_INVALID); - return reply ? dbus_returns_array_of_strings(env, reply) : NULL; - } + return bt_is_enabled(); #endif - return NULL; + return -1; } -static jstring common_Get(JNIEnv *env, jobject object, const char *func) { - LOGV("%s:%s", __FUNCTION__, func); +static jboolean setPinNative(JNIEnv *env, jobject object, jstring address, + jstring pin, int nativeData) { #ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); native_data_t *nat = get_native_data(env, object); if (nat) { - DBusError err; - dbus_error_init(&err); - DBusMessage *reply = - dbus_func_args_error(env, nat->conn, &err, nat->adapter, - DBUS_CLASS_NAME, func, - DBUS_TYPE_INVALID); - if (reply) { - return dbus_returns_string(env, reply); - } else { - LOG_AND_FREE_DBUS_ERROR(&err); - return NULL; + DBusMessage *msg = (DBusMessage *)nativeData; + DBusMessage *reply = dbus_message_new_method_return(msg); + if (!reply) { + LOGE("%s: Cannot create message reply to return PIN code to " + "D-Bus\n", __FUNCTION__); + dbus_message_unref(msg); + return JNI_FALSE; } - } -#endif - return NULL; -} - -static jstring getAddressNative(JNIEnv *env, jobject obj) { - return common_Get(env, obj, "GetAddress"); -} - -static jstring getVersionNative(JNIEnv *env, jobject obj) { - return common_Get(env, obj, "GetVersion"); -} -static jstring getRevisionNative(JNIEnv *env, jobject obj) { - return common_Get(env, obj, "GetRevision"); -} + const char *c_pin = env->GetStringUTFChars(pin, NULL); -static jstring getManufacturerNative(JNIEnv *env, jobject obj) { - return common_Get(env, obj, "GetManufacturer"); -} + dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin, + DBUS_TYPE_INVALID); -static jstring getCompanyNative(JNIEnv *env, jobject obj) { - return common_Get(env, obj, "GetCompany"); + dbus_connection_send(nat->conn, reply, NULL); + dbus_message_unref(msg); + dbus_message_unref(reply); + env->ReleaseStringUTFChars(pin, c_pin); + return JNI_TRUE; + } +#endif + return JNI_FALSE; } -static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) { +static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address, + int nativeData) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, obj); + native_data_t *nat = get_native_data(env, object); if (nat) { - const char *c_name = env->GetStringUTFChars(name, NULL); - DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "SetName", - DBUS_TYPE_STRING, &c_name, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(name, c_name); - if (reply) { - dbus_message_unref(reply); - return JNI_TRUE; + DBusMessage *msg = (DBusMessage *)nativeData; + DBusMessage *reply = dbus_message_new_error(msg, + "org.bluez.Error.Canceled", "PIN Entry was canceled"); + if (!reply) { + LOGE("%s: Cannot create message reply to return PIN cancel to " + "D-BUS\n", __FUNCTION__); + dbus_message_unref(msg); + return JNI_FALSE; } + + dbus_connection_send(nat->conn, reply, NULL); + dbus_message_unref(msg); + dbus_message_unref(reply); + return JNI_TRUE; } #endif return JNI_FALSE; } -static jstring common_getRemote(JNIEnv *env, jobject object, const char *func, - jstring address) { - LOGV("%s:%s", __FUNCTION__, func); +static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object, + jstring path) +{ #ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); native_data_t *nat = get_native_data(env, object); if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); + DBusMessage *msg, *reply; DBusError err; dbus_error_init(&err); - LOGV("... address = %s", c_address); + const char *c_path = env->GetStringUTFChars(path, NULL); + reply = dbus_func_args_timeout(env, + nat->conn, -1, c_path, + DBUS_DEVICE_IFACE, "GetProperties", + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); - DBusMessage *reply = - dbus_func_args_error(env, nat->conn, &err, nat->adapter, - DBUS_CLASS_NAME, func, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - if (reply) { - return dbus_returns_string(env, reply); - } else if (!strcmp(func, "GetRemoteName") && - dbus_error_has_name(&err, "org.bluez.Error.RequestDeferred")) { - // This error occurs if we request name during device discovery, - // its fine - LOGV("... %s: %s", func, err.message); - dbus_error_free(&err); - return NULL; - } else { - LOG_AND_FREE_DBUS_ERROR(&err); + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } else + LOGE("DBus reply is NULL in function %s", __FUNCTION__); return NULL; } + DBusMessageIter iter; + jobjectArray str_array = NULL; + if (dbus_message_iter_init(reply, &iter)) + str_array = parse_remote_device_properties(env, &iter); + dbus_message_unref(reply); + return str_array; } #endif return NULL; } -static jstring getRemoteVersionNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "GetRemoteVersion", address); -} - -static jstring getRemoteRevisionNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "GetRemoteRevision", address); -} - -static jstring getRemoteManufacturerNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "GetRemoteManufacturer", address); -} - -static jstring getRemoteCompanyNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "GetRemoteCompany", address); -} - -static jstring getRemoteNameNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "GetRemoteName", address); -} - -static jstring lastSeenNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "LastSeen", address); -} - -static jstring lastUsedNative(JNIEnv *env, jobject obj, jstring address) { - return common_getRemote(env, obj, "LastUsed", address); -} - -static jint getRemoteClassNative(JNIEnv *env, jobject object, jstring address) { - jint result = BLUETOOTH_CLASS_ERROR; +static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); native_data_t *nat = get_native_data(env, object); if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - - LOGV("... address = %s", c_address); + DBusMessage *msg, *reply; + DBusError err; + dbus_error_init(&err); - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetRemoteClass", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - if (reply) - { - DBusError err; - dbus_error_init(&err); - if (!dbus_message_get_args(reply, &err, - DBUS_TYPE_UINT32, &result, - DBUS_TYPE_INVALID)) { - LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); - } - dbus_message_unref(reply); + reply = dbus_func_args_timeout(env, + nat->conn, -1, get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "GetProperties", + DBUS_TYPE_INVALID); + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } else + LOGE("DBus reply is NULL in function %s", __FUNCTION__); + return NULL; } - } -#endif - return result; -} - -static jbyteArray getRemoteFeaturesNative(JNIEnv *env, jobject object, - jstring address) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - - LOGV("... address = %s", c_address); - - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetRemoteFeatures", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - /* array of DBUS_TYPE_BYTE_AS_STRING */ - return reply ? dbus_returns_array_of_bytes(env, reply) : NULL; + DBusMessageIter iter; + jobjectArray str_array = NULL; + if (dbus_message_iter_init(reply, &iter)) + str_array = parse_adapter_properties(env, &iter); + dbus_message_unref(reply); + return str_array; } #endif return NULL; } -static jintArray getRemoteServiceHandlesNative(JNIEnv *env, jobject object, - jstring address, jstring match) { +static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key, + void *value, jint type) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); native_data_t *nat = get_native_data(env, object); if (nat) { - jintArray intArray = NULL; - const char *c_address = env->GetStringUTFChars(address, NULL); - const char *c_match = env->GetStringUTFChars(match, NULL); - - LOGV("... address = %s match = %s", c_address, c_match); + DBusMessage *reply, *msg; + DBusMessageIter iter; + DBusError err; + const char *c_key = env->GetStringUTFChars(key, NULL); + dbus_error_init(&err); - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetRemoteServiceHandles", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_STRING, &c_match, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - env->ReleaseStringUTFChars(match, c_match); - if (reply) - { - DBusError err; - jint *list; - int i, len; - - dbus_error_init(&err); - if (dbus_message_get_args (reply, &err, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, - &list, &len, - DBUS_TYPE_INVALID)) { - if (len) { - intArray = env->NewIntArray(len); - if (intArray) - env->SetIntArrayRegion(intArray, 0, len, list); - } - } else { - LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); - } - - dbus_message_unref(reply); + msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "SetProperty"); + if (!msg) { + LOGE("%s: Can't allocate new method call for GetProperties!", + __FUNCTION__); + return JNI_FALSE; } - return intArray; - } -#endif - return NULL; -} - -static jbyteArray getRemoteServiceRecordNative(JNIEnv *env, jobject object, - jstring address, jint handle) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - LOGV("... address = %s", c_address); + dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID); + dbus_message_iter_init_append(msg, &iter); + append_variant(&iter, type, value); - DBusMessage *reply = - dbus_func_args(env, nat->conn, nat->adapter, - DBUS_CLASS_NAME, "GetRemoteServiceRecord", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - return reply ? dbus_returns_array_of_bytes(env, reply) : NULL; - } -#endif - return NULL; -} + reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); + dbus_message_unref(msg); -static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object, - jstring address, jshort uuid16) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - jobject eventLoop = env->GetObjectField(object, field_mEventLoop); - struct event_loop_native_data_t *eventLoopNat = - get_EventLoop_native_data(env, eventLoop); - if (nat && eventLoopNat) { - const char *c_address = env->GetStringUTFChars(address, NULL); - char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); - strlcpy(context_address, c_address, BTADDR_SIZE); + env->ReleaseStringUTFChars(key, c_key); - LOGV("... address = %s", c_address); - LOGV("... uuid16 = %#X", uuid16); - - bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms - onGetRemoteServiceChannelResult, context_address, - eventLoopNat, - nat->adapter, - DBUS_CLASS_NAME, "GetRemoteServiceChannel", - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_UINT16, &uuid16, - DBUS_TYPE_INVALID); - env->ReleaseStringUTFChars(address, c_address); - return ret ? JNI_TRUE : JNI_FALSE; + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + } else + LOGE("DBus reply is NULL in function %s", __FUNCTION__); + return JNI_FALSE; + } + return JNI_TRUE; } #endif return JNI_FALSE; } -static jint enableNative(JNIEnv *env, jobject object) { +static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key, + jstring value) { #ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - return bt_enable(); + const char *c_value = env->GetStringUTFChars(value, NULL); + jboolean ret = setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING); + env->ReleaseStringUTFChars(value, (char *)c_value); + return ret; +#else + return JNI_FALSE; #endif - return -1; } -static jint disableNative(JNIEnv *env, jobject object) { +static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key, + jint value) { #ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - return bt_disable(); -#endif - return -1; -} - -static jint isEnabledNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - return bt_is_enabled(); + return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32); +#else + return JNI_FALSE; #endif - return -1; } -static jboolean setPinNative(JNIEnv *env, jobject object, jstring address, - jstring pin, int nativeData) { +static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key, + jint value) { #ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *msg = (DBusMessage *)nativeData; - DBusMessage *reply = dbus_message_new_method_return(msg); - if (!reply) { - LOGE("%s: Cannot create message reply to return PIN code to " - "D-Bus\n", __FUNCTION__); - dbus_message_unref(msg); - return JNI_FALSE; - } - - const char *c_pin = env->GetStringUTFChars(pin, NULL); - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin, - DBUS_TYPE_INVALID); - - dbus_connection_send(nat->conn, reply, NULL); - dbus_message_unref(msg); - dbus_message_unref(reply); - env->ReleaseStringUTFChars(pin, c_pin); - return JNI_TRUE; - } -#endif + return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN); +#else return JNI_FALSE; -} - -static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address, - int nativeData) { -#ifdef HAVE_BLUETOOTH - LOGV(__FUNCTION__); - native_data_t *nat = get_native_data(env, object); - if (nat) { - DBusMessage *msg = (DBusMessage *)nativeData; - DBusMessage *reply = dbus_message_new_error(msg, - "org.bluez.Error.Canceled", "PIN Entry was canceled"); - if (!reply) { - LOGE("%s: Cannot create message reply to return PIN cancel to " - "D-BUS\n", __FUNCTION__); - dbus_message_unref(msg); - return JNI_FALSE; - } - - dbus_connection_send(nat->conn, reply, NULL); - dbus_message_unref(msg); - dbus_message_unref(reply); - return JNI_TRUE; - } #endif - return JNI_FALSE; } + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"classInitNative", "()V", (void*)classInitNative}, {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, + {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative}, + {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative}, {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative}, @@ -983,46 +646,25 @@ static JNINativeMethod sMethods[] = { {"enableNative", "()I", (void *)enableNative}, {"disableNative", "()I", (void *)disableNative}, - {"getAddressNative", "()Ljava/lang/String;", (void *)getAddressNative}, - {"getNameNative", "()Ljava/lang/String;", (void*)getNameNative}, - {"setNameNative", "(Ljava/lang/String;)Z", (void *)setNameNative}, - {"getVersionNative", "()Ljava/lang/String;", (void *)getVersionNative}, - {"getRevisionNative", "()Ljava/lang/String;", (void *)getRevisionNative}, - {"getManufacturerNative", "()Ljava/lang/String;", (void *)getManufacturerNative}, - {"getCompanyNative", "()Ljava/lang/String;", (void *)getCompanyNative}, - - {"getModeNative", "()Ljava/lang/String;", (void *)getModeNative}, - {"setModeNative", "(Ljava/lang/String;)Z", (void *)setModeNative}, - - {"getDiscoverableTimeoutNative", "()I", (void *)getDiscoverableTimeoutNative}, - {"setDiscoverableTimeoutNative", "(I)Z", (void *)setDiscoverableTimeoutNative}, - - {"startDiscoveryNative", "(Z)Z", (void*)startDiscoveryNative}, - {"cancelDiscoveryNative", "()Z", (void *)cancelDiscoveryNative}, - {"startPeriodicDiscoveryNative", "()Z", (void *)startPeriodicDiscoveryNative}, - {"stopPeriodicDiscoveryNative", "()Z", (void *)stopPeriodicDiscoveryNative}, - {"isPeriodicDiscoveryNative", "()Z", (void *)isPeriodicDiscoveryNative}, - {"listRemoteDevicesNative", "()[Ljava/lang/String;", (void *)listRemoteDevicesNative}, - - {"listConnectionsNative", "()[Ljava/lang/String;", (void *)listConnectionsNative}, - {"isConnectedNative", "(Ljava/lang/String;)Z", (void *)isConnectedNative}, - {"disconnectRemoteDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectRemoteDeviceNative}, - - {"createBondingNative", "(Ljava/lang/String;I)Z", (void *)createBondingNative}, - {"cancelBondingProcessNative", "(Ljava/lang/String;)Z", (void *)cancelBondingProcessNative}, - {"listBondingsNative", "()[Ljava/lang/String;", (void *)listBondingsNative}, - {"removeBondingNative", "(Ljava/lang/String;)Z", (void *)removeBondingNative}, - - {"getRemoteNameNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteNameNative}, - {"getRemoteVersionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteVersionNative}, - {"getRemoteRevisionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteRevisionNative}, - {"getRemoteClassNative", "(Ljava/lang/String;)I", (void *)getRemoteClassNative}, - {"getRemoteManufacturerNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteManufacturerNative}, - {"getRemoteCompanyNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteCompanyNative}, - {"getRemoteServiceChannelNative", "(Ljava/lang/String;S)Z", (void *)getRemoteServiceChannelNative}, - {"getRemoteFeaturesNative", "(Ljava/lang/String;)[B", (void *)getRemoteFeaturesNative}, - {"lastSeenNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastSeenNative}, - {"lastUsedNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastUsedNative}, + {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative}, + {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", + (void *)getDevicePropertiesNative}, + {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z", + (void *)setAdapterPropertyStringNative}, + {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z", + (void *)setAdapterPropertyBooleanNative}, + {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z", + (void *)setAdapterPropertyIntegerNative}, + + {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative}, + {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative}, + + {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative}, + {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative}, + {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative}, + {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I", + (void *)getDeviceServiceChannelNative}, + {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative}, {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative}, }; diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index ad24136..0857cb3 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -39,30 +39,19 @@ namespace android { #ifdef HAVE_BLUETOOTH static jfieldID field_mNativeData; -static jmethodID method_onModeChanged; -static jmethodID method_onNameChanged; -static jmethodID method_onDiscoveryStarted; -static jmethodID method_onDiscoveryCompleted; -static jmethodID method_onRemoteDeviceFound; -static jmethodID method_onRemoteDeviceDisappeared; -static jmethodID method_onRemoteClassUpdated; -static jmethodID method_onRemoteNameUpdated; -static jmethodID method_onRemoteNameFailed; -static jmethodID method_onRemoteDeviceConnected; -static jmethodID method_onRemoteDeviceDisconnectRequested; -static jmethodID method_onRemoteDeviceDisconnected; -static jmethodID method_onBondingCreated; -static jmethodID method_onBondingRemoved; - -static jmethodID method_onCreateBondingResult; -static jmethodID method_onGetRemoteServiceChannelResult; - -static jmethodID method_onPasskeyAgentRequest; -static jmethodID method_onPasskeyAgentCancel; -static jmethodID method_onAuthAgentAuthorize; -static jmethodID method_onAuthAgentCancel; - -static jmethodID method_onRestartRequired; +static jmethodID method_onPropertyChanged; +static jmethodID method_onDevicePropertyChanged; +static jmethodID method_onDeviceFound; +static jmethodID method_onDeviceDisappeared; +static jmethodID method_onDeviceCreated; +static jmethodID method_onDeviceRemoved; + +static jmethodID method_onCreatePairedDeviceResult; +static jmethodID method_onGetDeviceServiceChannelResult; + +static jmethodID method_onRequestPinCode; +static jmethodID method_onAgentAuthorize; +static jmethodID method_onAgentCancel; typedef event_loop_native_data_t native_data_t; @@ -80,30 +69,26 @@ static void classInitNative(JNIEnv* env, jclass clazz) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH - method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V"); - method_onNameChanged = env->GetMethodID(clazz, "onNameChanged", "(Ljava/lang/String;)V"); - method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V"); - method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V"); - method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V"); - method_onRemoteDeviceDisappeared = env->GetMethodID(clazz, "onRemoteDeviceDisappeared", "(Ljava/lang/String;)V"); - method_onRemoteClassUpdated = env->GetMethodID(clazz, "onRemoteClassUpdated", "(Ljava/lang/String;I)V"); - method_onRemoteNameUpdated = env->GetMethodID(clazz, "onRemoteNameUpdated", "(Ljava/lang/String;Ljava/lang/String;)V"); - method_onRemoteNameFailed = env->GetMethodID(clazz, "onRemoteNameFailed", "(Ljava/lang/String;)V"); - method_onRemoteDeviceConnected = env->GetMethodID(clazz, "onRemoteDeviceConnected", "(Ljava/lang/String;)V"); - method_onRemoteDeviceDisconnectRequested = env->GetMethodID(clazz, "onRemoteDeviceDisconnectRequested", "(Ljava/lang/String;)V"); - method_onRemoteDeviceDisconnected = env->GetMethodID(clazz, "onRemoteDeviceDisconnected", "(Ljava/lang/String;)V"); - method_onBondingCreated = env->GetMethodID(clazz, "onBondingCreated", "(Ljava/lang/String;)V"); - method_onBondingRemoved = env->GetMethodID(clazz, "onBondingRemoved", "(Ljava/lang/String;)V"); - - method_onCreateBondingResult = env->GetMethodID(clazz, "onCreateBondingResult", "(Ljava/lang/String;I)V"); - - method_onPasskeyAgentRequest = env->GetMethodID(clazz, "onPasskeyAgentRequest", "(Ljava/lang/String;I)V"); - method_onPasskeyAgentCancel = env->GetMethodID(clazz, "onPasskeyAgentCancel", "(Ljava/lang/String;)V"); - method_onAuthAgentAuthorize = env->GetMethodID(clazz, "onAuthAgentAuthorize", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); - method_onAuthAgentCancel = env->GetMethodID(clazz, "onAuthAgentCancel", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - method_onGetRemoteServiceChannelResult = env->GetMethodID(clazz, "onGetRemoteServiceChannelResult", "(Ljava/lang/String;I)V"); - - method_onRestartRequired = env->GetMethodID(clazz, "onRestartRequired", "()V"); + method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged", + "([Ljava/lang/String;)V"); + method_onDevicePropertyChanged = env->GetMethodID(clazz, + "onDevicePropertyChanged", + "(Ljava/lang/String;[Ljava/lang/String;)V"); + method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound", + "(Ljava/lang/String;[Ljava/lang/String;)V"); + method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared", + "(Ljava/lang/String;)V"); + method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V"); + method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V"); + + method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult", + "(Ljava/lang/String;I)V"); + + method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize", + "(Ljava/lang/String;Ljava/lang/String;)Z"); + method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V"); + method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode", + "(Ljava/lang/String;I)V"); field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I"); #endif @@ -154,9 +139,11 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) { #ifdef HAVE_BLUETOOTH static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, void *data); -static DBusHandlerResult agent_event_filter(DBusConnection *conn, - DBusMessage *msg, - void *data); +DBusHandlerResult agent_event_filter(DBusConnection *conn, + DBusMessage *msg, + void *data); +static int register_agent(native_data_t *nat, + const char *agent_path, const char *capabilities); static const DBusObjectPathVTable agent_vtable = { NULL, agent_event_filter, NULL, NULL, NULL, NULL @@ -178,11 +165,12 @@ static short dbus_flags_to_unix_events(unsigned int flags) { static jboolean setUpEventLoop(native_data_t *nat) { LOGV(__FUNCTION__); - dbus_threads_init_default(); - DBusError err; - dbus_error_init(&err); if (nat != NULL && nat->conn != NULL) { + dbus_threads_init_default(); + DBusError err; + dbus_error_init(&err); + // Add a filter for all incoming messages if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){ return JNI_FALSE; @@ -204,108 +192,143 @@ static jboolean setUpEventLoop(native_data_t *nat) { return JNI_FALSE; } dbus_bus_add_match(nat->conn, - "type='signal',interface='org.bluez.audio.Manager'", + "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'", &err); if (dbus_error_is_set(&err)) { LOG_AND_FREE_DBUS_ERROR(&err); return JNI_FALSE; } dbus_bus_add_match(nat->conn, - "type='signal',interface='org.bluez.audio.Device'", - &err); - if (dbus_error_is_set(&err)) { - LOG_AND_FREE_DBUS_ERROR(&err); - return JNI_FALSE; - } - dbus_bus_add_match(nat->conn, - "type='signal',interface='org.bluez.audio.Sink'", + "type='signal',interface='org.bluez.AudioSink'", &err); if (dbus_error_is_set(&err)) { LOG_AND_FREE_DBUS_ERROR(&err); return JNI_FALSE; } - // Add an object handler for passkey agent method calls - const char *path = "/android/bluetooth/Agent"; - if (!dbus_connection_register_object_path(nat->conn, path, - &agent_vtable, nat)) { - LOGE("%s: Can't register object path %s for agent!", - __FUNCTION__, path); + const char *agent_path = "/android/bluetooth/agent"; + const char *capabilities = "DisplayYesNo"; + if (register_agent(nat, agent_path, capabilities) < 0) { + dbus_connection_unregister_object_path (nat->conn, agent_path); return JNI_FALSE; } + return JNI_TRUE; + } + return JNI_FALSE; +} - // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep - // trying for 10 seconds. - int attempt; - for (attempt = 0; attempt < 1000; attempt++) { - DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err, - BLUEZ_DBUS_BASE_PATH, - "org.bluez.Security", "RegisterDefaultPasskeyAgent", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - if (reply) { - // Success - dbus_message_unref(reply); - LOGV("Registered agent on attempt %d of 1000\n", attempt); - break; - } else if (dbus_error_has_name(&err, - "org.freedesktop.DBus.Error.ServiceUnknown")) { - // hcid is still down, retry - dbus_error_free(&err); - usleep(10000); // 10 ms - } else { - // Some other error we weren't expecting - LOG_AND_FREE_DBUS_ERROR(&err); - return JNI_FALSE; - } + +const char * get_adapter_path(DBusConnection *conn) { + DBusMessage *msg, *reply; + DBusError err; + const char *device_path = NULL; + msg = dbus_message_new_method_call("org.bluez", "/", + "org.bluez.Manager", "DefaultAdapter"); + if (!msg) { + LOGE("%s: Can't allocate new method call for GetProperties!", + __FUNCTION__); + return NULL; + } + dbus_message_append_args(msg, DBUS_TYPE_INVALID); + + dbus_error_init(&err); + reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); + dbus_message_unref(msg); + + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); } - if (attempt == 1000) { - LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), " - "is hcid running?"); - return JNI_FALSE; + return NULL; + } + if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH, + &device_path, DBUS_TYPE_INVALID) + || !device_path){ + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); } + return NULL; + } + return device_path; +} - // Now register the Auth agent - DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err, - BLUEZ_DBUS_BASE_PATH, - "org.bluez.Security", "RegisterDefaultAuthorizationAgent", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - if (!reply) { +static int register_agent(native_data_t *nat, + const char * agent_path, const char * capabilities) +{ + DBusMessage *msg, *reply; + DBusError err; + + if (!dbus_connection_register_object_path(nat->conn, agent_path, + &agent_vtable, nat)) { + LOGE("%s: Can't register object path %s for agent!", + __FUNCTION__, agent_path); + return -1; + } + + nat->adapter = get_adapter_path(nat->conn); + msg = dbus_message_new_method_call("org.bluez", nat->adapter, + "org.bluez.Adapter", "RegisterAgent"); + if (!msg) { + LOGE("%s: Can't allocate new method call for agent!", + __FUNCTION__); + return -1; + } + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_STRING, &capabilities, + DBUS_TYPE_INVALID); + + dbus_error_init(&err); + reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); + dbus_message_unref(msg); + + if (!reply) { + LOGE("%s: Can't register agent!", __FUNCTION__); + if (dbus_error_is_set(&err)) { LOG_AND_FREE_DBUS_ERROR(&err); - return JNI_FALSE; } - - dbus_message_unref(reply); - return JNI_TRUE; + return -1; } - return JNI_FALSE; + dbus_message_unref(reply); + dbus_connection_flush(nat->conn); + + return 0; } static void tearDownEventLoop(native_data_t *nat) { LOGV(__FUNCTION__); if (nat != NULL && nat->conn != NULL) { + DBusMessage *msg, *reply; DBusError err; dbus_error_init(&err); + const char * agent_path = "/android/bluetooth/agent"; + + msg = dbus_message_new_method_call("org.bluez", + nat->adapter, + "org.bluez.Adapter", + "UnregisterAgent"); + if (msg != NULL) { + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_INVALID); + reply = dbus_connection_send_with_reply_and_block(nat->conn, + msg, -1, &err); - const char *path = "/android/bluetooth/Agent"; - DBusMessage *reply = - dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH, - "org.bluez.Security", "UnregisterDefaultPasskeyAgent", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - if (reply) dbus_message_unref(reply); - - reply = - dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH, - "org.bluez.Security", "UnregisterDefaultAuthorizationAgent", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - if (reply) dbus_message_unref(reply); + if (!reply) { + if (dbus_error_is_set(&err)) { + LOG_AND_FREE_DBUS_ERROR(&err); + dbus_error_free(&err); + } + } else { + dbus_message_unref(reply); + } + dbus_message_unref(msg); + } else { + LOGE("%s: Can't create new method call!", __FUNCTION__); + } - dbus_connection_unregister_object_path(nat->conn, path); + dbus_connection_flush(nat->conn); + dbus_connection_unregister_object_path(nat->conn, agent_path); dbus_bus_remove_match(nat->conn, "type='signal',interface='org.bluez.audio.Sink'", @@ -660,267 +683,129 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - LOGV("%s: Received signal %s:%s from %s", __FUNCTION__, - dbus_message_get_interface(msg), dbus_message_get_member(msg), - dbus_message_get_path(msg)); + // STOPSHIP: Change to LOGV + LOGE("%s: Received signal %s:%s from %s", __FUNCTION__, + dbus_message_get_interface(msg), dbus_message_get_member(msg), + dbus_message_get_path(msg)); if (dbus_message_is_signal(msg, "org.bluez.Adapter", - "RemoteDeviceFound")) { + "DeviceFound")) { char *c_address; - int n_class; - short n_rssi; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_UINT32, &n_class, - DBUS_TYPE_INT16, &n_rssi, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s class = %#X rssi = %hd", c_address, n_class, - n_rssi); + DBusMessageIter iter; + jobjectArray str_array = NULL; + if (dbus_message_iter_init(msg, &iter)) { + dbus_message_iter_get_basic(&iter, &c_address); + if (dbus_message_iter_next(&iter)) + str_array = + parse_remote_device_properties(env, &iter); + } + if (str_array != NULL) { env->CallVoidMethod(nat->me, - method_onRemoteDeviceFound, + method_onDeviceFound, env->NewStringUTF(c_address), - (jint)n_class, - (jshort)n_rssi); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + str_array); + } else + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "DiscoveryStarted")) { - LOGI("DiscoveryStarted signal received"); - env->CallVoidMethod(nat->me, method_onDiscoveryStarted); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "DiscoveryCompleted")) { - LOGI("DiscoveryCompleted signal received"); - env->CallVoidMethod(nat->me, method_onDiscoveryCompleted); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteDeviceDisappeared")) { + "org.bluez.Adapter", + "DeviceDisappeared")) { char *c_address; if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &c_address, DBUS_TYPE_INVALID)) { LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, method_onRemoteDeviceDisappeared, + env->CallVoidMethod(nat->me, method_onDeviceDisappeared, env->NewStringUTF(c_address)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteClassUpdated")) { - char *c_address; - int n_class; + "org.bluez.Adapter", + "DeviceCreated")) { + char *c_object_path; if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_UINT32, &n_class, + DBUS_TYPE_OBJECT_PATH, &c_object_path, DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, method_onRemoteClassUpdated, - env->NewStringUTF(c_address), (jint)n_class); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteNameUpdated")) { - char *c_address; - char *c_name; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_STRING, &c_name, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s, name = %s", c_address, c_name); - env->CallVoidMethod(nat->me, - method_onRemoteNameUpdated, - env->NewStringUTF(c_address), - env->NewStringUTF(c_name)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteNameFailed")) { - char *c_address; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); + LOGV("... address = %s", c_object_path); env->CallVoidMethod(nat->me, - method_onRemoteNameFailed, - env->NewStringUTF(c_address)); + method_onDeviceCreated, + env->NewStringUTF(c_object_path)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteDeviceConnected")) { - char *c_address; + "org.bluez.Adapter", + "DeviceRemoved")) { + char *c_object_path; if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, - method_onRemoteDeviceConnected, - env->NewStringUTF(c_address)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteDeviceDisconnectRequested")) { - char *c_address; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, - method_onRemoteDeviceDisconnectRequested, - env->NewStringUTF(c_address)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "RemoteDeviceDisconnected")) { - char *c_address; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, - method_onRemoteDeviceDisconnected, - env->NewStringUTF(c_address)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "BondingCreated")) { - char *c_address; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, - method_onBondingCreated, - env->NewStringUTF(c_address)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "BondingRemoved")) { - char *c_address; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_address, - DBUS_TYPE_INVALID)) { - LOGV("... address = %s", c_address); - env->CallVoidMethod(nat->me, - method_onBondingRemoved, - env->NewStringUTF(c_address)); + DBUS_TYPE_OBJECT_PATH, &c_object_path, + DBUS_TYPE_INVALID)) { + LOGV("... Object Path = %s", c_object_path); + env->CallVoidMethod(nat->me, + method_onDeviceRemoved, + env->NewStringUTF(c_object_path)); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", - "ModeChanged")) { - char *c_mode; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_mode, - DBUS_TYPE_INVALID)) { - LOGV("... mode = %s", c_mode); + "PropertyChanged")) { + jobjectArray str_array = parse_adapter_property_change(env, msg); + if (str_array != NULL) { + /* Check if bluetoothd has (re)started, if so update the path. */ + jstring property =(jstring) env->GetObjectArrayElement(str_array, 0); + const char *c_property = env->GetStringUTFChars(property, NULL); + if (!strncmp(c_property, "Powered", strlen("Powered"))) { + jstring value = + (jstring) env->GetObjectArrayElement(str_array, 1); + const char *c_value = env->GetStringUTFChars(value, NULL); + if (!strncmp(c_value, "true", strlen("true"))) + nat->adapter = get_adapter_path(nat->conn); + env->ReleaseStringUTFChars(value, c_value); + } + env->ReleaseStringUTFChars(property, c_property); + env->CallVoidMethod(nat->me, - method_onModeChanged, - env->NewStringUTF(c_mode)); + method_onPropertyChanged, + str_array); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal(msg, - "org.bluez.Adapter", - "NameChanged")) { - char *c_name; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_name, - DBUS_TYPE_INVALID)) { - LOGV("... name = %s", c_name); + "org.bluez.Device", + "PropertyChanged")) { + jobjectArray str_array = parse_remote_device_property_change(env, msg); + if (str_array != NULL) { + const char *remote_device_path = dbus_message_get_path(msg); env->CallVoidMethod(nat->me, - method_onNameChanged, - env->NewStringUTF(c_name)); - } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(msg, - "org.freedesktop.DBus", - "NameOwnerChanged")) { - char *c_name; - char *c_old_owner; - char *c_new_owner; - if (dbus_message_get_args(msg, &err, - DBUS_TYPE_STRING, &c_name, - DBUS_TYPE_STRING, &c_old_owner, - DBUS_TYPE_STRING, &c_new_owner, - DBUS_TYPE_INVALID)) { - LOGV("... name = %s", c_name); - LOGV("... old_owner = %s", c_old_owner); - LOGV("... new_owner = %s", c_new_owner); - if (!strcmp(c_name, "org.bluez") && c_new_owner[0] != '\0') { - // New owner of org.bluez. This can only happen when hcid - // restarts. Need to restart framework BT services to recover. - LOGE("Looks like hcid restarted"); - env->CallVoidMethod(nat->me, method_onRestartRequired); - } + method_onDevicePropertyChanged, + env->NewStringUTF(remote_device_path), + str_array); } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); return DBUS_HANDLER_RESULT_HANDLED; - } + } return a2dp_event_filter(msg, env); } // Called by dbus during WaitForAndDispatchEventNative() -static DBusHandlerResult agent_event_filter(DBusConnection *conn, - DBusMessage *msg, void *data) { +DBusHandlerResult agent_event_filter(DBusConnection *conn, + DBusMessage *msg, void *data) { native_data_t *nat = (native_data_t *)data; JNIEnv *env; - nat->vm->GetEnv((void**)&env, nat->envVer); if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) { LOGV("%s: not interested (not a method call).", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - LOGV("%s: Received method %s:%s", __FUNCTION__, + LOGI("%s: Received method %s:%s", __FUNCTION__, dbus_message_get_interface(msg), dbus_message_get_member(msg)); - if (dbus_message_is_method_call(msg, - "org.bluez.PasskeyAgent", "Request")) { - - const char *adapter; - const char *address; - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &adapter, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) { - LOGE("%s: Invalid arguments for Request() method", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - LOGV("... address = %s", address); - - dbus_message_ref(msg); // increment refcount because we pass to java + if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED; - env->CallVoidMethod(nat->me, method_onPasskeyAgentRequest, - env->NewStringUTF(address), (int)msg); - - return DBUS_HANDLER_RESULT_HANDLED; - - } else if (dbus_message_is_method_call(msg, - "org.bluez.PasskeyAgent", "Cancel")) { - - const char *adapter; - const char *address; - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &adapter, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) { - LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - LOGV("... address = %s", address); + nat->vm->GetEnv((void**)&env, nat->envVer); + if (dbus_message_is_method_call(msg, + "org.bluez.Agent", "Cancel")) { - env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel, - env->NewStringUTF(address)); + env->CallVoidMethod(nat->me, method_onAgentCancel); // reply DBusMessage *reply = dbus_message_new_method_return(msg); @@ -933,41 +818,23 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call(msg, - "org.bluez.PasskeyAgent", "Release")) { - LOGW("We are no longer the passkey agent!"); - - // reply - DBusMessage *reply = dbus_message_new_method_return(msg); - if (!reply) { - LOGE("%s: Cannot create message reply\n", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - dbus_connection_send(nat->conn, reply, NULL); - dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_method_call(msg, - "org.bluez.AuthorizationAgent", "Authorize")) { - const char *adapter; - const char *address; - const char *service; + "org.bluez.Agent", "Authorize")) { + char *object_path; const char *uuid; if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &adapter, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_STRING, &service, + DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID)) { LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - LOGV("... address = %s", address); - LOGV("... service = %s", service); + LOGV("... object_path = %s", object_path); LOGV("... uuid = %s", uuid); - bool auth_granted = env->CallBooleanMethod(nat->me, - method_onAuthAgentAuthorize, env->NewStringUTF(address), - env->NewStringUTF(service), env->NewStringUTF(uuid)); + bool auth_granted = + env->CallBooleanMethod(nat->me, method_onAgentAuthorize, + env->NewStringUTF(object_path), env->NewStringUTF(uuid)); // reply if (auth_granted) { @@ -990,43 +857,22 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, } return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call(msg, - "org.bluez.AuthorizationAgent", "Cancel")) { - const char *adapter; - const char *address; - const char *service; - const char *uuid; + "org.bluez.Agent", "RequestPinCode")) { + char *object_path; if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &adapter, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_STRING, &service, - DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID)) { - LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__); + LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - LOGV("... address = %s", address); - LOGV("... service = %s", service); - LOGV("... uuid = %s", uuid); - - env->CallVoidMethod(nat->me, - method_onAuthAgentCancel, env->NewStringUTF(address), - env->NewStringUTF(service), env->NewStringUTF(uuid)); - - // reply - DBusMessage *reply = dbus_message_new_method_return(msg); - if (!reply) { - LOGE("%s: Cannot create message reply\n", __FUNCTION__); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - dbus_connection_send(nat->conn, reply, NULL); - dbus_message_unref(reply); + dbus_message_ref(msg); // increment refcount because we pass to java + env->CallVoidMethod(nat->me, method_onRequestPinCode, + env->NewStringUTF(object_path), + int(msg)); return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_method_call(msg, - "org.bluez.AuthorizationAgent", "Release")) { - LOGW("We are no longer the auth agent!"); - + "org.bluez.Agent", "Release")) { // reply DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) { @@ -1037,7 +883,7 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, dbus_message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } else { - LOGV("... ignored"); + LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg)); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -1055,7 +901,7 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, #define BOND_RESULT_REMOTE_DEVICE_DOWN 4 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5 -void onCreateBondingResult(DBusMessage *msg, void *user, void *n) { +void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) { LOGV(__FUNCTION__); native_data_t *nat = (native_data_t *)n; @@ -1106,7 +952,7 @@ void onCreateBondingResult(DBusMessage *msg, void *user, void *n) { } env->CallVoidMethod(nat->me, - method_onCreateBondingResult, + method_onCreatePairedDeviceResult, env->NewStringUTF(address), result); done: @@ -1114,7 +960,7 @@ done: free(user); } -void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) { +void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) { LOGV(__FUNCTION__); const char *address = (const char *) user; @@ -1133,14 +979,13 @@ void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) { !dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &channel, DBUS_TYPE_INVALID)) { - /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); dbus_error_free(&err); } done: env->CallVoidMethod(nat->me, - method_onGetRemoteServiceChannelResult, + method_onGetDeviceServiceChannelResult, env->NewStringUTF(address), channel); free(user); diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 7325432..f0885fd 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -25,12 +25,12 @@ #include <stdio.h> #include <utils/Atomic.h> -#include <utils/IInterface.h> -#include <utils/IPCThreadState.h> +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> #include <utils/Log.h> -#include <utils/Parcel.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> #include <android_runtime/AndroidRuntime.h> diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h index 16d993d..495e76a 100644 --- a/core/jni/android_util_Binder.h +++ b/core/jni/android_util_Binder.h @@ -15,7 +15,7 @@ ** limitations under the License. */ -#include <utils/IBinder.h> +#include <binder/IBinder.h> #include "jni.h" diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 945a325..1c9ee7d 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -18,9 +18,9 @@ #define LOG_TAG "Process" #include <utils/Log.h> -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> #include <utils/String8.h> #include <utils/Vector.h> |