189 lines
6.6 KiB
C++
Raw Normal View History

#pragma once
#include "art/runtime/art_method.hpp"
#include "art/runtime/handle.hpp"
#include "common.hpp"
namespace lsplant::art {
class Thread;
namespace dex {
class ClassDef {};
} // namespace dex
namespace mirror {
class Class {
private:
CREATE_MEM_FUNC_SYMBOL_ENTRY(const char *, GetDescriptor, Class *thiz, std::string *storage) {
if (GetDescriptorSym) [[likely]]
return GetDescriptorSym(thiz, storage);
else
return "";
}
CREATE_MEM_FUNC_SYMBOL_ENTRY(const dex::ClassDef *, GetClassDef, Class *thiz) {
if (GetClassDefSym) [[likely]]
return GetClassDefSym(thiz);
return nullptr;
}
using BackupMethods = std::list<std::tuple<art::ArtMethod *, void *>>;
2023-10-04 23:53:48 +08:00
inline static phmap::flat_hash_map<const art::Thread *,
phmap::flat_hash_map<const dex::ClassDef *, BackupMethods>>
backup_methods_;
inline static std::mutex backup_methods_lock_;
static void BackupClassMethods(const dex::ClassDef *class_def, art::Thread *self) {
std::list<std::tuple<art::ArtMethod *, void *>> out;
if (!class_def) return;
{
2023-10-04 23:53:48 +08:00
hooked_classes_.if_contains(class_def, [&out](const auto &it) {
for (auto method : it.second) {
if (method->IsStatic()) {
LOGV("Backup hooked method %p because of initialization", method);
out.emplace_back(method, method->GetEntryPoint());
}
}
2023-10-04 23:53:48 +08:00
});
}
{
2023-10-04 23:53:48 +08:00
deoptimized_classes_.if_contains(class_def, [&out](const auto &it) {
for (auto method : it.second) {
if (method->IsStatic()) {
LOGV("Backup deoptimized method %p because of initialization", method);
out.emplace_back(method, method->GetEntryPoint());
}
}
2023-10-04 23:53:48 +08:00
});
}
2022-10-29 14:18:12 +08:00
if (!out.empty()) [[unlikely]] {
std::unique_lock lk(backup_methods_lock_);
backup_methods_[self].emplace(class_def, std::move(out));
}
}
CREATE_HOOK_STUB_ENTRY(
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS_11ClassStatusEPNS_6ThreadE", void,
2022-10-29 07:21:17 +08:00
SetClassStatus, (TrivialHandle<Class> h, uint8_t new_status, Thread *self), {
if (new_status == initialized_status) {
BackupClassMethods(h->GetClassDef(), self);
}
return backup(h, new_status, self);
});
CREATE_HOOK_STUB_ENTRY(
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE", void, SetStatus,
(Handle<Class> h, int new_status, Thread *self), {
if (new_status == static_cast<int>(initialized_status)) {
BackupClassMethods(h->GetClassDef(), self);
}
return backup(h, new_status, self);
});
2022-10-29 07:21:17 +08:00
CREATE_HOOK_STUB_ENTRY(
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE", void,
TrivialSetStatus, (TrivialHandle<Class> h, uint32_t new_status, Thread *self), {
if (new_status == initialized_status) {
BackupClassMethods(h->GetClassDef(), self);
}
return backup(h, new_status, self);
});
CREATE_MEM_HOOK_STUB_ENTRY("_ZN3art6mirror5Class9SetStatusENS1_6StatusEPNS_6ThreadE", void,
ClassSetStatus, (Class * thiz, int new_status, Thread *self), {
if (new_status == static_cast<int>(initialized_status)) {
BackupClassMethods(thiz->GetClassDef(), self);
}
return backup(thiz, new_status, self);
});
inline static uint8_t initialized_status = 0;
public:
static bool Init(const HookHandler &handler) {
if (!RETRIEVE_MEM_FUNC_SYMBOL(GetDescriptor,
"_ZN3art6mirror5Class13GetDescriptorEPNSt3__112"
"basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE")) {
return false;
}
if (!RETRIEVE_MEM_FUNC_SYMBOL(GetClassDef, "_ZN3art6mirror5Class11GetClassDefEv")) {
return false;
}
2022-10-29 07:21:17 +08:00
int sdk_int = GetAndroidApiLevel();
if (sdk_int < __ANDROID_API_O__) {
if (!HookSyms(handler, SetStatus, ClassSetStatus)) {
return false;
}
} else {
if (!HookSyms(handler, SetClassStatus, TrivialSetStatus)) {
return false;
}
}
2022-10-29 05:43:02 +08:00
if (sdk_int >= __ANDROID_API_R__) {
initialized_status = 15;
2022-10-29 05:43:02 +08:00
} else if (sdk_int >= __ANDROID_API_P__) {
initialized_status = 14;
} else if (sdk_int == __ANDROID_API_O_MR1__) {
initialized_status = 11;
} else {
initialized_status = 10;
}
return true;
}
const char *GetDescriptor(std::string *storage) {
if (GetDescriptorSym) {
return GetDescriptor(this, storage);
}
return "";
}
std::string GetDescriptor() {
std::string storage;
return GetDescriptor(&storage);
}
const dex::ClassDef *GetClassDef() {
if (GetClassDefSym) return GetClassDef(this);
return nullptr;
}
static auto PopBackup(const dex::ClassDef *class_def, art::Thread *self) {
BackupMethods methods;
if (!backup_methods_.size()) [[likely]] {
return methods;
}
if (class_def) {
std::unique_lock lk(backup_methods_lock_);
for (auto it = backup_methods_.begin(); it != backup_methods_.end();) {
if (auto found = it->second.find(class_def); found != it->second.end()) {
methods.merge(std::move(found->second));
it->second.erase(found);
}
if (it->second.empty()) {
backup_methods_.erase(it++);
} else {
it++;
}
}
2022-10-29 05:43:02 +08:00
} else if (self) {
std::unique_lock lk(backup_methods_lock_);
if (auto found = backup_methods_.find(self); found != backup_methods_.end()) {
for (auto it = found->second.begin(); it != found->second.end();) {
methods.merge(std::move(it->second));
found->second.erase(it++);
}
backup_methods_.erase(found);
}
}
return methods;
}
};
} // namespace mirror
} // namespace lsplant::art