asLody/VirtualApp · error · SecurityException
not allowed after commit
Error message
not allowed after commit
What it means
After commit() runs, the session sets mSealed = true; the same assertPreparedAndNotSealed guard then throws SecurityException('<cookie> not allowed after commit') for any subsequent openWrite/openRead/getNames. Sealing freezes the staged payload so the install pass sees a consistent set of APK files.
Solutions
- Do not call openWrite/openRead after commit(); create a new session if more data must be staged.
- Finish all writes and close all streams before calling commit().
- If commit failed, abandon() the session, create a fresh one via createSession, and re-stage everything.
Example fix
// before
session.commit(callback);
OutputStream out = session.openWrite("split2.apk", 0, -1); // SecurityException
// after
try (OutputStream out = session.openWrite("split2.apk", 0, -1)) {
out.write(splitBytes);
}
session.commit(callback); Defensive patterns
Strategy: try-catch
Validate before calling
// Track commit state; never call openWrite/openRead after commit()
if (committed) throw new IllegalStateException("Session already committed"); Try / catch
try {
stream = session.openWrite(name, offset, length);
} catch (SecurityException e) {
if (String.valueOf(e.getMessage()).endsWith("not allowed after commit")) {
// create a fresh session and re-stage
} else throw e;
} Prevention
- Close all write streams before commit() (try-with-resources).
- Mark session objects as committed in your wrapper and refuse further IO.
- Recreate a new session instead of reusing a committed one.
When it happens
Trigger: Calling openWrite/openRead/getNames after commit() (or after setPermissionsResult-triggered re-seal); trying to append more data or list files once the session has been submitted for install.
Common situations: Retry logic that re-opens the stream after a failed commit; writing remaining split APKs after commit was already called; keeping a stale session handle around and reusing it post-commit.
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
- Files still open
- before prepared
- Invalid name:
- Must be sealed to accept permissions
- Exactly one of stageDir or stageCid stage must be set
AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09).
Data as JSON: /api/errors/48714c6396ded0fb.
Report an issue: GitHub.
Appendix: source
Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java:283
}
}
@Override
public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) throws RemoteException {
try {
return openWriteInternal(name, offsetBytes, lengthBytes);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
private void assertPreparedAndNotSealed(String cookie) {
synchronized (mLock) {
if (!mPrepared) {
throw new IllegalStateException(cookie + " before prepared");
}
if (mSealed) {
throw new SecurityException(cookie + " not allowed after commit");
}
}
}
private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
throws IOException {
// Quick sanity check of state, and allocate a pipe for ourselves. We
// then do heavy disk allocation outside the lock, but this open pipe
// will block any attempted install transitions.
final FileBridge bridge;
synchronized (mLock) {
assertPreparedAndNotSealed("openWrite");
bridge = new FileBridge();
mBridges.add(bridge);
}
try {View on GitHub (pinned to 666fefcb5d)