Home | History | Annotate | Download | only in 674-hiddenapi
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    286 extern "C" JNIEXPORT jint JNICALL Java_Reflection_getHiddenApiAccessFlags(JNIEnv*, jclass) {
    287   return static_cast<jint>(kAccHiddenApiBits);
    288 }
    289 
    290 extern "C" JNIEXPORT jboolean JNICALL Java_ChildClass_hasPendingWarning(JNIEnv*, jclass) {
    291   return Runtime::Current()->HasPendingHiddenApiWarning();
    292 }
    293 
    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