From 54cf7eed35aaa0a3be77a5574eaf5cb5b5182753 Mon Sep 17 00:00:00 2001 From: Nullptr Date: Tue, 8 Nov 2022 02:53:56 +0800 Subject: [PATCH] Use service instead of content provider to send binder --- manager/src/main/AndroidManifest.xml | 9 +-- .../lsposed/lspatch/manager/ModuleProvider.kt | 52 --------------- .../lsposed/lspatch/manager/ModuleService.kt | 20 ++++++ .../lspatch/loader/LSPApplication.java | 46 +++++++------ .../service/RemoteApplicationService.java | 64 ++++++++++++++++--- 5 files changed, 101 insertions(+), 90 deletions(-) delete mode 100644 manager/src/main/java/org/lsposed/lspatch/manager/ModuleProvider.kt create mode 100644 manager/src/main/java/org/lsposed/lspatch/manager/ModuleService.kt 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);