asLody/VirtualApp · error · java.lang.SecurityException

Caller has no access to session

Error message

Caller has no access to session 

What it means

Session handles in VPackageInstallerService are owner-scoped: updateSessionAppIcon looks up the session and requires that the caller's UID equals the session's creator UID (isCallingUidOwner). If the session doesn't exist or the caller isn't its owner, it throws SecurityException('Caller has no access to session ' + sessionId).

Solutions

  1. Verify the sessionId came from createSession in the same process/UID and is still active.
  2. Set the app icon in the SessionParams before createSession instead of mutating afterwards.
  3. Handle the SecurityException by re-creating the session rather than retrying with the same ID.
  4. If cross-process control is needed, route the call through the owning process.

Example fix

// before
installer.updateSessionAppIcon(42, icon); // SecurityException if not owner/session gone

// after
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setAppIcon(icon);
int sessionId = installer.createSession(params); // icon set at creation, owned by this UID
Defensive patterns

Strategy: try-catch

Validate before calling

// Only touch sessionIds returned by createSession in this process
if (!ownedSessions.contains(sessionId)) {
    throw new SecurityException("Not the owner of session " + sessionId);
}

Type guard

boolean ownsSession(Set<Integer> owned, int sessionId) { return owned.contains(sessionId); }

Try / catch

try {
    installer.updateSessionAppIcon(sessionId, icon);
} catch (SecurityException e) {
    if (String.valueOf(e.getMessage()).startsWith("Caller has no access to session")) {
        // recreate the session with icon set in params
    } else throw e;
}

Prevention

When it happens

Trigger: Calling updateSessionAppIcon(sessionId, icon) with an expired/invalid sessionId, or from a different UID/process than the one that created the session.

Common situations: Two app processes (or an app and a service) sharing session IDs; session already finished/abandoned and its ID recycled or removed; using a hardcoded sessionId copied from another app's flow; VirtualApp multi-user setups calling across user/UID boundaries.

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/89402a4b25e270a7. Report an issue: GitHub.

Appendix: source

Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/VPackageInstallerService.java:129

            // Sanity check that installer isn't going crazy
            final int activeCount = getSessionCount(mSessions, callingUid);
            if (activeCount >= MAX_ACTIVE_SESSIONS) {
                throw new IllegalStateException(
                        "Too many active sessions for UID " + callingUid);
            }
            sessionId = allocateSessionIdLocked();
            session = new PackageInstallerSession(mInternalCallback, mContext, mInstallHandler.getLooper(), installerPackageName, sessionId, userId, callingUid, params, VEnvironment.getPackageInstallerStageDir());
        }
        mCallbacks.notifySessionCreated(session.sessionId, session.userId);
        return sessionId;
    }

    @Override
    public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
        synchronized (mSessions) {
            final PackageInstallerSession session = mSessions.get(sessionId);
            if (session == null || !isCallingUidOwner(session)) {
                throw new SecurityException("Caller has no access to session " + sessionId);
            }

            session.params.appIcon = appIcon;
            session.params.appIconLastModified = -1;

            mInternalCallback.onSessionBadgingChanged(session);
        }
    }

    @Override
    public void updateSessionAppLabel(int sessionId, String appLabel) throws RemoteException {
        synchronized (mSessions) {
            final PackageInstallerSession session = mSessions.get(sessionId);
            if (session == null || !isCallingUidOwner(session)) {
                throw new SecurityException("Caller has no access to session " + sessionId);
            }
            session.params.appLabel = appLabel;
            mInternalCallback.onSessionBadgingChanged(session);

View on GitHub (pinned to 666fefcb5d)