{"record":{"id":"33998c11abadc8a2","repo":"asLody/VirtualApp","slug":"files-still-open","errorCode":null,"errorMessage":"Files still open","messagePattern":"Files still open","errorType":"exception","errorClass":"java.lang.SecurityException","httpStatus":null,"severity":"error","filePath":"VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java","lineNumber":392,"sourceCode":"    }\n\n    @Override\n    public void close() throws RemoteException {\n        if (mActiveCount.decrementAndGet() == 0) {\n            mCallback.onSessionActiveChanged(this, false);\n        }\n    }\n\n    @Override\n    public void commit(IntentSender statusReceiver) throws RemoteException {\n        final boolean wasSealed;\n        synchronized (mLock) {\n            wasSealed = mSealed;\n            if (!mSealed) {\n                // Verify that all writers are hands-off\n                for (FileBridge bridge : mBridges) {\n                    if (!bridge.isClosed()) {\n                        throw new SecurityException(\"Files still open\");\n                    }\n                }\n                mSealed = true;\n            }\n\n            // Client staging is fully done at this point\n            mClientProgress = 1f;\n            computeProgressLocked(true);\n        }\n\n        if (!wasSealed) {\n            // Persist the fact that we've sealed ourselves to prevent\n            // mutations of any hard links we create. We do this without holding\n            // the session lock, since otherwise it's a lock inversion.\n            mCallback.onSessionSealedBlocking(this);\n        }\n\n        // This ongoing commit should keep session active, even though client","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/asLody/VirtualApp/blob/666fefcb5d3f39cc944001c3457c38ffd6544c87/VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/installer/PackageInstallerSession.java#L374-L410","documentation":"commit() seals the session, but first requires that every active FileBridge (the write stream bridge for openWrite) is closed. If any writer still holds an open bridge, it throws SecurityException('Files still open') and refuses to seal, protecting against installing a partially written APK.","triggerScenarios":"Calling session.commit() while an OutputStream from openWrite() is still open (not closed/flushed); leaking a stream on an exception path; another thread still mid-write.","commonSituations":"Exception during APK copy leaves stream unclosed, later commit fails; writing multiple splits and forgetting to close one; asynchronous copy tasks not joined before commit.","solutions":["Close every OutputStream returned by openWrite() (use try-with-resources) before commit().","On failure paths, close streams in a finally block or call session.abandon() and start over.","Await/join all background copy tasks before invoking commit()."],"exampleFix":"// before\nOutputStream out = session.openWrite(\"base.apk\", 0, -1);\nout.write(apkBytes);\nsession.commit(callback); // SecurityException: Files still open\n\n// after\ntry (OutputStream out = session.openWrite(\"base.apk\", 0, -1)) {\n    out.write(apkBytes);\n    out.flush();\n}\nsession.commit(callback);","handlingStrategy":"try-catch","validationCode":"// Ensure all openWrite streams closed before commit\nSet<OutputStream> openStreams; // maintained by your wrapper\nif (!openStreams.isEmpty()) {\n    openStreams.forEach(IOUtils::closeQuietly);\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.commit(statusReceiver);\n} catch (SecurityException e) {\n    if (String.valueOf(e.getMessage()).contains(\"Files still open\")) {\n        closeAllStreams();\n        session.abandon(); // or re-commit after closing if still valid\n    } else throw e;\n}","preventionTips":["Use try-with-resources for every openWrite() stream.","Join background copy threads before commit().","Wrap writes so exceptions always close streams (finally)."],"tags":["security-exception","unclosed-stream","package-installer","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"}