diff options
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/Android.mk | 3 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 7 | ||||
-rw-r--r-- | core/jni/android_app_NativeActivity.cpp | 251 | ||||
-rw-r--r-- | core/jni/android_bluetooth_HeadsetBase.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_bluetooth_common.cpp | 1 | ||||
-rw-r--r-- | core/jni/android_hardware_Camera.cpp | 17 | ||||
-rwxr-xr-x | core/jni/android_location_GpsLocationProvider.cpp | 542 | ||||
-rw-r--r-- | core/jni/android_os_MessageQueue.cpp | 338 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 21 | ||||
-rw-r--r-- | core/jni/android_view_Surface.cpp | 5 | ||||
-rw-r--r-- | core/jni/android_view_ViewRoot.cpp | 39 | ||||
-rw-r--r-- | core/jni/com_google_android_gles_jni_EGLImpl.cpp | 2 |
12 files changed, 668 insertions, 562 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a39d06b..dbad7e9 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -28,6 +28,7 @@ LOCAL_SRC_FILES:= \ Time.cpp \ com_google_android_gles_jni_EGLImpl.cpp \ com_google_android_gles_jni_GLImpl.cpp.arm \ + android_app_NativeActivity.cpp \ android_opengl_GLES10.cpp \ android_opengl_GLES10Ext.cpp \ android_opengl_GLES11.cpp \ @@ -50,6 +51,7 @@ LOCAL_SRC_FILES:= \ android_os_Debug.cpp \ android_os_FileUtils.cpp \ android_os_MemoryFile.cpp \ + android_os_MessageQueue.cpp \ android_os_ParcelFileDescriptor.cpp \ android_os_Power.cpp \ android_os_StatFs.cpp \ @@ -122,7 +124,6 @@ LOCAL_SRC_FILES:= \ android_server_BluetoothA2dpService.cpp \ android_message_digest_sha1.cpp \ android_ddm_DdmHandleNativeHeap.cpp \ - android_location_GpsLocationProvider.cpp \ com_android_internal_os_ZygoteInit.cpp \ com_android_internal_graphics_NativeUtils.cpp \ android_backup_BackupDataInput.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 9fbf171..76df9db 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -128,6 +128,7 @@ extern int register_android_nio_utils(JNIEnv* env); extern int register_android_pim_EventRecurrence(JNIEnv* env); extern int register_android_text_format_Time(JNIEnv* env); extern int register_android_os_Debug(JNIEnv* env); +extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_ParcelFileDescriptor(JNIEnv *env); extern int register_android_os_Power(JNIEnv *env); extern int register_android_os_StatFs(JNIEnv *env); @@ -155,11 +156,11 @@ extern int register_android_server_BluetoothEventLoop(JNIEnv *env); extern int register_android_server_BluetoothA2dpService(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env); -extern int register_android_location_GpsLocationProvider(JNIEnv* env); extern int register_android_backup_BackupDataInput(JNIEnv *env); extern int register_android_backup_BackupDataOutput(JNIEnv *env); extern int register_android_backup_FileBackupHelperBase(JNIEnv *env); extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env); +extern int register_android_app_NativeActivity(JNIEnv *env); static AndroidRuntime* gCurRuntime = NULL; @@ -1249,6 +1250,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_Debug), REG_JNI(register_android_os_FileObserver), REG_JNI(register_android_os_FileUtils), + REG_JNI(register_android_os_MessageQueue), REG_JNI(register_android_os_ParcelFileDescriptor), REG_JNI(register_android_os_Power), REG_JNI(register_android_os_StatFs), @@ -1278,11 +1280,12 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_server_BluetoothA2dpService), REG_JNI(register_android_message_digest_sha1), REG_JNI(register_android_ddm_DdmHandleNativeHeap), - REG_JNI(register_android_location_GpsLocationProvider), REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataOutput), REG_JNI(register_android_backup_FileBackupHelperBase), REG_JNI(register_android_backup_BackupHelperDispatcher), + + REG_JNI(register_android_app_NativeActivity), }; /* diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp new file mode 100644 index 0000000..f2ab134 --- /dev/null +++ b/core/jni/android_app_NativeActivity.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2010 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 "NativeActivity" +#include <utils/Log.h> + +#include "JNIHelp.h" +#include <android_runtime/AndroidRuntime.h> +#include <android/native_activity.h> + +#include <dlfcn.h> + +namespace android +{ + +struct NativeCode { + NativeCode(void* _dlhandle, android_activity_create_t* _createFunc) { + memset(&activity, sizeof(activity), 0); + memset(&callbacks, sizeof(callbacks), 0); + dlhandle = _dlhandle; + createActivityFunc = _createFunc; + surface = NULL; + } + + ~NativeCode() { + if (callbacks.onDestroy != NULL) { + callbacks.onDestroy(&activity); + } + if (dlhandle != NULL) { + dlclose(dlhandle); + } + } + + void setSurface(jobject _surface) { + if (surface != NULL) { + activity.env->DeleteGlobalRef(surface); + } + if (_surface != NULL) { + surface = activity.env->NewGlobalRef(_surface); + } else { + surface = NULL; + } + } + + android_activity_t activity; + android_activity_callbacks_t callbacks; + + void* dlhandle; + android_activity_create_t* createActivityFunc; + + jobject surface; +}; + +static jint +loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path) +{ + const char* pathStr = env->GetStringUTFChars(path, NULL); + NativeCode* code = NULL; + + void* handle = dlopen(pathStr, RTLD_LAZY); + + env->ReleaseStringUTFChars(path, pathStr); + + if (handle != NULL) { + code = new NativeCode(handle, (android_activity_create_t*) + dlsym(handle, "android_onCreateActivity")); + if (code->createActivityFunc == NULL) { + LOGW("android_onCreateActivity not found"); + delete code; + return 0; + } + code->activity.callbacks = &code->callbacks; + code->activity.env = env; + code->activity.clazz = clazz; + code->createActivityFunc(&code->activity, NULL, 0); + } + + return (jint)code; +} + +static void +unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + delete code; + } +} + +static void +onStart_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStart != NULL) { + code->callbacks.onStart(&code->activity); + } + } +} + +static void +onResume_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onResume != NULL) { + code->callbacks.onResume(&code->activity); + } + } +} + +static void +onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onSaveInstanceState != NULL) { + size_t len = 0; + code->callbacks.onSaveInstanceState(&code->activity, &len); + } + } +} + +static void +onPause_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onPause != NULL) { + code->callbacks.onPause(&code->activity); + } + } +} + +static void +onStop_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStop != NULL) { + code->callbacks.onStop(&code->activity); + } + } +} + +static void +onLowMemory_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onLowMemory != NULL) { + code->callbacks.onLowMemory(&code->activity); + } + } +} + +static void +onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onWindowFocusChanged != NULL) { + code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0); + } + } +} + +static void +onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + code->setSurface(surface); + if (code->callbacks.onSurfaceCreated != NULL) { + code->callbacks.onSurfaceCreated(&code->activity, + (android_surface_t*)code->surface); + } + } +} + +static void +onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface, + jint format, jint width, jint height) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) { + code->callbacks.onSurfaceChanged(&code->activity, + (android_surface_t*)code->surface, format, width, height); + } + } +} + +static void +onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) { + code->callbacks.onSurfaceDestroyed(&code->activity, + (android_surface_t*)code->surface); + } + code->setSurface(NULL); + } +} + +static const JNINativeMethod g_methods[] = { + { "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native }, + { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, + { "onStartNative", "(I)V", (void*)onStart_native }, + { "onResumeNative", "(I)V", (void*)onResume_native }, + { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native }, + { "onPauseNative", "(I)V", (void*)onPause_native }, + { "onStopNative", "(I)V", (void*)onStop_native }, + { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native }, + { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native }, + { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native }, + { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native }, + { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native }, +}; + +static const char* const kNativeActivityPathName = "android/app/NativeActivity"; + +int register_android_app_NativeActivity(JNIEnv* env) +{ + //LOGD("register_android_app_NativeActivity"); + + jclass clazz; + + clazz = env->FindClass(kNativeActivityPathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity"); + + return AndroidRuntime::registerNativeMethods( + env, kNativeActivityPathName, + g_methods, NELEM(g_methods)); +} + +} diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp index b0b0cb8..5593a26 100644 --- a/core/jni/android_bluetooth_HeadsetBase.cpp +++ b/core/jni/android_bluetooth_HeadsetBase.cpp @@ -169,7 +169,7 @@ again: // never receive non-ASCII UTF-8). // This was added because of the BMW 2005 E46 which sends binary junk. if (is_ascii(buf)) { - LOG(LOG_INFO, "Bluetooth AT recv", buf); + LOG(LOG_INFO, "Bluetooth AT recv", "%s", buf); } else { LOGW("Ignoring invalid AT command: %s", buf); buf[0] = NULL; @@ -494,7 +494,7 @@ static void pretty_log_urc(const char *urc) { } } } - LOG(LOG_INFO, "Bluetooth AT sent", buf); + LOG(LOG_INFO, "Bluetooth AT sent", "%s", buf); free(buf); } diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp index 343fa53..9a8f1b8 100644 --- a/core/jni/android_bluetooth_common.cpp +++ b/core/jni/android_bluetooth_common.cpp @@ -65,6 +65,7 @@ static Properties adapter_properties[] = { {"PairableTimeout", DBUS_TYPE_UINT32}, {"Discovering", DBUS_TYPE_BOOLEAN}, {"Devices", DBUS_TYPE_ARRAY}, + {"UUIDs", DBUS_TYPE_ARRAY}, }; typedef union { diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index b85466b..c363156 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -288,10 +288,16 @@ void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) } } +static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz) +{ + return Camera::getNumberOfCameras(); +} + // connect to camera service -static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) +static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, + jobject weak_this, jint cameraId) { - sp<Camera> camera = Camera::connect(); + sp<Camera> camera = Camera::connect(cameraId); if (camera == NULL) { jniThrowException(env, "java/lang/RuntimeException", @@ -566,8 +572,11 @@ static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject t //------------------------------------------------- static JNINativeMethod camMethods[] = { + { "getNumberOfCameras", + "()I", + (void *)android_hardware_Camera_getNumberOfCameras }, { "native_setup", - "(Ljava/lang/Object;)V", + "(Ljava/lang/Object;I)V", (void*)android_hardware_Camera_native_setup }, { "native_release", "()V", @@ -659,7 +668,7 @@ int register_android_hardware_Camera(JNIEnv *env) { field fields_to_find[] = { { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, - { "android/view/Surface", "mSurface", "I", &fields.surface } + { "android/view/Surface", ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface } }; if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp deleted file mode 100755 index f60fe6d..0000000 --- a/core/jni/android_location_GpsLocationProvider.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright (C) 2008 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 "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 GpsPrivacyInterface* sGpsPrivacyInterface = NULL; -static const GpsNiInterface* sGpsNiInterface = NULL; -static const GpsDebugInterface* sGpsDebugInterface = 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_COUNT]; -static int mNmeaSentenceCount = 0; - -// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event -// and android_location_GpsLocationProvider_read_status -static GpsLocation sGpsLocationCopy; -static GpsStatus sGpsStatusCopy; -static GpsSvStatus sGpsSvStatusCopy; -static AGpsStatus sAGpsStatusCopy; -static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_COUNT]; -static GpsNiNotification sGpsNiNotificationCopy; - -enum CallbackType { - kLocation = 1, - kStatus = 2, - kSvStatus = 4, - kAGpsStatus = 8, - kXtraDownloadRequest = 16, - kDisableRequest = 32, - kNmeaAvailable = 64, - kNiNotification = 128, -}; -static int sPendingCallbacks; - -namespace android { - -static void location_callback(GpsLocation* location) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kLocation; - memcpy(&sGpsLocation, location, sizeof(sGpsLocation)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void status_callback(GpsStatus* status) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kStatus; - memcpy(&sGpsStatus, status, sizeof(sGpsStatus)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void sv_status_callback(GpsSvStatus* sv_status) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kSvStatus; - memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus)); - - pthread_cond_signal(&sEventCond); - 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); - - sPendingCallbacks |= kAGpsStatus; - memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -GpsCallbacks sGpsCallbacks = { - location_callback, - status_callback, - sv_status_callback, - nmea_callback -}; - -static void -download_request_callback() -{ - pthread_mutex_lock(&sEventMutex); - sPendingCallbacks |= kXtraDownloadRequest; - pthread_cond_signal(&sEventCond); - 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, -}; - -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) { - if (!sGpsInterface) - sGpsInterface = gps_get_interface(); - return (sGpsInterface != NULL); -} - -static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) -{ - if (!sGpsInterface) - sGpsInterface = gps_get_interface(); - if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) - return false; - - if (!sAGpsInterface) - 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); - - // Clear privacy lock while enabled - if (!sGpsPrivacyInterface) - sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE); - if (sGpsPrivacyInterface) - sGpsPrivacyInterface->set_privacy_lock(0); - - if (!sGpsDebugInterface) - sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE); - - return true; -} - -static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj) -{ - // Enable privacy lock while disabled - if (!sGpsPrivacyInterface) - sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE); - if (sGpsPrivacyInterface) - sGpsPrivacyInterface->set_privacy_lock(1); - - pthread_mutex_lock(&sEventMutex); - sPendingCallbacks |= kDisableRequest; - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) -{ - sGpsInterface->cleanup(); -} - -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)); - if (result) { - return false; - } - - return (sGpsInterface->start() == 0); -} - -static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) -{ - return (sGpsInterface->stop() == 0); -} - -static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) -{ - sGpsInterface->delete_aiding_data(flags); -} - -static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj) -{ - pthread_mutex_lock(&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. - 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) { - env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags, - (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude, - (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 & 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, - jintArray maskArray) -{ - // this should only be called from within a call to reportStatus, so we don't need to lock here - - jint* prns = env->GetIntArrayElements(prnArray, 0); - jfloat* snrs = env->GetFloatArrayElements(snrArray, 0); - jfloat* elev = env->GetFloatArrayElements(elevArray, 0); - jfloat* azim = env->GetFloatArrayElements(azumArray, 0); - jint* mask = env->GetIntArrayElements(maskArray, 0); - - int num_svs = sGpsSvStatusCopy.num_svs; - for (int i = 0; i < num_svs; i++) { - prns[i] = sGpsSvStatusCopy.sv_list[i].prn; - snrs[i] = sGpsSvStatusCopy.sv_list[i].snr; - elev[i] = sGpsSvStatusCopy.sv_list[i].elevation; - azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth; - } - mask[0] = sGpsSvStatusCopy.ephemeris_mask; - mask[1] = sGpsSvStatusCopy.almanac_mask; - mask[2] = sGpsSvStatusCopy.used_in_fix_mask; - - env->ReleaseIntArrayElements(prnArray, prns, 0); - env->ReleaseFloatArrayElements(snrArray, snrs, 0); - env->ReleaseFloatArrayElements(elevArray, elev, 0); - env->ReleaseFloatArrayElements(azumArray, azim, 0); - env->ReleaseIntArrayElements(maskArray, mask, 0); - 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) -{ - sGpsInterface->inject_time(time, timeReference, uncertainty); -} - -static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj, - jdouble latitude, jdouble longitude, jfloat accuracy) -{ - sGpsInterface->inject_location(latitude, longitude, accuracy); -} - -static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) -{ - if (!sGpsXtraInterface) { - sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE); - if (sGpsXtraInterface) { - int result = sGpsXtraInterface->init(&sGpsXtraCallbacks); - if (result) { - sGpsXtraInterface = NULL; - } - } - } - - return (sGpsXtraInterface != NULL); -} - -static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, - jbyteArray data, jint length) -{ - jbyte* bytes = env->GetByteArrayElements(data, 0); - sGpsXtraInterface->inject_xtra_data((char *)bytes, length); - env->ReleaseByteArrayElements(data, bytes, 0); -} - -static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - if (apn == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return; - } - const char *apnStr = env->GetStringUTFChars(apn, NULL); - sAGpsInterface->data_conn_open(apnStr); - env->ReleaseStringUTFChars(apn, apnStr); - } -} - -static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - sAGpsInterface->data_conn_closed(); - } -} - -static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - sAGpsInterface->data_conn_failed(); - } -} - -static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, - jint type, jstring hostname, jint port) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - const char *c_hostname = env->GetStringUTFChars(hostname, NULL); - sAGpsInterface->set_server(type, c_hostname, port); - env->ReleaseStringUTFChars(hostname, c_hostname); - } -} - -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 jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj) -{ - jstring result = NULL; - if (sGpsDebugInterface) { - const size_t maxLength = 2047; - char buffer[maxLength+1]; - size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength); - if (length > maxLength) length = maxLength; - buffer[length] = 0; - result = env->NewStringUTF(buffer); - } - return result; -} - -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, - {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, - {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, - {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable}, - {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, - {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start}, - {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, - {"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}, - {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, - {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, - {"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}, - {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state}, -}; - -int register_android_location_GpsLocationProvider(JNIEnv* env) -{ - return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods)); -} - -} /* namespace android */ diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp new file mode 100644 index 0000000..8984057 --- /dev/null +++ b/core/jni/android_os_MessageQueue.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2010 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 "MQNative" + +#include "JNIHelp.h" + +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <fcntl.h> + +#include <android_runtime/AndroidRuntime.h> +#include <utils/SystemClock.h> +#include <utils/Vector.h> +#include <utils/Log.h> + +using namespace android; + +// ---------------------------------------------------------------------------- + +static struct { + jclass mClass; + + jfieldID mObject; // native object attached to the DVM MessageQueue +} gMessageQueueOffsets; + +static struct { + jclass mClass; + jmethodID mConstructor; +} gKeyEventOffsets; + +// TODO: also MotionEvent offsets etc. a la gKeyEventOffsets + +static struct { + jclass mClass; + jmethodID mObtain; // obtain(Handler h, int what, Object obj) +} gMessageOffsets; + +// ---------------------------------------------------------------------------- + +static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) +{ + if (jniThrowException(env, exc, msg) != 0) + assert(false); +} + +// ---------------------------------------------------------------------------- + +class MessageQueueNative { +public: + MessageQueueNative(int readSocket, int writeSocket); + ~MessageQueueNative(); + + // select on all FDs until the designated time; forever if wakeupTime is < 0 + int waitForSignal(jobject mqueue, jlong wakeupTime); + + // signal the queue-ready pipe + void signalQueuePipe(); + + // Specify a new input pipe, passing in responsibility for the socket fd and + // ashmem region + int registerInputPipe(JNIEnv* env, int socketFd, int memRegionFd, jobject handler); + + // Forget about this input pipe, closing the socket and ashmem region as well + int unregisterInputPipe(JNIEnv* env, int socketFd); + + size_t numRegisteredPipes() const { return mInputPipes.size(); } + +private: + struct InputPipe { + int fd; + int region; + jobject handler; + + InputPipe() {} + InputPipe(int _fd, int _r, jobject _h) : fd(_fd), region(_r), handler(_h) {} + }; + + // consume an event from a socket, put it on the DVM MessageQueue indicated, + // and notify the other end of the pipe that we've consumed it. + void queueEventFromPipe(const InputPipe& pipe, jobject mqueue); + + int mQueueReadFd, mQueueWriteFd; + Vector<InputPipe> mInputPipes; +}; + +MessageQueueNative::MessageQueueNative(int readSocket, int writeSocket) + : mQueueReadFd(readSocket), mQueueWriteFd(writeSocket) { +} + +MessageQueueNative::~MessageQueueNative() { +} + +int MessageQueueNative::waitForSignal(jobject mqueue, jlong timeoutMillis) { + struct timeval tv, *timeout; + fd_set fdset; + + if (timeoutMillis < 0) { + timeout = NULL; + } else { + if (timeoutMillis == 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = (timeoutMillis / 1000); + tv.tv_usec = (timeoutMillis - (1000 * tv.tv_sec)) * 1000; + } + timeout = &tv; + } + + // always rebuild the fd set from scratch + FD_ZERO(&fdset); + + // the queue signalling pipe + FD_SET(mQueueReadFd, &fdset); + int maxFd = mQueueReadFd; + + // and the input sockets themselves + for (size_t i = 0; i < mInputPipes.size(); i++) { + FD_SET(mInputPipes[i].fd, &fdset); + if (maxFd < mInputPipes[i].fd) { + maxFd = mInputPipes[i].fd; + } + } + + // now wait + int res = select(maxFd + 1, &fdset, NULL, NULL, timeout); + + // Error? Just return it and bail + if (res < 0) return res; + + // What happened -- timeout or actual data arrived? + if (res == 0) { + // select() returned zero, which means we timed out, which means that it's time + // to deliver the head element that was already on the queue. Just fall through + // without doing anything else. + } else { + // Data (or a queue signal) arrived! + // + // If it's data, pull the data off the pipe, build a new Message with it, put it on + // the DVM-side MessageQueue (pointed to by the 'mqueue' parameter), then proceed + // into the queue-signal case. + // + // If a queue signal arrived, just consume any data pending in that pipe and + // fall out. + bool queue_signalled = (FD_ISSET(mQueueReadFd, &fdset) != 0); + + for (size_t i = 0; i < mInputPipes.size(); i++) { + if (FD_ISSET(mInputPipes[i].fd, &fdset)) { + queueEventFromPipe(mInputPipes[i], mqueue); + queue_signalled = true; // we know a priori that queueing the event does this + } + } + + // Okay, stuff went on the queue. Consume the contents of the signal pipe + // now that we're awake and about to start dispatching messages again. + if (queue_signalled) { + uint8_t buf[16]; + ssize_t nRead; + do { + nRead = read(mQueueReadFd, buf, sizeof(buf)); + } while (nRead > 0); // in nonblocking mode we'll get -1 when it's drained + } + } + + return 0; +} + +// signals to the queue pipe are one undefined byte. it's just a "data has arrived" token +// and the pipe is drained on receipt of at least one signal +void MessageQueueNative::signalQueuePipe() { + int dummy[1]; + write(mQueueWriteFd, dummy, 1); +} + +void MessageQueueNative::queueEventFromPipe(const InputPipe& inPipe, jobject mqueue) { + // !!! TODO: read the event data from the InputPipe's ashmem region, convert it to a DVM + // event object of the proper type [MotionEvent or KeyEvent], create a Message holding + // it as appropriate, point the Message to the Handler associated with this InputPipe, + // and call up to the DVM MessageQueue implementation to enqueue it for delivery. +} + +// the number of registered pipes on success; < 0 on error +int MessageQueueNative::registerInputPipe(JNIEnv* env, + int socketFd, int memRegionFd, jobject handler) { + // make sure this fd is not already known to us + for (size_t i = 0; i < mInputPipes.size(); i++) { + if (mInputPipes[i].fd == socketFd) { + LOGE("Attempt to re-register input fd %d", socketFd); + return -1; + } + } + + mInputPipes.push( InputPipe(socketFd, memRegionFd, env->NewGlobalRef(handler)) ); + return mInputPipes.size(); +} + +// Remove an input pipe from our bookkeeping. Also closes the socket and ashmem +// region file descriptor! +// +// returns the number of remaining input pipes on success; < 0 on error +int MessageQueueNative::unregisterInputPipe(JNIEnv* env, int socketFd) { + for (size_t i = 0; i < mInputPipes.size(); i++) { + if (mInputPipes[i].fd == socketFd) { + close(mInputPipes[i].fd); + close(mInputPipes[i].region); + env->DeleteGlobalRef(mInputPipes[i].handler); + mInputPipes.removeAt(i); + return mInputPipes.size(); + } + } + LOGW("Tried to unregister input pipe %d but not found!", socketFd); + return -1; +} + +// ---------------------------------------------------------------------------- + +namespace android { + +static void android_os_MessageQueue_init(JNIEnv* env, jobject obj) { + // Create the pipe + int fds[2]; + int err = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); + if (err != 0) { + doThrow(env, "java/lang/RuntimeException", "Unable to create socket pair"); + } + + MessageQueueNative *mqn = new MessageQueueNative(fds[0], fds[1]); + if (mqn == NULL) { + close(fds[0]); + close(fds[1]); + doThrow(env, "java/lang/RuntimeException", "Unable to allocate native queue"); + } + + int flags = fcntl(fds[0], F_GETFL); + fcntl(fds[0], F_SETFL, flags | O_NONBLOCK); + flags = fcntl(fds[1], F_GETFL); + fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); + + env->SetIntField(obj, gMessageQueueOffsets.mObject, (jint)mqn); +} + +static void android_os_MessageQueue_signal(JNIEnv* env, jobject obj) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + mqn->signalQueuePipe(); + } else { + doThrow(env, "java/lang/IllegalStateException", "Queue not initialized"); + } +} + +static int android_os_MessageQueue_waitForNext(JNIEnv* env, jobject obj, jlong when) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + int res = mqn->waitForSignal(obj, when); + return res; // the DVM event, if any, has been constructed and queued now + } + + return -1; +} + +static void android_os_MessageQueue_registerInputStream(JNIEnv* env, jobject obj, + jint socketFd, jint regionFd, jobject handler) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + mqn->registerInputPipe(env, socketFd, regionFd, handler); + } else { + doThrow(env, "java/lang/IllegalStateException", "Queue not initialized"); + } +} + +static void android_os_MessageQueue_unregisterInputStream(JNIEnv* env, jobject obj, + jint socketFd) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + mqn->unregisterInputPipe(env, socketFd); + } else { + doThrow(env, "java/lang/IllegalStateException", "Queue not initialized"); + } +} + +// ---------------------------------------------------------------------------- + +const char* const kKeyEventPathName = "android/view/KeyEvent"; +const char* const kMessagePathName = "android/os/Message"; +const char* const kMessageQueuePathName = "android/os/MessageQueue"; + +static JNINativeMethod gMessageQueueMethods[] = { + /* name, signature, funcPtr */ + { "nativeInit", "()V", (void*)android_os_MessageQueue_init }, + { "nativeSignal", "()V", (void*)android_os_MessageQueue_signal }, + { "nativeWaitForNext", "(J)I", (void*)android_os_MessageQueue_waitForNext }, + { "nativeRegisterInputStream", "(IILandroid/os/Handler;)V", (void*)android_os_MessageQueue_registerInputStream }, + { "nativeUnregisterInputStream", "(I)V", (void*)android_os_MessageQueue_unregisterInputStream }, +}; + +int register_android_os_MessageQueue(JNIEnv* env) { + jclass clazz; + + clazz = env->FindClass(kMessageQueuePathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.MessageQueue"); + gMessageQueueOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gMessageQueueOffsets.mObject = env->GetFieldID(clazz, "mObject", "I"); + assert(gMessageQueueOffsets.mObject); + + clazz = env->FindClass(kMessagePathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Message"); + gMessageOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gMessageOffsets.mObtain = env->GetStaticMethodID(clazz, "obtain", + "(Landroid/os/Handler;ILjava/lang/Object;)Landroid/os/Message;"); + assert(gMessageOffsets.mObtain); + + clazz = env->FindClass(kKeyEventPathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.view.KeyEvent"); + gKeyEventOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gKeyEventOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(JJIIIIIII)V"); + assert(gKeyEventOffsets.mConstructor); + + return AndroidRuntime::registerNativeMethods(env, kMessageQueuePathName, + gMessageQueueMethods, NELEM(gMessageQueueMethods)); +} + + +}; // end of namespace android diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index a2b7cc4..b7d0c67 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1504,8 +1504,7 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* } jobjectArray array = env->NewObjectArray(N, cls, NULL); - if (array == NULL) { - doThrow(env, "java/lang/OutOfMemoryError"); + if (env->ExceptionCheck()) { res.unlockBag(startOfBag); return NULL; } @@ -1533,15 +1532,23 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* } else { const char16_t* str16 = pool->stringAt(value.data, &strLen); str = env->NewString(str16, strLen); - if (str == NULL) { - doThrow(env, "java/lang/OutOfMemoryError"); - res.unlockBag(startOfBag); - return NULL; - } + } + + // If one of our NewString{UTF} calls failed due to memory, an + // exception will be pending. + if (env->ExceptionCheck()) { + res.unlockBag(startOfBag); + return NULL; } } env->SetObjectArrayElement(array, i, str); + + // If we have a large amount of strings in our array, we might + // overflow the local reference table of the VM. + if (str != NULL) { + env->DeleteLocalRef(str); + } } res.unlockBag(startOfBag); return array; diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 788374b..838ef22 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -19,6 +19,7 @@ #include "android_util_Binder.h" #include <surfaceflinger/SurfaceComposerClient.h> +#include <surfaceflinger/Surface.h> #include <ui/Region.h> #include <ui/Rect.h> @@ -332,7 +333,7 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect) SkRegion clipReg; if (dirtyRegion.isRect()) { // very common case - const Rect& b(dirtyRegion.getBounds()); + const Rect b(dirtyRegion.getBounds()); clipReg.setRect(b.left, b.top, b.right, b.bottom); } else { size_t count; @@ -680,7 +681,7 @@ static JNINativeMethod gSurfaceMethods[] = { void nativeClassInit(JNIEnv* env, jclass clazz) { - so.surface = env->GetFieldID(clazz, "mSurface", "I"); + so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "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/android_view_ViewRoot.cpp b/core/jni/android_view_ViewRoot.cpp index 9d62d89..70ad8c5 100644 --- a/core/jni/android_view_ViewRoot.cpp +++ b/core/jni/android_view_ViewRoot.cpp @@ -16,6 +16,7 @@ #include <stdio.h> #include <assert.h> +#include <sys/socket.h> #include <core/SkCanvas.h> #include <core/SkDevice.h> @@ -24,6 +25,7 @@ #include "GraphicsJNI.h" #include "jni.h" +#include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include <utils/misc.h> @@ -78,6 +80,39 @@ static void android_view_ViewRoot_abandonGlCaches(JNIEnv* env, jobject) { SkGLCanvas::AbandonAllTextures(); } +static jintArray android_view_ViewRoot_makeInputChannel(JNIEnv* env, jobject) { + int fd[2]; + jint* arrayData = NULL; + + // Create the pipe + int err = socketpair(AF_LOCAL, SOCK_STREAM, 0, fd); + if (err != 0) { + fprintf(stderr, "socketpair() failed: %d\n", errno); + doThrow(env, "java/lang/RuntimeException", "Unable to create pipe"); + return NULL; + } + + // Set up the return array + jintArray array = env->NewIntArray(2); + if (env->ExceptionCheck()) { + fprintf(stderr, "Exception allocating fd array"); + goto bail; + } + + arrayData = env->GetIntArrayElements(array, 0); + arrayData[0] = fd[0]; + arrayData[1] = fd[1]; + env->ReleaseIntArrayElements(array, arrayData, 0); + + return array; + +bail: + env->DeleteLocalRef(array); + close(fd[0]); + close(fd[1]); + return NULL; +} + // ---------------------------------------------------------------------------- const char* const kClassPathName = "android/view/ViewRoot"; @@ -86,7 +121,9 @@ static JNINativeMethod gMethods[] = { { "nativeShowFPS", "(Landroid/graphics/Canvas;I)V", (void*)android_view_ViewRoot_showFPS }, { "nativeAbandonGlCaches", "()V", - (void*)android_view_ViewRoot_abandonGlCaches } + (void*)android_view_ViewRoot_abandonGlCaches }, + { "makeInputChannel", "()[I", + (void*)android_view_ViewRoot_makeInputChannel } }; int register_android_view_ViewRoot(JNIEnv* env) { diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index 6a8c4b9..01a1504 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -96,7 +96,7 @@ static void nativeClassInit(JNIEnv *_env, jclass eglImplClass) gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I"); jclass surface_class = _env->FindClass("android/view/Surface"); - gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I"); + gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, ANDROID_VIEW_SURFACE_JNI_ID, "I"); jclass bitmap_class = _env->FindClass("android/graphics/Bitmap"); gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I"); |