Skip to content

Commit 32d68b2

Browse files
committed
bump dexkit to 2.2.0
1 parent 63439c8 commit 32d68b2

7 files changed

Lines changed: 246 additions & 83 deletions

File tree

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ miuix = "1.0.12.5"
2020
# Xposed & Hooks
2121
xposed-api = "101.0.0"
2222
xposed-service = "101.0.0"
23-
dexkit = "2.1.0"
23+
dexkit = "2.2.0"
2424
ezxhelper = "3.1.1-rc1"
2525
hiddenapibypass = "6.1"
2626

library/common/src/main/java/com/sevtinge/hyperceiler/common/utils/PrefsBridge.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,17 @@ private static String wrap(String key) {
127127
return (key != null && !key.startsWith("prefs_key_")) ? "prefs_key_" + key : key;
128128
}
129129

130+
private static int parseStringInt(@Nullable String value, int def) {
131+
if (TextUtils.isEmpty(value)) {
132+
return def;
133+
}
134+
try {
135+
return Integer.parseInt(value);
136+
} catch (NumberFormatException ignored) {
137+
return def;
138+
}
139+
}
140+
130141
// --- 写入方法族 ---
131142
// 约定:所有写入都应由应用进程发起,再同步到远程。
132143

@@ -239,14 +250,7 @@ public static String getString(String key, String def) {
239250
*/
240251
public static int getStringAsInt(String key, int def) {
241252
String value = getString(key, String.valueOf(def));
242-
if (TextUtils.isEmpty(value)) {
243-
return def;
244-
}
245-
try {
246-
return Integer.parseInt(value);
247-
} catch (NumberFormatException ignored) {
248-
return def;
249-
}
253+
return parseStringInt(value, def);
250254
}
251255

252256
/**
@@ -255,7 +259,26 @@ public static int getStringAsInt(String key, int def) {
255259
public static int getInt(String key, int def) {
256260
String rKey = wrap(key);
257261
Object cached = sHookCache.get(rKey);
258-
return cached instanceof Integer ? (Integer) cached : requireImpl().getInt(rKey, def);
262+
if (cached instanceof Integer intValue) {
263+
return intValue;
264+
}
265+
if (cached instanceof Number numberValue) {
266+
return numberValue.intValue();
267+
}
268+
if (cached instanceof String stringValue) {
269+
return parseStringInt(stringValue, def);
270+
}
271+
272+
SharedPreferences prefs = requireImpl();
273+
try {
274+
return prefs.getInt(rKey, def);
275+
} catch (ClassCastException ignored) {
276+
try {
277+
return parseStringInt(prefs.getString(rKey, null), def);
278+
} catch (ClassCastException ignoredAgain) {
279+
return def;
280+
}
281+
}
259282
}
260283

261284
/**

library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/base/BaseHook.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ protected boolean useDexKit() {
117117
* return true;
118118
* }
119119
* }</pre>
120+
* <p>
121+
* 框架会在 {@link BaseLoad} 中自动把一批 Hook 的 {@link #initDexKit()} 并行执行。
120122
*
121123
* @return true 表示继续执行 {@link #init()};false 表示跳过当前 Hook。
122124
*/

library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/base/BaseLoad.java

Lines changed: 105 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,18 @@
2121
import com.sevtinge.hyperceiler.common.log.XposedLog;
2222
import com.sevtinge.hyperceiler.common.utils.api.ProjectApi;
2323
import com.sevtinge.hyperceiler.libhook.utils.api.ContextUtils;
24+
import com.sevtinge.hyperceiler.libhook.utils.api.ThreadPoolManager;
2425
import com.sevtinge.hyperceiler.libhook.utils.hookapi.dexkit.DexKit;
2526
import com.sevtinge.hyperceiler.libhook.utils.hookapi.tool.EzxHelpUtils;
2627
import com.sevtinge.hyperceiler.libhook.utils.hookapi.tool.ResourcesTool;
2728

2829
import java.io.PrintWriter;
2930
import java.io.StringWriter;
31+
import java.util.ArrayList;
32+
import java.util.List;
3033
import java.util.Objects;
34+
import java.util.concurrent.ExecutionException;
35+
import java.util.concurrent.Future;
3136
import java.util.function.BooleanSupplier;
3237

3338
import io.github.libxposed.api.XposedInterface;
@@ -54,6 +59,10 @@ public abstract class BaseLoad {
5459
private static volatile String sCurrentHookTag = "BaseLoad";
5560
public static ResourcesTool mResHook;
5661
private boolean mDexKitSessionPrepared = false;
62+
private final List<BaseHook> mPendingDexKitHooks = new ArrayList<>();
63+
64+
private record DexKitInitResult(BaseHook hook, boolean shouldInit, Throwable error) {
65+
}
5766

5867
/**
5968
* 初始化 Xposed 运行时入口。
@@ -121,6 +130,7 @@ public void onLoad(PackageReadyParam lpparam) {
121130
sCurrentHookTag = this.getClass().getSimpleName();
122131
mResHook = ResourcesTool.getInstance(getXposed().getModuleApplicationInfo().sourceDir);
123132
mDexKitSessionPrepared = false;
133+
mPendingDexKitHooks.clear();
124134
}
125135

126136
loadModuleResources();
@@ -141,6 +151,7 @@ public void onLoad(SystemServerStartingParam lpparam) {
141151
sCurrentHookTag = this.getClass().getSimpleName();
142152
mResHook = ResourcesTool.getInstance(getXposed().getModuleApplicationInfo().sourceDir);
143153
mDexKitSessionPrepared = false;
154+
mPendingDexKitHooks.clear();
144155
}
145156

146157
loadModuleResources();
@@ -167,7 +178,11 @@ private void executeHook() {
167178
try {
168179
onPackageLoaded();
169180
} finally {
170-
closeDexKitSession();
181+
try {
182+
flushPendingDexKitHooks();
183+
} finally {
184+
closeDexKitSession();
185+
}
171186
}
172187
}
173188

@@ -187,40 +202,106 @@ private void closeDexKitSession() {
187202
}
188203

189204
protected void initHook(BaseHook hook) {
190-
initHook(hook, () -> true);
205+
try {
206+
initHookInternal(hook, true);
207+
} catch (Throwable t) {
208+
logHookFailure(hook, t);
209+
}
191210
}
192211

193212
protected void initHook(BaseHook hook, boolean isInit) {
194-
initHook(hook, () -> isInit);
213+
try {
214+
initHookInternal(hook, isInit);
215+
} catch (Throwable t) {
216+
logHookFailure(hook, t);
217+
}
195218
}
196219

197220
protected void initHook(BaseHook hook, BooleanSupplier condition) {
198221
if (hook == null) return;
199222

200223
try {
201-
if (condition.getAsBoolean()) {
202-
if (hook.useDexKit() && !isSystemServer()) {
203-
prepareDexKitSession(hook.TAG);
204-
hook.setDexKitInitInProgress(true);
205-
try {
206-
if (!hook.initDexKit()) {
207-
XposedLog.w(hook.TAG, getPackageName(), "Skip hook because initDexKit returned false");
208-
return;
209-
}
210-
} catch (Throwable t) {
211-
XposedLog.e(hook.TAG, getPackageName(), "Skip hook because initDexKit failed", t);
212-
return;
213-
} finally {
214-
hook.setDexKitInitInProgress(false);
215-
}
216-
}
217-
hook.init();
218-
XposedLog.i(hook.TAG, getPackageName(), "Hook Success");
224+
if (!mPendingDexKitHooks.isEmpty()) {
225+
flushPendingDexKitHooks();
226+
}
227+
initHookInternal(hook, condition.getAsBoolean());
228+
} catch (Throwable t) {
229+
logHookFailure(hook, t);
230+
}
231+
}
232+
233+
private void initHookInternal(BaseHook hook, boolean shouldInit) {
234+
if (hook == null || !shouldInit) return;
235+
if (hook.useDexKit() && !isSystemServer()) {
236+
prepareDexKitSession(hook.TAG);
237+
mPendingDexKitHooks.add(hook);
238+
return;
239+
}
240+
flushPendingDexKitHooks();
241+
runHookInit(hook);
242+
}
243+
244+
private void flushPendingDexKitHooks() {
245+
if (mPendingDexKitHooks.isEmpty()) return;
246+
247+
List<BaseHook> pendingHooks = new ArrayList<>(mPendingDexKitHooks);
248+
mPendingDexKitHooks.clear();
249+
250+
List<Future<DexKitInitResult>> futures = new ArrayList<>(pendingHooks.size());
251+
for (BaseHook hook : pendingHooks) {
252+
futures.add(ThreadPoolManager.getInstance().submit(() -> runDexKitInit(hook)));
253+
}
254+
255+
List<DexKitInitResult> results = new ArrayList<>(pendingHooks.size());
256+
for (int i = 0; i < futures.size(); i++) {
257+
BaseHook hook = pendingHooks.get(i);
258+
try {
259+
results.add(futures.get(i).get());
260+
} catch (InterruptedException e) {
261+
Thread.currentThread().interrupt();
262+
results.add(new DexKitInitResult(hook, false, e));
263+
} catch (ExecutionException e) {
264+
Throwable cause = e.getCause() != null ? e.getCause() : e;
265+
results.add(new DexKitInitResult(hook, false, cause));
266+
}
267+
}
268+
269+
for (DexKitInitResult result : results) {
270+
if (result.error != null) {
271+
XposedLog.e(result.hook.TAG, getPackageName(), "Skip hook because initDexKit failed", result.error);
272+
continue;
273+
}
274+
if (!result.shouldInit) {
275+
XposedLog.w(result.hook.TAG, getPackageName(), "Skip hook because initDexKit returned false");
276+
continue;
277+
}
278+
try {
279+
runHookInit(result.hook);
280+
} catch (Throwable t) {
281+
logHookFailure(result.hook, t);
219282
}
283+
}
284+
}
285+
286+
private DexKitInitResult runDexKitInit(BaseHook hook) {
287+
hook.setDexKitInitInProgress(true);
288+
try {
289+
return new DexKitInitResult(hook, hook.initDexKit(), null);
220290
} catch (Throwable t) {
221-
StringWriter sw = new StringWriter();
222-
t.printStackTrace(new PrintWriter(sw));
223-
XposedLog.e(hook.TAG, getPackageName(), "Hook Failed: " + sw);
291+
return new DexKitInitResult(hook, false, t);
292+
} finally {
293+
hook.setDexKitInitInProgress(false);
224294
}
225295
}
296+
297+
private void runHookInit(BaseHook hook) {
298+
hook.init();
299+
XposedLog.i(hook.TAG, getPackageName(), "Hook Success");
300+
}
301+
302+
private void logHookFailure(BaseHook hook, Throwable t) {
303+
StringWriter sw = new StringWriter();
304+
t.printStackTrace(new PrintWriter(sw));
305+
XposedLog.e(hook.TAG, getPackageName(), "Hook Failed: " + sw);
306+
}
226307
}

library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/hookapi/dexkit/DexKit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
/**
3131
* DexKit 工具类 — 薄 Java 静态门面
3232
* <p>
33-
* 所有实际工作委托给 {@link DexKitCacheManager},后者基于 DexKit 2.1.0
33+
* 所有实际工作委托给 {@link DexKitCacheManager},后者基于 DexKit 2.2.0
3434
* 的 {@code DexKitCacheBridge} + {@code RecyclableBridge} 实现
3535
* 缓存与原生桥生命周期管理。
3636
*

library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/utils/hookapi/dexkit/DexKitCacheManager.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import java.io.File
5353
* 再把结果序列化后写回缓存。
5454
*
5555
* 线程安全约束:所有公开方法都可以跨线程调用。
56-
* [findMember] / [findMemberList] 整体同步执行(@Synchronized)
56+
* DexKit 2.2.0 已支持同桥并发访问,框架层会在 Hook 初始化阶段自动并行调度。
5757
* 生命周期方法([init] / [releaseBridge] / [clearAllCache])使用内部锁保护状态。
5858
*
5959
* @author Ling Qiqi
@@ -124,16 +124,11 @@ internal object DexKitCacheManager {
124124
*
125125
* 缓存命中时:从 JSON 反序列化并结合 classLoader 解析,不创建原生桥。
126126
* 缓存未命中时:获取原生桥,执行 [iDexKit],然后序列化并写入缓存。
127-
*
128-
* 整个方法同步执行:DexKit 内部使用多线程 native 扫描,
129-
* 同一个桥并发调用会导致线程争抢,性能急剧恶化。
130127
*/
131-
@Synchronized
132128
@Suppress("UNCHECKED_CAST")
133129
fun <T> findMember(key: String, iDexKit: IDexKit): T {
134130
val currentParam = param ?: throw IllegalStateException("DexKit not ready")
135131
val classLoader = currentParam.classLoader
136-
val currentBridge = bridge ?: throw IllegalStateException("DexKit not initialized")
137132

138133
// 缓存 key 不带前缀,由 strings / lists 分组隐式区分
139134
// 先尝试命中内存缓存,命中时不创建原生桥
@@ -142,6 +137,7 @@ internal object DexKitCacheManager {
142137
}
143138

144139
// 缓存未命中,获取原生桥执行查询
140+
val currentBridge = bridge ?: throw IllegalStateException("DexKit not initialized")
145141
var result: Any? = null
146142
currentBridge.withBridge { rawBridge ->
147143
val baseData: BaseData = try {
@@ -157,15 +153,11 @@ internal object DexKitCacheManager {
157153

158154
/**
159155
* 查找成员列表,并带缓存支持。
160-
*
161-
* 同步约束同 [findMember]。
162156
*/
163-
@Synchronized
164157
@Suppress("UNCHECKED_CAST")
165158
fun <T> findMemberList(key: String, iDexKitList: IDexKitList): List<T> {
166159
val currentParam = param ?: throw IllegalStateException("DexKit not ready")
167160
val classLoader = currentParam.classLoader
168-
val currentBridge = bridge ?: throw IllegalStateException("DexKit not initialized")
169161

170162
// 缓存 key 不带前缀,由 strings / lists 分组隐式区分
171163
// 先尝试命中缓存
@@ -174,6 +166,7 @@ internal object DexKitCacheManager {
174166
}
175167

176168
// 缓存未命中,获取原生桥执行查询
169+
val currentBridge = bridge ?: throw IllegalStateException("DexKit not initialized")
177170
val resultList = mutableListOf<T>()
178171
currentBridge.withBridge { rawBridge ->
179172
val baseDataList = try {

0 commit comments

Comments
 (0)