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