Support RootService on stub APKs

This commit is contained in:
topjohnwu
2021-12-13 03:57:27 -08:00
parent edcf9f1b0c
commit 54e3f1998a
9 changed files with 130 additions and 68 deletions
@@ -13,11 +13,6 @@ import io.michaelrocks.paranoid.Obfuscate;
@Obfuscate
public class DynAPK {
// Indices of the object array
private static final int STUB_VERSION_ENTRY = 0;
private static final int CLASS_COMPONENT_MAP = 1;
private static File dynDir;
private static Method addAssetPath;
@@ -41,21 +36,6 @@ public class DynAPK {
return new File(getDynDir(c), "update.apk");
}
public static Data load(Object o) {
Object[] arr = (Object[]) o;
Data data = new Data();
data.version = (int) arr[STUB_VERSION_ENTRY];
data.classToComponent = (Map<String, String>) arr[CLASS_COMPONENT_MAP];
return data;
}
public static Object pack(Data data) {
Object[] arr = new Object[2];
arr[STUB_VERSION_ENTRY] = data.version;
arr[CLASS_COMPONENT_MAP] = data.classToComponent;
return arr;
}
public static void addAssetPath(AssetManager asset, String path) {
try {
if (addAssetPath == null)
@@ -65,7 +45,28 @@ public class DynAPK {
}
public static class Data {
public int version;
public Map<String, String> classToComponent;
// Indices of the object array
private static final int STUB_VERSION = 0;
private static final int CLASS_COMPONENT_MAP = 1;
private static final int ROOT_SERVICE = 2;
private static final int ARR_SIZE = 3;
private final Object[] arr;
public Data() { arr = new Object[ARR_SIZE]; }
public Data(Object o) { arr = (Object[]) o; }
public Object getObject() { return arr; }
public int getVersion() { return (int) arr[STUB_VERSION]; }
public void setVersion(int version) { arr[STUB_VERSION] = version; }
public Map<String, String> getClassToComponent() {
// noinspection unchecked
return (Map<String, String>) arr[CLASS_COMPONENT_MAP];
}
public void setClassToComponent(Map<String, String> map) {
arr[CLASS_COMPONENT_MAP] = map;
}
public Class<?> getRootService() { return (Class<?>) arr[ROOT_SERVICE]; }
public void setRootService(Class<?> service) { arr[ROOT_SERVICE] = service; }
}
}
@@ -22,16 +22,15 @@ import kotlin.system.exitProcess
open class App() : Application() {
constructor(o: Any) : this() {
Info.stub = DynAPK.load(o)
val data = DynAPK.Data(o)
// Add the root service name mapping
data.classToComponent[RootRegistry::class.java.name] = data.rootService.name
// Send back the actual root service class
data.rootService = RootRegistry::class.java
Info.stub = data
}
init {
Shell.setDefaultBuilder(Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit::class.java)
.setTimeout(2))
Shell.EXECUTOR = IODispatcherExecutor()
// Always log full stack trace with Timber
Timber.plant(Timber.DebugTree())
Thread.setDefaultUncaughtExceptionHandler { _, e ->
@@ -41,6 +40,12 @@ open class App() : Application() {
}
override fun attachBaseContext(base: Context) {
Shell.setDefaultBuilder(Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit::class.java)
.setTimeout(2))
Shell.EXECUTOR = IODispatcherExecutor()
// Some context magic
val app: Application
val impl: Context
@@ -10,7 +10,11 @@ import timber.log.Timber
import java.util.concurrent.CountDownLatch
import kotlin.system.exitProcess
class RootRegistry : RootService() {
class RootRegistry(stub: Any?) : RootService() {
constructor() : this(null)
private val className: String? = stub?.javaClass?.name
init {
// Always log full stack trace with Timber
@@ -26,6 +30,10 @@ class RootRegistry : RootService() {
return Binder()
}
override fun getComponentName(): ComponentName {
return ComponentName(packageName, className ?: javaClass.name)
}
// TODO: PLACEHOLDER
object Connection : CountDownLatch(1), ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {