1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "JniConstants.h"
18
19 #include <pthread.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <string.h>
23
24 #define LOG_TAG "JniConstants"
25 #include "ALog-priv.h"
26
27 // jclass constants list:
28 // <class, signature, androidOnly>
29
30 #define JCLASS_CONSTANTS_LIST(V) \
31 V(FileDescriptor, "java/io/FileDescriptor", false) \
32 V(NIOAccess, "java/nio/NIOAccess", true) \
33 V(NioBuffer, "java/nio/Buffer", false)
34
35 // jmethodID's of public methods constants list:
36 // <Class, method, method-string, signature, is_static>
37 #define JMETHODID_CONSTANTS_LIST(V) \
38 V(FileDescriptor, init, "<init>", "()V", false) \
39 V(NIOAccess, getBaseArray, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;", true) \
40 V(NIOAccess, getBaseArrayOffset, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I", true) \
41 V(NioBuffer, array, "array", "()Ljava/lang/Object;", false) \
42 V(NioBuffer, arrayOffset, "arrayOffset", "()I", false)
43
44 // jfieldID constants list:
45 // <Class, field, signature, is_static>
46 #define JFIELDID_CONSTANTS_LIST(V) \
47 V(FileDescriptor, descriptor, "I", false) \
48 V(NioBuffer, _elementSizeShift, "I", false) \
49 V(NioBuffer, address, "J", false) \
50 V(NioBuffer, limit, "I", false) \
51 V(NioBuffer, position, "I", false)
52
53 #define CLASS_NAME(cls) g_ ## cls
54 #define METHOD_NAME(cls, method) g_ ## cls ## _ ## method
55 #define FIELD_NAME(cls, field) g_ ## cls ## _ ## field
56
57 //
58 // Declare storage for cached classes, methods and fields.
59 //
60
61 #define JCLASS_DECLARE_STORAGE(cls, ...) \
62 static jclass CLASS_NAME(cls) = NULL;
63 JCLASS_CONSTANTS_LIST(JCLASS_DECLARE_STORAGE)
64 #undef JCLASS_DECLARE_STORAGE
65
66 #define JMETHODID_DECLARE_STORAGE(cls, method, ...) \
67 static jmethodID METHOD_NAME(cls, method) = NULL;
JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE)68 JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE)
69 #undef JMETHODID_DECLARE_STORAGE
70
71 #define JFIELDID_DECLARE_STORAGE(cls, field, ...) \
72 static jfieldID FIELD_NAME(cls, field) = NULL;
73 JFIELDID_CONSTANTS_LIST(JFIELDID_DECLARE_STORAGE)
74 #undef JFIELDID_DECLARE_STORAGE
75
76 //
77 // Helper methods
78 //
79
80 static jclass FindClass(JNIEnv* env, const char* signature, bool androidOnly) {
81 jclass cls = (*env)->FindClass(env, signature);
82 if (cls == NULL) {
83 ALOG_ALWAYS_FATAL_IF(!androidOnly, "Class not found: %s", signature);
84 return NULL;
85 }
86 return (*env)->NewGlobalRef(env, cls);
87 }
88
FindMethod(JNIEnv * env,jclass cls,const char * name,const char * signature,bool isStatic)89 static jmethodID FindMethod(JNIEnv* env, jclass cls,
90 const char* name, const char* signature, bool isStatic) {
91 jmethodID method;
92 if (isStatic) {
93 method = (*env)->GetStaticMethodID(env, cls, name, signature);
94 } else {
95 method = (*env)->GetMethodID(env, cls, name, signature);
96 }
97 ALOG_ALWAYS_FATAL_IF(method == NULL, "Method not found: %s:%s", name, signature);
98 return method;
99 }
100
FindField(JNIEnv * env,jclass cls,const char * name,const char * signature,bool isStatic)101 static jfieldID FindField(JNIEnv* env, jclass cls,
102 const char* name, const char* signature, bool isStatic) {
103 jfieldID field;
104 if (isStatic) {
105 field = (*env)->GetStaticFieldID(env, cls, name, signature);
106 } else {
107 field = (*env)->GetFieldID(env, cls, name, signature);
108 }
109 ALOG_ALWAYS_FATAL_IF(field == NULL, "Field not found: %s:%s", name, signature);
110 return field;
111 }
112
113 static pthread_once_t g_initialized = PTHREAD_ONCE_INIT;
114 static JNIEnv* g_init_env;
115
InitializeConstants()116 static void InitializeConstants() {
117 // Initialize cached classes.
118 #define JCLASS_INITIALIZE(cls, signature, androidOnly) \
119 CLASS_NAME(cls) = FindClass(g_init_env, signature, androidOnly);
120 JCLASS_CONSTANTS_LIST(JCLASS_INITIALIZE)
121 #undef JCLASS_INITIALIZE
122
123 // Initialize cached methods.
124 #define JMETHODID_INITIALIZE(cls, method, name, signature, isStatic) \
125 METHOD_NAME(cls, method) = \
126 FindMethod(g_init_env, CLASS_NAME(cls), name, signature, isStatic);
127 JMETHODID_CONSTANTS_LIST(JMETHODID_INITIALIZE)
128 #undef JMETHODID_INITIALIZE
129
130 // Initialize cached fields.
131 #define JFIELDID_INITIALIZE(cls, field, signature, isStatic) \
132 FIELD_NAME(cls, field) = \
133 FindField(g_init_env, CLASS_NAME(cls), #field, signature, isStatic);
134 JFIELDID_CONSTANTS_LIST(JFIELDID_INITIALIZE)
135 #undef JFIELDID_INITIALIZE
136 }
137
EnsureInitialized(JNIEnv * env)138 void EnsureInitialized(JNIEnv* env) {
139 // This method has to be called in every cache accesses because library can be built
140 // 2 different ways and existing usage for compat version doesn't have a good hook for
141 // initialization and is widely used.
142 g_init_env = env;
143 pthread_once(&g_initialized, InitializeConstants);
144 }
145
146 // API exported by libnativehelper_api.h.
147
jniUninitializeConstants()148 void jniUninitializeConstants() {
149 // Uninitialize cached classes, methods and fields.
150 //
151 // NB we assume the runtime is stopped at this point and do not delete global
152 // references.
153 #define JCLASS_INVALIDATE(cls, ...) CLASS_NAME(cls) = NULL;
154 JCLASS_CONSTANTS_LIST(JCLASS_INVALIDATE);
155 #undef JCLASS_INVALIDATE
156
157 #define JMETHODID_INVALIDATE(cls, method, ...) METHOD_NAME(cls, method) = NULL;
158 JMETHODID_CONSTANTS_LIST(JMETHODID_INVALIDATE);
159 #undef JMETHODID_INVALIDATE
160
161 #define JFIELDID_INVALIDATE(cls, field, ...) FIELD_NAME(cls, field) = NULL;
162 JFIELDID_CONSTANTS_LIST(JFIELDID_INVALIDATE);
163 #undef JFIELDID_INVALIDATE
164
165 // If jniConstantsUninitialize is called, runtime has shutdown. Reset
166 // state as some tests re-start the runtime.
167 pthread_once_t o = PTHREAD_ONCE_INIT;
168 memcpy(&g_initialized, &o, sizeof(o));
169 }
170
171 //
172 // Accessors
173 //
174
175 #define JCLASS_ACCESSOR_IMPL(cls, ...) \
176 jclass JniConstants_ ## cls ## Class(JNIEnv* env) { \
177 EnsureInitialized(env); \
178 return CLASS_NAME(cls); \
179 }
180 JCLASS_CONSTANTS_LIST(JCLASS_ACCESSOR_IMPL)
181 #undef JCLASS_ACCESSOR_IMPL
182
183 #define JMETHODID_ACCESSOR_IMPL(cls, method, ...) \
184 jmethodID JniConstants_ ## cls ## _ ## method(JNIEnv* env) { \
185 EnsureInitialized(env); \
186 return METHOD_NAME(cls, method); \
187 }
188 JMETHODID_CONSTANTS_LIST(JMETHODID_ACCESSOR_IMPL)
189
190 #define JFIELDID_ACCESSOR_IMPL(cls, field, ...) \
191 jfieldID JniConstants_ ## cls ## _ ## field(JNIEnv* env) { \
192 EnsureInitialized(env); \
193 return FIELD_NAME(cls, field); \
194 }
195 JFIELDID_CONSTANTS_LIST(JFIELDID_ACCESSOR_IMPL)
196