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