{"record":{"id":"c1f531c50e5d8636","repo":"asLody/VirtualApp","slug":"virtualcore-startup-must-called-in-main-thread","errorCode":null,"errorMessage":"VirtualCore.startup() must called in main thread.","messagePattern":"VirtualCore\\.startup\\(\\) must called in main thread\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java","lineNumber":177,"sourceCode":"    }\n\n    public PackageManager getPackageManager() {\n        return context.getPackageManager();\n    }\n\n    public String getHostPkg() {\n        return hostPkgName;\n    }\n\n    public PackageManager getUnHookPackageManager() {\n        return unHookPackageManager;\n    }\n\n\n    public void startup(Context context) throws Throwable {\n        if (!isStartUp) {\n            if (Looper.myLooper() != Looper.getMainLooper()) {\n                throw new IllegalStateException(\"VirtualCore.startup() must called in main thread.\");\n            }\n            VASettings.STUB_CP_AUTHORITY = context.getPackageName() + \".\" + VASettings.STUB_DEF_AUTHORITY;\n            ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + \".\" + ServiceManagerNative.SERVICE_DEF_AUTH;\n            this.context = context;\n            mainThread = ActivityThread.currentActivityThread.call();\n            unHookPackageManager = context.getPackageManager();\n            hostPkgInfo = unHookPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);\n            IPCBus.initialize(new IServerCache() {\n                @Override\n                public void join(String serverName, IBinder binder) {\n                    ServiceCache.addService(serverName, binder);\n                }\n\n                @Override\n                public IBinder query(String serverName) {\n                    return ServiceManagerNative.getService(serverName);\n                }\n            });","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/asLody/VirtualApp/blob/666fefcb5d3f39cc944001c3457c38ffd6544c87/VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java#L159-L195","documentation":"VirtualCore.startup() hooks the app's main ActivityThread, PackageManager, and other main-thread-bound structures, so it must run on the Android main (UI) thread. If called from a worker thread it throws this IllegalStateException immediately, before any hooks are installed.","triggerScenarios":"Calling VirtualCore.get().startup(context) from a background thread, AsyncTask, IntentService, or any thread whose Looper differs from Looper.getMainLooper().","commonSituations":"Initializing the VA engine inside a coroutine, RxJava scheduler, or delayed Handler on a non-main looper; calling startup lazily from a background init SDK.","solutions":["Move the startup() call to Application.onCreate() on the main thread","If async init is required, post the startup call to the main Handler: new Handler(Looper.getMainLooper()).post(...)","Never wrap startup in background executors; the check is deliberate because hooking must happen before other main-thread activity"],"exampleFix":"// before\nnew Thread(() -> { VirtualCore.get().startup(this); }).start();\n// after\n@Override public void onCreate() { super.onCreate(); VirtualCore.get().startup(this); }","handlingStrategy":"validation","validationCode":"if (Looper.myLooper() == Looper.getMainLooper()) { VirtualCore.get().startup(context); } else { new Handler(Looper.getMainLooper()).post(() -> VirtualCore.get().startup(context)); }","typeGuard":null,"tryCatchPattern":"try { VirtualCore.get().startup(ctx); } catch (IllegalStateException e) { new Handler(Looper.getMainLooper()).post(() -> { try { VirtualCore.get().startup(ctx); } catch (Throwable t) { /* fatal */ } }); }","preventionTips":["Always call startup() from Application.onCreate()","Never initialize VA engine from background threads or coroutines on IO dispatchers","Check Looper.myLooper() before engine init if the call path is uncertain"],"tags":["android","threading","main-thread","initialization"],"backgroundTag":"invalid-state-transition","analyzedSha":"666fefcb5d3f39cc944001c3457c38ffd6544c87","analyzedAt":"2026-09-09T11:09:01.694Z","contentChangedAt":"2026-09-09T11:09:01.694Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}