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