patch-loader: 優化配置和資源處理

Add a shared Gson instance and harden config/module/asset loading to avoid NPEs and crashes. Guard legacy module iteration, use apply() for SharedPreferences, throw when config asset is missing, reuse GSON for parsing, and null-check resource streams before copying. Also set provider dex file writable only if created and remove some unused imports. These changes improve resilience when manager/asset data is unavailable and clean up file handling.
This commit is contained in:
NkBe 2026-02-10 17:44:59 +08:00
parent 59dc353e0e
commit 74bbeb9bda
No known key found for this signature in database
GPG Key ID: 9FACEE0DB6DF678E
2 changed files with 21 additions and 14 deletions

View File

@ -41,13 +41,11 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; 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;
@ -66,6 +64,8 @@ public class LSPApplication {
private static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; private static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
private static final int PER_USER_RANGE = 100000; private static final int PER_USER_RANGE = 100000;
private static final Gson GSON = new Gson();
private static ActivityThread activityThread; private static ActivityThread activityThread;
private static LoadedApk stubLoadedApk; private static LoadedApk stubLoadedApk;
private static LoadedApk appLoadedApk; private static LoadedApk appLoadedApk;
@ -105,14 +105,16 @@ public class LSPApplication {
service = new RemoteApplicationService(context); service = new RemoteApplicationService(context);
List<Module> m = service.getLegacyModulesList(); List<Module> m = service.getLegacyModulesList();
JSONArray moduleArr = new JSONArray(); JSONArray moduleArr = new JSONArray();
if (m != null) {
for (Module module : m) { for (Module module : m) {
JSONObject moduleObj = new JSONObject(); JSONObject moduleObj = new JSONObject();
moduleObj.put("path", module.apkPath); moduleObj.put("path", module.apkPath);
moduleObj.put("packageName", module.packageName); moduleObj.put("packageName", module.packageName);
moduleArr.put(moduleObj); moduleArr.put(moduleObj);
} }
}
SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE); SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE);
shared.edit().putString("modules", moduleArr.toString()).commit(); shared.edit().putString("modules", moduleArr.toString()).apply();
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");
@ -153,8 +155,9 @@ public class LSPApplication {
var baseClassLoader = stubLoadedApk.getClassLoader(); var baseClassLoader = stubLoadedApk.getClassLoader();
try (var is = baseClassLoader.getResourceAsStream(CONFIG_ASSET_PATH)) { try (var is = baseClassLoader.getResourceAsStream(CONFIG_ASSET_PATH)) {
if (is == null) throw new IOException("Config file not found in assets");
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
config = new Gson().fromJson(streamReader, PatchConfig.class); config = GSON.fromJson(streamReader, PatchConfig.class);
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Failed to load config file", e); Log.e(TAG, "Failed to load config file", e);
return null; return null;
@ -180,7 +183,7 @@ public class LSPApplication {
FileUtils.deleteFolderIfExists(originPath); FileUtils.deleteFolderIfExists(originPath);
Files.createDirectories(originPath); Files.createDirectories(originPath);
try (InputStream is = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) { try (InputStream is = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) {
Files.copy(is, cacheApkPath); if (is != null) Files.copy(is, cacheApkPath);
} }
} }
Path providerPath = null; Path providerPath = null;
@ -189,9 +192,13 @@ public class LSPApplication {
try { 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); if (is != null) Files.copy(is, providerPath);
} }
if (Files.exists(providerPath)) {
providerPath.toFile().setWritable(false); providerPath.toFile().setWritable(false);
} else {
providerPath = null;
}
} 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; providerPath = null;

View File

@ -6,7 +6,7 @@ public class Constants {
final static public String LOADER_DEX_ASSET_PATH = "assets/npatch/loader.dex"; final static public String LOADER_DEX_ASSET_PATH = "assets/npatch/loader.dex";
final static public String META_LOADER_DEX_ASSET_PATH = "assets/npatch/metaloader.dex"; final static public String META_LOADER_DEX_ASSET_PATH = "assets/npatch/metaloader.dex";
final static public String PROVIDER_DEX_ASSET_PATH = "assets/npatch/mtprovider.dex"; final static public String PROVIDER_DEX_ASSET_PATH = "assets/npatch/mtprovider.dex";
final static public String ORIGINAL_APK_ASSET_PATH = "assets/npatch/origin.apk.np"; final static public String ORIGINAL_APK_ASSET_PATH = "assets/npatch/origin.apk";
final static public String EMBEDDED_MODULES_ASSET_PATH = "assets/npatch/modules/"; final static public String EMBEDDED_MODULES_ASSET_PATH = "assets/npatch/modules/";
final static public String PATCH_FILE_SUFFIX = "-npatched.apk"; final static public String PATCH_FILE_SUFFIX = "-npatched.apk";