fix: improve service fallback and module loading

This commit is contained in:
NkBe 2025-10-01 17:51:27 +08:00
parent 9804125d1f
commit dbacad9876
No known key found for this signature in database
GPG Key ID: 75EF144ED8F4D7B8
3 changed files with 64 additions and 43 deletions

View File

@ -83,6 +83,7 @@ public class LSPApplication {
Log.d(TAG, "Initialize service client"); Log.d(TAG, "Initialize service client");
ILSPApplicationService service; ILSPApplicationService service;
if (config.useManager) { if (config.useManager) {
try { try {
service = new RemoteApplicationService(context); service = new RemoteApplicationService(context);
@ -95,14 +96,14 @@ public class LSPApplication {
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.i(TAG, "Success update module scope from Manager");
}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 (NLAS)");
service = new NeoLocalApplicationService(context); service = new NeoLocalApplicationService(context);
} }
} else { } else {
Log.i(TAG, "Manager is disabled, using remote service (NLAS)");
service = new NeoLocalApplicationService(context); service = new NeoLocalApplicationService(context);
} }

View File

@ -17,39 +17,50 @@ import org.lsposed.lspd.service.ILSPApplicationService;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public class NeoLocalApplicationService extends ILSPApplicationService.Stub { public class NeoLocalApplicationService extends ILSPApplicationService.Stub {
private static final String TAG = "NPatch"; private static final String TAG = "NPatch";
private final List<Module> cachedModule; private final List<Module> cachedModule;
public NeoLocalApplicationService(Context context){ public NeoLocalApplicationService(Context context) {
SharedPreferences shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE); cachedModule = Collections.synchronizedList(new ArrayList<>());
cachedModule = new ArrayList<>(); loadModulesFromSharedPreferences(context);
}
private void loadModulesFromSharedPreferences(Context context) {
var shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE);
try { try {
JSONArray mArr = new JSONArray(shared.getString("modules", "{}")); String modulesJsonString = shared.getString("modules", "[]");
Log.i(TAG,"use fixed local application service:"+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++) { for (int i = 0; i < mArr.length(); i++) {
JSONObject mObj = mArr.getJSONObject(i); var mObj = mArr.getJSONObject(i);
Module m = new Module(); var m = new Module();
String path = mObj.getString("path"); m.apkPath = mObj.getString("path");
String packageName = mObj.getString("packageName"); m.packageName = mObj.getString("packageName");
m.apkPath = path;
m.packageName = packageName; if (m.apkPath == null || !new File(m.apkPath).exists()) {
if (!new File(m.apkPath).exists()){ Log.w(TAG, "Module:" + m.packageName + " path not available, attempting reset.");
Log.i("NPatch","Module:" + m.packageName + " path not available, reset.");
try { try {
ApplicationInfo info = context.getPackageManager().getApplicationInfo(m.packageName, 0); ApplicationInfo info = context.getPackageManager().getApplicationInfo(m.packageName, 0);
m.apkPath = info.sourceDir; m.apkPath = info.sourceDir;
Log.i("NPatch","Module:" + m.packageName + " path reset to " + m.apkPath); Log.i(TAG, "Module:" + m.packageName + " path reset to " + m.apkPath);
}catch (Exception e){ } catch (Exception e) {
Log.e("NPatch",Log.getStackTraceString(e)); Log.e(TAG, "Failed to get ApplicationInfo for module: " + m.packageName, e);
continue;
} }
} }
m.file = ModuleLoader.loadModule(m.apkPath); m.file = ModuleLoader.loadModule(m.apkPath);
cachedModule.add(m); cachedModule.add(m);
} }
}catch (Exception e){ } catch (Throwable e) {
Log.e(TAG,Log.getStackTraceString(e)); Log.e(TAG, "Error loading modules from SharedPreferences.", e);
} }
} }

View File

@ -37,27 +37,27 @@ public class RemoteApplicationService implements ILSPApplicationService {
@SuppressLint("DiscouragedPrivateApi") @SuppressLint("DiscouragedPrivateApi")
public RemoteApplicationService(Context context) throws RemoteException { public RemoteApplicationService(Context context) throws RemoteException {
try { var intent = new Intent()
var intent = new Intent() .setComponent(new ComponentName(Constants.MANAGER_PACKAGE_NAME, MODULE_SERVICE))
.setComponent(new ComponentName(Constants.MANAGER_PACKAGE_NAME, MODULE_SERVICE)) .putExtra("packageName", context.getPackageName());
.putExtra("packageName", context.getPackageName()); // TODO: Authentication
// TODO: Authentication var latch = new CountDownLatch(1);
var latch = new CountDownLatch(1); var conn = new ServiceConnection() {
var conn = new ServiceConnection() { @Override
@Override public void onServiceConnected(ComponentName name, IBinder binder) {
public void onServiceConnected(ComponentName name, IBinder binder) { Log.i(TAG, "Manager binder received");
Log.i(TAG, "Manager binder received"); service = ILSPApplicationService.Stub.asInterface(binder);
service = ILSPApplicationService.Stub.asInterface(binder); latch.countDown();
latch.countDown(); }
}
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "Manager service died"); Log.e(TAG, "Manager service died");
service = null; service = null;
} }
}; };
Log.i(TAG, "Request manager binder"); Log.i(TAG, "Request manager binder");
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
context.bindService(intent, Context.BIND_AUTO_CREATE, Executors.newSingleThreadExecutor(), conn); context.bindService(intent, Context.BIND_AUTO_CREATE, Executors.newSingleThreadExecutor(), conn);
} else { } else {
@ -72,7 +72,16 @@ public class RemoteApplicationService implements ILSPApplicationService {
bindServiceAsUserMethod.invoke(context, intent, conn, Context.BIND_AUTO_CREATE, handler, userHandle); bindServiceAsUserMethod.invoke(context, intent, conn, Context.BIND_AUTO_CREATE, handler, userHandle);
} }
boolean success = latch.await(1, TimeUnit.SECONDS); 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 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
InterruptedException | TimeoutException e) { InterruptedException | TimeoutException e) {
var r = new RemoteException("Failed to get manager binder"); var r = new RemoteException("Failed to get manager binder");