mirror of
https://github.com/LSPosed/LSPlant.git
synced 2025-05-04 20:42:02 +08:00
Use phmap
This commit is contained in:
parent
7a6940e722
commit
c18f276177
@ -2,9 +2,9 @@ plugins {
|
||||
alias(libs.plugins.lsplugin.publish)
|
||||
}
|
||||
|
||||
val androidTargetSdkVersion by extra(33)
|
||||
val androidTargetSdkVersion by extra(34)
|
||||
val androidMinSdkVersion by extra(21)
|
||||
val androidBuildToolsVersion by extra("33.0.2")
|
||||
val androidCompileSdkVersion by extra(33)
|
||||
val androidNdkVersion by extra("25.2.9519653")
|
||||
val androidBuildToolsVersion by extra("34.0.0")
|
||||
val androidCompileSdkVersion by extra(34)
|
||||
val androidNdkVersion by extra("26.0.10792818")
|
||||
val androidCmakeVersion by extra("3.22.1+")
|
||||
|
@ -28,8 +28,8 @@ private:
|
||||
}
|
||||
|
||||
using BackupMethods = std::list<std::tuple<art::ArtMethod *, void *>>;
|
||||
inline static absl::flat_hash_map<const art::Thread *,
|
||||
absl::flat_hash_map<const dex::ClassDef *, BackupMethods>>
|
||||
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_;
|
||||
|
||||
@ -37,28 +37,24 @@ private:
|
||||
std::list<std::tuple<art::ArtMethod *, void *>> out;
|
||||
if (!class_def) return;
|
||||
{
|
||||
std::shared_lock lk(hooked_classes_lock_);
|
||||
if (auto found = hooked_classes_.find(class_def); found != hooked_classes_.end())
|
||||
[[unlikely]] {
|
||||
for (auto method : found->second) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
std::shared_lock lk(deoptimized_methods_lock_);
|
||||
if (auto found = deoptimized_classes_.find(class_def);
|
||||
found != deoptimized_classes_.end()) [[unlikely]] {
|
||||
for (auto method : found->second) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!out.empty()) [[unlikely]] {
|
||||
std::unique_lock lk(backup_methods_lock_);
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <absl/container/flat_hash_set.h>
|
||||
#include <parallel_hashmap/phmap.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include <list>
|
||||
@ -104,44 +103,47 @@ class Class;
|
||||
|
||||
namespace {
|
||||
// target, backup
|
||||
inline absl::flat_hash_map<art::ArtMethod *, std::pair<jobject, art::ArtMethod *>> hooked_methods_;
|
||||
inline std::shared_mutex hooked_methods_lock_;
|
||||
template <class K, class V, class Hash = phmap::priv::hash_default_hash<K>,
|
||||
class Eq = phmap::priv::hash_default_eq<K>,
|
||||
class Alloc = phmap::priv::Allocator<phmap::priv::Pair<const K, V>>, size_t N = 4>
|
||||
using SharedHashMap = phmap::parallel_flat_hash_map<K, V, Hash, Eq, Alloc, N, std::shared_mutex>;
|
||||
|
||||
inline absl::flat_hash_map<const art::dex::ClassDef *, absl::flat_hash_set<art::ArtMethod *>>
|
||||
template <class T, class Hash = phmap::priv::hash_default_hash<T>,
|
||||
class Eq = phmap::priv::hash_default_eq<T>, class Alloc = phmap::priv::Allocator<T>,
|
||||
size_t N = 4>
|
||||
using SharedHashSet = phmap::parallel_flat_hash_set<T, Hash, Eq, Alloc, N, std::shared_mutex>;
|
||||
|
||||
inline SharedHashMap<art::ArtMethod *, std::pair<jobject, art::ArtMethod *>> hooked_methods_;
|
||||
|
||||
inline SharedHashMap<const art::dex::ClassDef *, phmap::flat_hash_set<art::ArtMethod *>>
|
||||
hooked_classes_;
|
||||
inline std::shared_mutex hooked_classes_lock_;
|
||||
|
||||
inline absl::flat_hash_set<art::ArtMethod *> deoptimized_methods_set_;
|
||||
inline std::shared_mutex deoptimized_methods_lock_;
|
||||
inline SharedHashSet<art::ArtMethod *> deoptimized_methods_set_;
|
||||
|
||||
inline absl::flat_hash_map<const art::dex::ClassDef *, absl::flat_hash_set<art::ArtMethod *>>
|
||||
inline SharedHashMap<const art::dex::ClassDef *, phmap::flat_hash_set<art::ArtMethod *>>
|
||||
deoptimized_classes_;
|
||||
inline std::shared_mutex deoptimized_classes_lock_;
|
||||
|
||||
inline std::list<std::pair<art::ArtMethod *, art::ArtMethod *>> jit_movements_;
|
||||
inline std::shared_mutex jit_movements_lock_;
|
||||
} // namespace
|
||||
|
||||
inline art::ArtMethod *IsHooked(art::ArtMethod *art_method, bool including_backup = false) {
|
||||
std::shared_lock lk(hooked_methods_lock_);
|
||||
if (auto it = hooked_methods_.find(art_method);
|
||||
it != hooked_methods_.end() && (!including_backup || it->second.first)) {
|
||||
return it->second.second;
|
||||
}
|
||||
return nullptr;
|
||||
art::ArtMethod *backup = nullptr;
|
||||
hooked_methods_.if_contains(art_method, [&backup, &including_backup](const auto &it) {
|
||||
if (!including_backup || it.second.first) backup = it.second.second;
|
||||
});
|
||||
return backup;
|
||||
}
|
||||
|
||||
inline art::ArtMethod *IsBackup(art::ArtMethod *art_method) {
|
||||
std::shared_lock lk(hooked_methods_lock_);
|
||||
if (auto it = hooked_methods_.find(art_method);
|
||||
it != hooked_methods_.end() && !it->second.first) {
|
||||
return it->second.second;
|
||||
}
|
||||
art::ArtMethod *backup = nullptr;
|
||||
hooked_methods_.if_contains(art_method, [&backup](const auto &it) {
|
||||
if (!it.second.first) backup = it.second.second;
|
||||
});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool IsDeoptimized(art::ArtMethod *art_method) {
|
||||
std::shared_lock lk(deoptimized_methods_lock_);
|
||||
return deoptimized_methods_set_.contains(art_method);
|
||||
}
|
||||
|
||||
@ -152,26 +154,18 @@ inline std::list<std::pair<art::ArtMethod *, art::ArtMethod *>> GetJitMovements(
|
||||
|
||||
inline void RecordHooked(art::ArtMethod *target, const art::dex::ClassDef *class_def,
|
||||
jobject reflected_backup, art::ArtMethod *backup) {
|
||||
{
|
||||
std::unique_lock lk(hooked_classes_lock_);
|
||||
hooked_classes_[class_def].emplace(target);
|
||||
}
|
||||
{
|
||||
std::unique_lock lk(hooked_methods_lock_);
|
||||
hooked_methods_[target] = {reflected_backup, backup};
|
||||
hooked_methods_[backup] = {nullptr, target};
|
||||
}
|
||||
hooked_classes_.lazy_emplace_l(
|
||||
class_def, [&target](auto &it) { it.second.emplace(target); },
|
||||
[&class_def, &target](const auto &ctor) {
|
||||
ctor(class_def, phmap::flat_hash_set<art::ArtMethod *>{target});
|
||||
});
|
||||
hooked_methods_.insert({std::make_pair(target, std::make_pair(reflected_backup, backup)),
|
||||
std::make_pair(backup, std::make_pair(nullptr, target))});
|
||||
}
|
||||
|
||||
inline void RecordDeoptimized(const art::dex::ClassDef *class_def, art::ArtMethod *art_method) {
|
||||
{
|
||||
std::unique_lock lk(deoptimized_classes_lock_);
|
||||
deoptimized_classes_[class_def].emplace(art_method);
|
||||
}
|
||||
{
|
||||
std::unique_lock lk(deoptimized_methods_lock_);
|
||||
deoptimized_methods_set_.insert(art_method);
|
||||
}
|
||||
{ deoptimized_classes_[class_def].emplace(art_method); }
|
||||
deoptimized_methods_set_.insert(art_method);
|
||||
}
|
||||
|
||||
inline void RecordJitMovement(art::ArtMethod *target, art::ArtMethod *backup) {
|
||||
|
2
lsplant/src/main/jni/external/dex_builder
vendored
2
lsplant/src/main/jni/external/dex_builder
vendored
@ -1 +1 @@
|
||||
Subproject commit 60251dde8d7dcb49b2a6249a0214437836cc8991
|
||||
Subproject commit b5a00f2ea94ad4c3b92054fd53896dbb429298f9
|
@ -158,7 +158,8 @@ bool InitJNI(JNIEnv *env) {
|
||||
return false;
|
||||
}
|
||||
if (method_get_return_type =
|
||||
JNI_GetMethodID(env, JNI_FindClass(env, "java/lang/reflect/Method"), "getReturnType", "()Ljava/lang/Class;");
|
||||
JNI_GetMethodID(env, JNI_FindClass(env, "java/lang/reflect/Method"), "getReturnType",
|
||||
"()Ljava/lang/Class;");
|
||||
!method_get_return_type) {
|
||||
LOGE("Failed to find getReturnType method");
|
||||
return false;
|
||||
@ -620,7 +621,7 @@ struct JavaDebuggableGuard {
|
||||
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
|
||||
std::memory_order_acquire)) {
|
||||
Runtime::Current()->SetJavaDebuggable(
|
||||
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
|
||||
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
|
||||
count.fetch_add(1, std::memory_order_release);
|
||||
count.notify_all();
|
||||
break;
|
||||
@ -642,7 +643,7 @@ struct JavaDebuggableGuard {
|
||||
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
|
||||
std::memory_order_acquire)) {
|
||||
Runtime::Current()->SetJavaDebuggable(
|
||||
Runtime::RuntimeDebugState::kNonJavaDebuggable);
|
||||
Runtime::RuntimeDebugState::kNonJavaDebuggable);
|
||||
count.fetch_sub(1, std::memory_order_release);
|
||||
count.notify_all();
|
||||
break;
|
||||
@ -776,28 +777,19 @@ using ::lsplant::IsHooked;
|
||||
auto *target = ArtMethod::FromReflectedMethod(env, target_method);
|
||||
jobject reflected_backup = nullptr;
|
||||
art::ArtMethod *backup = nullptr;
|
||||
{
|
||||
std::unique_lock lk(hooked_methods_lock_);
|
||||
if (auto it = hooked_methods_.find(target); it != hooked_methods_.end()) [[likely]] {
|
||||
std::tie(reflected_backup, backup) = it->second;
|
||||
if (reflected_backup == nullptr) {
|
||||
LOGE("Unable to unhook a method that is not hooked");
|
||||
return false;
|
||||
}
|
||||
hooked_methods_.erase(it->second.second);
|
||||
hooked_methods_.erase(it);
|
||||
}
|
||||
}
|
||||
{
|
||||
std::unique_lock lk(hooked_classes_lock_);
|
||||
if (auto it = hooked_classes_.find(target->GetDeclaringClass()->GetClassDef());
|
||||
it != hooked_classes_.end()) {
|
||||
it->second.erase(target);
|
||||
if (it->second.empty()) {
|
||||
hooked_classes_.erase(it);
|
||||
}
|
||||
}
|
||||
if (!hooked_methods_.erase_if(target, [&reflected_backup, &backup](const auto &it) {
|
||||
std::tie(reflected_backup, backup) = it.second;
|
||||
return reflected_backup != nullptr;
|
||||
})) {
|
||||
LOGE("Unable to unhook a method that is not hooked");
|
||||
return false;
|
||||
}
|
||||
// FIXME: not atomic, but should be fine
|
||||
hooked_methods_.erase(backup);
|
||||
hooked_classes_.erase_if(target->GetDeclaringClass()->GetClassDef(), [&target](auto &it) {
|
||||
it.second.erase(target);
|
||||
return it.second.empty();
|
||||
});
|
||||
auto *backup_method = env->FromReflectedMethod(reflected_backup);
|
||||
env->DeleteGlobalRef(reflected_backup);
|
||||
if (DoUnHook(target, backup)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user