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