Use service instead of content provider to send binder
This commit is contained in:
parent
cb0c24deb4
commit
54cf7eed35
|
|
@ -26,12 +26,9 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<provider
|
<service
|
||||||
android:name=".manager.ModuleProvider"
|
android:name=".manager.ModuleService"
|
||||||
android:authorities="org.lsposed.lspatch.provider"
|
android:exported="true" />
|
||||||
android:enabled="true"
|
|
||||||
android:exported="true"
|
|
||||||
tools:ignore="ExportedContentProvider" />
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="rikka.shizuku.ShizukuProvider"
|
android:name="rikka.shizuku.ShizukuProvider"
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
package org.lsposed.lspatch.manager
|
|
||||||
|
|
||||||
import android.content.ContentProvider
|
|
||||||
import android.content.ContentValues
|
|
||||||
import android.database.Cursor
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Binder
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import org.lsposed.lspatch.lspApp
|
|
||||||
|
|
||||||
class ModuleProvider : ContentProvider() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "ModuleProvider"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun call(method: String, arg: String?, extras: Bundle?): Bundle {
|
|
||||||
val app = lspApp.packageManager.getNameForUid(Binder.getCallingUid())
|
|
||||||
Log.d(TAG, "$app requests ModuleProvider")
|
|
||||||
return when (method) {
|
|
||||||
"getBinder" -> Bundle().apply {
|
|
||||||
putBinder("binder", ManagerService.asBinder())
|
|
||||||
}
|
|
||||||
else -> throw IllegalArgumentException("Invalid method name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun query(p0: Uri, p1: Array<out String>?, p2: String?, p3: Array<out String>?, 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<out String>?): Int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array<out String>?): Int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.res.CompatibilityInfo;
|
import android.content.res.CompatibilityInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
@ -63,7 +64,7 @@ public class LSPApplication {
|
||||||
return (android.os.Process.myUid() % PER_USER_RANGE) >= FIRST_APP_ZYGOTE_ISOLATED_UID;
|
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()) {
|
if (isIsolated()) {
|
||||||
XLog.d(TAG, "Skip isolated process");
|
XLog.d(TAG, "Skip isolated process");
|
||||||
return;
|
return;
|
||||||
|
|
@ -75,30 +76,27 @@ public class LSPApplication {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
Log.d(TAG, "Initialize service client");
|
||||||
Log.d(TAG, "Initialize service client");
|
ILSPApplicationService service;
|
||||||
ILSPApplicationService service;
|
if (config.useManager) {
|
||||||
if (config.useManager) {
|
service = new RemoteApplicationService(context);
|
||||||
service = new RemoteApplicationService(context);
|
} else {
|
||||||
} else {
|
service = new LocalApplicationService(context);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
Log.i(TAG, "LSPatch bootstrap completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,82 @@
|
||||||
package org.lsposed.lspatch.service;
|
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.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.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.lsposed.lspatch.share.Constants;
|
||||||
import org.lsposed.lspd.models.Module;
|
import org.lsposed.lspd.models.Module;
|
||||||
import org.lsposed.lspd.service.ILSPApplicationService;
|
import org.lsposed.lspd.service.ILSPApplicationService;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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 {
|
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 {
|
public RemoteApplicationService(Context context) throws RemoteException {
|
||||||
try {
|
try {
|
||||||
Bundle back = context.getContentResolver().call(PROVIDER, "getBinder", null, null);
|
var intent = new Intent()
|
||||||
service = ILSPApplicationService.Stub.asInterface(back.getBinder("binder"));
|
.setComponent(new ComponentName(Constants.MANAGER_PACKAGE_NAME, MODULE_SERVICE))
|
||||||
} catch (IllegalArgumentException | NullPointerException e) {
|
.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();
|
Toast.makeText(context, "Manager died", Toast.LENGTH_SHORT).show();
|
||||||
var r = new RemoteException("Failed to get manager binder");
|
var r = new RemoteException("Failed to get manager binder");
|
||||||
r.initCause(e);
|
r.initCause(e);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue