summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-11-12 18:45:53 -0800
committerJean-Baptiste Queru <jbq@google.com>2009-11-13 13:53:39 -0800
commit9db3d07b9620b4269ab33f78604a36327e536ce1 (patch)
tree41e294f34b9695187af098cd42167489fb0c8fb0 /core/jni
parent6c63ee4fc4acae4bbbbd2a49e0a68206221f0de0 (diff)
downloadframeworks_base-9db3d07b9620b4269ab33f78604a36327e536ce1.zip
frameworks_base-9db3d07b9620b4269ab33f78604a36327e536ce1.tar.gz
frameworks_base-9db3d07b9620b4269ab33f78604a36327e536ce1.tar.bz2
eclair snapshot
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/.android_server_BluetoothEventLoop.cpp.swpbin0 -> 16384 bytes
-rw-r--r--core/jni/ActivityManager.cpp6
-rw-r--r--core/jni/Android.mk16
-rw-r--r--core/jni/AndroidRuntime.cpp226
-rw-r--r--core/jni/CursorWindow.cpp2
-rw-r--r--core/jni/CursorWindow.h2
-rw-r--r--core/jni/android/graphics/Bitmap.cpp17
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp7
-rw-r--r--core/jni/android/graphics/Canvas.cpp3
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp6
-rw-r--r--core/jni/android/graphics/Graphics.cpp6
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h2
-rw-r--r--core/jni/android/graphics/MaskFilter.cpp21
-rw-r--r--core/jni/android/graphics/NinePatch.cpp29
-rw-r--r--core/jni/android/graphics/NinePatchImpl.cpp40
-rw-r--r--core/jni/android/graphics/Paint.cpp23
-rw-r--r--core/jni/android/graphics/Path.cpp5
-rw-r--r--core/jni/android/graphics/Region.cpp2
-rw-r--r--core/jni/android/graphics/Typeface.cpp22
-rw-r--r--core/jni/android/opengl/util.cpp141
-rw-r--r--core/jni/android_bluetooth_BluetoothSocket.cpp557
-rw-r--r--core/jni/android_bluetooth_Database.cpp184
-rw-r--r--core/jni/android_bluetooth_HeadsetBase.cpp28
-rw-r--r--core/jni/android_bluetooth_RfcommSocket.cpp621
-rw-r--r--core/jni/android_bluetooth_common.cpp332
-rw-r--r--core/jni/android_bluetooth_common.h19
-rw-r--r--core/jni/android_database_CursorWindow.cpp65
-rw-r--r--core/jni/android_database_SQLiteDatabase.cpp5
-rw-r--r--core/jni/android_emoji_EmojiFactory.cpp7
-rw-r--r--core/jni/android_hardware_Camera.cpp201
-rwxr-xr-xcore/jni/android_location_GpsLocationProvider.cpp165
-rw-r--r--core/jni/android_media_AudioRecord.cpp26
-rw-r--r--core/jni/android_media_AudioSystem.cpp166
-rw-r--r--core/jni/android_media_AudioTrack.cpp49
-rw-r--r--core/jni/android_media_ToneGenerator.cpp8
-rw-r--r--core/jni/android_net_NetUtils.cpp12
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp24
-rw-r--r--core/jni/android_opengl_GLES11.cpp12
-rw-r--r--core/jni/android_os_Debug.cpp12
-rw-r--r--core/jni/android_os_Exec.cpp215
-rw-r--r--core/jni/android_os_MemoryFile.cpp12
-rw-r--r--core/jni/android_os_SystemProperties.cpp109
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp308
-rw-r--r--core/jni/android_server_BluetoothDeviceService.cpp1035
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp850
-rw-r--r--core/jni/android_server_BluetoothService.cpp915
-rw-r--r--core/jni/android_text_format_Time.cpp10
-rw-r--r--core/jni/android_util_Binder.cpp10
-rw-r--r--core/jni/android_util_Binder.h2
-rw-r--r--core/jni/android_util_EventLog.cpp92
-rw-r--r--core/jni/android_util_Process.cpp92
-rw-r--r--core/jni/android_view_Surface.cpp307
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp3
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp12
54 files changed, 3788 insertions, 3253 deletions
diff --git a/core/jni/.android_server_BluetoothEventLoop.cpp.swp b/core/jni/.android_server_BluetoothEventLoop.cpp.swp
new file mode 100644
index 0000000..d36e403
--- /dev/null
+++ b/core/jni/.android_server_BluetoothEventLoop.cpp.swp
Binary files differ
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 888cb11..015268b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,10 +11,16 @@ 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
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
LOCAL_SRC_FILES:= \
ActivityManager.cpp \
AndroidRuntime.cpp \
@@ -39,7 +45,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 \
@@ -104,13 +109,12 @@ 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_BluetoothService.cpp \
android_server_BluetoothEventLoop.cpp \
android_server_BluetoothA2dpService.cpp \
android_message_digest_sha1.cpp \
@@ -150,11 +154,11 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
+ libbinder \
libnetutils \
libui \
libskiagl \
- libsgl \
- libcorecg \
+ libskia \
libsqlite \
libdvm \
libEGL \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c815301..f61e247 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,12 +142,11 @@ 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_BluetoothService(JNIEnv* env);
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -509,11 +507,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,25 +525,20 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
+ char heapsizeOptsBuf[sizeof("-Xmx")-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) {
@@ -557,10 +556,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;
@@ -572,19 +580,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";
@@ -603,16 +598,10 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
mOptions.add(opt);
//options[curOpt++].optionString = "-verbose:class";
-#ifdef CUSTOM_RUNTIME_HEAP_MAX
-#define __make_max_heap_opt(val) #val
-#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val)
- opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX);
-#undef __make_max_heap_opt
-#undef _make_max_heap_opt
-#else
- /* limit memory use to 16MB */
- opt.optionString = "-Xmx16m";
-#endif
+ strcpy(heapsizeOptsBuf, "-Xmx");
+ property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
+ //LOGI("Heap size: %s", heapsizeOptsBuf);
+ opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
/*
@@ -658,6 +647,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);
}
}
@@ -697,13 +690,87 @@ 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);
+ }
+
+ /*
+ * Enable profile collection on JIT'ed code.
+ */
+ property_get("dalvik.vm.jit.profile", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xjitprofile";
+ 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";
@@ -771,11 +838,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.
*/
@@ -845,7 +962,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
bail:
free(slashClassName);
- free(stackTraceFile);
}
void AndroidRuntime::start()
@@ -1095,7 +1211,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),
@@ -1117,12 +1232,11 @@ 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_BluetoothService),
REG_JNI(register_android_server_BluetoothEventLoop),
REG_JNI(register_android_server_BluetoothA2dpService),
REG_JNI(register_android_message_digest_sha1),
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 3fb07a7..0f1b845 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"
@@ -317,6 +317,11 @@ static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
return !bitmap->isOpaque();
}
+static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap,
+ jboolean hasAlpha) {
+ bitmap->setIsOpaque(!hasAlpha);
+}
+
///////////////////////////////////////////////////////////////////////////////
static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
@@ -332,6 +337,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
const int width = p->readInt32();
const int height = p->readInt32();
const int rowBytes = p->readInt32();
+ const int density = p->readInt32();
if (SkBitmap::kARGB_8888_Config != config &&
SkBitmap::kRGB_565_Config != config &&
@@ -369,12 +375,13 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
memcpy(bitmap->getPixels(), p->readInplace(size), size);
bitmap->unlockPixels();
- return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL);
+ return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL, density);
}
static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
const SkBitmap* bitmap,
- jboolean isMutable, jobject parcel) {
+ jboolean isMutable, jint density,
+ jobject parcel) {
if (parcel == NULL) {
SkDebugf("------- writeToParcel null parcel\n");
return false;
@@ -387,6 +394,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
p->writeInt32(bitmap->width());
p->writeInt32(bitmap->height());
p->writeInt32(bitmap->rowBytes());
+ p->writeInt32(density);
if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
SkColorTable* ctable = bitmap->getColorTable();
@@ -543,10 +551,11 @@ static JNINativeMethod gBitmapMethods[] = {
{ "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
{ "nativeConfig", "(I)I", (void*)Bitmap_config },
{ "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
+ { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha },
{ "nativeCreateFromParcel",
"(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
(void*)Bitmap_createFromParcel },
- { "nativeWriteToParcel", "(IZLandroid/os/Parcel;)Z",
+ { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z",
(void*)Bitmap_writeToParcel },
{ "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
(void*)Bitmap_extractAlpha },
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 0c84265..65f6845 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -314,14 +314,15 @@ static jobject nullObjectReturn(const char msg[]) {
}
static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
- int sampleSize) {
- SkPixelRef* pr;
+ int sampleSize, bool ditherImage) {
+ SkImageRef* pr;
// only use ashmem for large images, since mmaps come at a price
if (bitmap->getSize() >= 32 * 1024) {
pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize);
} else {
pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize);
}
+ pr->setDitherImage(ditherImage);
bitmap->setPixelRef(pr)->unref();
return pr;
}
@@ -440,7 +441,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
SkPixelRef* pr;
if (isPurgeable) {
- pr = installPixelRef(bitmap, stream, sampleSize);
+ pr = installPixelRef(bitmap, stream, sampleSize, doDither);
} else {
// if we get here, we're in kDecodePixels_Mode and will therefore
// already have a pixelref installed.
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 1c2e055..dc72008 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/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index ca1cb7d..2e0caed 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -351,7 +351,7 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
///////////////////////////////////////////////////////////////////////////////////////////
jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
- jbyteArray ninepatch)
+ jbyteArray ninepatch, int density)
{
SkASSERT(bitmap != NULL);
SkASSERT(NULL != bitmap->pixelRef());
@@ -359,7 +359,7 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
jobject obj = env->AllocObject(gBitmap_class);
if (obj) {
env->CallVoidMethod(obj, gBitmap_constructorMethodID,
- (jint)bitmap, isMutable, ninepatch);
+ (jint)bitmap, isMutable, ninepatch, density);
if (hasException(env)) {
obj = NULL;
}
@@ -541,7 +541,7 @@ int register_android_graphics_Graphics(JNIEnv* env)
gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
- "(IZ[B)V");
+ "(IZ[BI)V");
gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index f8b60a8..7adadbc 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -50,7 +50,7 @@ public:
then the bitmap must be an owner of its natively allocated pixels (via allocPixels).
*/
static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
- jbyteArray ninePatch);
+ jbyteArray ninePatch, int density = -1);
static jobject createRegion(JNIEnv* env, SkRegion* region);
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index 0f8dff1..455449e 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -1,6 +1,7 @@
#include "GraphicsJNI.h"
#include "SkMaskFilter.h"
#include "SkBlurMaskFilter.h"
+#include "SkTableMaskFilter.h"
#include <jni.h>
@@ -39,6 +40,19 @@ public:
ThrowIAE_IfNull(env, filter);
return filter;
}
+
+ static SkMaskFilter* createTable(JNIEnv* env, jobject, jbyteArray jtable) {
+ AutoJavaByteArray autoTable(env, jtable, 256);
+ return new SkTableMaskFilter((const uint8_t*)autoTable.ptr());
+ }
+
+ static SkMaskFilter* createClipTable(JNIEnv* env, jobject, int min, int max) {
+ return SkTableMaskFilter::CreateClip(min, max);
+ }
+
+ static SkMaskFilter* createGammaTable(JNIEnv* env, jobject, float gamma) {
+ return SkTableMaskFilter::CreateGamma(gamma);
+ }
};
static JNINativeMethod gMaskFilterMethods[] = {
@@ -53,6 +67,12 @@ static JNINativeMethod gEmbossMaskFilterMethods[] = {
{ "nativeConstructor", "([FFFF)I", (void*)SkMaskFilterGlue::createEmboss }
};
+static JNINativeMethod gTableMaskFilterMethods[] = {
+ { "nativeNewTable", "([B)I", (void*)SkMaskFilterGlue::createTable },
+ { "nativeNewClip", "(II)I", (void*)SkMaskFilterGlue::createClipTable },
+ { "nativeNewGamma", "(F)I", (void*)SkMaskFilterGlue::createGammaTable }
+};
+
#include <android_runtime/AndroidRuntime.h>
#define REG(env, name, array) \
@@ -67,6 +87,7 @@ int register_android_graphics_MaskFilter(JNIEnv* env)
REG(env, "android/graphics/MaskFilter", gMaskFilterMethods);
REG(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods);
REG(env, "android/graphics/EmbossMaskFilter", gEmbossMaskFilterMethods);
+ REG(env, "android/graphics/TableMaskFilter", gTableMaskFilterMethods);
return 0;
}
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index fd5271e..50df0f7 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -1,4 +1,25 @@
+/*
+**
+** 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 "9patch"
+#define LOG_NDEBUG 1
+
#include <utils/ResourceTypes.h>
+#include <utils/Log.h>
#include "SkCanvas.h"
#include "SkRegion.h"
@@ -62,6 +83,9 @@ public:
if (destDensity == srcDensity || destDensity == 0
|| srcDensity == 0) {
+ LOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
+ SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+ SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
} else {
canvas->save();
@@ -74,6 +98,11 @@ public:
bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
bounds.fLeft = bounds.fTop = 0;
+ LOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
+ SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+ SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
+ srcDensity, destDensity);
+
NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
canvas->restore();
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index f82053c..ff24a87 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -16,8 +16,10 @@
*/
#define LOG_TAG "NinePatch"
+#define LOG_NDEBUG 1
#include <utils/ResourceTypes.h>
+#include <utils/Log.h>
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -25,7 +27,7 @@
#include "SkPaint.h"
#include "SkUnPreMultiply.h"
-#define USE_TRACEx
+#define USE_TRACE
#ifdef USE_TRACE
static bool gTrace;
@@ -106,6 +108,13 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
return;
}
+
+ SkPaint defaultPaint;
+ if (NULL == paint) {
+ // matches default dither in NinePatchDrawable.java.
+ defaultPaint.setDither(true);
+ paint = &defaultPaint;
+ }
// if our canvas is GL, draw this as a mesh, which will be faster than
// in parts (which is faster for raster)
@@ -123,10 +132,10 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
SkASSERT(canvas || outRegion);
-#if 0
+#ifdef USE_TRACE
if (canvas) {
const SkMatrix& m = canvas->getTotalMatrix();
- SkDebugf("ninepatch [%g %g %g] [%g %g %g]\n",
+ LOGV("ninepatch [%g %g %g] [%g %g %g]\n",
SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
}
@@ -134,10 +143,10 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
#ifdef USE_TRACE
if (gTrace) {
- SkDEBUGF(("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height())));
- SkDEBUGF(("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height()));
- SkDEBUGF(("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]));
- SkDEBUGF(("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]));
+ LOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()));
+ LOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
+ LOGV("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]);
+ LOGV("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]);
}
#endif
@@ -146,7 +155,7 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
(paint && paint->getXfermode() == NULL && paint->getAlpha() == 0))
{
#ifdef USE_TRACE
- if (gTrace) SkDEBUGF(("======== abort ninepatch draw\n"));
+ if (gTrace) LOGV("======== abort ninepatch draw\n");
#endif
return;
}
@@ -158,11 +167,6 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
if (bitmap.getPixels() == NULL)
return;
- SkPaint defaultPaint;
- if (NULL == paint) {
- paint = &defaultPaint;
- }
-
const bool hasXfer = paint->getXfermode() != NULL;
SkRect dst;
SkIRect src;
@@ -196,8 +200,8 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
}
int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;
-#if 0
- SkDebugf("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
+#ifdef USE_TRACE
+ LOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
bitmap.width(), bitmap.height(),
SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
@@ -300,13 +304,13 @@ void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
goto nextDiv;
}
if (canvas) {
-#if 0
- SkDebugf("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
+#ifdef USE_TRACE
+ LOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
src.fLeft, src.fTop, src.width(), src.height(),
SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
- SkDebugf("--- skip patch\n");
+ LOGV("--- skip patch\n");
}
#endif
drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d1fe83e..780badc 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -48,6 +48,13 @@ static JMetricsID gFontMetrics_fieldID;
static jclass gFontMetricsInt_class;
static JMetricsID gFontMetricsInt_fieldID;
+static void defaultSettingsForAndroid(SkPaint* paint) {
+ // looks best we decided
+ paint->setHinting(SkPaint::kSlight_Hinting);
+ // utf16 is required for java
+ paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+}
+
class SkPaintGlue {
public:
@@ -57,8 +64,7 @@ public:
static SkPaint* init(JNIEnv* env, jobject clazz) {
SkPaint* obj = new SkPaint();
- // utf16 is required for java
- obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ defaultSettingsForAndroid(obj);
return obj;
}
@@ -69,8 +75,7 @@ public:
static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
obj->reset();
- // utf16 is required for java
- obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ defaultSettingsForAndroid(obj);
}
static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
@@ -564,11 +569,11 @@ static JNINativeMethod methods[] = {
{"descent","()F", (void*) SkPaintGlue::descent},
{"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics},
{"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt},
- {"measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
- {"measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
- {"measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
- {"breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
- {"breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
+ {"native_measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
+ {"native_measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
+ {"native_measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
+ {"native_breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
+ {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
{"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
{"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___CIIFFPath},
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/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 21dde63..238ece1 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -141,6 +141,25 @@ static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath)
return SkTypeface::CreateFromFile(str.c_str());
}
+#define MIN_GAMMA (0.1f)
+#define MAX_GAMMA (10.0f)
+static float pinGamma(float gamma) {
+ if (gamma < MIN_GAMMA) {
+ gamma = MIN_GAMMA;
+ } else if (gamma > MAX_GAMMA) {
+ gamma = MAX_GAMMA;
+ }
+ return gamma;
+}
+
+extern void skia_set_text_gamma(float, float);
+
+static void Typeface_setGammaForText(JNIEnv* env, jobject, jfloat blackGamma,
+ jfloat whiteGamma) {
+ // Comment this out for release builds. This is only used during development
+ skia_set_text_gamma(pinGamma(blackGamma), pinGamma(whiteGamma));
+}
+
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gTypefaceMethods[] = {
@@ -151,7 +170,8 @@ static JNINativeMethod gTypefaceMethods[] = {
{ "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
(void*)Typeface_createFromAsset },
{ "nativeCreateFromFile", "(Ljava/lang/String;)I",
- (void*)Typeface_createFromFile }
+ (void*)Typeface_createFromFile },
+ { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
};
int register_android_graphics_Typeface(JNIEnv* env);
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 41044db..4041346 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -1,16 +1,16 @@
/**
** Copyright 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
+ ** 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
+ ** 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
+ ** 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.
*/
@@ -53,18 +53,18 @@ public:
MallocHelper() {
mData = 0;
}
-
+
~MallocHelper() {
if (mData != 0) {
free(mData);
}
}
-
+
void* alloc(size_t size) {
mData = malloc(size);
return mData;
}
-
+
private:
void* mData;
};
@@ -88,17 +88,17 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength,
int result = POLY_CLIP_OUT;
float* pTransformed = 0;
int transformedIndexCount = 0;
-
+
if ( indexCount < 3 ) {
return POLY_CLIP_OUT;
}
-
+
// Find out how many vertices we need to transform
// We transform every vertex between the min and max indices, inclusive.
// This is OK for the data sets we expect to use with this function, but
// for other loads it might be better to use a more sophisticated vertex
// cache of some sort.
-
+
int minIndex = 65536;
int maxIndex = -1;
for(int i = 0; i < indexCount; i++) {
@@ -110,18 +110,18 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength,
maxIndex = index;
}
}
-
+
if ( maxIndex * 3 > positionsLength) {
return -1;
}
-
+
transformedIndexCount = maxIndex - minIndex + 1;
pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
-
+
if (pTransformed == 0 ) {
return -2;
}
-
+
// Transform the vertices
{
const float* pSrc = pPositions + 3 * minIndex;
@@ -130,9 +130,9 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength,
mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS, pDst);
}
}
-
+
// Clip the triangles
-
+
Poly poly;
float* pDest = & poly.vert[0].sx;
for (int i = 0; i < indexCount; i += 3) {
@@ -166,14 +166,14 @@ public:
mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
}
}
-
+
// We seperate the bounds check from the initialization because we want to
// be able to bounds-check multiple arrays, and we can't throw an exception
// after we've called GetPrimitiveArrayCritical.
-
+
// Return true if the bounds check succeeded
// Else instruct the runtime to throw an exception
-
+
bool check() {
if ( ! mRef) {
mEnv->ThrowNew(gIAEClass, "array == null");
@@ -190,9 +190,9 @@ public:
}
return true;
}
-
+
// Bind the array.
-
+
void bind() {
mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
mData = mBase + mOffset;
@@ -201,10 +201,10 @@ public:
void commitChanges() {
mReleaseParam = 0;
}
-
+
T* mData;
int mLength;
-
+
private:
T* mBase;
JNIEnv* mEnv;
@@ -226,29 +226,29 @@ inline float distance2(float x, float y, float z) {
inline float distance(float x, float y, float z) {
return sqrtf(distance2(x, y, z));
}
-
+
static
void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
jfloatArray sphere_ref, jint sphereOffset) {
FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
-
+
bool checkOK = positions.check() && sphere.check();
if (! checkOK) {
return;
}
-
+
positions.bind();
sphere.bind();
-
+
if ( positionsCount < 1 ) {
env->ThrowNew(gIAEClass, "positionsCount < 1");
return;
}
-
+
const float* pSrc = positions.mData;
-
+
// find bounding box
float x0 = *pSrc++;
float x1 = x0;
@@ -256,7 +256,7 @@ void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
float y1 = y0;
float z0 = *pSrc++;
float z1 = z0;
-
+
for(int i = 1; i < positionsCount; i++) {
{
float x = *pSrc++;
@@ -286,7 +286,7 @@ void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
}
}
}
-
+
// Because we know our input meshes fit pretty well into bounding boxes,
// just take the diagonal of the box as defining our sphere.
float* pSphere = sphere.mData;
@@ -297,7 +297,7 @@ void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
*pSphere++ = y0 + dy * 0.5f;
*pSphere++ = z0 + dz * 0.5f;
*pSphere++ = distance(dx, dy, dz) * 0.5f;
-
+
sphere.commitChanges();
}
@@ -344,7 +344,7 @@ static void computeFrustum(const float* m, float* f) {
normalizePlane(f);
f+= 4;
- // left
+ // left
f[0] = m3 + m[0];
f[1] = m7 + m[4];
f[2] = m11 + m[8];
@@ -396,20 +396,20 @@ int util_frustumCullSpheres(JNIEnv *env, jclass clazz,
FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
-
+
bool initializedOK = mvp.check() && spheres.check() && results.check();
if (! initializedOK) {
return -1;
}
-
+
mvp.bind();
spheres.bind();
results.bind();
-
+
computeFrustum(mvp.mData, frustum);
-
+
// Cull the spheres
-
+
pSphere = spheres.mData;
pResults = results.mData;
outputCount = 0;
@@ -436,27 +436,27 @@ int util_visibilityTest(JNIEnv *env, jclass clazz,
jfloatArray ws_ref, jint wsOffset,
jfloatArray positions_ref, jint positionsOffset,
jcharArray indices_ref, jint indicesOffset, jint indexCount) {
-
+
FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
-
+
bool checkOK = ws.check() && positions.check() && indices.check();
if (! checkOK) {
// Return value will be ignored, because an exception has been thrown.
return -1;
}
-
+
if (indices.mLength < indexCount) {
env->ThrowNew(gIAEClass, "length < offset + indexCount");
// Return value will be ignored, because an exception has been thrown.
return -1;
}
-
+
ws.bind();
positions.bind();
indices.bind();
-
+
return visibilityTest(ws.mData,
positions.mData, positions.mLength,
indices.mData, indexCount);
@@ -496,19 +496,19 @@ void util_multiplyMM(JNIEnv *env, jclass clazz,
FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
-
+
bool checkOK = resultMat.check() && lhs.check() && rhs.check();
-
+
if ( !checkOK ) {
return;
}
-
+
resultMat.bind();
lhs.bind();
rhs.bind();
-
+
multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
-
+
resultMat.commitChanges();
}
@@ -527,19 +527,19 @@ void util_multiplyMV(JNIEnv *env, jclass clazz,
FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
-
+
bool checkOK = resultV.check() && lhs.check() && rhs.check();
-
+
if ( !checkOK ) {
return;
}
-
+
resultV.bind();
lhs.bind();
rhs.bind();
-
+
multiplyMV(resultV.mData, lhs.mData, rhs.mData);
-
+
resultV.commitChanges();
}
@@ -550,7 +550,7 @@ static jfieldID nativeBitmapID = 0;
void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
{
jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
- nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
+ nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
}
static int checkFormat(SkBitmap::Config config, int format, int type)
@@ -653,7 +653,7 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz,
}
int err = checkFormat(config, internalformat, type);
if (err)
- return err;
+ return err;
bitmap.lockPixels();
const int w = bitmap.width();
const int h = bitmap.height();
@@ -665,14 +665,15 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz,
}
const size_t size = bitmap.getSize();
const size_t palette_size = 256*sizeof(SkPMColor);
- void* const data = malloc(size + palette_size);
+ const size_t imageSize = size + palette_size;
+ void* const data = malloc(imageSize);
if (data) {
void* const pixels = (char*)data + palette_size;
SkColorTable* ctable = bitmap.getColorTable();
memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
memcpy(pixels, p, size);
ctable->unlockColors(false);
- glCompressedTexImage2D(target, level, internalformat, w, h, border, 0, data);
+ glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
free(data);
} else {
err = -1;
@@ -700,7 +701,7 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
}
int err = checkFormat(config, format, type);
if (err)
- return err;
+ return err;
bitmap.lockPixels();
const int w = bitmap.width();
const int h = bitmap.height();
@@ -723,22 +724,22 @@ lookupClasses(JNIEnv* env) {
}
static JNINativeMethod gMatrixMethods[] = {
- { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
- { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
+ { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
+ { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
};
static JNINativeMethod gVisiblityMethods[] = {
- { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
+ { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
{ "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
- { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
+ { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
};
static JNINativeMethod gUtilsMethods[] = {
{"nativeClassInit", "()V", (void*)nativeUtilsClassInit },
- { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
- { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
- { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
- { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
+ { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
+ { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
+ { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
+ { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
};
typedef struct _ClassRegistrationInfo {
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
new file mode 100644
index 0000000..31ebf8c
--- /dev/null
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -0,0 +1,557 @@
+/*
+ * 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 const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
+
+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;
+ int sndbuf;
+ 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;
+ lm |= (auth && encrypt) ? RFCOMM_LM_SECURE : 0;
+ break;
+ case TYPE_L2CAP:
+ lm |= auth ? L2CAP_LM_AUTH : 0;
+ lm |= encrypt ? L2CAP_LM_ENCRYPT : 0;
+ lm |= (auth && encrypt) ? L2CAP_LM_SECURE : 0;
+ break;
+ }
+
+ if (lm) {
+ if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
+ LOGV("setsockopt(RFCOMM_LM) failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+ }
+
+ if (type == TYPE_RFCOMM) {
+ sndbuf = RFCOMM_SO_SNDBUF;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
+ LOGV("setsockopt(SO_SNDBUF) 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);
+}
+
+/* Returns errno instead of throwing, so java can check errno */
+static int 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 EINVAL;
+
+ 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:
+ return ENOSYS;
+ }
+
+ if (bind(s->fd, addr, addr_sz)) {
+ LOGV("...bind(%d) gave errno %d", s->fd, errno);
+ return errno;
+ }
+
+ if (listen(s->fd, 1)) {
+ LOGV("...listen(%d) gave errno %d", s->fd, errno);
+ return errno;
+ }
+
+ LOGV("...bindListenNative(%d) success", s->fd);
+
+ return 0;
+
+#endif
+ return 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;
+}
+
+static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
+ jint length) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jbyte *b;
+ int sz;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+ if (jb == NULL) {
+ jniThrowIOException(env, EINVAL);
+ return -1;
+ }
+ sz = env->GetArrayLength(jb);
+ if (offset < 0 || length < 0 || offset + length > sz) {
+ jniThrowIOException(env, EINVAL);
+ 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;
+}
+
+static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
+ jint length) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jbyte *b;
+ int sz;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+ if (jb == NULL) {
+ jniThrowIOException(env, EINVAL);
+ return -1;
+ }
+ sz = env->GetArrayLength(jb);
+ if (offset < 0 || length < 0 || offset + length > sz) {
+ jniThrowIOException(env, EINVAL);
+ 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 abortNative(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 void throwErrnoNative(JNIEnv *env, jobject obj, jint err) {
+ jniThrowIOException(env, err);
+}
+
+static JNINativeMethod sMethods[] = {
+ {"initSocketNative", "()V", (void*) initSocketNative},
+ {"initSocketFromFdNative", "(I)V", (void*) initSocketFromFdNative},
+ {"connectNative", "()V", (void *) connectNative},
+ {"bindListenNative", "()I", (void *) bindListenNative},
+ {"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
+ {"availableNative", "()I", (void *) availableNative},
+ {"readNative", "([BII)I", (void *) readNative},
+ {"writeNative", "([BII)I", (void *) writeNative},
+ {"abortNative", "()V", (void *) abortNative},
+ {"destroyNative", "()V", (void *) destroyNative},
+ {"throwErrnoNative", "(I)V", (void *) throwErrnoNative},
+};
+
+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_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp
index bb19e92..71279b2 100644
--- a/core/jni/android_bluetooth_HeadsetBase.cpp
+++ b/core/jni/android_bluetooth_HeadsetBase.cpp
@@ -260,7 +260,7 @@ static jboolean connectNative(JNIEnv *env, jobject obj)
#endif
}
-static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
+static jint connectAsyncNative(JNIEnv *env, jobject obj) {
LOGV(__FUNCTION__);
#ifdef HAVE_BLUETOOTH
struct sockaddr_rc addr;
@@ -268,7 +268,7 @@ static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
if (nat->rfcomm_connected) {
LOGV("RFCOMM socket is already connected or connection is in progress.");
- return JNI_TRUE;
+ return 0;
}
if (nat->rfcomm_sock < 0) {
@@ -278,7 +278,7 @@ static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
if (nat->rfcomm_sock < 0) {
LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
strerror(errno));
- return JNI_FALSE;
+ return -1;
}
if (debug_no_encrypt()) {
@@ -291,7 +291,7 @@ static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
sizeof(lm)) < 0) {
LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
close(nat->rfcomm_sock);
- return JNI_FALSE;
+ return -1;
}
LOGI("Created RFCOMM socket fd %d.", nat->rfcomm_sock);
}
@@ -314,7 +314,7 @@ static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
if (rc >= 0) {
nat->rfcomm_connected = 1;
LOGI("async connect successful");
- return JNI_TRUE;
+ return 0;
}
else if (rc < 0) {
if (errno == EINPROGRESS || errno == EAGAIN)
@@ -322,20 +322,20 @@ static jboolean connectAsyncNative(JNIEnv *env, jobject obj) {
LOGI("async connect is in progress (%s)",
strerror(errno));
nat->rfcomm_connected = -1;
- return JNI_TRUE;
+ return 0;
}
else
{
LOGE("async connect error: %s (%d)", strerror(errno), errno);
close(nat->rfcomm_sock);
nat->rfcomm_sock = -1;
- return JNI_FALSE;
+ return -errno;
}
}
} // fcntl(nat->rfcomm_sock ...)
} // if (nat->rfcomm_sock_flags >= 0)
#endif
- return JNI_FALSE;
+ return -1;
}
static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
@@ -357,9 +357,11 @@ static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
close(nat->rfcomm_sock);
nat->rfcomm_sock = -1;
}
- if (JNI_FALSE == connectAsyncNative(env, obj)) {
+ int ret = connectAsyncNative(env, obj);
+
+ if (ret < 0) {
LOGI("Failed to re-open RFCOMM socket!");
- return -1;
+ return ret;
}
if (nat->rfcomm_sock >= 0) {
@@ -394,7 +396,7 @@ static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
LOGE("select() on RFCOMM socket: %s (%d)",
strerror(errno),
errno);
- return -1;
+ return -errno;
}
return 0;
}
@@ -427,7 +429,7 @@ static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
close(nat->rfcomm_sock);
nat->rfcomm_sock = -1;
- return -1;
+ return -errno;
}
}
/* Restore the blocking properties of the socket. */
@@ -532,7 +534,7 @@ static JNINativeMethod sMethods[] = {
{"initializeNativeDataNative", "(I)V", (void *)initializeNativeDataNative},
{"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
{"connectNative", "()Z", (void *)connectNative},
- {"connectAsyncNative", "()Z", (void *)connectAsyncNative},
+ {"connectAsyncNative", "()I", (void *)connectAsyncNative},
{"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
{"disconnectNative", "()V", (void *)disconnectNative},
{"sendURCNative", "(Ljava/lang/String;)Z", (void *)sendURCNative},
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..343fa53 100644
--- a/core/jni/android_bluetooth_common.cpp
+++ b/core/jni/android_bluetooth_common.cpp
@@ -36,6 +36,43 @@
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},
+};
+
+typedef union {
+ char *str_val;
+ int int_val;
+ char **array_val;
+} property_value;
+
jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
const char *mtype) {
jfieldID field = env->GetFieldID(clazz, member, mtype);
@@ -332,6 +369,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 +428,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 +462,263 @@ 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);
+}
+
+int get_property(DBusMessageIter iter, Properties *properties,
+ int max_num_properties, int *prop_index, property_value *value, int *len) {
+ DBusMessageIter prop_val, array_val_iter;
+ char *property = NULL;
+ uint32_t array_type;
+ char *str_val;
+ int i, j, type, int_val;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -1;
+ dbus_message_iter_get_basic(&iter, &property);
+ if (!dbus_message_iter_next(&iter))
+ return -1;
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return -1;
+ for (i = 0; i < max_num_properties; i++) {
+ if (!strncmp(property, properties[i].name, strlen(property)))
+ break;
+ }
+ *prop_index = i;
+ if (i == max_num_properties)
+ return -1;
+
+ 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 get_property: %d, expected:%d, index:%d",
+ dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
+ return -1;
+ }
+
+ switch(type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ dbus_message_iter_get_basic(&prop_val, &value->str_val);
+ *len = 1;
+ break;
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_BOOLEAN:
+ dbus_message_iter_get_basic(&prop_val, &int_val);
+ value->int_val = 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;
+ value->array_val = NULL;
+ if (array_type == DBUS_TYPE_OBJECT_PATH ||
+ array_type == DBUS_TYPE_STRING){
+ j = 0;
+ do {
+ j ++;
+ } while(dbus_message_iter_next(&array_val_iter));
+ dbus_message_iter_recurse(&prop_val, &array_val_iter);
+ // Allocate an array of char *
+ *len = j;
+ char **tmp = (char **)malloc(sizeof(char *) * *len);
+ if (!tmp)
+ return -1;
+ j = 0;
+ do {
+ dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
+ j ++;
+ } while(dbus_message_iter_next(&array_val_iter));
+ value->array_val = tmp;
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
+ property_value *value, int len, int *array_index ) {
+ char **prop_val = NULL;
+ char buf[32] = {'\0'}, buf1[32] = {'\0'};
+ int i;
+
+ char *name = property->name;
+ int prop_type = property->type;
+
+ set_object_array_element(env, strArray, name, *array_index);
+ *array_index += 1;
+
+ if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
+ sprintf(buf, "%d", value->int_val);
+ set_object_array_element(env, strArray, buf, *array_index);
+ *array_index += 1;
+ } else if (prop_type == DBUS_TYPE_BOOLEAN) {
+ sprintf(buf, "%s", value->int_val ? "true" : "false");
+
+ set_object_array_element(env, strArray, buf, *array_index);
+ *array_index += 1;
+ } else if (prop_type == DBUS_TYPE_ARRAY) {
+ // Write the length first
+ sprintf(buf1, "%d", len);
+ set_object_array_element(env, strArray, buf1, *array_index);
+ *array_index += 1;
+
+ prop_val = value->array_val;
+ for (i = 0; i < len; i++) {
+ set_object_array_element(env, strArray, prop_val[i], *array_index);
+ *array_index += 1;
+ }
+ } else {
+ set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
+ *array_index += 1;
+ }
+}
+
+jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
+ const int max_num_properties) {
+ DBusMessageIter dict_entry, dict;
+ jobjectArray strArray = NULL;
+ property_value value;
+ int i, size = 0,array_index = 0;
+ int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
+ struct {
+ property_value value;
+ int len;
+ bool used;
+ } values[max_num_properties];
+ int t, j;
+
+ jclass stringClass = env->FindClass("java/lang/String");
+ DBusError err;
+ dbus_error_init(&err);
+
+ for (i = 0; i < max_num_properties; i++) {
+ values[i].used = false;
+ }
+
+ if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ goto failure;
+ dbus_message_iter_recurse(iter, &dict);
+ do {
+ len = 0;
+ if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
+ goto failure;
+ dbus_message_iter_recurse(&dict, &dict_entry);
+
+ if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
+ &value, &len)) {
+ size += 2;
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY)
+ size += len;
+ values[prop_index].value = value;
+ values[prop_index].len = len;
+ values[prop_index].used = true;
+ } else {
+ goto failure;
+ }
+ } while(dbus_message_iter_next(&dict));
+
+ strArray = env->NewObjectArray(size, stringClass, NULL);
+
+ for (i = 0; i < max_num_properties; i++) {
+ if (values[i].used) {
+ create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
+ &array_index);
+
+ if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
+ && values[i].value.array_val != NULL)
+ free(values[i].value.array_val);
+ }
+
+ }
+ return strArray;
+
+failure:
+ if (dbus_error_is_set(&err))
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ for (i = 0; i < max_num_properties; i++)
+ if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
+ && values[i].value.array_val != NULL)
+ free(values[i].value.array_val);
+ return NULL;
+}
+
+jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
+ Properties *properties, int max_num_properties) {
+ DBusMessageIter iter;
+ DBusError err;
+ jobjectArray strArray = NULL;
+ jclass stringClass= env->FindClass("java/lang/String");
+ int len = 0, prop_index = -1;
+ int array_index = 0, size = 0;
+ property_value value;
+
+ dbus_error_init(&err);
+ if (!dbus_message_iter_init(msg, &iter))
+ goto failure;
+
+ if (!get_property(iter, properties, max_num_properties,
+ &prop_index, &value, &len)) {
+ size += 2;
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY)
+ size += len;
+ strArray = env->NewObjectArray(size, stringClass, NULL);
+
+ create_prop_array(env, strArray, &properties[prop_index],
+ &value, len, &array_index);
+
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
+ free(value.array_val);
+
+ return strArray;
+ }
+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_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 7d6e24f..63550fb 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -184,7 +184,7 @@ static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
jobject obj = env->AllocObject(gBitmap_class);
if (obj) {
env->CallVoidMethod(obj, gBitmap_constructorMethodID,
- reinterpret_cast<jint>(bitmap), false, NULL);
+ reinterpret_cast<jint>(bitmap), false, NULL, -1);
if (env->ExceptionCheck() != 0) {
LOGE("*** Uncaught exception returned from Java call!\n");
env->ExceptionDescribe();
@@ -197,8 +197,11 @@ static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
static void android_emoji_EmojiFactory_destructor(
JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ /*
+ // Must not delete this object!!
EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
delete factory;
+ */
}
static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
@@ -294,7 +297,7 @@ static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
int register_android_emoji_EmojiFactory(JNIEnv* env) {
gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
- "(IZ[B)V");
+ "(IZ[BI)V");
gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
gEmojiFactory_constructorMethodID = env->GetMethodID(
gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9053468..d57e526 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -23,9 +23,11 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include <utils/Vector.h>
+
#include <ui/Surface.h>
#include <ui/Camera.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
using namespace android;
@@ -47,16 +49,23 @@ public:
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+ void addCallbackBuffer(JNIEnv *env, jbyteArray cbb);
+ void setCallbackMode(JNIEnv *env, bool installed, bool manualMode);
sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
void release();
private:
void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);
+ void clearCallbackBuffers_l(JNIEnv *env);
jobject mCameraJObjectWeak; // weak reference to java object
jclass mCameraJClass; // strong reference to java class
- sp<Camera> mCamera; // strong reference to native object
+ sp<Camera> mCamera; // strong reference to native object
Mutex mLock;
+
+ Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[]
+ bool mManualBufferMode; // Whether to use application managed buffers.
+ bool mManualCameraCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback.
};
sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
@@ -81,6 +90,9 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz,
mCameraJObjectWeak = env->NewGlobalRef(weak_this);
mCameraJClass = (jclass)env->NewGlobalRef(clazz);
mCamera = camera;
+
+ mManualBufferMode = false;
+ mManualCameraCallbackSet = false;
}
void JNICameraContext::release()
@@ -97,6 +109,7 @@ void JNICameraContext::release()
env->DeleteGlobalRef(mCameraJClass);
mCameraJClass = NULL;
}
+ clearCallbackBuffers_l(env);
mCamera.clear();
}
@@ -112,7 +125,7 @@ void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
}
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
- mCameraJObjectWeak, msgType, ext1, ext2);
+ mCameraJObjectWeak, msgType, ext1, ext2, NULL);
}
void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
@@ -129,7 +142,42 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int
if (heapBase != NULL) {
const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset);
- obj = env->NewByteArray(size);
+
+ if (!mManualBufferMode) {
+ LOGV("Allocating callback buffer");
+ obj = env->NewByteArray(size);
+ } else {
+ // Vector access should be protected by lock in postData()
+ if(!mCallbackBuffers.isEmpty()) {
+ LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size());
+ jbyteArray globalBuffer = mCallbackBuffers.itemAt(0);
+ mCallbackBuffers.removeAt(0);
+
+ obj = (jbyteArray)env->NewLocalRef(globalBuffer);
+ env->DeleteGlobalRef(globalBuffer);
+
+ if (obj != NULL) {
+ jsize bufferLength = env->GetArrayLength(obj);
+ if ((int)bufferLength < (int)size) {
+ LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!",
+ size, bufferLength);
+ env->DeleteLocalRef(obj);
+ return;
+ }
+ }
+ }
+
+ if(mCallbackBuffers.isEmpty()) {
+ LOGW("Out of buffers, clearing callback!");
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ mManualCameraCallbackSet = false;
+
+ if (obj == NULL) {
+ return;
+ }
+ }
+ }
+
if (obj == NULL) {
LOGE("Couldn't allocate byte array for JPEG data");
env->ExceptionClear();
@@ -184,6 +232,62 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con
postData(msgType, dataPtr);
}
+void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode)
+{
+ Mutex::Autolock _l(mLock);
+ mManualBufferMode = manualMode;
+ mManualCameraCallbackSet = false;
+
+ // In order to limit the over usage of binder threads, all non-manual buffer
+ // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
+ //
+ // Continuous callbacks will have the callback re-registered from handleMessage.
+ // Manual buffer mode will operate as fast as possible, relying on the finite supply
+ // of buffers for throttling.
+
+ if (!installed) {
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ clearCallbackBuffers_l(env);
+ } else if (mManualBufferMode) {
+ if (!mCallbackBuffers.isEmpty()) {
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mManualCameraCallbackSet = true;
+ }
+ } else {
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
+ clearCallbackBuffers_l(env);
+ }
+}
+
+void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb)
+{
+ if (cbb != NULL) {
+ Mutex::Autolock _l(mLock);
+ jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
+ mCallbackBuffers.push(cbb);
+
+ LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size());
+
+ // We want to make sure the camera knows we're ready for the next frame.
+ // This may have come unset had we not had a callbackbuffer ready for it last time.
+ if (mManualBufferMode && !mManualCameraCallbackSet) {
+ mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mManualCameraCallbackSet = true;
+ }
+ } else {
+ LOGE("Null byte array!");
+ }
+}
+
+void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env)
+{
+ LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size());
+ while(!mCallbackBuffers.isEmpty()) {
+ env->DeleteGlobalRef(mCallbackBuffers.top());
+ mCallbackBuffers.pop();
+ }
+}
+
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
@@ -297,8 +401,9 @@ static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz)
return c->previewEnabled();
}
-static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot)
+static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer)
{
+ LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer);
// Important: Only install preview_callback if the Java code has called
// setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
// each preview frame for nothing.
@@ -306,13 +411,19 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
sp<Camera> camera = get_native_camera(env, thiz, &context);
if (camera == 0) return;
- int callback_flag;
- if (installed) {
- callback_flag = oneshot ? FRAME_CALLBACK_FLAG_BARCODE_SCANNER : FRAME_CALLBACK_FLAG_CAMERA;
- } else {
- callback_flag = FRAME_CALLBACK_FLAG_NOOP;
+ // setCallbackMode will take care of setting the context flags and calling
+ // camera->setPreviewCallbackFlags within a mutex for us.
+ context->setCallbackMode(env, installed, manualBuffer);
+}
+
+static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) {
+ LOGV("addCallbackBuffer");
+
+ JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
+
+ if (context != NULL) {
+ context->addCallbackBuffer(env, bytes);
}
- camera->setPreviewCallbackFlags(callback_flag);
}
static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
@@ -327,6 +438,18 @@ static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
}
}
+static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz)
+{
+ LOGV("cancelAutoFocus");
+ JNICameraContext* context;
+ sp<Camera> c = get_native_camera(env, thiz, &context);
+ if (c == 0) return;
+
+ if (c->cancelAutoFocus() != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "cancelAutoFocus failed");
+ }
+}
+
static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
{
LOGV("takePicture");
@@ -379,20 +502,48 @@ static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
}
}
-static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
{
LOGV("lock");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
- if (camera == 0) return INVALID_OPERATION;
- return (jint) camera->lock();
+ if (camera == 0) return;
+
+ if (camera->lock() != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "lock failed");
+ }
}
-static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
{
LOGV("unlock");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
- if (camera == 0) return INVALID_OPERATION;
- return (jint) camera->unlock();
+ if (camera == 0) return;
+
+ if (camera->unlock() != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "unlock failed");
+ }
+}
+
+static void android_hardware_Camera_startSmoothZoom(JNIEnv *env, jobject thiz, jint value)
+{
+ LOGD("startSmoothZoom");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
+
+ if (camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, value, 0) != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "start smooth zoom failed");
+ }
+}
+
+static void android_hardware_Camera_stopSmoothZoom(JNIEnv *env, jobject thiz)
+{
+ LOGD("stopSmoothZoom");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
+
+ if (camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, 0, 0) != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "stop smooth zoom failed");
+ }
}
//-------------------------------------------------
@@ -419,9 +570,15 @@ static JNINativeMethod camMethods[] = {
{ "setHasPreviewCallback",
"(ZZ)V",
(void *)android_hardware_Camera_setHasPreviewCallback },
+ { "addCallbackBuffer",
+ "([B)V",
+ (void *)android_hardware_Camera_addCallbackBuffer },
{ "native_autoFocus",
"()V",
(void *)android_hardware_Camera_autoFocus },
+ { "native_cancelAutoFocus",
+ "()V",
+ (void *)android_hardware_Camera_cancelAutoFocus },
{ "native_takePicture",
"()V",
(void *)android_hardware_Camera_takePicture },
@@ -435,11 +592,17 @@ static JNINativeMethod camMethods[] = {
"()V",
(void*)android_hardware_Camera_reconnect },
{ "lock",
- "()I",
+ "()V",
(void*)android_hardware_Camera_lock },
{ "unlock",
- "()I",
+ "()V",
(void*)android_hardware_Camera_unlock },
+ { "startSmoothZoom",
+ "(I)V",
+ (void *)android_hardware_Camera_startSmoothZoom },
+ { "stopSmoothZoom",
+ "()V",
+ (void *)android_hardware_Camera_stopSmoothZoom },
};
struct field {
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index bf0bd65..f845878 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -16,33 +16,49 @@
#define LOG_TAG "GpsLocationProvider"
+//#define LOG_NDDEBUG 0
+
#include "JNIHelp.h"
#include "jni.h"
#include "hardware_legacy/gps.h"
+#include "hardware_legacy/gps_ni.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include <string.h>
#include <pthread.h>
-
static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
static jmethodID method_reportLocation;
static jmethodID method_reportStatus;
static jmethodID method_reportSvStatus;
static jmethodID method_reportAGpsStatus;
+static jmethodID method_reportNmea;
static jmethodID method_xtraDownloadRequest;
+static jmethodID method_reportNiNotification;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsNiInterface* sGpsNiInterface = NULL;
// data written to by GPS callbacks
static GpsLocation sGpsLocation;
static GpsStatus sGpsStatus;
static GpsSvStatus sGpsSvStatus;
static AGpsStatus sAGpsStatus;
+static GpsNiNotification sGpsNiNotification;
+
+// buffer for NMEA data
+#define NMEA_SENTENCE_LENGTH 100
+#define NMEA_SENTENCE_COUNT 40
+struct NmeaSentence {
+ GpsUtcTime timestamp;
+ char nmea[NMEA_SENTENCE_LENGTH];
+};
+static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_LENGTH];
+static int mNmeaSentenceCount = 0;
// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
// and android_location_GpsLocationProvider_read_status
@@ -50,6 +66,8 @@ static GpsLocation sGpsLocationCopy;
static GpsStatus sGpsStatusCopy;
static GpsSvStatus sGpsSvStatusCopy;
static AGpsStatus sAGpsStatusCopy;
+static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_LENGTH];
+static GpsNiNotification sGpsNiNotificationCopy;
enum CallbackType {
kLocation = 1,
@@ -58,6 +76,8 @@ enum CallbackType {
kAGpsStatus = 8,
kXtraDownloadRequest = 16,
kDisableRequest = 32,
+ kNmeaAvailable = 64,
+ kNiNotification = 128,
};
static int sPendingCallbacks;
@@ -96,6 +116,30 @@ static void sv_status_callback(GpsSvStatus* sv_status)
pthread_mutex_unlock(&sEventMutex);
}
+static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
+{
+ pthread_mutex_lock(&sEventMutex);
+
+ if (length >= NMEA_SENTENCE_LENGTH) {
+ LOGE("NMEA data too long in nmea_callback (length = %d)\n", length);
+ length = NMEA_SENTENCE_LENGTH - 1;
+ }
+ if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) {
+ LOGE("NMEA data overflowed buffer\n");
+ pthread_mutex_unlock(&sEventMutex);
+ return;
+ }
+
+ sPendingCallbacks |= kNmeaAvailable;
+ sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp;
+ memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length);
+ sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0;
+ mNmeaSentenceCount++;
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
static void agps_status_callback(AGpsStatus* agps_status)
{
pthread_mutex_lock(&sEventMutex);
@@ -111,6 +155,7 @@ GpsCallbacks sGpsCallbacks = {
location_callback,
status_callback,
sv_status_callback,
+ nmea_callback
};
static void
@@ -122,6 +167,20 @@ download_request_callback()
pthread_mutex_unlock(&sEventMutex);
}
+static void
+gps_ni_notify_callback(GpsNiNotification *notification)
+{
+ LOGD("gps_ni_notify_callback: notif=%d", notification->notification_id);
+
+ pthread_mutex_lock(&sEventMutex);
+
+ sPendingCallbacks |= kNiNotification;
+ memcpy(&sGpsNiNotification, notification, sizeof(GpsNiNotification));
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
GpsXtraCallbacks sGpsXtraCallbacks = {
download_request_callback,
};
@@ -130,12 +189,18 @@ AGpsCallbacks sAGpsCallbacks = {
agps_status_callback,
};
+GpsNiCallbacks sGpsNiCallbacks = {
+ gps_ni_notify_callback,
+};
+
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+ method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
}
static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
@@ -155,6 +220,12 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o
sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
if (sAGpsInterface)
sAGpsInterface->init(&sAGpsCallbacks);
+
+ if (!sGpsNiInterface)
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ if (sGpsNiInterface)
+ sGpsNiInterface->init(&sGpsNiCallbacks);
+
return true;
}
@@ -171,7 +242,7 @@ static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject ob
sGpsInterface->cleanup();
}
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
jboolean singleFix, jint fixFrequency)
{
int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
@@ -195,46 +266,81 @@ static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env,
static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj)
{
pthread_mutex_lock(&sEventMutex);
- pthread_cond_wait(&sEventCond, &sEventMutex);
-
+ while (sPendingCallbacks == 0) {
+ pthread_cond_wait(&sEventCond, &sEventMutex);
+ }
+
// copy and clear the callback flags
int pendingCallbacks = sPendingCallbacks;
sPendingCallbacks = 0;
+ int nmeaSentenceCount = mNmeaSentenceCount;
+ mNmeaSentenceCount = 0;
// copy everything and unlock the mutex before calling into Java code to avoid the possibility
// of timeouts in the GPS engine.
- memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
- memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
- memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
- memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+ if (pendingCallbacks & kLocation)
+ memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
+ if (pendingCallbacks & kStatus)
+ memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
+ if (pendingCallbacks & kSvStatus)
+ memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
+ if (pendingCallbacks & kAGpsStatus)
+ memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+ if (pendingCallbacks & kNmeaAvailable)
+ memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
+ if (pendingCallbacks & kNiNotification)
+ memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy));
pthread_mutex_unlock(&sEventMutex);
- if (pendingCallbacks & kLocation) {
+ if (pendingCallbacks & kLocation) {
env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
(jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
- (jdouble)sGpsLocationCopy.altitude,
- (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
+ (jdouble)sGpsLocationCopy.altitude,
+ (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
(jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
}
if (pendingCallbacks & kStatus) {
env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
- }
+ }
if (pendingCallbacks & kSvStatus) {
env->CallVoidMethod(obj, method_reportSvStatus);
}
if (pendingCallbacks & kAGpsStatus) {
env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
}
- if (pendingCallbacks & kXtraDownloadRequest) {
+ if (pendingCallbacks & kNmeaAvailable) {
+ for (int i = 0; i < nmeaSentenceCount; i++) {
+ env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
+ }
+ }
+ if (pendingCallbacks & kXtraDownloadRequest) {
env->CallVoidMethod(obj, method_xtraDownloadRequest);
}
if (pendingCallbacks & kDisableRequest) {
// don't need to do anything - we are just poking so wait_for_event will return.
}
+ if (pendingCallbacks & kNiNotification) {
+ LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback.");
+ jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id);
+ jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text);
+ jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras);
+ env->CallVoidMethod(obj, method_reportNiNotification,
+ sGpsNiNotificationCopy.notification_id,
+ sGpsNiNotificationCopy.ni_type,
+ sGpsNiNotificationCopy.notify_flags,
+ sGpsNiNotificationCopy.timeout,
+ sGpsNiNotificationCopy.default_response,
+ reqId,
+ text,
+ sGpsNiNotificationCopy.requestor_id_encoding,
+ sGpsNiNotificationCopy.text_encoding,
+ extras
+ );
+ }
}
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
- jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
+static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
+ jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
jintArray maskArray)
{
// this should only be called from within a call to reportStatus, so we don't need to lock here
@@ -264,6 +370,21 @@ static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, job
return num_svs;
}
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size)
+{
+ // this should only be called from within a call to reportNmea, so we don't need to lock here
+
+ jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0);
+
+ int length = strlen(sNmeaBufferCopy[index].nmea);
+ if (length > buffer_size)
+ length = buffer_size;
+ memcpy(nmea, sNmeaBufferCopy[index].nmea, length);
+
+ env->ReleaseByteArrayElements(nmeaArray, nmea, 0);
+ return length;
+}
+
static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time,
jlong timeReference, jint uncertainty)
{
@@ -291,7 +412,7 @@ static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env,
return (sGpsXtraInterface != NULL);
}
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
+static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
jbyteArray data, jint length)
{
jbyte* bytes = env->GetByteArrayElements(data, 0);
@@ -348,6 +469,16 @@ static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jo
}
}
+static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
+ jint notifId, jint response)
+{
+ if (!sGpsNiInterface)
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ if (sGpsNiInterface) {
+ sGpsNiInterface->respond(notifId, response);
+ }
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -360,6 +491,7 @@ static JNINativeMethod sMethods[] = {
{"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
{"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
{"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
{"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
@@ -368,6 +500,7 @@ static JNINativeMethod sMethods[] = {
{"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
{"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
+ {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
};
int register_android_location_GpsLocationProvider(JNIEnv* env)
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 44a9e8c..0be996d 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -28,8 +28,8 @@
#include "android_runtime/AndroidRuntime.h"
#include "utils/Log.h"
-#include "media/AudioSystem.h"
#include "media/AudioRecord.h"
+#include "media/mediarecorder.h"
// ----------------------------------------------------------------------------
@@ -62,7 +62,7 @@ struct audiorecord_callback_cookie {
#define AUDIORECORD_ERROR_BAD_VALUE -2
#define AUDIORECORD_ERROR_INVALID_OPERATION -3
#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
-#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
@@ -122,17 +122,18 @@ static void recorderCallback(int event, void* user, void *info) {
// ----------------------------------------------------------------------------
static int
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint source, jint sampleRateInHertz, jint nbChannels,
+ jint source, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes)
{
//LOGV(">> Entering android_media_AudioRecord_setup");
- //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d",
- // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
+ // sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
- if ((nbChannels == 0) || (nbChannels > 2)) {
+ if (!AudioSystem::isInputChannel(channels)) {
LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
- return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
+ uint32_t nbChannels = AudioSystem::popCount(channels);
// compare the format against the Java constants
if ((audioFormat != javaAudioRecordFields.PCM16)
@@ -152,12 +153,7 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
- // convert and check input source value
- // input_source values defined in AudioRecord.h are equal to
- // JAVA MediaRecord.AudioSource values minus 1.
- AudioRecord::input_source arSource = (AudioRecord::input_source)(source - 1);
- if (arSource < AudioRecord::DEFAULT_INPUT ||
- arSource >= AudioRecord::NUM_INPUT_SOURCES) {
+ if (source >= AUDIO_SOURCE_LIST_END) {
LOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
@@ -184,10 +180,10 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
// we use a weak reference so the AudioRecord object can be garbage collected.
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
- lpRecorder->set(arSource,
+ lpRecorder->set(source,
sampleRateInHertz,
format, // word length, PCM
- nbChannels,
+ channels,
frameCount,
0, // flags
recorderCallback,// callback_t
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 692610e..3d8d296 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -50,25 +50,6 @@ static int check_AudioSystem_Command(status_t status)
}
static int
-android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
-{
- LOGV("setVolume(%d)", int(volume));
-
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
-}
-
-static int
-android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
-{
- float v;
- int v_int = -1;
- if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
- v_int = AudioSystem::logToLinear(v);
- }
- return v_int;
-}
-
-static int
android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
{
return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
@@ -82,34 +63,6 @@ android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
return state;
}
-static int
-android_media_AudioSystem_setRouting(JNIEnv *env, jobject clazz, jint mode, jint routes, jint mask)
-{
- return check_AudioSystem_Command(AudioSystem::setRouting(mode, uint32_t(routes), uint32_t(mask)));
-}
-
-static jint
-android_media_AudioSystem_getRouting(JNIEnv *env, jobject clazz, jint mode)
-{
- uint32_t routes = -1;
- AudioSystem::getRouting(mode, &routes);
- return jint(routes);
-}
-
-static int
-android_media_AudioSystem_setMode(JNIEnv *env, jobject clazz, jint mode)
-{
- return check_AudioSystem_Command(AudioSystem::setMode(mode));
-}
-
-static jint
-android_media_AudioSystem_getMode(JNIEnv *env, jobject clazz)
-{
- int mode = AudioSystem::MODE_INVALID;
- AudioSystem::getMode(&mode);
- return jint(mode);
-}
-
static jboolean
android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
{
@@ -118,16 +71,29 @@ android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
return state;
}
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-static void
-android_media_AudioSystem_setParameter(JNIEnv *env, jobject thiz, jstring key, jstring value)
+static int
+android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
- const char *c_key = env->GetStringUTFChars(key, NULL);
- const char *c_value = env->GetStringUTFChars(value, NULL);
- AudioSystem::setParameter(c_key, c_value);
- env->ReleaseStringUTFChars(key, c_key);
- env->ReleaseStringUTFChars(value, c_value);
+ const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
+ String8 c_keyValuePairs8;
+ if (keyValuePairs) {
+ c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
+ env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
+ }
+ int status = check_AudioSystem_Command(AudioSystem::setParameters(0, c_keyValuePairs8));
+ return status;
+}
+
+static jstring
+android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
+{
+ const jchar* c_keys = env->GetStringCritical(keys, 0);
+ String8 c_keys8;
+ if (keys) {
+ c_keys8 = String8(c_keys, env->GetStringLength(keys));
+ env->ReleaseStringCritical(keys, c_keys);
+ }
+ return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
}
void android_media_AudioSystem_error_callback(status_t err)
@@ -152,19 +118,93 @@ void android_media_AudioSystem_error_callback(status_t err)
env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
}
+static int
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
+{
+ const char *c_address = env->GetStringUTFChars(device_address, NULL);
+ int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+ static_cast <AudioSystem::device_connection_state>(state),
+ c_address));
+ env->ReleaseStringUTFChars(device_address, c_address);
+ return status;
+}
+
+static int
+android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
+{
+ const char *c_address = env->GetStringUTFChars(device_address, NULL);
+ int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+ c_address));
+ env->ReleaseStringUTFChars(device_address, c_address);
+ return state;
+}
+
+static int
+android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
+{
+ return check_AudioSystem_Command(AudioSystem::setPhoneState(state));
+}
+
+static int
+android_media_AudioSystem_setRingerMode(JNIEnv *env, jobject thiz, jint mode, jint mask)
+{
+ return check_AudioSystem_Command(AudioSystem::setRingerMode(mode, mask));
+}
+
+static int
+android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
+{
+ return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <AudioSystem::force_use>(usage),
+ static_cast <AudioSystem::forced_config>(config)));
+}
+
+static int
+android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
+{
+ return static_cast <int>(AudioSystem::getForceUse(static_cast <AudioSystem::force_use>(usage)));
+}
+
+static int
+android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
+{
+ return check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <AudioSystem::stream_type>(stream),
+ indexMin,
+ indexMax));
+}
+
+static int
+android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream, jint index)
+{
+ return check_AudioSystem_Command(AudioSystem::setStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), index));
+}
+
+static int
+android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream)
+{
+ int index;
+ if (AudioSystem::getStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), &index) != NO_ERROR) {
+ index = -1;
+ }
+ return index;
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"setVolume", "(II)I", (void *)android_media_AudioSystem_setVolume},
- {"getVolume", "(I)I", (void *)android_media_AudioSystem_getVolume},
- {"setParameter", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)android_media_AudioSystem_setParameter},
+ {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
+ {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
{"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
{"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
- {"setRouting", "(III)I", (void *)android_media_AudioSystem_setRouting},
- {"getRouting", "(I)I", (void *)android_media_AudioSystem_getRouting},
- {"setMode", "(I)I", (void *)android_media_AudioSystem_setMode},
- {"getMode", "()I", (void *)android_media_AudioSystem_getMode},
{"isMusicActive", "()Z", (void *)android_media_AudioSystem_isMusicActive},
+ {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+ {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
+ {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
+ {"setRingerMode", "(II)I", (void *)android_media_AudioSystem_setRingerMode},
+ {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
+ {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
+ {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
+ {"setStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
+ {"getStreamVolumeIndex","(I)I", (void *)android_media_AudioSystem_getStreamVolumeIndex}
};
const char* const kClassPathName = "android/media/AudioSystem";
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index fd92fbe..65c0435 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>
// ----------------------------------------------------------------------------
@@ -53,10 +53,11 @@ struct fields_t {
int STREAM_MUSIC; //... stream type constants
int STREAM_ALARM; //... stream type constants
int STREAM_NOTIFICATION; //... stream type constants
- int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_DTMF; //... stream type constants
int MODE_STREAM; //... memory mode
int MODE_STATIC; //... memory mode
- jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
+ jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
};
static fields_t javaAudioTrackFields;
@@ -103,7 +104,7 @@ class AudioTrackJniStorage {
#define AUDIOTRACK_ERROR_BAD_VALUE -2
#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
-#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
@@ -164,11 +165,11 @@ static void audioCallback(int event, void* user, void *info) {
// ----------------------------------------------------------------------------
static int
android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint streamType, jint sampleRateInHertz, jint nbChannels,
+ jint streamType, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes, jint memoryMode)
{
- LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d",
- sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ LOGV("sampleRate=%d, audioFormat(from Java)=%d, channels=%x, buffSize=%d",
+ sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
int afSampleRate;
int afFrameCount;
@@ -181,10 +182,11 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
- if ((nbChannels == 0) || (nbChannels > 2)) {
- LOGE("Error creating AudioTrack: channel count is not 1 or 2.");
- return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ if (!AudioSystem::isOutputChannel(channels)) {
+ LOGE("Error creating AudioTrack: invalid channel mask.");
+ return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
}
+ int nbChannels = AudioSystem::popCount(channels);
// check the stream type
AudioSystem::stream_type atStreamType;
@@ -202,6 +204,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
atStreamType = AudioSystem::NOTIFICATION;
} else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
atStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (streamType == javaAudioTrackFields.STREAM_DTMF) {
+ atStreamType = AudioSystem::DTMF;
} else {
LOGE("Error creating AudioTrack: unknown stream type.");
return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
@@ -231,15 +235,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
int format = audioFormat == javaAudioTrackFields.PCM16 ?
AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
- int frameCount;
- if (buffSizeInBytes == -1) {
- // compute the frame count based on the system's output frame count
- // and the native sample rate
- frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate;
- } else {
- // compute the frame count based on the specified buffer size
- frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
- }
+ int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
@@ -271,7 +267,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
- nbChannels,
+ channels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
@@ -291,7 +287,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
- nbChannels,
+ channels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
@@ -734,6 +730,8 @@ static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobjec
nativeStreamType = AudioSystem::NOTIFICATION;
} else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
nativeStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_DTMF) {
+ nativeStreamType = AudioSystem::DTMF;
} else {
nativeStreamType = AudioSystem::DEFAULT;
}
@@ -829,6 +827,7 @@ static JNINativeMethod gMethods[] = {
#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
+#define JAVA_CONST_STREAM_DTMF_NAME "STREAM_DTMF"
#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
@@ -950,8 +949,10 @@ int register_android_media_AudioTrack(JNIEnv *env)
JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION))
|| !android_media_getIntConstantFromClass(env, audioManagerClass,
JAVA_AUDIOMANAGER_CLASS_NAME,
- JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME,
- &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))) {
+ JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME, &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_DTMF_NAME, &(javaAudioTrackFields.STREAM_DTMF))) {
// error log performed in android_media_getIntConstantFromClass()
return -1;
}
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index a4388de..50aa967 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -38,7 +38,7 @@ struct fields_t {
};
static fields_t fields;
-static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType) {
+static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType, jint durationMs) {
LOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz);
ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
@@ -48,7 +48,7 @@ static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz,
return false;
}
- return lpToneGen->startTone(toneType);
+ return lpToneGen->startTone(toneType, durationMs);
}
static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) {
@@ -79,7 +79,7 @@ static void android_media_ToneGenerator_release(JNIEnv *env, jobject thiz) {
static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
jint streamType, jint volume) {
- ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume));
+ ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume), true);
env->SetIntField(thiz, fields.context, 0);
@@ -120,7 +120,7 @@ static void android_media_ToneGenerator_native_finalize(JNIEnv *env,
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- { "startTone", "(I)Z", (void *)android_media_ToneGenerator_startTone },
+ { "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone },
{ "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone },
{ "release", "()V", (void *)android_media_ToneGenerator_release },
{ "native_setup", "(II)V", (void *)android_media_ToneGenerator_native_setup },
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8383deb..feb0dad 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
extern "C" {
+int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
int ifc_add_host_route(const char *ifname, uint32_t addr);
int ifc_remove_host_routes(const char *ifname);
@@ -66,6 +67,16 @@ static struct fieldIds {
jfieldID leaseDuration;
} dhcpInfoFieldIds;
+static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_enable(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -209,6 +220,7 @@ static jboolean android_net_utils_configureInterface(JNIEnv* env,
static JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
+ { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
{ "addHostRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_addHostRoute },
{ "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes },
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index ae744a8..38f3fda 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -311,18 +311,26 @@ 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.
if (strcmp(reply, "OK") != 0) {
+ // beware of trailing spaces
+ char* end = reply + strlen(reply);
+ while (end > reply && end[-1] == ' ') {
+ end--;
+ }
+ *end = 0;
+
char* lastSpace = strrchr(reply, ' ');
// lastSpace should be preceded by "rssi" and followed by the value
if (lastSpace && !strncmp(lastSpace - 4, "rssi", 4)) {
@@ -332,6 +340,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];
@@ -527,6 +545,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_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index ed8dfc8..44213ed 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -144,6 +144,10 @@ android_glBufferData__IILjava_nio_Buffer_2I
if (data_buf) {
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ if (_remaining < size) {
+ _env->ThrowNew(IAEClass, "remaining() < size");
+ goto exit;
+ }
}
glBufferData(
(GLenum)target,
@@ -151,6 +155,8 @@ android_glBufferData__IILjava_nio_Buffer_2I
(GLvoid *)data,
(GLenum)usage
);
+
+exit:
if (_array) {
releasePointer(_env, _array, data, JNI_FALSE);
}
@@ -165,12 +171,18 @@ android_glBufferSubData__IIILjava_nio_Buffer_2
GLvoid *data = (GLvoid *) 0;
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ if (_remaining < size) {
+ _env->ThrowNew(IAEClass, "remaining() < size");
+ goto exit;
+ }
glBufferSubData(
(GLenum)target,
(GLintptr)offset,
(GLsizeiptr)size,
(GLvoid *)data
);
+
+exit:
if (_array) {
releasePointer(_env, _array, data, JNI_FALSE);
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index b4c60f1..3ee404a 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -200,12 +200,13 @@ static void load_maps(int pid, stats_t* stats)
fclose(fp);
}
-static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
+static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
+ jint pid, jobject object)
{
stats_t stats;
memset(&stats, 0, sizeof(stats_t));
- load_maps(getpid(), &stats);
+ load_maps(pid, &stats);
env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
@@ -220,6 +221,11 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o
env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
}
+static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
+{
+ android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
+}
+
static jint read_binder_stat(const char* stat)
{
FILE* fp = fopen(BINDER_STATS, "r");
@@ -281,6 +287,8 @@ static JNINativeMethod gMethods[] = {
(void*) android_os_Debug_getNativeHeapFreeSize },
{ "getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
(void*) android_os_Debug_getDirtyPages },
+ { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V",
+ (void*) android_os_Debug_getDirtyPagesPid },
{ "getBinderSentTransactions", "()I",
(void*) android_os_Debug_getBinderSentTransactions },
{ "getBinderReceivedTransactions", "()I",
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_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index ca4fa11..406884b 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -36,9 +36,9 @@ static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
"key must not be null.");
goto error;
}
-
+
key = env->GetStringUTFChars(keyJ, NULL);
-
+
len = property_get(key, buf, "");
if ((len <= 0) && (defJ != NULL)) {
rvJ = defJ;
@@ -47,9 +47,9 @@ static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
} else {
rvJ = env->NewStringUTF("");
}
-
+
env->ReleaseStringUTFChars(keyJ, key);
-
+
error:
return rvJ;
}
@@ -60,6 +60,101 @@ static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
return SystemProperties_getSS(env, clazz, keyJ, NULL);
}
+static jint SystemProperties_get_int(JNIEnv *env, jobject clazz,
+ jstring keyJ, jint defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jint result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len > 0) {
+ jint temp;
+ if (sscanf(buf, "%d", &temp) == 1)
+ result = temp;
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
+static jlong SystemProperties_get_long(JNIEnv *env, jobject clazz,
+ jstring keyJ, jlong defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jlong result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len > 0) {
+ jlong temp;
+ if (sscanf(buf, "%lld", &temp) == 1)
+ result = temp;
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
+static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,
+ jstring keyJ, jboolean defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jboolean result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n')
+ result = false;
+ else if (ch == '1' || ch == 'y')
+ result = true;
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
static void SystemProperties_set(JNIEnv *env, jobject clazz,
jstring keyJ, jstring valJ)
{
@@ -94,6 +189,12 @@ static JNINativeMethod method_table[] = {
(void*) SystemProperties_getS },
{ "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getSS },
+ { "native_get_int", "(Ljava/lang/String;I)I",
+ (void*) SystemProperties_get_int },
+ { "native_get_long", "(Ljava/lang/String;J)J",
+ (void*) SystemProperties_get_long },
+ { "native_get_boolean", "(Ljava/lang/String;Z)Z",
+ (void*) SystemProperties_get_boolean },
{ "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) SystemProperties_set },
};
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 91a8e8e..7a3bbbb 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,213 +95,107 @@ 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) {
+
+static jboolean connectSinkNative(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);
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.AudioSink", "Connect",
+ DBUS_TYPE_INVALID);
+
env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_string(env, reply) : NULL;
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
- return NULL;
+ return JNI_FALSE;
}
-static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
+static jboolean disconnectSinkNative(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);
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.AudioSink", "Disconnect",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- if (!ret) {
- free(c_path_copy);
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
return JNI_FALSE;
}
-static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
+static jboolean suspendSinkNative(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,
- onDisconnectSinkResult, (void *)c_path_copy, nat,
- c_path,
- "org.bluez.audio.Sink", "Disconnect",
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.audio.Sink", "Suspend",
DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- if (!ret) {
- free(c_path_copy);
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
return JNI_FALSE;
}
-static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) {
+static jboolean resumeSinkNative(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",
+ bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+ c_path, "org.bluez.audio.Sink", "Resume",
DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
+ return ret ? JNI_TRUE : 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 +213,19 @@ 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));
+ method_onSinkPropertyChanged,
+ env->NewStringUTF(c_path),
+ str_array);
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));
- result = DBUS_HANDLER_RESULT_HANDLED;
- }
-
- if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) {
+ return result;
+ } else {
LOGV("... ignored");
}
if (env->ExceptionCheck()) {
@@ -407,14 +244,13 @@ 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},
+ {"suspendSinkNative", "(Ljava/lang/String;)Z", (void*)suspendSinkNative},
+ {"resumeSinkNative", "(Ljava/lang/String;)Z", (void*)resumeSinkNative},
+ {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+ (void *)getSinkPropertiesNative},
};
int register_android_server_BluetoothA2dpService(JNIEnv *env) {
@@ -425,12 +261,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
deleted file mode 100644
index 58ae4f6..0000000
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ /dev/null
@@ -1,1035 +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 DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Adapter"
-#define LOG_TAG "BluetoothDeviceService.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 <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#ifdef HAVE_BLUETOOTH
-#include <dbus/dbus.h>
-#include <bluedroid/bluetooth.h>
-#endif
-
-#include <cutils/properties.h>
-
-namespace android {
-
-#define BLUETOOTH_CLASS_ERROR 0xFF000000
-
-#ifdef HAVE_BLUETOOTH
-// We initialize these variables when we load class
-// android.server.BluetoothDeviceService
-static jfieldID field_mNativeData;
-static jfieldID field_mEventLoop;
-
-typedef struct {
- JNIEnv *env;
- DBusConnection *conn;
- const char *adapter; // dbus object name of the local adapter
-} native_data_t;
-
-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);
-
-/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
- * Perform quick sanity check, if there are any problems return NULL
- */
-static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
- native_data_t *nat =
- (native_data_t *)(env->GetIntField(object, field_mNativeData));
- if (nat == NULL || nat->conn == NULL) {
- LOGE("Uninitialized native data\n");
- return NULL;
- }
- return nat;
-}
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- field_mNativeData = get_field(env, clazz, "mNativeData", "I");
- field_mEventLoop = get_field(env, clazz, "mEventLoop",
- "Landroid/server/BluetoothEventLoop;");
-#endif
-}
-
-/* Returns true on success (even if adapter is present but disabled).
- * Return false if dbus is down, or another serious error (out of memory)
-*/
-static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
- if (NULL == nat) {
- LOGE("%s: out of memory!", __FUNCTION__);
- return false;
- }
- nat->env = env;
-
- env->SetIntField(object, field_mNativeData, (jint)nat);
- DBusError err;
- dbus_error_init(&err);
- dbus_threads_init_default();
- nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- if (dbus_error_is_set(&err)) {
- LOGE("Could not get onto the system bus: %s", err.message);
- dbus_error_free(&err);
- 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) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat =
- (native_data_t *)env->GetIntField(object, field_mNativeData);
- if (nat) {
- free(nat);
- nat = NULL;
- }
-#endif
-}
-
-static jstring getNameNative(JNIEnv *env, jobject object){
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- 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;
- }
-#endif
- return NULL;
-}
-
-static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- return (env->NewStringUTF(nat->adapter));
- }
-#endif
- return NULL;
-}
-
-
-static jboolean startDiscoveryNative(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);
-
- /* Compose the command */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "DiscoverDevices");
-
- if (msg == NULL) {
- LOGE("%s: Could not allocate D-Bus message object!", __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.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;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static void cancelDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jstring ret;
- native_data_t *nat;
-
- dbus_error_init(&err);
-
- nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- /* Compose the command */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "CancelDiscovery");
-
- if (msg == NULL) {
- LOGE("%s: Could not allocate D-Bus message object!", __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)) {
- if(strcmp(err.name, 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);
- } else {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- }
- }
-
-done:
- if (msg) dbus_message_unref(msg);
- if (reply) dbus_message_unref(reply);
-#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) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- 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);
- LOGV("... address = %s", c_address);
- char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
- strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
- bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
- onCreateBondingResult, // callback
- context_address,
- eventLoopNat,
- nat->adapter,
- DBUS_CLASS_NAME, "CreateBonding",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return ret ? JNI_TRUE : JNI_FALSE;
-
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean cancelBondingProcessNative(JNIEnv *env, jobject object,
- jstring address) {
- LOGV(__FUNCTION__);
-#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);
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, -1, nat->adapter,
- DBUS_CLASS_NAME, "CancelBondingProcess",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) {
- dbus_message_unref(reply);
- }
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean removeBondingNative(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);
- LOGV("... address = %s", c_address);
- 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_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);
- }
- } else {
- result = JNI_TRUE;
- }
-
- env->ReleaseStringUTFChars(address, c_address);
- dbus_error_free(&err);
- if (reply) dbus_message_unref(reply);
- }
-#endif
- return result;
-}
-
-static jobjectArray listBondingsNative(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;
- }
-#endif
- return NULL;
-}
-
-static jobjectArray listConnectionsNative(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;
- }
-#endif
- return NULL;
-}
-
-static jobjectArray listRemoteDevicesNative(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;
- }
-#endif
- return NULL;
-}
-
-static jstring common_Get(JNIEnv *env, jobject object, const char *func) {
- LOGV("%s:%s", __FUNCTION__, func);
-#ifdef HAVE_BLUETOOTH
- 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;
- }
- }
-#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");
-}
-
-static jstring getManufacturerNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetManufacturer");
-}
-
-static jstring getCompanyNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetCompany");
-}
-
-static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, obj);
- 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;
- }
- }
-#endif
- return JNI_FALSE;
-}
-
-static jstring common_getRemote(JNIEnv *env, jobject object, const char *func,
- jstring address) {
- LOGV("%s:%s", __FUNCTION__, func);
-#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_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);
- return NULL;
- }
- }
-#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;
-#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, "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);
- }
- }
-#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;
- }
-#endif
- return NULL;
-}
-
-static jintArray getRemoteServiceHandlesNative(JNIEnv *env, jobject object,
- jstring address, jstring match) {
-#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 =
- 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);
- }
- 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);
-
- 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;
-}
-
-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);
-
- 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;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint enableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_enable();
-#endif
- return -1;
-}
-
-static jint disableNative(JNIEnv *env, jobject object) {
-#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();
-#endif
- return -1;
-}
-
-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) {
- 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 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},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
- {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
-
- {"isEnabledNative", "()I", (void *)isEnabledNative},
- {"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},
- {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
- {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative},
-};
-
-int register_android_server_BluetoothDeviceService(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index ad24136..d2e9454 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -36,36 +36,38 @@
namespace android {
+#define CREATE_DEVICE_ALREADY_EXISTS 1
+#define CREATE_DEVICE_SUCCESS 0
+#define CREATE_DEVICE_FAILED -1
+
#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_onDeviceDisconnectRequested;
+
+static jmethodID method_onCreatePairedDeviceResult;
+static jmethodID method_onCreateDeviceResult;
+static jmethodID method_onDiscoverServicesResult;
+static jmethodID method_onGetDeviceServiceChannelResult;
+
+static jmethodID method_onRequestPinCode;
+static jmethodID method_onRequestPasskey;
+static jmethodID method_onRequestPasskeyConfirmation;
+static jmethodID method_onRequestPairingConsent;
+static jmethodID method_onDisplayPasskey;
+static jmethodID method_onAgentAuthorize;
+static jmethodID method_onAgentCancel;
typedef event_loop_native_data_t native_data_t;
+#define EVENT_LOOP_REFS 10
+
static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object,
field_mNativeData));
@@ -80,30 +82,40 @@ 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_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
+ "(Ljava/lang/String;)V");
+
+ method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
+ "(Ljava/lang/String;I)V");
+ method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
+ "(Ljava/lang/String;I)V");
+ method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
+ "(Ljava/lang/String;Z)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");
+ method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
+ "(Ljava/lang/String;I)V");
+ method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
+ "(Ljava/lang/String;II)V");
+ method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
+ "(Ljava/lang/String;I)V");
+ method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
+ "(Ljava/lang/String;II)V");
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
#endif
@@ -154,9 +166,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 +192,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 +219,167 @@ 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'",
+ "type='signal',interface='org.bluez.AudioSink'",
&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'",
- &err);
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
+
+ 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;
+}
- // 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);
- return JNI_FALSE;
+
+const char * get_adapter_path(DBusConnection *conn) {
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusError err;
+ const char *device_path = NULL;
+ int attempt = 0;
+
+ for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
+ msg = dbus_message_new_method_call("org.bluez", "/",
+ "org.bluez.Manager", "DefaultAdapter");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for get_adapter_path!",
+ __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);
- // 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,
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ 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;
+ // bluetoothd is still down, retry
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ usleep(10000); // 10 ms
+ continue;
+ } else {
+ // Some other error we weren't expecting
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
}
+ goto failed;
}
- if (attempt == 1000) {
- LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
- "is hcid running?");
- return JNI_FALSE;
- }
+ }
+ if (attempt == 1000) {
+ LOGE("Time out while trying to get Adapter path, is bluetoothd up ?");
+ goto failed;
+ }
- // 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) {
+ 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 JNI_FALSE;
}
+ goto failed;
+ }
+ dbus_message_unref(msg);
+ return device_path;
- dbus_message_unref(reply);
- return JNI_TRUE;
+failed:
+ dbus_message_unref(msg);
+ return NULL;
+}
+
+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;
}
- return JNI_FALSE;
+ nat->adapter = get_adapter_path(nat->conn);
+ if (nat->adapter == NULL) {
+ return -1;
+ }
+ 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 -1;
+ }
+
+ 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'",
@@ -650,6 +724,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
native_data_t *nat;
JNIEnv *env;
DBusError err;
+ DBusHandlerResult ret;
dbus_error_init(&err);
@@ -660,321 +735,178 @@ 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));
+ LOGE("%s: Received signal %s:%s from %s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg),
+ dbus_message_get_path(msg));
+ env->PushLocalFrame(EVENT_LOOP_REFS);
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);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceFound,
- env->NewStringUTF(c_address),
- (jint)n_class,
- (jshort)n_rssi);
- } 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")) {
- 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->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;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &n_class,
- 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);
+ 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_onRemoteNameUpdated,
+ method_onDeviceFound,
env->NewStringUTF(c_address),
- env->NewStringUTF(c_name));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ str_array);
+ } else
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteNameFailed")) {
+ "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_onRemoteNameFailed,
+ 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;
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceConnected")) {
- char *c_address;
+ "org.bluez.Adapter",
+ "DeviceCreated")) {
+ char *c_object_path;
if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
+ LOGV("... address = %s", c_object_path);
env->CallVoidMethod(nat->me,
- method_onRemoteDeviceConnected,
- 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;
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisconnectRequested")) {
- 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_onRemoteDeviceDisconnectRequested,
- 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;
+ goto success;
} 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));
- } 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;
+ goto success;
} 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));
+ method_onDevicePropertyChanged,
+ env->NewStringUTF(remote_device_path),
+ str_array);
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} 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);
- }
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ "org.bluez.Device",
+ "DisconnectRequested")) {
+ const char *remote_device_path = dbus_message_get_path(msg);
+ env->CallVoidMethod(nat->me,
+ method_onDeviceDisconnectRequested,
+ env->NewStringUTF(remote_device_path));
+ goto success;
}
- return a2dp_event_filter(msg, env);
+ ret = a2dp_event_filter(msg, env);
+ env->PopLocalFrame(NULL);
+ return ret;
+
+success:
+ env->PopLocalFrame(NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
// 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")) {
+ if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
- 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
-
- 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);
-
- env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel,
- env->NewStringUTF(address));
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+ env->PushLocalFrame(EVENT_LOOP_REFS);
+ if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "Cancel")) {
+ env->CallVoidMethod(nat->me, method_onAgentCancel);
// 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;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} 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;
+ goto failure;
}
- 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) {
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;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
@@ -983,64 +915,116 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn,
"org.bluez.Error.Rejected", "Authorization rejected");
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
}
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} 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__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
+ goto failure;
}
- LOGV("... address = %s", address);
- LOGV("... service = %s", service);
- LOGV("... uuid = %s", uuid);
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPinCode,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "RequestPasskey")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
+ goto failure;
+ }
- env->CallVoidMethod(nat->me,
- method_onAuthAgentCancel, env->NewStringUTF(address),
- env->NewStringUTF(service), env->NewStringUTF(uuid));
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPasskey,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "DisplayPasskey")) {
+ char *object_path;
+ uint32_t passkey;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
+ goto failure;
+ }
- // 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_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onDisplayPasskey,
+ env->NewStringUTF(object_path),
+ passkey,
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "RequestConfirmation")) {
+ char *object_path;
+ uint32_t passkey;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
+ goto failure;
}
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
+ env->NewStringUTF(object_path),
+ passkey,
+ int(msg));
+ goto success;
} else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Release")) {
- LOGW("We are no longer the auth agent!");
+ "org.bluez.Agent", "RequestPairingConsent")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
+ goto failure;
+ }
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "Release")) {
// 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;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else {
- LOGV("... ignored");
+ LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
}
+failure:
+ env->PopLocalFrame(NULL);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+success:
+ env->PopLocalFrame(NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
}
#endif
@@ -1054,8 +1038,10 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn,
#define BOND_RESULT_AUTH_CANCELED 3
#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
+#define BOND_RESULT_AUTH_TIMEOUT 6
+#define BOND_RESULT_REPEATED_ATTEMPTS 7
-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;
@@ -1099,6 +1085,12 @@ void onCreateBondingResult(DBusMessage *msg, void *user, void *n) {
!strcmp(err.message, "Discover in progress")) {
LOGV("... error = %s (%s)\n", err.name, err.message);
result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_REPEATED_ATTEMPTS;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_AUTH_TIMEOUT;
} else {
LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
result = BOND_RESULT_ERROR;
@@ -1106,7 +1098,7 @@ void onCreateBondingResult(DBusMessage *msg, void *user, void *n) {
}
env->CallVoidMethod(nat->me,
- method_onCreateBondingResult,
+ method_onCreatePairedDeviceResult,
env->NewStringUTF(address),
result);
done:
@@ -1114,7 +1106,58 @@ done:
free(user);
}
-void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) {
+void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
+ LOGV(__FUNCTION__);
+
+ native_data_t *nat = (native_data_t *)n;
+ const char *address= (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env;
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+
+ LOGV("... Address = %s", address);
+
+ jint result = CREATE_DEVICE_SUCCESS;
+ if (dbus_set_error_from_message(&err, msg)) {
+ if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
+ result = CREATE_DEVICE_ALREADY_EXISTS;
+ }
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ result = CREATE_DEVICE_FAILED;
+ }
+ env->CallVoidMethod(nat->me,
+ method_onCreateDeviceResult,
+ env->NewStringUTF(address),
+ result);
+ free(user);
+}
+
+void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
+ LOGV(__FUNCTION__);
+
+ native_data_t *nat = (native_data_t *)n;
+ const char *path = (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env;
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+
+ LOGV("... Device Path = %s", path);
+
+ bool result = JNI_TRUE;
+ if (dbus_set_error_from_message(&err, msg)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ result = JNI_FALSE;
+ }
+ env->CallVoidMethod(nat->me,
+ method_onDiscoverServicesResult,
+ env->NewStringUTF(path),
+ result);
+ free(user);
+}
+
+void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
const char *address = (const char *) user;
@@ -1133,14 +1176,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_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
new file mode 100644
index 0000000..ea64305
--- /dev/null
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -0,0 +1,915 @@
+/*
+** 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 DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
+#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
+#define LOG_TAG "BluetoothService.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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#include <bluedroid/bluetooth.h>
+#endif
+
+#include <cutils/properties.h>
+
+namespace android {
+
+#define BLUETOOTH_CLASS_ERROR 0xFF000000
+#define PROPERTIES_NREFS 10
+
+#ifdef HAVE_BLUETOOTH
+// We initialize these variables when we load class
+// android.server.BluetoothService
+static jfieldID field_mNativeData;
+static jfieldID field_mEventLoop;
+
+typedef struct {
+ JNIEnv *env;
+ DBusConnection *conn;
+ const char *adapter; // dbus object name of the local adapter
+} native_data_t;
+
+extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
+ jobject);
+extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
+void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
+void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
+void onCreateDeviceResult(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
+ */
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ native_data_t *nat =
+ (native_data_t *)(env->GetIntField(object, field_mNativeData));
+ if (nat == NULL || nat->conn == NULL) {
+ LOGE("Uninitialized native data\n");
+ return NULL;
+ }
+ return nat;
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ field_mEventLoop = get_field(env, clazz, "mEventLoop",
+ "Landroid/server/BluetoothEventLoop;");
+#endif
+}
+
+/* Returns true on success (even if adapter is present but disabled).
+ * Return false if dbus is down, or another serious error (out of memory)
+*/
+static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return false;
+ }
+ nat->env = env;
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("Could not get onto the system bus: %s", err.message);
+ dbus_error_free(&err);
+ return false;
+ }
+ dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
+#endif /*HAVE_BLUETOOTH*/
+ return true;
+}
+
+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);
+ 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 /*HAVE_BLUETOOTH*/
+ return JNI_TRUE;
+}
+
+static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ 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) {
+ free(nat);
+ nat = NULL;
+ }
+#endif
+}
+
+static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ return (env->NewStringUTF(get_adapter_path(env, object)));
+ }
+#endif
+ return NULL;
+}
+
+
+static jboolean startDiscoveryNative(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);
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "StartDiscovery");
+
+ if (msg == NULL) {
+ 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)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ 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 void stopDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jstring ret;
+ native_data_t *nat;
+
+ dbus_error_init(&err);
+
+ nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "StopDiscovery");
+ if (msg == NULL) {
+ 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(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);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ }
+ }
+
+done:
+ if (msg) dbus_message_unref(msg);
+ if (reply) dbus_message_unref(reply);
+#endif
+}
+
+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);
+ 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);
+ 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,
+ onCreatePairedDeviceResult, // callback
+ context_address,
+ eventLoopNat,
+ 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;
+
+ }
+#endif
+ return JNI_FALSE;
+}
+
+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,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ 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;
+ }
+ dbus_message_unref(reply);
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
+ bool ret = dbus_func_args_async(env, nat->conn, -1,
+ NULL,
+ NULL,
+ NULL,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "RemoveDevice",
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(object_path, c_object_path);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint enableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_enable();
+#endif
+ return -1;
+}
+
+static jint disableNative(JNIEnv *env, jobject object) {
+#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();
+#endif
+ return -1;
+}
+
+static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
+ jstring address, bool confirm,
+ int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply;
+ if (confirm) {
+ reply = dbus_message_new_method_return(msg);
+ } else {
+ reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Rejected", "User rejected confirmation");
+ }
+
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or"
+ "RequestPairingConsent 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 jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
+ int passkey, 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_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return Passkey code to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+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) {
+ 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 JNI_FALSE;
+}
+
+static jboolean cancelPairingUserInputNative(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", "Pairing User Input was canceled");
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return cancelUserInput 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 jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
+ jstring path)
+{
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ 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);
+
+ 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;
+ }
+ env->PushLocalFrame(PROPERTIES_NREFS);
+
+ 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);
+
+ env->PopLocalFrame(NULL);
+
+ return str_array;
+ }
+#endif
+ return NULL;
+}
+
+static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ 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;
+ }
+ env->PushLocalFrame(PROPERTIES_NREFS);
+
+ DBusMessageIter iter;
+ jobjectArray str_array = NULL;
+ if (dbus_message_iter_init(reply, &iter))
+ str_array = parse_adapter_properties(env, &iter);
+ dbus_message_unref(reply);
+
+ env->PopLocalFrame(NULL);
+ return str_array;
+ }
+#endif
+ return NULL;
+}
+
+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) {
+ DBusMessage *reply, *msg;
+ DBusMessageIter iter;
+ DBusError err;
+ const char *c_key = env->GetStringUTFChars(key, NULL);
+ dbus_error_init(&err);
+
+ 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__);
+ env->ReleaseStringUTFChars(key, c_key);
+ return JNI_FALSE;
+ }
+
+ 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);
+
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ env->ReleaseStringUTFChars(key, c_key);
+
+ 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 jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
+ jstring value) {
+#ifdef HAVE_BLUETOOTH
+ 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
+}
+
+static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
+ jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
+ jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path,
+ jstring key, void *value, jint type) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply, *msg;
+ DBusMessageIter iter;
+ DBusError err;
+
+ const char *c_key = env->GetStringUTFChars(key, NULL);
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+
+ dbus_error_init(&err);
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ c_path, DBUS_DEVICE_IFACE, "SetProperty");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for device SetProperty!", __FUNCTION__);
+ env->ReleaseStringUTFChars(key, c_key);
+ env->ReleaseStringUTFChars(path, c_path);
+ return JNI_FALSE;
+ }
+
+ 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);
+
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ env->ReleaseStringUTFChars(key, c_key);
+ env->ReleaseStringUTFChars(path, c_path);
+ 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 jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object,
+ jstring path, jstring key, jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setDevicePropertyNative(env, object, path, key,
+ (void *)&value, DBUS_TYPE_BOOLEAN);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+
+static jboolean createDeviceNative(JNIEnv *env, jobject object,
+ jstring address) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ 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);
+ LOGV("... address = %s", c_address);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1,
+ onCreateDeviceResult,
+ context_address,
+ eventLoopNat,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "CreateDevice",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean discoverServicesNative(JNIEnv *env, jobject object,
+ jstring path, jstring pattern) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ 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_path = env->GetStringUTFChars(path, NULL);
+ const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
+ int len = env->GetStringLength(path) + 1;
+ char *context_path = (char *)calloc(len, sizeof(char));
+ strlcpy(context_path, c_path, len); // for callback
+
+ LOGV("... Object Path = %s", c_path);
+ LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern));
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1,
+ onDiscoverServicesResult,
+ context_path,
+ eventLoopNat,
+ c_path,
+ DBUS_DEVICE_IFACE,
+ "DiscoverServices",
+ DBUS_TYPE_STRING, &c_pattern,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ env->ReleaseStringUTFChars(pattern, c_pattern);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
+ jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_name = env->GetStringUTFChars(name, NULL);
+ LOGV("... name = %s", c_name);
+ LOGV("... uuid1 = %llX", uuidMsb);
+ LOGV("... uuid2 = %llX", uuidLsb);
+ LOGV("... channel = %d", channel);
+ DBusMessage *reply = dbus_func_args(env, nat->conn,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "AddRfcommServiceRecord",
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_UINT64, &uuidMsb,
+ DBUS_TYPE_UINT64, &uuidLsb,
+ DBUS_TYPE_UINT16, &channel,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(name, c_name);
+ return reply ? dbus_returns_uint32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ LOGV("... handle = %X", handle);
+ DBusMessage *reply = dbus_func_args(env, nat->conn,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "RemoveServiceRecord",
+ DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ return reply ? JNI_TRUE : JNI_FALSE;
+ }
+#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},
+
+ {"isEnabledNative", "()I", (void *)isEnabledNative},
+ {"enableNative", "()I", (void *)enableNative},
+ {"disableNative", "()I", (void *)disableNative},
+
+ {"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},
+
+ {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
+ (void *)setPairingConfirmationNative},
+ {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
+ {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
+ {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
+ (void *)cancelPairingUserInputNative},
+ {"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
+ (void *)setDevicePropertyBooleanNative},
+ {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
+ {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
+ {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative},
+ {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative},
+};
+
+int register_android_server_BluetoothService(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index 98f4e03..fde6ca6 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -367,10 +367,12 @@ static int get_char(JNIEnv* env, const jchar *s, int spos, int mul,
if (c >= '0' && c <= '9') {
return (c - '0') * mul;
} else {
- char msg[100];
- sprintf(msg, "Parse error at pos=%d", spos);
- jniThrowException(env, "android/util/TimeFormatException", msg);
- *thrown = true;
+ if (!*thrown) {
+ char msg[100];
+ sprintf(msg, "Parse error at pos=%d", spos);
+ jniThrowException(env, "android/util/TimeFormatException", msg);
+ *thrown = true;
+ }
return 0;
}
}
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_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 5e5103a..34b7c89 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -51,17 +51,17 @@ struct ByteBuf {
size_t len;
size_t capacity;
uint8_t* buf;
-
+
ByteBuf(size_t initSize) {
buf = (uint8_t*)malloc(initSize);
len = 0;
- capacity = initSize;
+ capacity = initSize;
}
-
+
~ByteBuf() {
free(buf);
}
-
+
bool ensureExtraCapacity(size_t extra) {
size_t spaceNeeded = len + extra;
if (spaceNeeded > capacity) {
@@ -77,7 +77,7 @@ struct ByteBuf {
return true;
}
}
-
+
void putIntEvent(jint value) {
bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
buf[len++] = EVENT_TYPE_INT;
@@ -162,7 +162,7 @@ static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env, jobject clazz,
* In class android.util.EventLog:
* static native int writeEvent(long tag, long value)
*/
-static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
+static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
jint tag, jlong value)
{
return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
@@ -210,6 +210,8 @@ static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
/*
* In class android.util.EventLog:
* static native void readEvents(int[] tags, Collection<Event> output)
+ *
+ * Reads events from the event log, typically /dev/log/events
*/
static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
jintArray tags,
@@ -273,6 +275,80 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
env->ReleaseIntArrayElements(tags, tagValues, 0);
}
+/*
+ * In class android.util.EventLog:
+ * static native void readEvents(String path, Collection<Event> output)
+ *
+ * Reads events from a file (See Checkin.Aggregation). Events are stored in
+ * native raw format (logger_entry + payload).
+ */
+static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
+ jobject out) {
+ if (path == NULL || out == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const char *pathString = env->GetStringUTFChars(path, 0);
+ int fd = open(pathString, O_RDONLY | O_NONBLOCK);
+ env->ReleaseStringUTFChars(path, pathString);
+
+ if (fd < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+ for (;;) {
+ // read log entry structure from file
+ int len = read(fd, buf, sizeof(logger_entry));
+ if (len == 0) {
+ break; // end of file
+ } else if (len < 0) {
+ jniThrowIOException(env, errno);
+ } else if ((size_t) len < sizeof(logger_entry)) {
+ jniThrowException(env, "java/io/IOException", "Event header too short");
+ break;
+ }
+
+ // read event payload
+ logger_entry* entry = (logger_entry*) buf;
+ if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Too much data for event payload. Corrupt file?");
+ break;
+ }
+
+ len = read(fd, buf + sizeof(logger_entry), entry->len);
+ if (len == 0) {
+ break; // end of file
+ } else if (len < 0) {
+ jniThrowIOException(env, errno);
+ } else if ((size_t) len < entry->len) {
+ jniThrowException(env, "java/io/IOException", "Event payload too short");
+ break;
+ }
+
+ // create EventLog$Event and add it to the collection
+ int buffer_size = sizeof(logger_entry) + entry->len;
+ jbyteArray array = env->NewByteArray(buffer_size);
+ if (array == NULL) break;
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, buf, buffer_size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ jobject event = env->NewObject(gEventClass, gEventInitID, array);
+ if (event == NULL) break;
+
+ env->CallBooleanMethod(out, gCollectionAddID, event);
+ env->DeleteLocalRef(event);
+ env->DeleteLocalRef(array);
+ }
+
+ close(fd);
+}
/*
* JNI registration.
@@ -292,6 +368,10 @@ static JNINativeMethod gRegisterMethods[] = {
{ "readEvents",
"([ILjava/util/Collection;)V",
(void*) android_util_EventLog_readEvents
+ },
+ { "readEvents",
+ "(Ljava/lang/String;Ljava/util/Collection;)V",
+ (void*) android_util_EventLog_readEventsFile
}
};
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 98fe0e65..d8c2234 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>
@@ -32,6 +32,7 @@
#include <sys/errno.h>
#include <sys/resource.h>
#include <sys/types.h>
+#include <cutils/sched_policy.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
@@ -50,13 +51,7 @@ pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
-/*
- * List of cgroup names which map to ANDROID_TGROUP_ values in Thread.h
- * and Process.java
- * These names are used to construct the path to the cgroup control dir
- */
-
-static const char *cgroup_names[] = { NULL, "bg_non_interactive", "fg_boost" };
+#define POLICY_DEBUG 0
using namespace android;
@@ -194,28 +189,6 @@ jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
return -1;
}
-static int add_pid_to_cgroup(int pid, int grp)
-{
- int fd;
- char path[255];
- char text[64];
-
- sprintf(path, "/dev/cpuctl/%s/tasks",
- (cgroup_names[grp] ? cgroup_names[grp] : ""));
-
- if ((fd = open(path, O_WRONLY)) < 0)
- return -1;
-
- sprintf(text, "%d", pid);
- if (write(fd, text, strlen(text)) < 0) {
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
if (grp > ANDROID_TGROUP_MAX || grp < 0) {
@@ -223,10 +196,9 @@ void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint
return;
}
- if (add_pid_to_cgroup(pid, grp)) {
- // If the thread exited on us, don't generate an exception
- if (errno != ESRCH && errno != ENOENT)
- signalExceptionForGroupError(env, clazz, errno);
+ if (set_sched_policy(pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ signalExceptionForGroupError(env, clazz, errno);
}
}
@@ -242,6 +214,26 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
return;
}
+#if POLICY_DEBUG
+ char cmdline[32];
+ int fd;
+
+ strcpy(cmdline, "unknown");
+
+ sprintf(proc_path, "/proc/%d/cmdline", pid);
+ fd = open(proc_path, O_RDONLY);
+ if (fd >= 0) {
+ int rc = read(fd, cmdline, sizeof(cmdline)-1);
+ cmdline[rc] = 0;
+ close(fd);
+ }
+
+ if (grp == ANDROID_TGROUP_BG_NONINTERACT) {
+ LOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline);
+ } else {
+ LOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline);
+ }
+#endif
sprintf(proc_path, "/proc/%d/task", pid);
if (!(d = opendir(proc_path))) {
// If the process exited on us, don't generate an exception
@@ -271,13 +263,9 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
continue;
}
- if (add_pid_to_cgroup(t_pid, grp)) {
- // If the thread exited on us, ignore it and keep going
- if (errno != ESRCH && errno != ENOENT) {
- signalExceptionForGroupError(env, clazz, errno);
- closedir(d);
- return;
- }
+ if (set_sched_policy(t_pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ signalExceptionForGroupError(env, clazz, errno);
}
}
closedir(d);
@@ -286,10 +274,16 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
jint pid, jint pri)
{
+ int rc = 0;
+
if (pri >= ANDROID_PRIORITY_BACKGROUND) {
- add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT);
+ rc = set_sched_policy(pid, SP_BACKGROUND);
} else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
- add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT);
+ rc = set_sched_policy(pid, SP_FOREGROUND);
+ }
+
+ if (rc) {
+ signalExceptionForGroupError(env, clazz, errno);
}
if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
@@ -385,7 +379,7 @@ static int pid_compare(const void* v1, const void* v2)
return *((const jint*)v1) - *((const jint*)v2);
}
-jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
+static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
{
int fd = open("/proc/meminfo", O_RDONLY);
@@ -405,7 +399,7 @@ jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
buffer[len] = 0;
int numFound = 0;
- int mem = 0;
+ jlong mem = 0;
static const char* const sums[] = { "MemFree:", "Cached:", NULL };
static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
@@ -424,7 +418,7 @@ jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
p++;
if (*p == 0) p--;
}
- mem += atoi(num) * 1024;
+ mem += atoll(num) * 1024;
numFound++;
break;
}
@@ -874,7 +868,7 @@ static const JNINativeMethod methods[] = {
{"setGid", "(I)I", (void*)android_os_Process_setGid},
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
- {"getFreeMemory", "()I", (void*)android_os_Process_getFreeMemory},
+ {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
{"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
{"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 076775f..40c8aa0 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -24,6 +24,7 @@
#include <SkCanvas.h>
#include <SkBitmap.h>
+#include <SkRegion.h>
#include "jni.h"
#include <android_runtime/AndroidRuntime.h>
@@ -45,6 +46,7 @@ struct sso_t {
static sso_t sso;
struct so_t {
+ jfieldID surfaceControl;
jfieldID surface;
jfieldID saveCount;
jfieldID canvas;
@@ -121,10 +123,50 @@ static void SurfaceSession_kill(JNIEnv* env, jobject clazz)
// ----------------------------------------------------------------------------
+static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject clazz)
+{
+ SurfaceControl* const p =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ return sp<SurfaceControl>(p);
+}
+
+static void setSurfaceControl(JNIEnv* env, jobject clazz,
+ const sp<SurfaceControl>& surface)
+{
+ SurfaceControl* const p =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ if (surface.get()) {
+ surface->incStrong(clazz);
+ }
+ if (p) {
+ p->decStrong(clazz);
+ }
+ env->SetIntField(clazz, so.surfaceControl, (int)surface.get());
+}
+
static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
{
- Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
- return sp<Surface>(p);
+ sp<Surface> result((Surface*)env->GetIntField(clazz, so.surface));
+ if (result == 0) {
+ /*
+ * if this method is called from the WindowManager's process, it means
+ * the client is is not remote, and therefore is allowed to have
+ * a Surface (data), so we create it here.
+ * If we don't have a SurfaceControl, it means we're in a different
+ * process.
+ */
+
+ SurfaceControl* const control =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ if (control) {
+ result = control->getSurface();
+ if (result != 0) {
+ result->incStrong(clazz);
+ env->SetIntField(clazz, so.surface, (int)result.get());
+ }
+ }
+ }
+ return result;
}
static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
@@ -153,12 +195,12 @@ static void Surface_init(
SurfaceComposerClient* client =
(SurfaceComposerClient*)env->GetIntField(session, sso.client);
- sp<Surface> surface(client->createSurface(pid, dpy, w, h, format, flags));
+ sp<SurfaceControl> surface(client->createSurface(pid, dpy, w, h, format, flags));
if (surface == 0) {
doThrow(env, OutOfResourcesException);
return;
}
- setSurface(env, clazz, surface);
+ setSurfaceControl(env, clazz, surface);
}
static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
@@ -168,28 +210,44 @@ static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
doThrow(env, "java/lang/NullPointerException", NULL);
return;
}
- const sp<Surface>& rhs = Surface::readFromParcel(parcel);
+ sp<Surface> rhs = new Surface(*parcel);
setSurface(env, clazz, rhs);
}
-static void Surface_clear(JNIEnv* env, jobject clazz, uintptr_t *ostack)
+static void Surface_destroy(JNIEnv* env, jobject clazz, uintptr_t *ostack)
+{
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (SurfaceControl::isValid(surface)) {
+ surface->clear();
+ }
+ setSurfaceControl(env, clazz, 0);
+ setSurface(env, clazz, 0);
+}
+
+static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack)
{
+ setSurfaceControl(env, clazz, 0);
setSurface(env, clazz, 0);
}
static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- return surface->isValid() ? JNI_TRUE : JNI_FALSE;
+ const sp<SurfaceControl>& surfaceControl(getSurfaceControl(env, clazz));
+ if (surfaceControl != 0) {
+ return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
+ }
+ const sp<Surface>& surface(getSurface(env, clazz));
+ return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
}
static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
{
- /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then
+ /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
we can map to SkBitmap::kARGB_8888_Config, and optionally call
bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
*/
switch (format) {
+ case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
@@ -200,8 +258,8 @@ static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
+ const sp<Surface>& surface(getSurface(env, clazz));
+ if (!Surface::isValid(surface))
return 0;
// get dirty region
@@ -212,7 +270,7 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
dirty.top = env->GetIntField(dirtyRect, ro.t);
dirty.right = env->GetIntField(dirtyRect, ro.r);
dirty.bottom= env->GetIntField(dirtyRect, ro.b);
- if (dirty.left < dirty.right && dirty.top < dirty.bottom) {
+ if (!dirty.isEmpty()) {
dirtyRegion.set(dirty);
}
} else {
@@ -235,7 +293,11 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
SkBitmap bitmap;
- bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, info.bpr);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
+ if (info.format == PIXEL_FORMAT_RGBX_8888) {
+ bitmap.setIsOpaque(true);
+ }
if (info.w > 0 && info.h > 0) {
bitmap.setPixels(info.bits);
} else {
@@ -243,13 +305,27 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
bitmap.setPixels(NULL);
}
nativeCanvas->setBitmapDevice(bitmap);
- nativeCanvas->clipRegion(dirtyRegion.toSkRegion());
+
+ SkRegion clipReg;
+ if (dirtyRegion.isRect()) { // very common case
+ const Rect& b(dirtyRegion.getBounds());
+ clipReg.setRect(b.left, b.top, b.right, b.bottom);
+ } else {
+ size_t count;
+ Rect const* r = dirtyRegion.getArray(&count);
+ while (count) {
+ clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
+ r++, count--;
+ }
+ }
+
+ nativeCanvas->clipRegion(clipReg);
int saveCount = nativeCanvas->save();
env->SetIntField(clazz, so.saveCount, saveCount);
if (dirtyRect) {
- Rect bounds(dirtyRegion.bounds());
+ const Rect& bounds(dirtyRegion.getBounds());
env->SetIntField(dirtyRect, ro.l, bounds.left);
env->SetIntField(dirtyRect, ro.t, bounds.top);
env->SetIntField(dirtyRect, ro.r, bounds.right);
@@ -268,8 +344,8 @@ static void Surface_unlockCanvasAndPost(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
+ const sp<Surface>& surface(getSurface(env, clazz));
+ if (!Surface::isValid(surface))
return;
// detach the canvas from the surface
@@ -289,26 +365,8 @@ static void Surface_unlockCanvasAndPost(
static void Surface_unlockCanvas(
JNIEnv* env, jobject clazz, jobject argCanvas)
{
- jobject canvas = env->GetObjectField(clazz, so.canvas);
- if (canvas != argCanvas) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
- return;
-
- status_t err = surface->unlock();
- if (err < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
- SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
- int saveCount = env->GetIntField(clazz, so.saveCount);
- nativeCanvas->restoreToCount(saveCount);
- nativeCanvas->setBitmapDevice(SkBitmap());
- env->SetIntField(clazz, so.saveCount, 0);
+ // XXX: this API has been removed
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_openTransaction(
@@ -353,138 +411,140 @@ static void Surface_unfreezeDisplay(
static void Surface_setLayer(
JNIEnv* env, jobject clazz, jint zorder)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setLayer(zorder) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setLayer(zorder);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setPosition(
JNIEnv* env, jobject clazz, jint x, jint y)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setPosition(x, y) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setPosition(x, y);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setSize(
JNIEnv* env, jobject clazz, jint w, jint h)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setSize(w, h) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setSize(w, h);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_hide(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->hide() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->hide();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_show(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->show() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->show();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_freeze(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->freeze() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->freeze();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_unfreeze(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->unfreeze() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->unfreeze();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setFlags(
JNIEnv* env, jobject clazz, jint flags, jint mask)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setFlags(flags, mask) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setFlags(flags, mask);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setTransparentRegion(
JNIEnv* env, jobject clazz, jobject argRegion)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
- if (surface->setTransparentRegionHint(Region(*nativeRegion)) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
+
+ const SkIRect& b(nativeRegion->getBounds());
+ Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
+ if (nativeRegion->isComplex()) {
+ SkRegion::Iterator it(*nativeRegion);
+ while (!it.done()) {
+ const SkIRect& r(it.rect());
+ reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
+ it.next();
}
}
+
+ status_t err = surface->setTransparentRegionHint(reg);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setAlpha(
JNIEnv* env, jobject clazz, jfloat alpha)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setAlpha(alpha) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setAlpha(alpha);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setMatrix(
JNIEnv* env, jobject clazz,
jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setMatrix(dsdx, dtdx, dsdy, dtdy) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setFreezeTint(
JNIEnv* env, jobject clazz,
jint tint)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setFreezeTint(tint) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setFreezeTint(tint);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
+// ----------------------------------------------------------------------------
+
static void Surface_copyFrom(
JNIEnv* env, jobject clazz, jobject other)
{
@@ -496,16 +556,21 @@ static void Surface_copyFrom(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- const sp<Surface>& rhs = getSurface(env, other);
- if (!Surface::isSameSurface(surface, rhs)) {
+ /*
+ * This is used by the WindowManagerService just after constructing
+ * a Surface and is necessary for returning the Surface reference to
+ * the caller. At this point, we should only have a SurfaceControl.
+ */
+
+ const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
+ const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
+ if (!SurfaceControl::isSameSurface(surface, rhs)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
- setSurface(env, clazz, rhs->dup());
+ setSurfaceControl(env, clazz, rhs);
}
}
-
static void Surface_readFromParcel(
JNIEnv* env, jobject clazz, jobject argParcel)
{
@@ -515,9 +580,9 @@ static void Surface_readFromParcel(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- const sp<Surface>& rhs = Surface::readFromParcel(parcel);
- if (!Surface::isSameSurface(surface, rhs)) {
+ const sp<Surface>& control(getSurface(env, clazz));
+ sp<Surface> rhs = new Surface(*parcel);
+ if (!Surface::isSameSurface(control, rhs)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
setSurface(env, clazz, rhs);
@@ -535,8 +600,8 @@ static void Surface_writeToParcel(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- Surface::writeToParcel(surface, parcel);
+ const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
+ SurfaceControl::writeSurfaceToParcel(control, parcel);
}
// ----------------------------------------------------------------------------
@@ -557,7 +622,8 @@ static JNINativeMethod gSurfaceMethods[] = {
{"nativeClassInit", "()V", (void*)nativeClassInit },
{"init", "(Landroid/view/SurfaceSession;IIIIII)V", (void*)Surface_init },
{"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
- {"clear", "()V", (void*)Surface_clear },
+ {"destroy", "()V", (void*)Surface_destroy },
+ {"release", "()V", (void*)Surface_release },
{"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
{"isValid", "()Z", (void*)Surface_isValid },
{"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
@@ -586,7 +652,8 @@ static JNINativeMethod gSurfaceMethods[] = {
void nativeClassInit(JNIEnv* env, jclass clazz)
{
- so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 4452065..974fc0b 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -21,7 +21,6 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
-#include <ui/EGLNativeWindowSurface.h>
#include <ui/Surface.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -338,7 +337,7 @@ not_valid_surface:
goto not_valid_surface;
jint* base = beginNativeAttribList(_env, attrib_list);
- EGLSurface sur = eglCreateWindowSurface(dpy, cnf, new EGLNativeWindowSurface(window), base);
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window, base);
endNativeAttributeList(_env, attrib_list, base);
return (jint)sur;
}
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 89b1f96..3e0aea5 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -3593,6 +3593,10 @@ android_glBufferData__IILjava_nio_Buffer_2I
if (data_buf) {
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ if (_remaining < size) {
+ _env->ThrowNew(IAEClass, "remaining() < size");
+ goto exit;
+ }
}
glBufferData(
(GLenum)target,
@@ -3600,6 +3604,8 @@ android_glBufferData__IILjava_nio_Buffer_2I
(GLvoid *)data,
(GLenum)usage
);
+
+exit:
if (_array) {
releasePointer(_env, _array, data, JNI_FALSE);
}
@@ -3614,12 +3620,18 @@ android_glBufferSubData__IIILjava_nio_Buffer_2
GLvoid *data = (GLvoid *) 0;
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
+ if (_remaining < size) {
+ _env->ThrowNew(IAEClass, "remaining() < size");
+ goto exit;
+ }
glBufferSubData(
(GLenum)target,
(GLintptr)offset,
(GLsizeiptr)size,
(GLvoid *)data
);
+
+exit:
if (_array) {
releasePointer(_env, _array, data, JNI_FALSE);
}