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
- Verify the sessionId came from createSession in the same process/UID and is still active.
- Set the app icon in the SessionParams before createSession instead of mutating afterwards.
- Handle the SecurityException by re-creating the session rather than retrying with the same ID.
- 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
- Set appIcon via SessionParams at creation time instead of updating later.
- Never hardcode or share sessionIds across processes.
- Treat finished/abandoned sessions as inaccessible; re-create when needed.
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
- not allowed after commit
- Files still open
- Must be sealed to accept permissions
- Unable to create application
- Unable to start receiver
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)