/* * 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. */ #include "JniConstants.h" #include #include #include #include #define LOG_TAG "JniConstants" #include "ALog-priv.h" // jclass constants list: // #define JCLASS_CONSTANTS_LIST(V) \ V(FileDescriptor, "java/io/FileDescriptor", false) \ V(NIOAccess, "java/nio/NIOAccess", true) \ V(NioBuffer, "java/nio/Buffer", false) // jmethodID's of public methods constants list: // #define JMETHODID_CONSTANTS_LIST(V) \ V(FileDescriptor, init, "", "()V", false) \ V(NIOAccess, getBaseArray, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;", true) \ V(NIOAccess, getBaseArrayOffset, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I", true) \ V(NioBuffer, array, "array", "()Ljava/lang/Object;", false) \ V(NioBuffer, arrayOffset, "arrayOffset", "()I", false) // jfieldID constants list: // #define JFIELDID_CONSTANTS_LIST(V) \ V(FileDescriptor, descriptor, "I", false) \ V(NioBuffer, _elementSizeShift, "I", false) \ V(NioBuffer, address, "J", false) \ V(NioBuffer, limit, "I", false) \ V(NioBuffer, position, "I", false) #define CLASS_NAME(cls) g_ ## cls #define METHOD_NAME(cls, method) g_ ## cls ## _ ## method #define FIELD_NAME(cls, field) g_ ## cls ## _ ## field // // Declare storage for cached classes, methods and fields. // #define JCLASS_DECLARE_STORAGE(cls, ...) \ static jclass CLASS_NAME(cls) = NULL; JCLASS_CONSTANTS_LIST(JCLASS_DECLARE_STORAGE) #undef JCLASS_DECLARE_STORAGE #define JMETHODID_DECLARE_STORAGE(cls, method, ...) \ static jmethodID METHOD_NAME(cls, method) = NULL; JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE) #undef JMETHODID_DECLARE_STORAGE #define JFIELDID_DECLARE_STORAGE(cls, field, ...) \ static jfieldID FIELD_NAME(cls, field) = NULL; JFIELDID_CONSTANTS_LIST(JFIELDID_DECLARE_STORAGE) #undef JFIELDID_DECLARE_STORAGE // // Helper methods // static jclass FindClass(JNIEnv* env, const char* signature, bool androidOnly) { jclass cls = (*env)->FindClass(env, signature); if (cls == NULL) { ALOG_ALWAYS_FATAL_IF(!androidOnly, "Class not found: %s", signature); return NULL; } return (*env)->NewGlobalRef(env, cls); } static jmethodID FindMethod(JNIEnv* env, jclass cls, const char* name, const char* signature, bool isStatic) { jmethodID method; if (isStatic) { method = (*env)->GetStaticMethodID(env, cls, name, signature); } else { method = (*env)->GetMethodID(env, cls, name, signature); } ALOG_ALWAYS_FATAL_IF(method == NULL, "Method not found: %s:%s", name, signature); return method; } static jfieldID FindField(JNIEnv* env, jclass cls, const char* name, const char* signature, bool isStatic) { jfieldID field; if (isStatic) { field = (*env)->GetStaticFieldID(env, cls, name, signature); } else { field = (*env)->GetFieldID(env, cls, name, signature); } ALOG_ALWAYS_FATAL_IF(field == NULL, "Field not found: %s:%s", name, signature); return field; } static pthread_once_t g_initialized = PTHREAD_ONCE_INIT; static JNIEnv* g_init_env; static void InitializeConstants() { // Initialize cached classes. #define JCLASS_INITIALIZE(cls, signature, androidOnly) \ CLASS_NAME(cls) = FindClass(g_init_env, signature, androidOnly); JCLASS_CONSTANTS_LIST(JCLASS_INITIALIZE) #undef JCLASS_INITIALIZE // Initialize cached methods. #define JMETHODID_INITIALIZE(cls, method, name, signature, isStatic) \ METHOD_NAME(cls, method) = \ FindMethod(g_init_env, CLASS_NAME(cls), name, signature, isStatic); JMETHODID_CONSTANTS_LIST(JMETHODID_INITIALIZE) #undef JMETHODID_INITIALIZE // Initialize cached fields. #define JFIELDID_INITIALIZE(cls, field, signature, isStatic) \ FIELD_NAME(cls, field) = \ FindField(g_init_env, CLASS_NAME(cls), #field, signature, isStatic); JFIELDID_CONSTANTS_LIST(JFIELDID_INITIALIZE) #undef JFIELDID_INITIALIZE } void EnsureInitialized(JNIEnv* env) { // This method has to be called in every cache accesses because library can be built // 2 different ways and existing usage for compat version doesn't have a good hook for // initialization and is widely used. g_init_env = env; pthread_once(&g_initialized, InitializeConstants); } // API exported by libnativehelper_api.h. void jniUninitializeConstants() { // Uninitialize cached classes, methods and fields. // // NB we assume the runtime is stopped at this point and do not delete global // references. #define JCLASS_INVALIDATE(cls, ...) CLASS_NAME(cls) = NULL; JCLASS_CONSTANTS_LIST(JCLASS_INVALIDATE); #undef JCLASS_INVALIDATE #define JMETHODID_INVALIDATE(cls, method, ...) METHOD_NAME(cls, method) = NULL; JMETHODID_CONSTANTS_LIST(JMETHODID_INVALIDATE); #undef JMETHODID_INVALIDATE #define JFIELDID_INVALIDATE(cls, field, ...) FIELD_NAME(cls, field) = NULL; JFIELDID_CONSTANTS_LIST(JFIELDID_INVALIDATE); #undef JFIELDID_INVALIDATE // If jniConstantsUninitialize is called, runtime has shutdown. Reset // state as some tests re-start the runtime. pthread_once_t o = PTHREAD_ONCE_INIT; memcpy(&g_initialized, &o, sizeof(o)); } // // Accessors // #define JCLASS_ACCESSOR_IMPL(cls, ...) \ jclass JniConstants_ ## cls ## Class(JNIEnv* env) { \ EnsureInitialized(env); \ return CLASS_NAME(cls); \ } JCLASS_CONSTANTS_LIST(JCLASS_ACCESSOR_IMPL) #undef JCLASS_ACCESSOR_IMPL #define JMETHODID_ACCESSOR_IMPL(cls, method, ...) \ jmethodID JniConstants_ ## cls ## _ ## method(JNIEnv* env) { \ EnsureInitialized(env); \ return METHOD_NAME(cls, method); \ } JMETHODID_CONSTANTS_LIST(JMETHODID_ACCESSOR_IMPL) #define JFIELDID_ACCESSOR_IMPL(cls, field, ...) \ jfieldID JniConstants_ ## cls ## _ ## field(JNIEnv* env) { \ EnsureInitialized(env); \ return FIELD_NAME(cls, field); \ } JFIELDID_CONSTANTS_LIST(JFIELDID_ACCESSOR_IMPL)