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(FileDescriptor, setInt$, "setInt$", "(I)V", false)                                      \
40   V(NIOAccess, getBaseArray, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;", true) \
41   V(NIOAccess, getBaseArrayOffset, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I", true)      \
42   V(NioBuffer, array, "array", "()Ljava/lang/Object;", false)                               \
43   V(NioBuffer, arrayOffset, "arrayOffset", "()I", false)
44 
45 // jfieldID constants list:
46 //   <Class, field, signature, is_static>
47 #define JFIELDID_CONSTANTS_LIST(V)                                          \
48   V(FileDescriptor, descriptor, "I", false)                                 \
49   V(NioBuffer, _elementSizeShift, "I", false)                               \
50   V(NioBuffer, address, "J", false)                                         \
51   V(NioBuffer, limit, "I", false)                                           \
52   V(NioBuffer, position, "I", false)
53 
54 #define CLASS_NAME(cls)             g_ ## cls
55 #define METHOD_NAME(cls, method)    g_ ## cls ## _ ## method
56 #define FIELD_NAME(cls, field)      g_ ## cls ## _ ## field
57 
58 //
59 // Declare storage for cached classes, methods and fields.
60 //
61 
62 #define JCLASS_DECLARE_STORAGE(cls, ...)                                    \
63   static jclass CLASS_NAME(cls) = NULL;
64 JCLASS_CONSTANTS_LIST(JCLASS_DECLARE_STORAGE)
65 #undef JCLASS_DECLARE_STORAGE
66 
67 #define JMETHODID_DECLARE_STORAGE(cls, method, ...)                         \
68   static jmethodID METHOD_NAME(cls, method) = NULL;
JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE)69 JMETHODID_CONSTANTS_LIST(JMETHODID_DECLARE_STORAGE)
70 #undef JMETHODID_DECLARE_STORAGE
71 
72 #define JFIELDID_DECLARE_STORAGE(cls, field, ...)                           \
73   static jfieldID FIELD_NAME(cls, field) = NULL;
74 JFIELDID_CONSTANTS_LIST(JFIELDID_DECLARE_STORAGE)
75 #undef JFIELDID_DECLARE_STORAGE
76 
77 //
78 // Helper methods
79 //
80 
81 static jclass FindClass(JNIEnv* env, const char* signature, bool androidOnly) {
82     jclass cls = (*env)->FindClass(env, signature);
83     if (cls == NULL) {
84         ALOG_ALWAYS_FATAL_IF(!androidOnly, "Class not found: %s", signature);
85         return NULL;
86     }
87     return (*env)->NewGlobalRef(env, cls);
88 }
89 
FindMethod(JNIEnv * env,jclass cls,const char * name,const char * signature,bool isStatic)90 static jmethodID FindMethod(JNIEnv* env, jclass cls,
91                             const char* name, const char* signature, bool isStatic) {
92     jmethodID method;
93     if (isStatic) {
94         method = (*env)->GetStaticMethodID(env, cls, name, signature);
95     } else {
96         method = (*env)->GetMethodID(env, cls, name, signature);
97     }
98     ALOG_ALWAYS_FATAL_IF(method == NULL, "Method not found: %s:%s", name, signature);
99     return method;
100 }
101 
FindField(JNIEnv * env,jclass cls,const char * name,const char * signature,bool isStatic)102 static jfieldID FindField(JNIEnv* env, jclass cls,
103                           const char* name, const char* signature, bool isStatic) {
104     jfieldID field;
105     if (isStatic) {
106         field = (*env)->GetStaticFieldID(env, cls, name, signature);
107     } else {
108         field = (*env)->GetFieldID(env, cls, name, signature);
109     }
110     ALOG_ALWAYS_FATAL_IF(field == NULL, "Field not found: %s:%s", name, signature);
111     return field;
112 }
113 
114 static pthread_once_t g_initialized = PTHREAD_ONCE_INIT;
115 static JNIEnv* g_init_env;
116 
InitializeConstants()117 static void InitializeConstants() {
118     // Initialize cached classes.
119 #define JCLASS_INITIALIZE(cls, signature, androidOnly)                      \
120     CLASS_NAME(cls) = FindClass(g_init_env, signature, androidOnly);
121     JCLASS_CONSTANTS_LIST(JCLASS_INITIALIZE)
122 #undef JCLASS_INITIALIZE
123 
124     // Initialize cached methods.
125 #define JMETHODID_INITIALIZE(cls, method, name, signature, isStatic)        \
126     METHOD_NAME(cls, method) =                                              \
127         FindMethod(g_init_env, CLASS_NAME(cls), name, signature, isStatic);
128     JMETHODID_CONSTANTS_LIST(JMETHODID_INITIALIZE)
129 #undef JMETHODID_INITIALIZE
130 
131     // Initialize cached fields.
132 #define JFIELDID_INITIALIZE(cls, field, signature, isStatic)                \
133     FIELD_NAME(cls, field) =                                                \
134         FindField(g_init_env, CLASS_NAME(cls), #field, signature, isStatic);
135     JFIELDID_CONSTANTS_LIST(JFIELDID_INITIALIZE)
136 #undef JFIELDID_INITIALIZE
137 }
138 
EnsureInitialized(JNIEnv * env)139 void EnsureInitialized(JNIEnv* env) {
140     // This method has to be called in every cache accesses because library can be built
141     // 2 different ways and existing usage for compat version doesn't have a good hook for
142     // initialization and is widely used.
143     g_init_env = env;
144     pthread_once(&g_initialized, InitializeConstants);
145 }
146 
147 // API exported by libnativehelper_api.h.
148 
jniUninitializeConstants()149 void jniUninitializeConstants() {
150     // Uninitialize cached classes, methods and fields.
151     //
152     // NB we assume the runtime is stopped at this point and do not delete global
153     // references.
154 #define JCLASS_INVALIDATE(cls, ...) CLASS_NAME(cls) = NULL;
155     JCLASS_CONSTANTS_LIST(JCLASS_INVALIDATE);
156 #undef JCLASS_INVALIDATE
157 
158 #define JMETHODID_INVALIDATE(cls, method, ...) METHOD_NAME(cls, method) = NULL;
159     JMETHODID_CONSTANTS_LIST(JMETHODID_INVALIDATE);
160 #undef JMETHODID_INVALIDATE
161 
162 #define JFIELDID_INVALIDATE(cls, field, ...) FIELD_NAME(cls, field) = NULL;
163     JFIELDID_CONSTANTS_LIST(JFIELDID_INVALIDATE);
164 #undef JFIELDID_INVALIDATE
165 
166     // If jniConstantsUninitialize is called, runtime has shutdown. Reset
167     // state as some tests re-start the runtime.
168     pthread_once_t o = PTHREAD_ONCE_INIT;
169     memcpy(&g_initialized, &o, sizeof(o));
170 }
171 
172 //
173 // Accessors
174 //
175 
176 #define JCLASS_ACCESSOR_IMPL(cls, ...)                                      \
177 jclass JniConstants_ ## cls ## Class(JNIEnv* env) {                         \
178     EnsureInitialized(env);                                                 \
179     return CLASS_NAME(cls);                                                 \
180 }
181 JCLASS_CONSTANTS_LIST(JCLASS_ACCESSOR_IMPL)
182 #undef JCLASS_ACCESSOR_IMPL
183 
184 #define JMETHODID_ACCESSOR_IMPL(cls, method, ...)                           \
185 jmethodID JniConstants_ ## cls ## _ ## method(JNIEnv* env) {                \
186     EnsureInitialized(env);                                                 \
187     return METHOD_NAME(cls, method);                                        \
188 }
189 JMETHODID_CONSTANTS_LIST(JMETHODID_ACCESSOR_IMPL)
190 
191 #define JFIELDID_ACCESSOR_IMPL(cls, field, ...)                             \
192 jfieldID JniConstants_ ## cls ## _ ## field(JNIEnv* env) {                  \
193     EnsureInitialized(env);                                                 \
194     return FIELD_NAME(cls, field);                                          \
195 }
196 JFIELDID_CONSTANTS_LIST(JFIELDID_ACCESSOR_IMPL)
197