fix: run Module.onContext properly for recreated processes

This commit is contained in:
PalmDevs 2025-10-13 02:52:19 +07:00
parent 4de1a97144
commit 3ec9b9a4f7
No known key found for this signature in database
GPG key ID: 6FAE8F8677ACA8BA
2 changed files with 27 additions and 7 deletions

View file

@ -16,8 +16,19 @@ import io.github.revenge.xposed.modules.bridge.AdditionalBridgeMethodsModule
import io.github.revenge.xposed.modules.bridge.BridgeModule
import kotlinx.coroutines.CompletableDeferred
object HookReadyHolder {
val deferred = CompletableDeferred<Unit>()
object HookStateHolder {
/**
* Whether all hooks are completed, and we are ready to load the JS bundle.
*/
val readyDeferred = CompletableDeferred<Unit>()
/**
* Whether we have successfully received a [Context] yet.
* Sometimes the app process is recreated and Xposed hooks way too late for us to get [Context] from [ContextWrapper.attachBaseContext].
* But since Xposed hooks before [Activity.onCreate], we can still get it from there and still initialize properly.
*/
@Volatile
var gotContext = false
}
class Main : Module(), IXposedHookLoadPackage, IXposedHookZygoteInit {
@ -51,16 +62,25 @@ class Main : Module(), IXposedHookLoadPackage, IXposedHookZygoteInit {
ContextWrapper::class.java.hookMethod("attachBaseContext", Context::class.java) {
after {
val ctx = args[0] as Context
HookStateHolder.gotContext = true
Log.i("Received Context")
this@Main.onContext(args[0] as Context)
this@Main.onContext(ctx)
}
}
reactActivity.hookMethod("onCreate", Bundle::class.java) {
after {
val act = thisObject as Activity
Log.i("Received Activity")
this@Main.onActivity(thisObject as Activity)
HookReadyHolder.deferred.complete(Unit)
if (!HookStateHolder.gotContext) {
Log.w("Activity created before we got Context, process may have been recreated!")
this@Main.onContext(act.applicationContext)
}
this@Main.onActivity(act)
HookStateHolder.readyDeferred.complete(Unit)
}
}

View file

@ -6,7 +6,7 @@ import de.robv.android.xposed.IXposedHookZygoteInit
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage
import io.github.revenge.xposed.Constants
import io.github.revenge.xposed.HookReadyHolder
import io.github.revenge.xposed.HookStateHolder
import io.github.revenge.xposed.Module
import io.github.revenge.xposed.Utils.Log
import io.github.revenge.xposed.modules.HookScriptLoaderModule.Companion.PRELOADS_DIR
@ -88,7 +88,7 @@ class HookScriptLoaderModule : Module() {
Log.i("Running custom scripts...")
runBlocking {
val ready = async { HookReadyHolder.deferred.join() }
val ready = async { HookStateHolder.readyDeferred.join() }
val download = async { UpdaterModule.downloadScript().join() }
awaitAll(ready, download)