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