diff --git a/manager/src/main/AndroidManifest.xml b/manager/src/main/AndroidManifest.xml
index 5ef34f9..1ba125d 100644
--- a/manager/src/main/AndroidManifest.xml
+++ b/manager/src/main/AndroidManifest.xml
@@ -26,12 +26,9 @@
-
+
Bundle().apply {
- putBinder("binder", ManagerService.asBinder())
- }
- else -> throw IllegalArgumentException("Invalid method name")
- }
- }
-
- override fun query(p0: Uri, p1: Array?, p2: String?, p3: Array?, p4: String?): Cursor? {
- return null
- }
-
- override fun getType(p0: Uri): String? {
- return null
- }
-
- override fun insert(p0: Uri, p1: ContentValues?): Uri? {
- return null
- }
-
- override fun delete(p0: Uri, p1: String?, p2: Array?): Int {
- return 0
- }
-
- override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array?): Int {
- return 0
- }
-}
diff --git a/manager/src/main/java/org/lsposed/lspatch/manager/ModuleService.kt b/manager/src/main/java/org/lsposed/lspatch/manager/ModuleService.kt
new file mode 100644
index 0000000..f4e2511
--- /dev/null
+++ b/manager/src/main/java/org/lsposed/lspatch/manager/ModuleService.kt
@@ -0,0 +1,20 @@
+package org.lsposed.lspatch.manager
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import android.util.Log
+
+class ModuleService : Service() {
+
+ companion object {
+ private const val TAG = "ModuleService"
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ val packageName = intent.getStringExtra("packageName") ?: return null
+ // TODO: Authentication
+ Log.i(TAG, "$packageName requests binder")
+ return ManagerService.asBinder()
+ }
+}
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 32e7bf0..1a27d2e 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
@@ -9,6 +9,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.os.Build;
+import android.os.RemoteException;
import android.system.Os;
import android.util.Log;
@@ -63,7 +64,7 @@ public class LSPApplication {
return (android.os.Process.myUid() % PER_USER_RANGE) >= FIRST_APP_ZYGOTE_ISOLATED_UID;
}
- public static void onLoad() {
+ public static void onLoad() throws RemoteException, IOException {
if (isIsolated()) {
XLog.d(TAG, "Skip isolated process");
return;
@@ -75,30 +76,27 @@ public class LSPApplication {
return;
}
- try {
- Log.d(TAG, "Initialize service client");
- ILSPApplicationService service;
- if (config.useManager) {
- service = new RemoteApplicationService(context);
- } else {
- service = new LocalApplicationService(context);
- }
-
- disableProfile(context);
- Startup.initXposed(false, ActivityThread.currentProcessName(), service);
- Log.i(TAG, "Bootstrap Xposed");
- Startup.bootstrapXposed();
- // WARN: Since it uses `XResource`, the following class should not be initialized
- // before forkPostCommon is invoke. Otherwise, you will get failure of XResources
- Log.i(TAG, "Load modules");
- LSPLoader.initModules(appLoadedApk);
- Log.i(TAG, "Modules initialized");
-
- switchAllClassLoader();
- SigBypass.doSigBypass(context, config.sigBypassLevel);
- } catch (Throwable e) {
- throw new RuntimeException("Do hook", e);
+ Log.d(TAG, "Initialize service client");
+ ILSPApplicationService service;
+ if (config.useManager) {
+ service = new RemoteApplicationService(context);
+ } else {
+ service = new LocalApplicationService(context);
}
+
+ disableProfile(context);
+ Startup.initXposed(false, ActivityThread.currentProcessName(), service);
+ Log.i(TAG, "Bootstrap Xposed");
+ Startup.bootstrapXposed();
+ // WARN: Since it uses `XResource`, the following class should not be initialized
+ // before forkPostCommon is invoke. Otherwise, you will get failure of XResources
+ Log.i(TAG, "Load modules");
+ LSPLoader.initModules(appLoadedApk);
+ Log.i(TAG, "Modules initialized");
+
+ switchAllClassLoader();
+ SigBypass.doSigBypass(context, config.sigBypassLevel);
+
Log.i(TAG, "LSPatch bootstrap completed");
}
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 7e711fe..e080de6 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
@@ -1,34 +1,82 @@
package org.lsposed.lspatch.service;
-import static org.lsposed.lspatch.share.Constants.MANAGER_PACKAGE_NAME;
-
+import android.annotation.SuppressLint;
+import android.content.ComponentName;
import android.content.Context;
-import android.net.Uri;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
import android.widget.Toast;
+import org.lsposed.lspatch.share.Constants;
import org.lsposed.lspd.models.Module;
import org.lsposed.lspd.service.ILSPApplicationService;
import java.io.File;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
public class RemoteApplicationService implements ILSPApplicationService {
- private static final Uri PROVIDER = Uri.parse("content://" + MANAGER_PACKAGE_NAME + ".provider");
+ private static final String TAG = "LSPatch";
+ private static final String MODULE_SERVICE = Constants.MANAGER_PACKAGE_NAME + ".manager.ModuleService";
- private final ILSPApplicationService service;
+ private ILSPApplicationService service;
+ @SuppressLint("DiscouragedPrivateApi")
public RemoteApplicationService(Context context) throws RemoteException {
try {
- Bundle back = context.getContentResolver().call(PROVIDER, "getBinder", null, null);
- service = ILSPApplicationService.Stub.asInterface(back.getBinder("binder"));
- } catch (IllegalArgumentException | NullPointerException e) {
+ 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");
+ latch.countDown();
+ service = Stub.asInterface(binder);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.e(TAG, "Manager service died");
+ service = null;
+ }
+ };
+ Log.i(TAG, "Request manager binder");
+ context.startService(intent);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ context.bindService(intent, Context.BIND_AUTO_CREATE, Executors.newSingleThreadExecutor(), conn);
+ } else {
+ var handlerThread = new HandlerThread("RemoteApplicationService");
+ handlerThread.start();
+ var handler = new Handler(handlerThread.getLooper());
+ var contextImplClass = context.getClass();
+ var getUserMethod = contextImplClass.getMethod("getUser");
+ var bindServiceAsUserMethod = contextImplClass.getDeclaredMethod(
+ "bindServiceAsUser", Intent.class, ServiceConnection.class, int.class, Handler.class, UserHandle.class);
+ var userHandle = (UserHandle) getUserMethod.invoke(context);
+ bindServiceAsUserMethod.invoke(context, intent, conn, Context.BIND_AUTO_CREATE, handler, userHandle);
+ }
+ boolean success = latch.await(5, TimeUnit.SECONDS);
+ if (!success) throw new TimeoutException("Bind service timeout");
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InterruptedException | TimeoutException e) {
Toast.makeText(context, "Manager died", Toast.LENGTH_SHORT).show();
var r = new RemoteException("Failed to get manager binder");
r.initCause(e);