diff options
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/android/graphics/Typeface.cpp | 2 | ||||
-rw-r--r-- | core/jni/android/opengl/util.cpp | 309 | ||||
-rw-r--r-- | core/jni/android_hardware_Camera.cpp | 2 | ||||
-rw-r--r-- | core/jni/android_os_MemoryFile.cpp | 8 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothA2dpService.cpp | 38 | ||||
-rw-r--r-- | core/jni/android_text_format_Time.cpp | 46 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 1 | ||||
-rw-r--r-- | core/jni/android_util_EventLog.cpp | 285 |
9 files changed, 451 insertions, 241 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index c92a86c..67a0bda 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -165,6 +165,7 @@ LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv1_CM \ libGLESv2 \ + libETC1 \ libhardware \ libhardware_legacy \ libsonivox \ diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index 238ece1..7c7bfeb 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -46,7 +46,7 @@ static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* } static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) { - face->unref(); + SkSafeUnref(face); } static int Typeface_getStyle(JNIEnv* env, jobject obj, SkTypeface* face) { diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 4041346..589b255 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -23,6 +23,7 @@ #include <dlfcn.h> #include <GLES/gl.h> +#include <ETC1/etc1.h> #include <core/SkBitmap.h> @@ -39,6 +40,7 @@ namespace android { static jclass gIAEClass; static jclass gUOEClass; +static jclass gAIOOBEClass; static inline void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) { @@ -712,6 +714,297 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz, } /* + * ETC1 methods. + */ + +static jclass nioAccessClass; +static jclass bufferClass; +static jmethodID getBasePointerID; +static jmethodID getBaseArrayID; +static jmethodID getBaseArrayOffsetID; +static jfieldID positionID; +static jfieldID limitID; +static jfieldID elementSizeShiftID; + +/* Cache method IDs each time the class is loaded. */ + +static void +nativeClassInitBuffer(JNIEnv *_env) +{ + jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); + nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); + + jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); + bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); + + getBasePointerID = _env->GetStaticMethodID(nioAccessClass, + "getBasePointer", "(Ljava/nio/Buffer;)J"); + getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, + "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); + getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, + "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); + positionID = _env->GetFieldID(bufferClass, "position", "I"); + limitID = _env->GetFieldID(bufferClass, "limit", "I"); + elementSizeShiftID = + _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); +} + +static void * +getPointer(JNIEnv *_env, jobject buffer, jint *remaining) +{ + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + jint offset; + void *data; + + position = _env->GetIntField(buffer, positionID); + limit = _env->GetIntField(buffer, limitID); + elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + *remaining = (limit - position) << elementSizeShift; + pointer = _env->CallStaticLongMethod(nioAccessClass, + getBasePointerID, buffer); + if (pointer != 0L) { + return (void *) (jint) pointer; + } + return NULL; +} + +class BufferHelper { +public: + BufferHelper(JNIEnv *env, jobject buffer) { + mEnv = env; + mBuffer = buffer; + mData = NULL; + mRemaining = 0; + } + + bool checkPointer(const char* errorMessage) { + if (mBuffer) { + mData = getPointer(mEnv, mBuffer, &mRemaining); + if (mData == NULL) { + mEnv->ThrowNew(gIAEClass, errorMessage); + } + return mData != NULL; + } else { + mEnv->ThrowNew(gIAEClass, errorMessage); + return false; + } + } + + inline void* getData() { + return mData; + } + + inline jint remaining() { + return mRemaining; + } + +private: + JNIEnv* mEnv; + jobject mBuffer; + void* mData; + jint mRemaining; +}; + +/** + * Encode a block of pixels. + * + * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a + * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R + * value of pixel (x, y). + * + * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether + * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing. + * + * @param out an ETC1 compressed version of the data. + * + */ +static void etc1_encodeBlock(JNIEnv *env, jclass clazz, + jobject in, jint validPixelMask, jobject out) { + if (validPixelMask < 0 || validPixelMask > 15) { + env->ThrowNew(gIAEClass, "validPixelMask"); + return; + } + BufferHelper inB(env, in); + BufferHelper outB(env, out); + if (inB.checkPointer("in") && outB.checkPointer("out")) { + if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) { + env->ThrowNew(gIAEClass, "in's remaining data < DECODED_BLOCK_SIZE"); + } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) { + env->ThrowNew(gIAEClass, "out's remaining data < ENCODED_BLOCK_SIZE"); + } else { + etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask, + (etc1_byte*) outB.getData()); + } + } +} + +/** + * Decode a block of pixels. + * + * @param in an ETC1 compressed version of the data. + * + * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a + * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R + * value of pixel (x, y). + */ +static void etc1_decodeBlock(JNIEnv *env, jclass clazz, + jobject in, jobject out){ + BufferHelper inB(env, in); + BufferHelper outB(env, out); + if (inB.checkPointer("in") && outB.checkPointer("out")) { + if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) { + env->ThrowNew(gIAEClass, "in's remaining data < ENCODED_BLOCK_SIZE"); + } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) { + env->ThrowNew(gIAEClass, "out's remaining data < DECODED_BLOCK_SIZE"); + } else { + etc1_decode_block((etc1_byte*) inB.getData(), + (etc1_byte*) outB.getData()); + } + } +} + +/** + * Return the size of the encoded image data (does not include size of PKM header). + */ +static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz, + jint width, jint height) { + return etc1_get_encoded_data_size(width, height); +} + +/** + * Encode an entire image. + * @param in pointer to the image data. Formatted such that + * pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; + * @param out pointer to encoded data. Must be large enough to store entire encoded image. + */ +static void etc1_encodeImage(JNIEnv *env, jclass clazz, + jobject in, jint width, jint height, + jint pixelSize, jint stride, jobject out) { + if (pixelSize < 2 || pixelSize > 3) { + env->ThrowNew(gIAEClass, "pixelSize must be 2 or 3"); + return; + } + BufferHelper inB(env, in); + BufferHelper outB(env, out); + if (inB.checkPointer("in") && outB.checkPointer("out")) { + jint imageSize = stride * height; + jint encodedImageSize = etc1_get_encoded_data_size(width, height); + if (inB.remaining() < imageSize) { + env->ThrowNew(gIAEClass, "in's remaining data < image size"); + } else if (outB.remaining() < encodedImageSize) { + env->ThrowNew(gIAEClass, "out's remaining data < encoded image size"); + } else { + int result = etc1_encode_image((etc1_byte*) inB.getData(), + width, height, pixelSize, + stride, + (etc1_byte*) outB.getData()); + } + } +} + +/** + * Decode an entire image. + * @param in the encoded data. + * @param out pointer to the image data. Will be written such that + * pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be + * large enough to store entire image. + */ +static void etc1_decodeImage(JNIEnv *env, jclass clazz, + jobject in, jobject out, + jint width, jint height, + jint pixelSize, jint stride) { + if (pixelSize < 2 || pixelSize > 3) { + env->ThrowNew(gIAEClass, "pixelSize must be 2 or 3"); + return; + } + BufferHelper inB(env, in); + BufferHelper outB(env, out); + if (inB.checkPointer("in") && outB.checkPointer("out")) { + jint imageSize = stride * height; + jint encodedImageSize = etc1_get_encoded_data_size(width, height); + if (inB.remaining() < encodedImageSize) { + env->ThrowNew(gIAEClass, "in's remaining data < encoded image size"); + } else if (outB.remaining() < imageSize) { + env->ThrowNew(gIAEClass, "out's remaining data < image size"); + } else { + int result = etc1_decode_image((etc1_byte*) inB.getData(), + (etc1_byte*) outB.getData(), + width, height, pixelSize, + stride); + } + } +} + +/** + * Format a PKM header + */ +static void etc1_formatHeader(JNIEnv *env, jclass clazz, + jobject header, jint width, jint height) { + BufferHelper headerB(env, header); + if (headerB.checkPointer("header") ){ + if (headerB.remaining() < ETC_PKM_HEADER_SIZE) { + env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE"); + } else { + etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height); + } + } +} + +/** + * Check if a PKM header is correctly formatted. + */ +static jboolean etc1_isValid(JNIEnv *env, jclass clazz, + jobject header) { + jboolean result = false; + BufferHelper headerB(env, header); + if (headerB.checkPointer("header") ){ + if (headerB.remaining() < ETC_PKM_HEADER_SIZE) { + env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE"); + } else { + result = etc1_pkm_is_valid((etc1_byte*) headerB.getData()); + } + } + return result; +} + +/** + * Read the image width from a PKM header + */ +static jint etc1_getWidth(JNIEnv *env, jclass clazz, + jobject header) { + jint result = 0; + BufferHelper headerB(env, header); + if (headerB.checkPointer("header") ){ + if (headerB.remaining() < ETC_PKM_HEADER_SIZE) { + env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE"); + } else { + result = etc1_pkm_get_width((etc1_byte*) headerB.getData()); + } + } + return result; +} + +/** + * Read the image height from a PKM header + */ +static int etc1_getHeight(JNIEnv *env, jclass clazz, + jobject header) { + jint result = 0; + BufferHelper headerB(env, header); + if (headerB.checkPointer("header") ){ + if (headerB.remaining() < ETC_PKM_HEADER_SIZE) { + env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE"); + } else { + result = etc1_pkm_get_height((etc1_byte*) headerB.getData()); + } + } + return result; +} + +/* * JNI registration */ @@ -721,6 +1014,8 @@ lookupClasses(JNIEnv* env) { env->FindClass("java/lang/IllegalArgumentException")); gUOEClass = (jclass) env->NewGlobalRef( env->FindClass("java/lang/UnsupportedOperationException")); + gAIOOBEClass = (jclass) env->NewGlobalRef( + env->FindClass("java/lang/ArrayIndexOutOfBoundsException")); } static JNINativeMethod gMatrixMethods[] = { @@ -742,6 +1037,18 @@ static JNINativeMethod gUtilsMethods[] = { { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D }, }; +static JNINativeMethod gEtc1Methods[] = { + { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock }, + { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock }, + { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize }, + { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage }, + { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage }, + { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader }, + { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid }, + { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth }, + { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight }, +}; + typedef struct _ClassRegistrationInfo { const char* classPath; JNINativeMethod* methods; @@ -752,11 +1059,13 @@ static ClassRegistrationInfo gClasses[] = { {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)}, {"android/opengl/Visibility", gVisiblityMethods, NELEM(gVisiblityMethods)}, {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)}, + {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)}, }; int register_android_opengl_classes(JNIEnv* env) { lookupClasses(env); + nativeClassInitBuffer(env); int result = 0; for (int i = 0; i < NELEM(gClasses); i++) { ClassRegistrationInfo* cri = &gClasses[i]; diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index d57e526..11463a2 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -220,7 +220,7 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) break; default: // TODO: Change to LOGV - LOGD("dataCallback(%d, %p)", msgType, dataPtr.get()); + LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); copyAndPost(env, dataPtr, msgType); break; } diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp index 1ae3ec7..ee8d836 100644 --- a/core/jni/android_os_MemoryFile.cpp +++ b/core/jni/android_os_MemoryFile.cpp @@ -30,8 +30,6 @@ static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring na { const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL); - // round up length to page boundary - length = (((length - 1) / getpagesize()) + 1) * getpagesize(); int result = ashmem_create_region(namestr, length); if (name) @@ -118,7 +116,7 @@ static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDe } } -static jint android_os_MemoryFile_get_mapped_size(JNIEnv* env, jobject clazz, +static jint android_os_MemoryFile_get_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. @@ -146,8 +144,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_get_mapped_size", "(Ljava/io/FileDescriptor;)I", - (void*)android_os_MemoryFile_get_mapped_size} + {"native_get_size", "(Ljava/io/FileDescriptor;)I", + (void*)android_os_MemoryFile_get_size} }; static const char* const kClassPathName = "android/os/MemoryFile"; diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp index 7a3bbbb..4eab4b3 100644 --- a/core/jni/android_server_BluetoothA2dpService.cpp +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -38,6 +38,7 @@ namespace android { #ifdef HAVE_BLUETOOTH static jmethodID method_onSinkPropertyChanged; +static jmethodID method_onConnectSinkResult; typedef struct { JavaVM *vm; @@ -47,6 +48,7 @@ typedef struct { } native_data_t; static native_data_t *nat = NULL; // global native data +static void onConnectSinkResult(DBusMessage *msg, void *user, void *n); static Properties sink_properties[] = { {"State", DBUS_TYPE_STRING}, @@ -133,9 +135,12 @@ static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) { LOGV(__FUNCTION__); if (nat) { const char *c_path = env->GetStringUTFChars(path, NULL); + int len = env->GetStringLength(path) + 1; + char *context_path = (char *)calloc(len, sizeof(char)); + strlcpy(context_path, c_path, len); // for callback - bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, - c_path, "org.bluez.AudioSink", "Connect", + bool ret = dbus_func_args_async(env, nat->conn, -1, onConnectSinkResult, context_path, + nat, c_path, "org.bluez.AudioSink", "Connect", DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(path, c_path); @@ -237,6 +242,31 @@ DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) { return result; } + +void onConnectSinkResult(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); + + + bool result = JNI_TRUE; + if (dbus_set_error_from_message(&err, msg)) { + LOG_AND_FREE_DBUS_ERROR(&err); + result = JNI_FALSE; + } + LOGV("... Device Path = %s, result = %d", path, result); + env->CallVoidMethod(nat->me, + method_onConnectSinkResult, + env->NewStringUTF(path), + result); + free(user); +} + #endif @@ -244,7 +274,7 @@ static JNINativeMethod sMethods[] = { {"initNative", "()Z", (void *)initNative}, {"cleanupNative", "()V", (void *)cleanupNative}, - /* Bluez audio 4.40 API */ + /* Bluez audio 4.47 API */ {"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative}, {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative}, {"suspendSinkNative", "(Ljava/lang/String;)Z", (void*)suspendSinkNative}, @@ -263,6 +293,8 @@ int register_android_server_BluetoothA2dpService(JNIEnv *env) { #ifdef HAVE_BLUETOOTH method_onSinkPropertyChanged = env->GetMethodID(clazz, "onSinkPropertyChanged", "(Ljava/lang/String;[Ljava/lang/String;)V"); + method_onConnectSinkResult = env->GetMethodID(clazz, "onConnectSinkResult", + "(Ljava/lang/String;Z)V"); #endif return AndroidRuntime::registerNativeMethods(env, diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp index fde6ca6..d89a7e6 100644 --- a/core/jni/android_text_format_Time.cpp +++ b/core/jni/android_text_format_Time.cpp @@ -382,7 +382,7 @@ static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected) jchar c = s[spos]; if (c != expected) { char msg[100]; - sprintf(msg, "Unexpected %c at pos=%d. Expected %c.", c, spos, + sprintf(msg, "Unexpected character 0x%02x at pos=%d. Expected %c.", c, spos, expected); jniThrowException(env, "android/util/TimeFormatException", msg); return false; @@ -483,6 +483,12 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, int n; jboolean inUtc = false; + if (len < 10) { + jniThrowException(env, "android/util/TimeFormatException", + "Time input is too short; must be at least 10 characters"); + return false; + } + // year n = get_char(env, s, 0, 1000, &thrown); n += get_char(env, s, 1, 100, &thrown); @@ -510,7 +516,7 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, if (thrown) return false; env->SetIntField(This, g_mdayField, n); - if (len >= 17) { + if (len >= 19) { // T if (!check_char(env, s, 10, 'T')) return false; @@ -541,10 +547,19 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, if (thrown) return false; env->SetIntField(This, g_secField, n); - // skip the '.XYZ' -- we don't care about subsecond precision. + // skip the '.XYZ' -- we don't care about subsecond precision. + int tz_index = 19; + if (tz_index < len && s[tz_index] == '.') { + do { + tz_index++; + } while (tz_index < len + && s[tz_index] >= '0' + && s[tz_index] <= '9'); + } + int offset = 0; - if (len >= 23) { - char c = s[23]; + if (len > tz_index) { + char c = s[tz_index]; // NOTE: the offset is meant to be subtracted to get from local time // to UTC. we therefore use 1 for '-' and -1 for '+'. @@ -561,27 +576,34 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, break; default: char msg[100]; - sprintf(msg, "Unexpected %c at position 19. Expected + or -", - c); + sprintf(msg, "Unexpected character 0x%02x at position %d. Expected + or -", + c, tz_index); jniThrowException(env, "android/util/TimeFormatException", msg); return false; } inUtc = true; if (offset != 0) { + if (len < tz_index + 5) { + char msg[100]; + sprintf(msg, "Unexpected length; should be %d characters", tz_index + 5); + jniThrowException(env, "android/util/TimeFormatException", msg); + return false; + } + // hour - n = get_char(env, s, 24, 10, &thrown); - n += get_char(env, s, 25, 1, &thrown); + n = get_char(env, s, tz_index + 1, 10, &thrown); + n += get_char(env, s, tz_index + 2, 1, &thrown); if (thrown) return false; n *= offset; hour += n; // : - if (!check_char(env, s, 26, ':')) return false; + if (!check_char(env, s, tz_index + 3, ':')) return false; // minute - n = get_char(env, s, 27, 10, &thrown); - n += get_char(env, s, 28, 1, &thrown); + n = get_char(env, s, tz_index + 4, 10, &thrown); + n += get_char(env, s, tz_index + 5, 1, &thrown); if (thrown) return false; n *= offset; minute += n; diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index e83d2e2..2fff727 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -524,7 +524,6 @@ static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject } for (int i=0; i<N; i++) { - LOGD("locale %2d: '%s'", i, locales[i].string()); env->SetObjectArrayElement(result, i, env->NewStringUTF(locales[i].string())); } diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp index 34b7c89..78356cf 100644 --- a/core/jni/android_util_EventLog.cpp +++ b/core/jni/android_util_EventLog.cpp @@ -21,13 +21,6 @@ #include "jni.h" #include "cutils/logger.h" -#define END_DELIMITER '\n' -#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER)) -#define LONG_BUFFER_SIZE (sizeof(jbyte)+sizeof(jlong)+sizeof(END_DELIMITER)) -#define INITAL_BUFFER_CAPACITY 256 - -#define MAX(a,b) ((a>b)?a:b) - namespace android { static jclass gCollectionClass; @@ -47,107 +40,6 @@ static jfieldID gLongValueID; static jclass gStringClass; -struct ByteBuf { - size_t len; - size_t capacity; - uint8_t* buf; - - ByteBuf(size_t initSize) { - buf = (uint8_t*)malloc(initSize); - len = 0; - capacity = initSize; - } - - ~ByteBuf() { - free(buf); - } - - bool ensureExtraCapacity(size_t extra) { - size_t spaceNeeded = len + extra; - if (spaceNeeded > capacity) { - size_t newCapacity = MAX(spaceNeeded, 2 * capacity); - void* newBuf = realloc(buf, newCapacity); - if (newBuf == NULL) { - return false; - } - capacity = newCapacity; - buf = (uint8_t*)newBuf; - return true; - } else { - return true; - } - } - - void putIntEvent(jint value) { - bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE); - buf[len++] = EVENT_TYPE_INT; - memcpy(buf+len, &value, sizeof(jint)); - len += sizeof(jint); - } - - void putByte(uint8_t value) { - bool succeeded = ensureExtraCapacity(sizeof(uint8_t)); - buf[len++] = value; - } - - void putLongEvent(jlong value) { - bool succeeded = ensureExtraCapacity(LONG_BUFFER_SIZE); - buf[len++] = EVENT_TYPE_LONG; - memcpy(buf+len, &value, sizeof(jlong)); - len += sizeof(jlong); - } - - - void putStringEvent(JNIEnv* env, jstring value) { - const char* strValue = env->GetStringUTFChars(value, NULL); - uint32_t strLen = strlen(strValue); //env->GetStringUTFLength(value); - bool succeeded = ensureExtraCapacity(1 + sizeof(uint32_t) + strLen); - buf[len++] = EVENT_TYPE_STRING; - memcpy(buf+len, &strLen, sizeof(uint32_t)); - len += sizeof(uint32_t); - memcpy(buf+len, strValue, strLen); - env->ReleaseStringUTFChars(value, strValue); - len += strLen; - } - - void putList(JNIEnv* env, jobject list) { - jobjectArray items = (jobjectArray) env->GetObjectField(list, gListItemsID); - if (items == NULL) { - jniThrowException(env, "java/lang/NullPointerException", NULL); - return; - } - - jsize numItems = env->GetArrayLength(items); - putByte(EVENT_TYPE_LIST); - putByte(numItems); - // We'd like to call GetPrimitveArrayCritical() but that might - // not be safe since we're going to be doing some I/O - for (int i = 0; i < numItems; i++) { - jobject item = env->GetObjectArrayElement(items, i); - if (env->IsInstanceOf(item, gIntegerClass)) { - jint intVal = env->GetIntField(item, gIntegerValueID); - putIntEvent(intVal); - } else if (env->IsInstanceOf(item, gLongClass)) { - jlong longVal = env->GetLongField(item, gLongValueID); - putLongEvent(longVal); - } else if (env->IsInstanceOf(item, gStringClass)) { - putStringEvent(env, (jstring)item); - } else if (env->IsInstanceOf(item, gListClass)) { - putList(env, item); - } else { - jniThrowException( - env, - "java/lang/IllegalArgumentException", - "Attempt to log an illegal item type."); - return; - } - env->DeleteLocalRef(item); - } - - env->DeleteLocalRef(items); - } -}; - /* * In class android.util.EventLog: * static native int writeEvent(int tag, int value) @@ -170,41 +62,80 @@ static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz, /* * In class android.util.EventLog: - * static native int writeEvent(long tag, List value) + * static native int writeEvent(int tag, String value) */ -static jint android_util_EventLog_writeEvent_List(JNIEnv* env, jobject clazz, - jint tag, jobject value) { - if (value == NULL) { - jclass clazz = env->FindClass("java/lang/IllegalArgumentException"); - env->ThrowNew(clazz, "writeEvent needs a value."); - return -1; - } - ByteBuf byteBuf(INITAL_BUFFER_CAPACITY); - byteBuf.putList(env, value); - byteBuf.putByte((uint8_t)END_DELIMITER); - int numBytesPut = byteBuf.len; - int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut); - return bytesWritten; +static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz, + jint tag, jstring value) { + uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD]; + + // Don't throw NPE -- I feel like it's sort of mean for a logging function + // to be all crashy if you pass in NULL -- but make the NULL value explicit. + const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL"; + jint len = strlen(str); + const int max = sizeof(buf) - sizeof(len) - 2; // Type byte, final newline + if (len > max) len = max; + + buf[0] = EVENT_TYPE_STRING; + memcpy(&buf[1], &len, sizeof(len)); + memcpy(&buf[1 + sizeof(len)], str, len); + buf[1 + sizeof(len) + len] = '\n'; + + if (value != NULL) env->ReleaseStringUTFChars(value, str); + return android_bWriteLog(tag, buf, 2 + sizeof(len) + len); } /* * In class android.util.EventLog: - * static native int writeEvent(int tag, String value) + * static native int writeEvent(long tag, Object... value) */ -static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz, - jint tag, jstring value) { +static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz, + jint tag, jobjectArray value) { if (value == NULL) { - jclass clazz = env->FindClass("java/lang/IllegalArgumentException"); - env->ThrowNew(clazz, "logEvent needs a value."); - return -1; + return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL); + } + + uint8_t buf[LOGGER_ENTRY_MAX_PAYLOAD]; + const size_t max = sizeof(buf) - 1; // leave room for final newline + size_t pos = 2; // Save room for type tag & array count + + jsize copied = 0, num = env->GetArrayLength(value); + for (; copied < num && copied < 256; ++copied) { + jobject item = env->GetObjectArrayElement(value, copied); + if (item == NULL || env->IsInstanceOf(item, gStringClass)) { + if (pos + 1 + sizeof(jint) > max) break; + const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL"; + jint len = strlen(str); + if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len); + buf[pos++] = EVENT_TYPE_STRING; + memcpy(&buf[pos], &len, sizeof(len)); + memcpy(&buf[pos + sizeof(len)], str, len); + pos += sizeof(len) + len; + if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str); + } else if (env->IsInstanceOf(item, gIntegerClass)) { + jint intVal = env->GetIntField(item, gIntegerValueID); + if (pos + 1 + sizeof(intVal) > max) break; + buf[pos++] = EVENT_TYPE_INT; + memcpy(&buf[pos], &intVal, sizeof(intVal)); + pos += sizeof(intVal); + } else if (env->IsInstanceOf(item, gLongClass)) { + jlong longVal = env->GetLongField(item, gLongValueID); + if (pos + 1 + sizeof(longVal) > max) break; + buf[pos++] = EVENT_TYPE_LONG; + memcpy(&buf[pos], &longVal, sizeof(longVal)); + pos += sizeof(longVal); + } else { + jniThrowException(env, + "java/lang/IllegalArgumentException", + "Invalid payload item type"); + return -1; + } + env->DeleteLocalRef(item); } - ByteBuf byteBuf(INITAL_BUFFER_CAPACITY); - byteBuf.putStringEvent(env, value); - byteBuf.putByte((uint8_t)END_DELIMITER); - int numBytesPut = byteBuf.len; - int bytesWritten = android_bWriteLog(tag, byteBuf.buf, numBytesPut); - return bytesWritten; + buf[0] = EVENT_TYPE_LIST; + buf[1] = copied; + buf[pos++] = '\n'; + return android_bWriteLog(tag, buf, pos); } /* @@ -276,81 +207,6 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz, } /* - * 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. */ static JNINativeMethod gRegisterMethods[] = { @@ -362,22 +218,17 @@ static JNINativeMethod gRegisterMethods[] = { (void*) android_util_EventLog_writeEvent_String }, { "writeEvent", - "(ILandroid/util/EventLog$List;)I", - (void*) android_util_EventLog_writeEvent_List + "(I[Ljava/lang/Object;)I", + (void*) android_util_EventLog_writeEvent_Array }, { "readEvents", "([ILjava/util/Collection;)V", (void*) android_util_EventLog_readEvents }, - { "readEvents", - "(Ljava/lang/String;Ljava/util/Collection;)V", - (void*) android_util_EventLog_readEventsFile - } }; static struct { const char *name; jclass *clazz; } gClasses[] = { { "android/util/EventLog$Event", &gEventClass }, - { "android/util/EventLog$List", &gListClass }, { "java/lang/Integer", &gIntegerClass }, { "java/lang/Long", &gLongClass }, { "java/lang/String", &gStringClass }, @@ -386,7 +237,6 @@ static struct { const char *name; jclass *clazz; } gClasses[] = { static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = { { &gIntegerClass, "value", "I", &gIntegerValueID }, - { &gListClass, "mItems", "[Ljava/lang/Object;", &gListItemsID }, { &gLongClass, "value", "J", &gLongValueID }, }; @@ -430,4 +280,3 @@ int register_android_util_EventLog(JNIEnv* env) { } }; // namespace android - |