• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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