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