1 /*
2 * Copyright (C) 2017 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 "class_linker.h"
18 #include "dex/art_dex_file_loader.h"
19 #include "hidden_api.h"
20 #include "jni.h"
21 #include "runtime.h"
22 #include "scoped_thread_state_change-inl.h"
23 #include "thread.h"
24 #include "ti-agent/scoped_utf_chars.h"
25
26 namespace art {
27 namespace Test674HiddenApi {
28
Java_Main_init(JNIEnv *,jclass)29 extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
30 Runtime* runtime = Runtime::Current();
31 runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
32 runtime->SetDedupeHiddenApiWarnings(false);
33 runtime->AlwaysSetHiddenApiWarningFlag();
34 }
35
Java_Main_appendToBootClassLoader(JNIEnv * env,jclass,jstring jpath)36 extern "C" JNIEXPORT void JNICALL Java_Main_appendToBootClassLoader(
37 JNIEnv* env, jclass, jstring jpath) {
38 ScopedUtfChars utf(env, jpath);
39 const char* path = utf.c_str();
40 if (path == nullptr) {
41 return;
42 }
43
44 ArtDexFileLoader dex_loader;
45 std::string error_msg;
46 std::vector<std::unique_ptr<const DexFile>> dex_files;
47 if (!dex_loader.Open(path,
48 path,
49 /* verify */ false,
50 /* verify_checksum */ true,
51 &error_msg,
52 &dex_files)) {
53 LOG(FATAL) << "Could not open " << path << " for boot classpath extension: " << error_msg;
54 UNREACHABLE();
55 }
56
57 ScopedObjectAccess soa(Thread::Current());
58 for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
59 Runtime::Current()->GetClassLinker()->AppendToBootClassPath(
60 Thread::Current(), *dex_file.release());
61 }
62 }
63
NewInstance(JNIEnv * env,jclass klass)64 static jobject NewInstance(JNIEnv* env, jclass klass) {
65 jmethodID constructor = env->GetMethodID(klass, "<init>", "()V");
66 if (constructor == NULL) {
67 return NULL;
68 }
69 return env->NewObject(klass, constructor);
70 }
71
Java_JNI_canDiscoverField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)72 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverField(
73 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
74 ScopedUtfChars utf_name(env, name);
75 jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
76 : env->GetFieldID(klass, utf_name.c_str(), "I");
77 if (field == NULL) {
78 env->ExceptionClear();
79 return JNI_FALSE;
80 }
81
82 return JNI_TRUE;
83 }
84
Java_JNI_canGetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)85 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canGetField(
86 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
87 ScopedUtfChars utf_name(env, name);
88 jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
89 : env->GetFieldID(klass, utf_name.c_str(), "I");
90 if (field == NULL) {
91 env->ExceptionClear();
92 return JNI_FALSE;
93 }
94 if (is_static) {
95 env->GetStaticIntField(klass, field);
96 } else {
97 jobject obj = NewInstance(env, klass);
98 if (obj == NULL) {
99 env->ExceptionDescribe();
100 env->ExceptionClear();
101 return JNI_FALSE;
102 }
103 env->GetIntField(obj, field);
104 }
105
106 if (env->ExceptionOccurred()) {
107 env->ExceptionDescribe();
108 env->ExceptionClear();
109 return JNI_FALSE;
110 }
111
112 return JNI_TRUE;
113 }
114
Java_JNI_canSetField(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)115 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canSetField(
116 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
117 ScopedUtfChars utf_name(env, name);
118 jfieldID field = is_static ? env->GetStaticFieldID(klass, utf_name.c_str(), "I")
119 : env->GetFieldID(klass, utf_name.c_str(), "I");
120 if (field == NULL) {
121 env->ExceptionClear();
122 return JNI_FALSE;
123 }
124 if (is_static) {
125 env->SetStaticIntField(klass, field, 42);
126 } else {
127 jobject obj = NewInstance(env, klass);
128 if (obj == NULL) {
129 env->ExceptionDescribe();
130 env->ExceptionClear();
131 return JNI_FALSE;
132 }
133 env->SetIntField(obj, field, 42);
134 }
135
136 if (env->ExceptionOccurred()) {
137 env->ExceptionDescribe();
138 env->ExceptionClear();
139 return JNI_FALSE;
140 }
141
142 return JNI_TRUE;
143 }
144
Java_JNI_canDiscoverMethod(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)145 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverMethod(
146 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
147 ScopedUtfChars utf_name(env, name);
148 jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
149 : env->GetMethodID(klass, utf_name.c_str(), "()I");
150 if (method == NULL) {
151 env->ExceptionClear();
152 return JNI_FALSE;
153 }
154
155 return JNI_TRUE;
156 }
157
Java_JNI_canInvokeMethodA(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)158 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodA(
159 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
160 ScopedUtfChars utf_name(env, name);
161 jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
162 : env->GetMethodID(klass, utf_name.c_str(), "()I");
163 if (method == NULL) {
164 env->ExceptionClear();
165 return JNI_FALSE;
166 }
167
168 if (is_static) {
169 env->CallStaticIntMethodA(klass, method, nullptr);
170 } else {
171 jobject obj = NewInstance(env, klass);
172 if (obj == NULL) {
173 env->ExceptionDescribe();
174 env->ExceptionClear();
175 return JNI_FALSE;
176 }
177 env->CallIntMethodA(obj, method, nullptr);
178 }
179
180 if (env->ExceptionOccurred()) {
181 env->ExceptionDescribe();
182 env->ExceptionClear();
183 return JNI_FALSE;
184 }
185
186 return JNI_TRUE;
187 }
188
Java_JNI_canInvokeMethodV(JNIEnv * env,jclass,jclass klass,jstring name,jboolean is_static)189 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeMethodV(
190 JNIEnv* env, jclass, jclass klass, jstring name, jboolean is_static) {
191 ScopedUtfChars utf_name(env, name);
192 jmethodID method = is_static ? env->GetStaticMethodID(klass, utf_name.c_str(), "()I")
193 : env->GetMethodID(klass, utf_name.c_str(), "()I");
194 if (method == NULL) {
195 env->ExceptionClear();
196 return JNI_FALSE;
197 }
198
199 if (is_static) {
200 env->CallStaticIntMethod(klass, method);
201 } else {
202 jobject obj = NewInstance(env, klass);
203 if (obj == NULL) {
204 env->ExceptionDescribe();
205 env->ExceptionClear();
206 return JNI_FALSE;
207 }
208 env->CallIntMethod(obj, method);
209 }
210
211 if (env->ExceptionOccurred()) {
212 env->ExceptionDescribe();
213 env->ExceptionClear();
214 return JNI_FALSE;
215 }
216
217 return JNI_TRUE;
218 }
219
220 static constexpr size_t kConstructorSignatureLength = 5; // e.g. (IZ)V
221 static constexpr size_t kNumConstructorArgs = kConstructorSignatureLength - 3;
222
Java_JNI_canDiscoverConstructor(JNIEnv * env,jclass,jclass klass,jstring args)223 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canDiscoverConstructor(
224 JNIEnv* env, jclass, jclass klass, jstring args) {
225 ScopedUtfChars utf_args(env, args);
226 jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
227 if (constructor == NULL) {
228 env->ExceptionClear();
229 return JNI_FALSE;
230 }
231
232 return JNI_TRUE;
233 }
234
Java_JNI_canInvokeConstructorA(JNIEnv * env,jclass,jclass klass,jstring args)235 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorA(
236 JNIEnv* env, jclass, jclass klass, jstring args) {
237 ScopedUtfChars utf_args(env, args);
238 jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
239 if (constructor == NULL) {
240 env->ExceptionClear();
241 return JNI_FALSE;
242 }
243
244 // CheckJNI won't allow out-of-range values, so just zero everything.
245 CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
246 size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
247 jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
248 memset(initargs, 0, initargs_size);
249
250 env->NewObjectA(klass, constructor, initargs);
251 if (env->ExceptionOccurred()) {
252 env->ExceptionDescribe();
253 env->ExceptionClear();
254 return JNI_FALSE;
255 }
256
257 return JNI_TRUE;
258 }
259
Java_JNI_canInvokeConstructorV(JNIEnv * env,jclass,jclass klass,jstring args)260 extern "C" JNIEXPORT jboolean JNICALL Java_JNI_canInvokeConstructorV(
261 JNIEnv* env, jclass, jclass klass, jstring args) {
262 ScopedUtfChars utf_args(env, args);
263 jmethodID constructor = env->GetMethodID(klass, "<init>", utf_args.c_str());
264 if (constructor == NULL) {
265 env->ExceptionClear();
266 return JNI_FALSE;
267 }
268
269 // CheckJNI won't allow out-of-range values, so just zero everything.
270 CHECK_EQ(strlen(utf_args.c_str()), kConstructorSignatureLength);
271 size_t initargs_size = sizeof(jvalue) * kNumConstructorArgs;
272 jvalue *initargs = reinterpret_cast<jvalue*>(alloca(initargs_size));
273 memset(initargs, 0, initargs_size);
274
275 static_assert(kNumConstructorArgs == 2, "Change the varargs below if you change the constant");
276 env->NewObject(klass, constructor, initargs[0], initargs[1]);
277 if (env->ExceptionOccurred()) {
278 env->ExceptionDescribe();
279 env->ExceptionClear();
280 return JNI_FALSE;
281 }
282
283 return JNI_TRUE;
284 }
285
Java_Reflection_getHiddenApiAccessFlags(JNIEnv *,jclass)286 extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) {
287 return static_cast<jint>(kAccHiddenApiBits);
288 }
289
Java_ChildClass_hasPendingWarning(JNIEnv *,jclass)290 extern "C" JNIEXPORT jboolean JNICALL Java_ChildClass_hasPendingWarning(JNIEnv*, jclass) {
291 return Runtime::Current()->HasPendingHiddenApiWarning();
292 }
293
Java_ChildClass_clearWarning(JNIEnv *,jclass)294 extern "C" JNIEXPORT void JNICALL Java_ChildClass_clearWarning(JNIEnv*, jclass) {
295 Runtime::Current()->SetPendingHiddenApiWarning(false);
296 }
297
298 } // namespace Test674HiddenApi
299 } // namespace art
300