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 26namespace art { 27namespace Test674HiddenApi { 28 29extern "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 36extern "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 64static 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 72extern "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 85extern "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 115extern "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 145extern "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 158extern "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 189extern "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 220static constexpr size_t kConstructorSignatureLength = 5; // e.g. (IZ)V 221static constexpr size_t kNumConstructorArgs = kConstructorSignatureLength - 3; 222 223extern "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 235extern "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 260extern "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 286extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) { 287 return static_cast<jint>(kAccHiddenApiBits); 288} 289 290extern "C" JNIEXPORT jboolean JNICALL Java_ChildClass_hasPendingWarning(JNIEnv*, jclass) { 291 return Runtime::Current()->HasPendingHiddenApiWarning(); 292} 293 294extern "C" JNIEXPORT void JNICALL Java_ChildClass_clearWarning(JNIEnv*, jclass) { 295 Runtime::Current()->SetPendingHiddenApiWarning(false); 296} 297 298} // namespace Test674HiddenApi 299} // namespace art 300