Skip to content
This repository has been archived by the owner on Aug 15, 2018. It is now read-only.

Commit

Permalink
After enabling Xposed
Browse files Browse the repository at this point in the history
  • Loading branch information
Ali Reza Barkhordari committed Jul 17, 2017
1 parent 2110f97 commit 1d14337
Show file tree
Hide file tree
Showing 19 changed files with 331 additions and 56 deletions.
9 changes: 9 additions & 0 deletions compiler/driver/compiler_driver-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
ArtField* resolved_field, uint16_t field_idx) {
DCHECK(!resolved_field->IsStatic());
mirror::Class* fields_class = resolved_field->GetDeclaringClass();
// Keep these classes in sync with prepareSubclassReplacement() calls in libxposed-art.
mirror::Class* super_class = fields_class->GetSuperClass();
while (super_class != nullptr) {
if (super_class->DescriptorEquals("Landroid/content/res/TypedArray;")) {
VLOG(compiler) << "Preventing fast access to " << PrettyField(resolved_field);
return std::make_pair(false, false);
}
super_class = super_class->GetSuperClass();
}
bool fast_get = referrer_class != nullptr &&
referrer_class->CanAccessResolvedField(fields_class, resolved_field,
dex_cache, field_idx);
Expand Down
3 changes: 2 additions & 1 deletion compiler/driver/compiler_driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1647,7 +1647,8 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType
gc::Heap* const heap = runtime->GetHeap();
auto* cl = runtime->GetClassLinker();
const auto pointer_size = cl->GetImagePointerSize();
bool use_dex_cache = GetCompilerOptions().GetCompilePic(); // Off by default
//bool use_dex_cache = GetCompilerOptions().GetCompilePic(); // Off by default
bool use_dex_cache = true;
const bool compiling_boot = heap->IsCompilingBoot();
// TODO This is somewhat hacky. We should refactor all of this invoke codepath.
const bool force_relocations = (compiling_boot ||
Expand Down
4 changes: 1 addition & 3 deletions compiler/optimizing/optimizing_compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,7 @@ static void MaybeRunInliner(HGraph* graph,
const DexCompilationUnit& dex_compilation_unit,
PassObserver* pass_observer,
StackHandleScopeCollection* handles) {
const CompilerOptions& compiler_options = driver->GetCompilerOptions();
bool should_inline = (compiler_options.GetInlineDepthLimit() > 0)
&& (compiler_options.GetInlineMaxCodeUnits() > 0);
bool should_inline = false;
if (!should_inline) {
return;
}
Expand Down
42 changes: 24 additions & 18 deletions runtime/art_method-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,21 +280,21 @@ inline const char* ArtMethod::GetDeclaringClassDescriptor() {
if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
return "<runtime method>";
}
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
}

inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
}

inline const Signature ArtMethod::GetSignature() {
uint32_t dex_method_idx = GetDexMethodIndex();
if (dex_method_idx != DexFile::kDexNoIndex) {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
}
Expand All @@ -304,7 +304,7 @@ inline const Signature ArtMethod::GetSignature() {
inline const char* ArtMethod::GetName() {
uint32_t dex_method_idx = GetDexMethodIndex();
if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
}
Expand All @@ -325,11 +325,14 @@ inline const char* ArtMethod::GetName() {
}

inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
if (UNLIKELY(IsXposedHookedMethod())) {
return nullptr;
}
return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
}

inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx, size_t ptr_size) {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
return GetDexCacheResolvedType(type_idx, ptr_size) != nullptr;
}

Expand All @@ -342,13 +345,13 @@ inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
}

inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
return dex_file->GetMethodPrototype(dex_file->GetMethodId(GetDexMethodIndex()));
}

inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
dex_file->GetMethodId(GetDexMethodIndex()));
Expand All @@ -361,17 +364,17 @@ inline const char* ArtMethod::GetDeclaringClassSourceFile() {
}

inline uint16_t ArtMethod::GetClassDefIndex() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
return GetDeclaringClass()->GetDexClassDefIndex();
}

inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
return GetDexFile()->GetClassDef(GetClassDefIndex());
}

inline const char* ArtMethod::GetReturnTypeDescriptor() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
Expand All @@ -380,27 +383,27 @@ inline const char* ArtMethod::GetReturnTypeDescriptor() {
}

inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
}

inline mirror::ClassLoader* ArtMethod::GetClassLoader() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
return GetDeclaringClass()->GetClassLoader();
}

inline mirror::DexCache* ArtMethod::GetDexCache() {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
return GetDeclaringClass()->GetDexCache();
}

inline bool ArtMethod::IsProxyMethod() {
return GetDeclaringClass()->IsProxyClass();
inline bool ArtMethod::IsProxyMethod(bool ignore_xposed) {
return GetDeclaringClass()->IsProxyClass() || (!ignore_xposed && IsXposedHookedMethod());
}

inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(size_t pointer_size) {
if (LIKELY(!IsProxyMethod())) {
if (LIKELY(!IsProxyMethod(true))) {
return this;
}
mirror::Class* klass = GetDeclaringClass();
Expand All @@ -425,7 +428,7 @@ inline void ArtMethod::SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_c
}

inline mirror::Class* ArtMethod::GetReturnType(bool resolve, size_t ptr_size) {
DCHECK(!IsProxyMethod());
DCHECK(!IsProxyMethod(true));
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
Expand Down Expand Up @@ -455,6 +458,9 @@ void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) {
Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
interface_method->VisitRoots(visitor, pointer_size);
}
if (UNLIKELY(IsXposedHookedMethod())) {

This comment has been minimized.

Copy link
@abforce

abforce Jul 17, 2017

Owner

VisitRoots completely changed from M to N, so this method could be the source of the problem

GetXposedOriginalMethod()->VisitRoots(visitor, pointer_size);
}
visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
// We know we don't have profiling information if the class hasn't been verified. Note
// that this check also ensures the IsNative call can be made, as IsNative expects a fully
Expand All @@ -463,7 +469,7 @@ void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) {
// Runtime methods and native methods use the same field as the profiling info for
// storing their own data (jni entrypoint for native methods, and ImtConflictTable for
// some runtime methods).
if (!IsNative() && !IsRuntimeMethod()) {
if (!IsNative() && !IsRuntimeMethod() && !IsXposedHookedMethod()) {

This comment has been minimized.

Copy link
@abforce

abforce Jul 17, 2017

Owner

Completely uncertain about this method. && !IsXposedHookedMethod() seems to need to be here, since hooked methods may not be native but their backup_method may be.

This comment has been minimized.

Copy link
@rovo89

rovo89 Jul 20, 2017

See the comment above this line. The same field that is mentioned is not only used for the JNI entrypoint and the IMT conflict table, but also for Xposed's hooking information. So a hooked method can't have profiling info, hence the check is needed here.

My implementation of this method is effectively the same, I just moved it around a bit.

ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size);
if (profiling_info != nullptr) {
profiling_info->VisitRoots(visitor);
Expand Down
102 changes: 98 additions & 4 deletions runtime/art_method.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@
#include "jni_internal.h"
#include "mirror/abstract_method.h"
#include "mirror/class-inl.h"
#include "mirror/method.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "oat_file-inl.h"
#include "scoped_thread_state_change.h"
#include "thread_list.h"
#include "well_known_classes.h"

namespace art {
Expand All @@ -47,6 +49,9 @@ extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*,
extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
const char*);

jclass ArtMethod::xposed_callback_class = nullptr;
jmethodID ArtMethod::xposed_callback_method = nullptr;

ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
jobject jlr_method) {
auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(jlr_method);
Expand All @@ -55,7 +60,7 @@ ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnabl
}

mirror::String* ArtMethod::GetNameAsString(Thread* self) {
CHECK(!IsProxyMethod());
CHECK(!IsProxyMethod(true));
StackHandleScope<1> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
auto* dex_file = dex_cache->GetDexFile();
Expand Down Expand Up @@ -134,7 +139,7 @@ ArtMethod* ArtMethod::FindOverriddenMethod(size_t pointer_size) {
result = super_class->GetVTableEntry(method_index, pointer_size);
} else {
// Method didn't override superclass method so search interfaces
if (IsProxyMethod()) {
if (IsProxyMethod(true)) {
result = mirror::DexCache::GetElementPtrSize(GetDexCacheResolvedMethods(pointer_size),
GetDexMethodIndex(),
pointer_size);
Expand Down Expand Up @@ -313,6 +318,10 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue*
}

void ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
if (UNLIKELY(IsXposedHookedMethod())) {
GetXposedOriginalMethod()->RegisterNative(native_method, is_fast);
return;
}
CHECK(IsNative()) << PrettyMethod(this);
CHECK(!IsFastNative()) << PrettyMethod(this);
CHECK(native_method != nullptr) << PrettyMethod(this);
Expand All @@ -323,6 +332,10 @@ void ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
}

void ArtMethod::UnregisterNative() {
if (UNLIKELY(IsXposedHookedMethod())) {
GetXposedOriginalMethod()->UnregisterNative();
return;
}
CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this);
// restore stub to lookup native pointer via dlsym
RegisterNative(GetJniDlsymLookupStub(), false);
Expand Down Expand Up @@ -388,7 +401,7 @@ const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
}

if (existing_entry_point == GetQuickProxyInvokeHandler()) {
DCHECK(IsProxyMethod() && !IsConstructor());
DCHECK(IsProxyMethod(true) && !IsConstructor());
// The proxy entry point does not have any method header.
return nullptr;
}
Expand Down Expand Up @@ -418,7 +431,7 @@ const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
<< ", pc=" << std::hex << pc
<< ", entry_point=" << std::hex << reinterpret_cast<uintptr_t>(existing_entry_point)
<< ", copy=" << std::boolalpha << IsCopied()
<< ", proxy=" << std::boolalpha << IsProxyMethod();
<< ", proxy=" << std::boolalpha << IsProxyMethod(true);
}
}

Expand Down Expand Up @@ -497,4 +510,85 @@ void ArtMethod::CopyFrom(ArtMethod* src, size_t image_pointer_size) {
hotness_count_ = 0;
}

static void StackReplaceMethod(Thread* thread, void* arg) SHARED_REQUIRES(Locks::mutator_lock_) {
struct StackReplaceMethodVisitor FINAL : public StackVisitor {
StackReplaceMethodVisitor(Thread* thread_in, ArtMethod* search, ArtMethod* replace)
: StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kSkipInlinedFrames),
search_(search), replace_(replace) {};

bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
if (GetMethod() == search_) {
SetMethod(replace_);
}
return true;
}

ArtMethod* search_;
ArtMethod* replace_;
};

ArtMethod* search = reinterpret_cast<ArtMethod*>(arg);

// We cannot use GetXposedOriginalMethod() because the access flags aren't modified yet.
auto hook_info = reinterpret_cast<const XposedHookInfo*>(search->GetEntryPointFromJni());
ArtMethod* replace = hook_info->originalMethod;

StackReplaceMethodVisitor visitor(thread, search, replace);
visitor.WalkStack();
}

void ArtMethod::EnableXposedHook(ScopedObjectAccess& soa, jobject additional_info) {
if (UNLIKELY(IsXposedHookedMethod())) {
// Already hooked
return;
} else if (UNLIKELY(IsXposedOriginalMethod())) {
// This should never happen
ThrowIllegalArgumentException(StringPrintf("Cannot hook the method backup: %s", PrettyMethod(this).c_str()).c_str());
return;
}

// Create a backup of the ArtMethod object
auto cl = Runtime::Current()->GetClassLinker();
//auto allocator = GetClassLoader()->GetAllocator(); SIGSEGV
auto allocator = Runtime::Current()->GetLinearAlloc();
const size_t method_alignment = ArtMethod::Alignment(cl->GetImagePointerSize());
const size_t method_size = ArtMethod::Size(cl->GetImagePointerSize());
LengthPrefixedArray<ArtMethod>* method_array = cl->AllocArtMethodArray(Thread::Current(), allocator, 1);
ArtMethod* backup_method = &method_array->At(0, method_size, method_alignment);
backup_method->CopyFrom(this, cl->GetImagePointerSize());
backup_method->SetAccessFlags(backup_method->GetAccessFlags() | kAccXposedOriginalMethod);

// Create a Method/Constructor object for the backup ArtMethod object
mirror::AbstractMethod* reflect_method;
if (IsConstructor()) {
reflect_method = mirror::Constructor::CreateFromArtMethod(soa.Self(), backup_method);
} else {
reflect_method = mirror::Method::CreateFromArtMethod(soa.Self(), backup_method);
}
reflect_method->SetAccessible<false>(true);

// Save extra information in a separate structure, stored instead of the native method
XposedHookInfo* hookInfo = reinterpret_cast<XposedHookInfo*>(calloc(1, sizeof(XposedHookInfo)));
hookInfo->reflectedMethod = soa.Vm()->AddGlobalRef(soa.Self(), reflect_method);
hookInfo->additionalInfo = soa.Env()->NewGlobalRef(additional_info);
hookInfo->originalMethod = backup_method;
SetEntryPointFromJni(reinterpret_cast<uint8_t*>(hookInfo));

ThreadList* tl = Runtime::Current()->GetThreadList();
soa.Self()->TransitionFromRunnableToSuspended(kSuspended);
tl->SuspendAll("Hooking method");
{
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
tl->ForEach(StackReplaceMethod, this);
}
tl->ResumeAll();
soa.Self()->TransitionFromSuspendedToRunnable();

SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
//SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);

// Adjust access flags
SetAccessFlags((GetAccessFlags() & ~kAccNative & ~kAccSynchronized) | kAccXposedHookedMethod);
}

} // namespace art
Loading

0 comments on commit 1d14337

Please sign in to comment.