diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java index c3af21b..4925fe9 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java @@ -83,6 +83,7 @@ public class LSPApplication { Log.d(TAG, "Initialize service client"); ILSPApplicationService service; + if (config.useManager) { try { service = new RemoteApplicationService(context); @@ -95,14 +96,14 @@ public class LSPApplication { moduleArr.put(moduleObj); } SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE); - shared.edit().putString("modules",moduleArr.toString()).commit(); - Log.e(TAG, "Success update module scope"); + shared.edit().putString("modules",moduleArr.toString()).apply(); + Log.i(TAG, "Success update module scope from Manager"); }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 (NLAS)"); service = new NeoLocalApplicationService(context); } - } else { + Log.i(TAG, "Manager is disabled, using remote service (NLAS)"); service = new NeoLocalApplicationService(context); } diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/service/NeoLocalApplicationService.java b/patch-loader/src/main/java/org/lsposed/lspatch/service/NeoLocalApplicationService.java index 0f804fe..85cdb76 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/service/NeoLocalApplicationService.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/service/NeoLocalApplicationService.java @@ -17,39 +17,50 @@ import org.lsposed.lspd.service.ILSPApplicationService; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class NeoLocalApplicationService extends ILSPApplicationService.Stub { private static final String TAG = "NPatch"; private final List cachedModule; - public NeoLocalApplicationService(Context context){ - SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE); - cachedModule = new ArrayList<>(); + public NeoLocalApplicationService(Context context) { + cachedModule = Collections.synchronizedList(new ArrayList<>()); + loadModulesFromSharedPreferences(context); + } + + private void loadModulesFromSharedPreferences(Context context) { + var shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE); try { - JSONArray mArr = new JSONArray(shared.getString("modules", "{}")); - Log.i(TAG,"use fixed local application service:"+shared.getString("modules", "{}")); + String modulesJsonString = shared.getString("modules", "[]"); + Log.i(TAG, "using local application service with modules:" + modulesJsonString); + + if (modulesJsonString.equals("{}")) { + modulesJsonString = "[]"; + } + + var mArr = new JSONArray(modulesJsonString); for (int i = 0; i < mArr.length(); i++) { - JSONObject mObj = mArr.getJSONObject(i); - Module m = new Module(); - String path = mObj.getString("path"); - String packageName = mObj.getString("packageName"); - m.apkPath = path; - m.packageName = packageName; - if (!new File(m.apkPath).exists()){ - Log.i("NPatch","Module:" + m.packageName + " path not available, reset."); + var mObj = mArr.getJSONObject(i); + var m = new Module(); + m.apkPath = mObj.getString("path"); + m.packageName = mObj.getString("packageName"); + + if (m.apkPath == null || !new File(m.apkPath).exists()) { + Log.w(TAG, "Module:" + m.packageName + " path not available, attempting reset."); try { ApplicationInfo info = context.getPackageManager().getApplicationInfo(m.packageName, 0); m.apkPath = info.sourceDir; - Log.i("NPatch","Module:" + m.packageName + " path reset to " + m.apkPath); - }catch (Exception e){ - Log.e("NPatch",Log.getStackTraceString(e)); + 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; } } m.file = ModuleLoader.loadModule(m.apkPath); cachedModule.add(m); } - }catch (Exception e){ - Log.e(TAG,Log.getStackTraceString(e)); + } catch (Throwable e) { + Log.e(TAG, "Error loading modules from SharedPreferences.", e); } } diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java b/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java index fd64f6a..4aa7461 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/service/RemoteApplicationService.java @@ -37,27 +37,27 @@ public class RemoteApplicationService implements ILSPApplicationService { @SuppressLint("DiscouragedPrivateApi") public RemoteApplicationService(Context context) throws RemoteException { - try { - var intent = new Intent() - .setComponent(new ComponentName(Constants.MANAGER_PACKAGE_NAME, MODULE_SERVICE)) - .putExtra("packageName", context.getPackageName()); - // TODO: Authentication - var latch = new CountDownLatch(1); - var conn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder binder) { - Log.i(TAG, "Manager binder received"); - service = ILSPApplicationService.Stub.asInterface(binder); - latch.countDown(); - } + var intent = new Intent() + .setComponent(new ComponentName(Constants.MANAGER_PACKAGE_NAME, MODULE_SERVICE)) + .putExtra("packageName", context.getPackageName()); + // TODO: Authentication + var latch = new CountDownLatch(1); + var conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder binder) { + Log.i(TAG, "Manager binder received"); + service = ILSPApplicationService.Stub.asInterface(binder); + latch.countDown(); + } - @Override - public void onServiceDisconnected(ComponentName name) { - Log.e(TAG, "Manager service died"); - service = null; - } - }; - Log.i(TAG, "Request manager binder"); + @Override + public void onServiceDisconnected(ComponentName name) { + Log.e(TAG, "Manager service died"); + service = null; + } + }; + Log.i(TAG, "Request manager binder"); + try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { context.bindService(intent, Context.BIND_AUTO_CREATE, Executors.newSingleThreadExecutor(), conn); } else { @@ -72,7 +72,16 @@ public class RemoteApplicationService implements ILSPApplicationService { bindServiceAsUserMethod.invoke(context, intent, conn, Context.BIND_AUTO_CREATE, handler, userHandle); } boolean success = latch.await(1, TimeUnit.SECONDS); - if (!success) throw new TimeoutException("Bind service timeout"); + + if (!success) { + // Attempt to unbind the service before throwing a timeout for cleanup + try { + context.unbindService(conn); + } catch (IllegalArgumentException | IllegalStateException ignored) { + // Ignored + } + throw new TimeoutException("Bind service timeout"); + } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InterruptedException | TimeoutException e) { var r = new RemoteException("Failed to get manager binder");