diff --git a/manager/proguard-rules.pro b/manager/proguard-rules.pro
index 41a0a0d..af7b132 100644
--- a/manager/proguard-rules.pro
+++ b/manager/proguard-rules.pro
@@ -16,6 +16,7 @@
-keep class com.beust.jcommander.** { *; }
-keep class org.lsposed.npatch.database.** { *; }
+-keep class org.lsposed.npatch.manager.ConfigProvider { *; }
-keep class org.lsposed.npatch.Patcher$Options { *; }
-keep class org.lsposed.npatch.share.LSPConfig { *; }
-keep class org.lsposed.npatch.share.PatchConfig { *; }
diff --git a/manager/src/main/AndroidManifest.xml b/manager/src/main/AndroidManifest.xml
index 7b5eb1a..888fefc 100644
--- a/manager/src/main/AndroidManifest.xml
+++ b/manager/src/main/AndroidManifest.xml
@@ -89,5 +89,12 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
+
+
+
\ No newline at end of file
diff --git a/manager/src/main/java/org/lsposed/npatch/manager/ConfigProvider.kt b/manager/src/main/java/org/lsposed/npatch/manager/ConfigProvider.kt
new file mode 100644
index 0000000..3b9a232
--- /dev/null
+++ b/manager/src/main/java/org/lsposed/npatch/manager/ConfigProvider.kt
@@ -0,0 +1,51 @@
+package org.lsposed.npatch.manager
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.database.Cursor
+import android.database.MatrixCursor
+import android.net.Uri
+import android.util.Log
+import kotlinx.coroutines.runBlocking
+import org.lsposed.npatch.config.ConfigManager
+
+class ConfigProvider : ContentProvider() {
+
+ companion object {
+ const val AUTHORITY = "org.lsposed.npatch.manager.provider.config"
+ const val TAG = "ConfigProvider"
+ }
+
+ override fun onCreate(): Boolean = true
+
+ override fun query(
+ uri: Uri,
+ projection: Array?,
+ selection: String?,
+ selectionArgs: Array?,
+ sortOrder: String?
+ ): Cursor? {
+ val targetPackage = uri.getQueryParameter("package")
+ if (targetPackage.isNullOrEmpty()) return null
+
+ val modulesList = runBlocking {
+ try {
+ // 修正:直接使用 ConfigManager 來獲取該 APP 啟用的模組列表
+ ConfigManager.getModulesForApp(targetPackage).map { it.pkgName }
+ } catch (e: Exception) {
+ Log.e(TAG, "Database query failed", e)
+ emptyList()
+ }
+ }
+
+ // 返回 Cursor 給被修補的 APP
+ val cursor = MatrixCursor(arrayOf("packageName"))
+ modulesList.forEach { cursor.addRow(arrayOf(it)) }
+ return cursor
+ }
+
+ override fun getType(uri: Uri): String? = null
+ override fun insert(uri: Uri, values: ContentValues?): Uri? = null
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = 0
+ override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int = 0
+}
diff --git a/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java b/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java
index 0cf2ef5..924dfe8 100644
--- a/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java
+++ b/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java
@@ -1,12 +1,15 @@
package org.lsposed.npatch.service;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.util.Log;
-import org.json.JSONArray;
import org.lsposed.npatch.util.ModuleLoader;
import org.lsposed.lspd.models.Module;
import org.lsposed.lspd.service.ILSPApplicationService;
@@ -18,64 +21,55 @@ import java.util.List;
public class NeoLocalApplicationService extends ILSPApplicationService.Stub {
private static final String TAG = "NPatch";
+ private static final String AUTHORITY = "org.lsposed.npatch.manager.provider.config";
+ private static final Uri PROVIDER_URI = Uri.parse("content://" + AUTHORITY + "/config");
+
private final List cachedModule;
public NeoLocalApplicationService(Context context) {
cachedModule = Collections.synchronizedList(new ArrayList<>());
- loadModulesFromSharedPreferences(context);
+ loadModulesFromProvider(context);
}
- private void loadModulesFromSharedPreferences(Context context) {
- var shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE);
+ private void loadModulesFromProvider(Context context) {
+ PackageManager pm = context.getPackageManager();
+ String myPackageName = context.getPackageName();
+
+ Uri queryUri = PROVIDER_URI.buildUpon()
+ .appendQueryParameter("package", myPackageName)
+ .build();
+
+ try (Cursor cursor = context.getContentResolver().query(queryUri, null, null, null, null)) {
+ if (cursor == null) {
+ Log.w(TAG, "NeoLocal: Cannot reach Manager Provider.");
+ return;
+ }
+
+ while (cursor.moveToNext()) {
+ int colIndex = cursor.getColumnIndex("packageName");
+ if (colIndex != -1) {
+ loadSingleModule(pm, cursor.getString(colIndex));
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "NeoLocal: Provider query failed", e);
+ }
+ }
+
+ private void loadSingleModule(PackageManager pm, String pkgName) {
try {
- var modulesJsonString = shared.getString("modules", "[]");
- Log.i(TAG, "Loading modules from local SharedPreferences...");
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);
+ Module m = new Module();
+ m.packageName = pkgName;
+ m.apkPath = appInfo.sourceDir;
- if (modulesJsonString.equals("{}")) {
- modulesJsonString = "[]";
- }
-
- var mArr = new JSONArray(modulesJsonString);
- if (mArr.length() > 0) {
- Log.i(TAG, "Found " + mArr.length() + " modules.");
- }
-
- for (int i = 0; i < mArr.length(); i++) {
- var mObj = mArr.getJSONObject(i);
- var m = new Module();
-
- m.packageName = mObj.optString("packageName", null);
- var apkPath = mObj.optString("path", null);
-
- if (m.packageName == null) {
- Log.w(TAG, "Module at index " + i + " has no package name, skipping.");
- continue;
- }
-
- // 如果路徑為 null 或文件不存在,嘗試從 PackageManager 恢復
- if (apkPath == null || !new File(apkPath).exists()) {
- Log.w(TAG, "Module:" + m.packageName + " path not available, attempting reset.");
- try {
- var info = context.getPackageManager().getApplicationInfo(m.packageName, 0);
- m.apkPath = info.sourceDir;
- Log.i(TAG, "Module:" + m.packageName + " path reset to " + m.apkPath);
- } catch (Exception e) {
- Log.e(TAG, "Failed to get ApplicationInfo for module: " + m.packageName, e);
- continue;
- }
- } else {
- m.apkPath = apkPath;
- }
-
- if (m.apkPath != null) {
- m.file = ModuleLoader.loadModule(m.apkPath);
- cachedModule.add(m);
- } else {
- Log.w(TAG, "Could not load module " + m.packageName + ": final path is null.");
- }
+ if (m.apkPath != null && new File(m.apkPath).exists()) {
+ m.file = ModuleLoader.loadModule(m.apkPath);
+ cachedModule.add(m);
+ Log.i(TAG, "NeoLocal: Loaded module " + pkgName);
}
} catch (Throwable e) {
- Log.e(TAG, "Error loading modules from SharedPreferences.", e);
+ Log.e(TAG, "NeoLocal: Failed to load " + pkgName, e);
}
}
@@ -90,15 +84,9 @@ public class NeoLocalApplicationService extends ILSPApplicationService.Stub {
}
@Override
- public String getPrefsPath(String packageName) throws RemoteException {
- return "/data/data/" + packageName + "/shared_prefs/";
- }
-
+ public String getPrefsPath(String packageName) throws RemoteException { return "/data/data/" + packageName + "/shared_prefs/"; }
@Override
- public ParcelFileDescriptor requestInjectedManagerBinder(List binder) throws RemoteException {
- return null;
- }
-
+ public ParcelFileDescriptor requestInjectedManagerBinder(List binder) throws RemoteException { return null; }
@Override
public IBinder asBinder() {
return this;
diff --git a/patch-loader/src/main/jni/src/jni/bypass_svc.cpp b/patch-loader/src/main/jni/src/jni/bypass_svc.cpp
index f159093..731f471 100644
--- a/patch-loader/src/main/jni/src/jni/bypass_svc.cpp
+++ b/patch-loader/src/main/jni/src/jni/bypass_svc.cpp
@@ -21,6 +21,11 @@
namespace lspd {
// --- 共用結構與變數 ---
+ // 將此變數移出 #if 區塊,確保 IDE 和編譯器在任何架構下都能識別,避免未定義錯誤。
+ static bool g_is_hook_active = false;
+
+#if defined(__aarch64__)
+
struct SyscallRequest {
long sys_no;
long args[6];
@@ -31,7 +36,6 @@ namespace lspd {
};
static pthread_t g_trusted_thread;
- static bool g_is_hook_active = false;
static std::queue g_request_queue;
static std::mutex g_queue_mtx;
static std::condition_variable g_queue_cv;
@@ -53,8 +57,8 @@ namespace lspd {
if (req) {
// 執行真正的 syscall
req->result = syscall(req->sys_no,
- req->args[0], req->args[1], req->args[2],
- req->args[3], req->args[4], req->args[5]);
+ req->args[0], req->args[1], req->args[2],
+ req->args[3], req->args[4], req->args[5]);
{
std::lock_guard lock(req->mtx);
@@ -74,7 +78,6 @@ namespace lspd {
SyscallRequest req;
// ARM64: 從 regs 讀取 (x8=sys_no, x0-x5=args)
- // 直接存取 ARM64 特有的 regs 結構
req.sys_no = ctx->uc_mcontext.regs[8];
for (int i = 0; i < 6; ++i) {
req.args[i] = ctx->uc_mcontext.regs[i];
@@ -98,12 +101,17 @@ namespace lspd {
ctx->uc_mcontext.regs[0] = req.result;
}
- // --- JNI 接口層 ---
+#endif // 結束 __aarch64__ 專用區塊
+
+
+ // -------------------------------------------------------------------------
+ // JNI 接口層 (處理架構差異)
+ // -------------------------------------------------------------------------
LSP_DEF_NATIVE_METHOD(jboolean, SvcBypass, initSvcHook) {
- // 如果已經激活,直接返回成功
if (g_is_hook_active) return JNI_TRUE;
+#if defined(__aarch64__)
int ret = pthread_create(&g_trusted_thread, nullptr, trusted_thread_loop, nullptr);
if (ret != 0) {
LOGE("SvcBypass: Failed to create trusted thread");
@@ -122,16 +130,22 @@ namespace lspd {
g_is_hook_active = true;
LOGI("SvcBypass: Initialized successfully (ARM64)");
return JNI_TRUE;
+#else
+ // x86/x86_64: 僅標記為激活,但不做實際 Hook
+ g_is_hook_active = true;
+ LOGI("SvcBypass: Skipped on non-ARM64 architecture");
+ return JNI_TRUE;
+#endif
}
LSP_DEF_NATIVE_METHOD(void, SvcBypass, enableSvcRedirect,
- jstring path, jstring orig, jstring pkg) {
+ jstring path, jstring orig, jstring pkg) {
if (!g_is_hook_active) {
LOGW("SvcBypass: Hook not initialized.");
return;
}
- // ARM64 BPF 規則
+#if defined(__aarch64__)
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_openat, 0, 1),
@@ -154,6 +168,7 @@ namespace lspd {
} else {
LOGI("SvcBypass: Seccomp filter applied (ARM64)");
}
+#endif
}
LSP_DEF_NATIVE_METHOD(void, SvcBypass, disableSvcRedirect) {
@@ -165,7 +180,11 @@ namespace lspd {
}
LSP_DEF_NATIVE_METHOD(jstring, SvcBypass, getDebugInfo) {
+#if defined(__aarch64__)
return env->NewStringUTF("SvcBypass: Active (ARM64)");
+#else
+ return env->NewStringUTF("SvcBypass: Stub (Non-ARM64)");
+#endif
}
LSP_DEF_NATIVE_METHOD(jint, SvcBypass, getCurrentPid) {