asLody/VirtualApp · error · SecurityException

Who are you?

Error message

Who are you?

What it means

acquireProviderClient() resolves the calling process via VActivityManagerService's mPidsSelfLocked map. If findProcessLocked(getCallingPid()) returns null, the caller is not a process VirtualApp spawned or recorded, and it throws SecurityException("Who are you?") to reject untrusted/unregistered callers.

Solutions

  1. Ensure the caller process is started through VirtualApp's VActivityManager/StubActivity path so its ProcessRecord is registered in mPidsSelfLocked.
  2. Retry after the process has fully initialized; if the process was killed, restart it via the virtual framework before accessing providers.
  3. Verify provider access goes through the in-app ContentResolver (virtualized), not a raw cross-app binder call from an unmanaged process.
  4. Check for races: acquire the provider after ActivityThread/daemon installProvider startup completes, or add the caller record earlier in process setup.

Example fix

// before (raw call from an unregistered process)
IBinder client = vAms.acquireProviderClient(userId, providerInfo);
// after (go through the virtualized resolver in the managed process)
ContentResolver resolver = getContext().getContentResolver();
Cursor c = resolver.query(VirtualAppProvider.uriFor(userId, providerInfo), ...);
Defensive patterns

Strategy: retry

Validate before calling

ProcessRecord rec = VActivityManagerService.get().findProcessLocked(android.os.Process.myPid());
if (rec == null) {
    throw new IllegalStateException("Process not registered with VirtualApp; cannot acquire provider client");
}

Try / catch

try {
    IBinder client = vAms.acquireProviderClient(userId, providerInfo);
} catch (SecurityException e) {
    if ("Who are you?".equals(e.getMessage())) {
        // caller not registered: re-attach/restart the process via VirtualApp then retry once
        vAms.startProcessIfNeedLocked(processName, userId, packageName);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: A process whose PID is not in VActivityManagerService's process table requests a provider client: the call is made from a process not launched through VirtualApp (e.g. an outside app binding the service directly), the ProcessRecord was removed (process killed/restarted) before acquireProviderClient ran, or the provider request races with process startup.

Common situations: ContentProvider access from a newly forked app process before VActivityManager registered it; multi-process apps where a secondary process was started natively (not via VirtualApp); timing issues after the virtual process was killed by the system and re-attached without re-registering.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/am/VActivityManagerService.java:240

            while (iterator.hasNext()) {
                ServiceRecord r = iterator.next();
                if (r.process != null && r.process.pid == record.pid) {
                    iterator.remove();
                }
            }
            mMainStack.processDied(record);
        }
    }


    @Override
    public IBinder acquireProviderClient(int userId, ProviderInfo info) {
        ProcessRecord callerApp;
        synchronized (mPidsSelfLocked) {
            callerApp = findProcessLocked(getCallingPid());
        }
        if (callerApp == null) {
            throw new SecurityException("Who are you?");
        }
        String processName = info.processName;
        ProcessRecord r;
        synchronized (this) {
            r = startProcessIfNeedLocked(processName, userId, info.packageName);
        }
        if (r != null && r.client.asBinder().isBinderAlive()) {
            try {
                return r.client.acquireProviderClient(info);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public ComponentName getCallingActivity(int userId, IBinder token) {

View on GitHub (pinned to 666fefcb5d)