{"record":{"id":"9e4e3069d1b88a01","repo":"asLody/VirtualApp","slug":"before-prepared","errorCode":null,"errorMessage":" before prepared","messagePattern":" before prepared","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java","lineNumber":280,"sourceCode":"                }\n            }\n            return mResolvedStageDir;\n        }\n    }\n\n    @Override\n    public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) throws RemoteException {\n        try {\n            return openWriteInternal(name, offsetBytes, lengthBytes);\n        } catch (IOException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private void assertPreparedAndNotSealed(String cookie) {\n        synchronized (mLock) {\n            if (!mPrepared) {\n                throw new IllegalStateException(cookie + \" before prepared\");\n            }\n            if (mSealed) {\n                throw new SecurityException(cookie + \" not allowed after commit\");\n            }\n        }\n    }\n\n\n    private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)\n            throws IOException {\n        // Quick sanity check of state, and allocate a pipe for ourselves. We\n        // then do heavy disk allocation outside the lock, but this open pipe\n        // will block any attempted install transitions.\n        final FileBridge bridge;\n        synchronized (mLock) {\n            assertPreparedAndNotSealed(\"openWrite\");\n\n            bridge = new FileBridge();","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/asLody/VirtualApp/blob/666fefcb5d3f39cc944001c3457c38ffd6544c87/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java#L262-L298","documentation":"PackageInstallerSession tracks session lifecycle with an mPrepared flag, set only when open() is called with a valid stageDir/stageCid. assertPreparedAndNotSealed guards getNames, openWrite, and openRead; if any of these is invoked before the session was prepared, it throws IllegalStateException('<cookie> before prepared'). The library enforces that a staging session must be opened/initialized before any file operations.","triggerScenarios":"Calling session.getNames(), session.openWrite(name,...) or session.openRead(name) on a PackageInstallerSession that was created but never had open(stageDir, userId) invoked, so mPrepared is still false.","commonSituations":"Obtaining a session object through an unusual path (e.g. reconstructed or looked-up session) and skipping the open() step; calling openWrite immediately after createSession without opening; race where another thread checks before the open() synchronized block completes.","solutions":["Call session.open(stageDir, currentUser.id) (or the service API that opens the session) before any openWrite/openRead/getNames call.","Use PackageInstaller.openSession(sessionId) to get a properly prepared session rather than constructing/holding the raw session object.","If managing sessions directly, verify session.mPrepared (or track your own 'opened' state) before file operations."],"exampleFix":"// before\nPackageInstallerSession session = createSession(params);\nOutputStream out = session.openWrite(\"base.apk\", 0, -1); // IllegalStateException\n\n// after\nPackageInstallerSession session = createSession(params);\nsession.open(new File(VEnvironment.getPackageInstallerStageDir(), String.valueOf(session.sessionId)), userId);\nOutputStream out = session.openWrite(\"base.apk\", 0, -1);","handlingStrategy":"validation","validationCode":"// Java: track session state yourself\nif (!sessionOpened) {\n    throw new IllegalStateException(\"Call open(stageDir, userId) before openWrite/openRead/getNames\");\n}","typeGuard":"// Java: wrap session and expose isOpened\nboolean isReady(PackageInstallerSession s) { return s != null && s.mPrepared; }","tryCatchPattern":"try {\n    stream = session.openWrite(name, offset, length);\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().endsWith(\"before prepared\")) {\n        session.open(stageDir, userId);\n        stream = session.openWrite(name, offset, length);\n    } else throw e;\n}","preventionTips":["Always open the session immediately after createSession.","Centralize session creation + open in one factory method.","Avoid caching raw session objects across calls."],"tags":["illegal-state","package-installer","lifecycle","android"],"backgroundTag":"invalid-state-transition","analyzedSha":"666fefcb5d3f39cc944001c3457c38ffd6544c87","analyzedAt":"2026-09-09T11:09:01.694Z","contentChangedAt":"2026-09-09T11:09:01.694Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}