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