fix: 正確設定共享偏好設定鍵並提升加載穩定性
- 修正了 SharedPreferences 鍵配置錯誤,確保模組緩存能正確加載。 - 優化 檔案注入器: 減少 ZipFile 重複 I/O,提升啟動效率。 - 優化 profile 禁用: 採用冪等性檢查和 Truncate 替代 Delete/Create 流程,增強對系統監控的穩定性,避免用戶配置意外清除。 - 代碼精簡: 改進了變數命名和程式碼結構。 fix: 正確設定共享偏好設定鍵並提升加載穩定性 - 修正了 SharedPreferences 鍵配置錯誤,確保模組緩存能正確加載。 - 優化 檔案注入器: 減少 ZipFile 重複 I/O,提升啟動效率。 - 優化 profile 禁用: 採用冪等性檢查和 Truncate 替代 Delete/Create 流程,增強對系統監控的穩定性,避免用戶配置意外清除。 - 改進 manager 構建檔案確保所有庫檔案不被壓縮。 - 代碼精簡: 改進了變數命名和程式碼結構。
This commit is contained in:
parent
799bc1d022
commit
5a90ed436e
|
|
@ -8,6 +8,11 @@
|
||||||
-assumenosideeffects public class kotlin.coroutines.jvm.internal.DebugMetadataKt {
|
-assumenosideeffects public class kotlin.coroutines.jvm.internal.DebugMetadataKt {
|
||||||
private static ** getDebugMetadataAnnotation(...) return null;
|
private static ** getDebugMetadataAnnotation(...) return null;
|
||||||
}
|
}
|
||||||
|
-keep class com.beust.jcommander.** { *; }
|
||||||
|
-keep interface com.beust.jcommander.** { *; }
|
||||||
|
-keepclassmembers class org.lsposed.patch.NPatch {
|
||||||
|
@com.beust.jcommander.Parameter *;
|
||||||
|
}
|
||||||
|
|
||||||
-keep class com.beust.jcommander.** { *; }
|
-keep class com.beust.jcommander.** { *; }
|
||||||
-keep class org.lsposed.npatch.database.** { *; }
|
-keep class org.lsposed.npatch.database.** { *; }
|
||||||
|
|
|
||||||
|
|
@ -24,22 +24,12 @@ class LSPApplication : Application() {
|
||||||
var targetApkFiles: ArrayList<File>? = null
|
var targetApkFiles: ArrayList<File>? = null
|
||||||
val globalScope = CoroutineScope(Dispatchers.Default)
|
val globalScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
|
||||||
companion object {
|
|
||||||
init {
|
|
||||||
try {
|
|
||||||
System.loadLibrary("verify")
|
|
||||||
} catch (e: UnsatisfiedLinkError) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
verifySignature()
|
verifySignature()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nativeVerify()
|
|
||||||
} catch (e: UnsatisfiedLinkError) {
|
} catch (e: UnsatisfiedLinkError) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
@ -75,4 +65,8 @@ class LSPApplication : Application() {
|
||||||
killApp()
|
killApp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun killApp() {
|
||||||
|
Process.killProcess(Process.myPid())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,15 @@ import com.google.gson.Gson;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.lsposed.lspd.core.Startup;
|
||||||
|
import org.lsposed.lspd.models.Module;
|
||||||
|
import org.lsposed.lspd.service.ILSPApplicationService;
|
||||||
import org.lsposed.npatch.loader.util.FileUtils;
|
import org.lsposed.npatch.loader.util.FileUtils;
|
||||||
import org.lsposed.npatch.loader.util.XLog;
|
import org.lsposed.npatch.loader.util.XLog;
|
||||||
import org.lsposed.npatch.service.IntegrApplicationService;
|
import org.lsposed.npatch.service.IntegrApplicationService;
|
||||||
import org.lsposed.npatch.service.NeoLocalApplicationService;
|
import org.lsposed.npatch.service.NeoLocalApplicationService;
|
||||||
import org.lsposed.npatch.service.RemoteApplicationService;
|
import org.lsposed.npatch.service.RemoteApplicationService;
|
||||||
import org.lsposed.npatch.share.PatchConfig;
|
import org.lsposed.npatch.share.PatchConfig;
|
||||||
import org.lsposed.lspd.core.Startup;
|
|
||||||
import org.lsposed.lspd.models.Module;
|
|
||||||
import org.lsposed.lspd.service.ILSPApplicationService;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -47,6 +47,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
import dalvik.system.DexFile;
|
import dalvik.system.DexFile;
|
||||||
|
|
@ -56,6 +57,7 @@ import hidden.HiddenApiBridge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Windysha
|
* Created by Windysha
|
||||||
|
* Updated by NkBe
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class LSPApplication {
|
public class LSPApplication {
|
||||||
|
|
@ -109,8 +111,8 @@ public class LSPApplication {
|
||||||
moduleObj.put("packageName", module.packageName);
|
moduleObj.put("packageName", module.packageName);
|
||||||
moduleArr.put(moduleObj);
|
moduleArr.put(moduleObj);
|
||||||
}
|
}
|
||||||
SharedPreferences shared = context.getSharedPreferences("opatch", Context.MODE_PRIVATE);
|
SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE);
|
||||||
shared.edit().putString("modules",moduleArr.toString()).commit();
|
shared.edit().putString("modules", moduleArr.toString()).commit();
|
||||||
Log.e(TAG, "Success update module scope");
|
Log.e(TAG, "Success update module scope");
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
Log.e(TAG, "Failed to connect to manager, fallback to fixed local service");
|
Log.e(TAG, "Failed to connect to manager, fallback to fixed local service");
|
||||||
|
|
@ -123,7 +125,7 @@ public class LSPApplication {
|
||||||
disableProfile(context);
|
disableProfile(context);
|
||||||
Startup.initXposed(false, ActivityThread.currentProcessName(), context.getApplicationInfo().dataDir, service);
|
Startup.initXposed(false, ActivityThread.currentProcessName(), context.getApplicationInfo().dataDir, service);
|
||||||
Startup.bootstrapXposed();
|
Startup.bootstrapXposed();
|
||||||
|
|
||||||
// WARN: Since it uses `XResource`, the following class should not be initialized
|
// WARN: Since it uses `XResource`, the following class should not be initialized
|
||||||
// before forkPostCommon is invoke. Otherwise, you will get failure of XResources
|
// before forkPostCommon is invoke. Otherwise, you will get failure of XResources
|
||||||
|
|
||||||
|
|
@ -161,11 +163,13 @@ public class LSPApplication {
|
||||||
Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel);
|
Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel);
|
||||||
|
|
||||||
Path originPath = Paths.get(appInfo.dataDir, "cache/npatch/origin/");
|
Path originPath = Paths.get(appInfo.dataDir, "cache/npatch/origin/");
|
||||||
Path cacheApkPath;
|
String originalSourceDir = appInfo.sourceDir;
|
||||||
try (ZipFile sourceFile = new ZipFile(appInfo.sourceDir)) {
|
|
||||||
cacheApkPath = originPath.resolve(sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk");
|
long sourceCrc;
|
||||||
|
try (ZipFile sourceFile = new ZipFile(originalSourceDir)) {
|
||||||
|
sourceCrc = sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc();
|
||||||
}
|
}
|
||||||
String sourceFileaa = appInfo.sourceDir;
|
Path cacheApkPath = originPath.resolve(sourceCrc + ".apk");
|
||||||
|
|
||||||
appInfo.sourceDir = cacheApkPath.toString();
|
appInfo.sourceDir = cacheApkPath.toString();
|
||||||
appInfo.publicSourceDir = cacheApkPath.toString();
|
appInfo.publicSourceDir = cacheApkPath.toString();
|
||||||
|
|
@ -181,17 +185,16 @@ public class LSPApplication {
|
||||||
}
|
}
|
||||||
Path providerPath = null;
|
Path providerPath = null;
|
||||||
if (config.injectProvider) {
|
if (config.injectProvider) {
|
||||||
try (ZipFile sourceFile = new ZipFile(sourceFileaa)) {
|
providerPath = originPath.resolve("p_" + sourceCrc + ".dex");
|
||||||
providerPath = Paths.get(appInfo.dataDir, "cache/npatch/origin/p_" + sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".dex");
|
try {
|
||||||
Files.deleteIfExists(providerPath);
|
Files.deleteIfExists(providerPath);
|
||||||
try (InputStream is = baseClassLoader.getResourceAsStream(PROVIDER_DEX_ASSET_PATH)) {
|
try (InputStream is = baseClassLoader.getResourceAsStream(PROVIDER_DEX_ASSET_PATH)) {
|
||||||
Files.copy(is, providerPath);
|
Files.copy(is, providerPath);
|
||||||
}
|
}
|
||||||
if (providerPath != null) {
|
providerPath.toFile().setWritable(false);
|
||||||
providerPath.toFile().setWritable(false);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Failed to inject provider:" + Log.getStackTraceString(e));
|
Log.e(TAG, "Failed to inject provider:" + Log.getStackTraceString(e));
|
||||||
|
providerPath = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,48 +263,31 @@ public class LSPApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disableProfile(Context context) {
|
public static void disableProfile(Context context) {
|
||||||
final ArrayList<String> codePaths = new ArrayList<>();
|
|
||||||
var appInfo = context.getApplicationInfo();
|
var appInfo = context.getApplicationInfo();
|
||||||
var pkgName = context.getPackageName();
|
|
||||||
if (appInfo == null) return;
|
if (appInfo == null) return;
|
||||||
if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
|
|
||||||
codePaths.add(appInfo.sourceDir);
|
|
||||||
}
|
|
||||||
if (appInfo.splitSourceDirs != null) {
|
|
||||||
Collections.addAll(codePaths, appInfo.splitSourceDirs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codePaths.isEmpty()) {
|
var codePaths = new ArrayList<String>();
|
||||||
// If there are no code paths there's no need to setup a profile file and register with
|
if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) codePaths.add(appInfo.sourceDir);
|
||||||
// the runtime,
|
if (appInfo.splitSourceDirs != null) Collections.addAll(codePaths, appInfo.splitSourceDirs);
|
||||||
return;
|
if (codePaths.isEmpty()) return;
|
||||||
}
|
|
||||||
|
|
||||||
var profileDir = HiddenApiBridge.Environment_getDataProfilesDePackageDirectory(appInfo.uid / PER_USER_RANGE, pkgName);
|
var profileDir = HiddenApiBridge.Environment_getDataProfilesDePackageDirectory(appInfo.uid / PER_USER_RANGE, context.getPackageName());
|
||||||
|
|
||||||
var attrs = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("r--------"));
|
|
||||||
|
|
||||||
for (int i = codePaths.size() - 1; i >= 0; i--) {
|
for (int i = codePaths.size() - 1; i >= 0; i--) {
|
||||||
String splitName = i == 0 ? null : appInfo.splitNames[i - 1];
|
String splitName = i == 0 ? null : appInfo.splitNames[i - 1];
|
||||||
File curProfileFile = new File(profileDir, splitName == null ? "primary.prof" : splitName + ".split.prof").getAbsoluteFile();
|
File profile = new File(profileDir, splitName == null ? "primary.prof" : splitName + ".split.prof");
|
||||||
Log.d(TAG, "Processing " + curProfileFile.getAbsolutePath());
|
|
||||||
try {
|
try {
|
||||||
if (!curProfileFile.canWrite() && Files.size(curProfileFile.toPath()) == 0) {
|
// 如果已是 0 字節且唯讀,直接跳過
|
||||||
Log.d(TAG, "Skip profile " + curProfileFile.getAbsolutePath());
|
if (profile.exists() && profile.length() == 0 && !profile.canWrite()) continue;
|
||||||
continue;
|
// 自動將已存在的檔案內容清空或建立新檔
|
||||||
}
|
try (var ignored = new FileOutputStream(profile)) {
|
||||||
if (curProfileFile.exists() && !curProfileFile.delete()) {
|
|
||||||
try (var writer = new FileOutputStream(curProfileFile)) {
|
|
||||||
Log.d(TAG, "Failed to delete, try to clear content " + curProfileFile.getAbsolutePath());
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Log.e(TAG, "Failed to delete and clear profile file " + curProfileFile.getAbsolutePath(), e);
|
|
||||||
}
|
|
||||||
Os.chmod(curProfileFile.getAbsolutePath(), 00400);
|
|
||||||
} else {
|
|
||||||
Files.createFile(curProfileFile.toPath(), attrs);
|
|
||||||
}
|
}
|
||||||
|
// 設定檔案只讀
|
||||||
|
Os.chmod(profile.getAbsolutePath(), 00444);
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Log.e(TAG, "Failed to disable profile file " + curProfileFile.getAbsolutePath(), e);
|
Log.e(TAG, "Failed to disable profile: " + profile.getName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue