Skip to content

Commit 30043e2

Browse files
committed
Avoid resolving libart symbols twice
LSPlt is only used to hook libart symbols. The file `native_util.h` is reformatted by clangd. Fallback to Dobby if LSPlt fails.
1 parent 1730700 commit 30043e2

File tree

5 files changed

+73
-81
lines changed

5 files changed

+73
-81
lines changed

core/src/main/jni/include/native_util.h

+59-69
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,30 @@
1919
*/
2020

2121
#include <dlfcn.h>
22-
#include "lsplt.hpp"
2322
#include <sys/mman.h>
23+
24+
#include "elf_util.h"
25+
#include "lsplt.hpp"
26+
#include "symbol_cache.h"
2427
#pragma clang diagnostic push
2528
#pragma clang diagnostic ignored "-Wunused-value"
2629
#pragma once
2730

2831
#include <context.h>
29-
#include "utils/jni_helper.hpp"
30-
#include "logging.h"
31-
#include "config.h"
32+
3233
#include <cassert>
34+
35+
#include "../src/native_api.h"
36+
#include "config.h"
3337
#include "config_bridge.h"
38+
#include "logging.h"
39+
#include "utils/jni_helper.hpp"
3440

3541
namespace lspd {
3642

3743
[[gnu::always_inline]]
38-
inline bool RegisterNativeMethodsInternal(JNIEnv *env,
39-
std::string_view class_name,
40-
const JNINativeMethod *methods,
41-
jint method_count) {
42-
44+
inline bool RegisterNativeMethodsInternal(JNIEnv *env, std::string_view class_name,
45+
const JNINativeMethod *methods, jint method_count) {
4346
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name.data());
4447
if (clazz.get() == nullptr) {
4548
LOGF("Couldn't find class: {}", class_name.data());
@@ -49,83 +52,70 @@ inline bool RegisterNativeMethodsInternal(JNIEnv *env,
4952
}
5053

5154
#if defined(__cplusplus)
52-
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \
53-
reinterpret_cast<to>
55+
#define _NATIVEHELPER_JNI_MACRO_CAST(to) reinterpret_cast<to>
5456
#else
55-
#define _NATIVEHELPER_JNI_MACRO_CAST(to) \
56-
(to)
57+
#define _NATIVEHELPER_JNI_MACRO_CAST(to) (to)
5758
#endif
5859

5960
#ifndef LSP_NATIVE_METHOD
60-
#define LSP_NATIVE_METHOD(className, functionName, signature) \
61-
{ #functionName, \
62-
signature, \
63-
_NATIVEHELPER_JNI_MACRO_CAST(void*) (Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName) \
64-
}
61+
#define LSP_NATIVE_METHOD(className, functionName, signature) \
62+
{#functionName, signature, \
63+
_NATIVEHELPER_JNI_MACRO_CAST(void *)( \
64+
Java_org_lsposed_lspd_nativebridge_##className##_##functionName)}
6565
#endif
6666

67-
#define JNI_START [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz
67+
#define JNI_START [[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass clazz
6868

6969
#ifndef LSP_DEF_NATIVE_METHOD
70-
#define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \
71-
extern "C" ret Java_org_lsposed_lspd_nativebridge_## className ## _ ## functionName (JNI_START, ## __VA_ARGS__)
70+
#define LSP_DEF_NATIVE_METHOD(ret, className, functionName, ...) \
71+
extern "C" ret Java_org_lsposed_lspd_nativebridge_##className##_##functionName(JNI_START, \
72+
##__VA_ARGS__)
7273
#endif
7374

74-
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
75-
RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, arraysize(gMethods))
76-
77-
static std::vector<std::tuple<dev_t, ino_t, const char *, void **>> plt_hook_list = {};
78-
static auto scan_maps = lsplt::MapInfo::Scan();
79-
80-
inline int plt_hook(const char *lib, const char *symbol, void *callback, void **backup) {
81-
dev_t dev = 0;
82-
ino_t inode = 0;
83-
for (auto map : scan_maps) {
84-
if (map.path == lib) {
85-
inode = map.inode;
86-
dev = map.dev;
87-
break;
75+
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
76+
RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, \
77+
arraysize(gMethods))
78+
79+
static dev_t dev = 0;
80+
static ino_t inode = 0;
81+
static std::vector<std::pair<std::string_view, void **>> plt_hook_saved = {};
82+
83+
inline int HookArtFunction(void *original, void *callback, void **backup, bool save = true) {
84+
auto symbol = *reinterpret_cast<std::string_view *>(original);
85+
if (dev == 0 || inode == 0) {
86+
auto libart_path = GetArt()->name();
87+
for (auto map : lsplt::MapInfo::Scan()) {
88+
if (map.path == libart_path) {
89+
inode = map.inode;
90+
dev = map.dev;
91+
break;
92+
}
8893
}
8994
}
9095

9196
auto result = lsplt::RegisterHook(dev, inode, symbol, callback, backup) && lsplt::CommitHook();
92-
if (result) {
93-
plt_hook_list.emplace_back(dev, inode, symbol, backup);
94-
return 0;
97+
if (result && *backup != nullptr) {
98+
if (save) plt_hook_saved.emplace_back(symbol, backup);
99+
} else if (auto addr = GetArt()->getSymbAddress(symbol); addr) {
100+
Dl_info info;
101+
if (dladdr(addr, &info) && info.dli_sname != nullptr && info.dli_sname == symbol)
102+
HookFunction(addr, callback, backup);
103+
} else if (*backup == nullptr && isDebug) {
104+
LOGW("Failed to {} Art symbol {}", save ? "hook" : "unhook", symbol);
95105
}
96-
return 1;
106+
return *backup == nullptr;
97107
}
98108

99-
inline int HookFunction(void *original, void *replace, void **backup) {
100-
Dl_info info;
101-
if (dladdr(original, &info)) {
102-
if constexpr (isDebug) {
103-
LOGD("Hooking {} ({}) from {} ({})",
104-
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
105-
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
106-
}
107-
if (info.dli_sname != NULL && info.dli_fname != NULL)
108-
return plt_hook(info.dli_fname, info.dli_sname, replace, backup);
109-
}
110-
return 1;
111-
}
112-
113-
inline int UnhookFunction(void *original) {
114-
Dl_info info;
115-
if (dladdr(original, &info)) {
116-
if constexpr (isDebug) {
117-
LOGD("Unhooking {} ({}) from {} ({})",
118-
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
119-
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
120-
}
109+
inline int UnhookArtFunction(void *original) {
110+
std::string_view func_name = *reinterpret_cast<std::string_view *>(original);
111+
auto hook_iter = std::find_if(plt_hook_saved.begin(), plt_hook_saved.end(),
112+
[func_name](auto record) { return record.first == func_name; });
121113

122-
for (const auto [dev, inode, symbol, backup] : plt_hook_list) {
123-
if (info.dli_sname == symbol) {
124-
auto result = lsplt::RegisterHook(dev, inode, symbol, backup, nullptr)
125-
&& lsplt::CommitHook();
126-
return 1 - result;
127-
}
128-
}
114+
void *stub = nullptr;
115+
if (hook_iter != plt_hook_saved.end() &&
116+
HookArtFunction(original, *(hook_iter->second), &stub, false)) {
117+
plt_hook_saved.erase(hook_iter);
118+
return 0;
129119
}
130120
return 1;
131121
}
@@ -136,6 +126,6 @@ inline std::string GetNativeBridgeSignature() {
136126
return signature;
137127
}
138128

139-
} // namespace lspd
129+
} // namespace lspd
140130

141131
#pragma clang diagnostic pop

core/src/main/jni/src/native_api.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ namespace lspd {
5858
const auto[entries] = []() {
5959
auto *entries = new(protected_page.get()) NativeAPIEntries{
6060
.version = 2,
61-
.hookFunc = &DobbyHookFunction,
62-
.unhookFunc = &DobbyUnhookFunction,
61+
.hookFunc = &HookFunction,
62+
.unhookFunc = &UnhookFunction,
6363
};
6464

6565
mprotect(protected_page.get(), 4096, PROT_READ);
@@ -71,7 +71,7 @@ namespace lspd {
7171
return InstallNativeAPI({
7272
.inline_hooker = [](auto t, auto r) {
7373
void* bk = nullptr;
74-
return DobbyHookFunction(t, r, &bk) == 0 ? bk : nullptr;
74+
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
7575
},
7676
});
7777
}();

core/src/main/jni/src/native_api.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,25 @@ namespace lspd {
5252

5353
void RegisterNativeLib(const std::string &library_name);
5454

55-
inline int DobbyHookFunction(void *original, void *replace, void **backup) {
55+
inline int HookFunction(void *original, void *replace, void **backup) {
5656
if constexpr (isDebug) {
5757
Dl_info info;
5858
if (dladdr(original, &info))
5959
LOGD("Dobby hooking {} ({}) from {} ({})",
60-
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
60+
info.dli_sname ? info.dli_sname : "(unknown symbol)",
61+
info.dli_saddr ? info.dli_saddr : original,
6162
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
6263
}
6364
return DobbyHook(original, reinterpret_cast<dobby_dummy_func_t>(replace), reinterpret_cast<dobby_dummy_func_t *>(backup));
6465
}
6566

66-
inline int DobbyUnhookFunction(void *original) {
67+
inline int UnhookFunction(void *original) {
6768
if constexpr (isDebug) {
6869
Dl_info info;
6970
if (dladdr(original, &info))
7071
LOGD("Dobby unhooking {} ({}) from {} ({})",
71-
info.dli_sname ? info.dli_sname : "(unknown symbol)", info.dli_saddr,
72+
info.dli_sname ? info.dli_sname : "(unknown symbol)",
73+
info.dli_saddr ? info.dli_saddr : original,
7274
info.dli_fname ? info.dli_fname : "(unknown file)", info.dli_fbase);
7375
}
7476
return DobbyDestroy(original);

magisk-loader/src/main/jni/src/magisk_loader.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ namespace lspd {
119119
lsplant::InitInfo initInfo{
120120
.inline_hooker = [](auto t, auto r) {
121121
void* bk = nullptr;
122-
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
122+
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
123123
},
124124
.inline_unhooker = [](auto t) {
125-
return UnhookFunction(t) == 0 ;
125+
return UnhookArtFunction(t) == 0 ;
126126
},
127127
.art_symbol_resolver = [](auto symbol) {
128128
return GetArt()->getSymbAddress(symbol);
@@ -198,10 +198,10 @@ namespace lspd {
198198
lsplant::InitInfo initInfo{
199199
.inline_hooker = [](auto t, auto r) {
200200
void* bk = nullptr;
201-
return HookFunction(t, r, &bk) == 0 ? bk : nullptr;
201+
return HookArtFunction(t, r, &bk) == 0 ? bk : nullptr;
202202
},
203203
.inline_unhooker = [](auto t) {
204-
return UnhookFunction(t) == 0;
204+
return UnhookArtFunction(t) == 0;
205205
},
206206
.art_symbol_resolver = [](auto symbol){
207207
return GetArt()->getSymbAddress(symbol);

0 commit comments

Comments
 (0)