Skip to content

Commit

Permalink
Detect special devics (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
canyie committed Feb 13, 2021
1 parent 2f9961b commit b572c74
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 20 deletions.
32 changes: 31 additions & 1 deletion core/src/main/cpp/art/art_method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ void* ArtMethod::art_interpreter_to_compiled_code_bridge = nullptr;
void* ArtMethod::art_interpreter_to_interpreter_bridge = nullptr;

void (*ArtMethod::copy_from)(ArtMethod*, ArtMethod*, size_t) = nullptr;
void (*ArtMethod::throw_invocation_time_error)(ArtMethod*) = nullptr;

Member<ArtMethod, uint32_t> ArtMethod::access_flags_;
Member<ArtMethod, void*> ArtMethod::entry_point_from_jni_;
Expand Down Expand Up @@ -67,6 +68,10 @@ void ArtMethod::Init(const ElfImg* handle) {
if (symbol_copy_from)
copy_from = reinterpret_cast<void (*)(ArtMethod*, ArtMethod*, size_t)>(
handle->GetSymbolAddress(symbol_copy_from));

if (Android::version == Android::kO)
throw_invocation_time_error = reinterpret_cast<void (*)(ArtMethod*)>(handle->GetSymbolAddress(
"_ZN3art9ArtMethod24ThrowInvocationTimeErrorEv"));
}

ArtMethod* ArtMethod::FromReflectedMethod(JNIEnv* env, jobject javaMethod) {
Expand Down Expand Up @@ -95,7 +100,7 @@ static inline size_t Difference(intptr_t a, intptr_t b) {
return static_cast<size_t>(size);
}

void ArtMethod::InitMembers(ArtMethod* m1, ArtMethod* m2, uint32_t access_flags) {
void ArtMethod::InitMembers(JNIEnv* env, ArtMethod* m1, ArtMethod* m2, ArtMethod* m3, uint32_t access_flags) {
if (Android::version >= Android::kN) {
kAccCompileDontBother = (Android::version >= Android::kOMr1)
? AccessFlags::kCompileDontBother_O_MR1
Expand Down Expand Up @@ -193,6 +198,15 @@ void ArtMethod::InitMembers(ArtMethod* m1, ArtMethod* m2, uint32_t access_flags)
// FIXME This offset has not been verified, so it may be wrong
entry_point_from_interpreter_ = new Member<ArtMethod, void*>(36);
}

if (UNLIKELY(Android::version == Android::kO)) {
// See https://github.com/canyie/pine/issues/8
if (UNLIKELY(m3->TestDontCompile(env))) {
LOGW("Detected android 8.1 runtime on android 8.0 device");
LOGW("For more info, see https://github.com/canyie/pine/issues/8");
kAccCompileDontBother = AccessFlags::kCompileDontBother_O_MR1;
}
}
}

void ArtMethod::BackupFrom(ArtMethod* source, void* entry, bool is_inline_hook, bool is_native_or_proxy) {
Expand Down Expand Up @@ -279,3 +293,19 @@ void ArtMethod::AfterHook(bool is_inline_hook, bool is_native_or_proxy) {
}
}

bool ArtMethod::TestDontCompile(JNIEnv* env) {
// ThrowInvocationTimeError() has a DCHECK(IsAbstract()), so we should use abstract method to test it.
// assert(IsAbstract());
jclass AbstractMethodError = env->FindClass("java/lang/AbstractMethodError");
uint32_t access_flags = GetAccessFlags();
SetAccessFlags(access_flags | AccessFlags::kCompileDontBother_N);
throw_invocation_time_error(this);
SetAccessFlags(access_flags);
jthrowable exception = env->ExceptionOccurred();
env->ExceptionClear();
bool special = exception != nullptr && !env->IsInstanceOf(exception, AbstractMethodError);
env->DeleteLocalRef(AbstractMethodError);
env->DeleteLocalRef(exception);
return special;
}

7 changes: 5 additions & 2 deletions core/src/main/cpp/art/art_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace pine::art {
public:
static void Init(const ElfImg* handle);

static void InitMembers(ArtMethod* m1, ArtMethod* m2, uint32_t access_flags);
static void InitMembers(JNIEnv* env, ArtMethod* m1, ArtMethod* m2, ArtMethod* m3, uint32_t access_flags);

static ArtMethod* FromReflectedMethod(JNIEnv* env, jobject javaMethod);

Expand Down Expand Up @@ -54,7 +54,7 @@ namespace pine::art {
}

jmethodID ToMethodID() {
return reinterpret_cast<jmethodID> (this);
return reinterpret_cast<jmethodID>(this);
}

// Only works on android 7.0+
Expand Down Expand Up @@ -299,6 +299,8 @@ namespace pine::art {
}
}

bool TestDontCompile(JNIEnv* env);

void* GetInterpreterBridge() {
return UNLIKELY(IsNative()) ? art_quick_generic_jni_trampoline
: art_quick_to_interpreter_bridge;
Expand All @@ -313,6 +315,7 @@ namespace pine::art {
static void* art_interpreter_to_compiled_code_bridge;

static void (*copy_from)(ArtMethod*, ArtMethod*, size_t);
static void (*throw_invocation_time_error)(ArtMethod*);

static Member<ArtMethod, uint32_t> access_flags_;
static Member<ArtMethod, void*> entry_point_from_compiled_code_;
Expand Down
35 changes: 18 additions & 17 deletions core/src/main/cpp/pine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,26 @@ void Pine_init0(JNIEnv* env, jclass Pine, jint androidVersion, jboolean debug, j
if (androidVersion >= Android::kQ) {
expected_access_flags |= AccessFlags::kPublicApi;
}
art::ArtMethod::InitMembers(m1, m2, expected_access_flags);
}

if (UNLIKELY(!art::ArtMethod::GetQuickToInterpreterBridge())) {
// This is a workaround for art_quick_to_interpreter_bridge not found.
// This case is almost impossible to enter
// because its symbols are found almost always on all devices.
// But if it happened... Try to get it with an abstract method (it is not compilable
// and its entry is art_quick_to_interpreter_bridge)
// Note: We DO NOT use platform's abstract methods
// because their entry may not be interpreter entry.

LOGE("art_quick_to_interpreter_bridge not found, try workaround");

ScopedLocalClassRef I(env, "top/canyie/pine/Ruler$I");
auto m = art::ArtMethod::Require(env, I.Get(), "m", "()V", false);
void* entry = m->GetEntryPointFromCompiledCode();
LOGE("New art_quick_to_interpreter_bridge %p", entry);
art::ArtMethod::SetQuickToInterpreterBridge(entry);
auto abstract_method = art::ArtMethod::Require(env, I.Get(), "m", "()V", false);
art::ArtMethod::InitMembers(env, m1, m2, abstract_method, expected_access_flags);

if (UNLIKELY(!art::ArtMethod::GetQuickToInterpreterBridge())) {
// This is a workaround for art_quick_to_interpreter_bridge not found.
// This case is almost impossible to enter
// because its symbols are found almost always on all devices.
// But if it happened... Try to get it with an abstract method (it is not compilable
// and its entry is art_quick_to_interpreter_bridge)
// Note: We DO NOT use platform's abstract methods
// because their entry may not be interpreter entry.

LOGE("art_quick_to_interpreter_bridge not found, try workaround");

void* entry = abstract_method->GetEntryPointFromCompiledCode();
LOGE("New art_quick_to_interpreter_bridge %p", entry);
art::ArtMethod::SetQuickToInterpreterBridge(entry);
}
}

env->SetStaticIntField(Pine, env->GetStaticFieldID(Pine, "arch", "I"), kCurrentArch);
Expand Down

0 comments on commit b572c74

Please sign in to comment.