asLody/VirtualApp · error · IllegalStateException

VirtualCore.startup() must called in main thread.

Error message

VirtualCore.startup() must called in main thread.

What it means

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.

Solutions

  1. Move the startup() call to Application.onCreate() on the main thread
  2. If async init is required, post the startup call to the main Handler: new Handler(Looper.getMainLooper()).post(...)
  3. Never wrap startup in background executors; the check is deliberate because hooking must happen before other main-thread activity

Example fix

// before
new Thread(() -> { VirtualCore.get().startup(this); }).start();
// after
@Override public void onCreate() { super.onCreate(); VirtualCore.get().startup(this); }
Defensive patterns

Strategy: validation

Validate before calling

if (Looper.myLooper() == Looper.getMainLooper()) { VirtualCore.get().startup(context); } else { new Handler(Looper.getMainLooper()).post(() -> VirtualCore.get().startup(context)); }

Try / catch

try { VirtualCore.get().startup(ctx); } catch (IllegalStateException e) { new Handler(Looper.getMainLooper()).post(() -> { try { VirtualCore.get().startup(ctx); } catch (Throwable t) { /* fatal */ } }); }

Prevention

When it happens

Trigger: Calling VirtualCore.get().startup(context) from a background thread, AsyncTask, IntentService, or any thread whose Looper differs from Looper.getMainLooper().

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09). Data as JSON: /api/errors/c1f531c50e5d8636. Report an issue: GitHub.

Appendix: source

Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/client/core/VirtualCore.java:177

    }

    public PackageManager getPackageManager() {
        return context.getPackageManager();
    }

    public String getHostPkg() {
        return hostPkgName;
    }

    public PackageManager getUnHookPackageManager() {
        return unHookPackageManager;
    }


    public void startup(Context context) throws Throwable {
        if (!isStartUp) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                throw new IllegalStateException("VirtualCore.startup() must called in main thread.");
            }
            VASettings.STUB_CP_AUTHORITY = context.getPackageName() + "." + VASettings.STUB_DEF_AUTHORITY;
            ServiceManagerNative.SERVICE_CP_AUTH = context.getPackageName() + "." + ServiceManagerNative.SERVICE_DEF_AUTH;
            this.context = context;
            mainThread = ActivityThread.currentActivityThread.call();
            unHookPackageManager = context.getPackageManager();
            hostPkgInfo = unHookPackageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);
            IPCBus.initialize(new IServerCache() {
                @Override
                public void join(String serverName, IBinder binder) {
                    ServiceCache.addService(serverName, binder);
                }

                @Override
                public IBinder query(String serverName) {
                    return ServiceManagerNative.getService(serverName);
                }
            });

View on GitHub (pinned to 666fefcb5d)