asLody/VirtualApp · error · java.lang.IllegalStateException
Too many active sessions for UID
Error message
Too many active sessions for UID
What it means
VPackageInstallerService caps concurrently active (non-finalized) install sessions per calling UID at MAX_ACTIVE_SESSIONS. createSessionInternal counts existing sessions for callingUid and, if at the cap, throws IllegalStateException('Too many active sessions for UID ' + callingUid) to stop a runaway installer from exhausting storage/session IDs.
Solutions
- Call session.abandon() on sessions you will not commit (especially in catch/finally blocks).
- Serialize installs: commit or abandon the current session before creating the next.
- Track and clean up leaked sessions from previous runs (e.g. via PackageInstaller.getAllSessions / mySessions and abandon stale ones).
Example fix
// before
for (File apk : apks) {
int id = installer.createSession(params);
writeApk(installer.openSession(id), apk); // may fail -> session leaked
}
// after
for (File apk : apks) {
Session session = null;
try {
session = installer.openSession(installer.createSession(params));
writeApk(session, apk);
session.commit(callback);
session = null;
} finally {
if (session != null) session.abandon();
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Best effort pre-check of your own active session count before creating more List<SessionInfo> mine = installer.getMySessions(); long active = mine.stream().filter(s -> s.isActive()).count(); // if active >= MAX_ACTIVE_SESSIONS, abandon stale sessions first
Try / catch
try {
sessionId = installer.createSession(params);
} catch (IllegalStateException e) {
if (String.valueOf(e.getMessage()).startsWith("Too many active sessions")) {
abandonStaleSessions();
sessionId = installer.createSession(params);
} else throw e;
} Prevention
- abandon() sessions in finally blocks on failure.
- Commit or abandon each session before creating the next.
- Clean up orphaned sessions at app startup.
When it happens
Trigger: Calling createSession repeatedly without commit()ing or abandon()ing previous sessions until activeCount >= MAX_ACTIVE_SESSIONS for the app's UID.
Common situations: Retry loops that create a new session on each failure and never abandon the failed ones; app crash leaving orphaned active sessions that still count; parallel installs of many APKs in one process.
Related errors
- before prepared
- Must specify package name to remove a split
- Unable to create application
- Unable to start receiver
- VirtualCore.startup() must called in main thread.
AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09).
Data as JSON: /api/errors/ef74432bc2283eb5.
Report an issue: GitHub.
Appendix: source
Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/VPackageInstallerService.java:114
@Override
public int createSession(SessionParams params, String installerPackageName, int userId) throws RemoteException {
try {
return createSessionInternal(params, installerPackageName, userId);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
throws IOException {
final int callingUid = VBinder.getCallingUid();
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// 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;View on GitHub (pinned to 666fefcb5d)