{"record":{"id":"acad970982df8026","repo":"Tencent/tinker","slug":"tinker-exception-filelockhelper-lock-file-failed","errorCode":null,"errorMessage":"Tinker Exception:FileLockHelper lock file failed: {}","messagePattern":"Tinker Exception:FileLockHelper lock file failed: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/ShareFileLockHelper.java","lineNumber":66,"sourceCode":"                if (isGetLockSuccess) {\n                    break;\n                }\n\n            } catch (Exception e) {\n                saveException = e;\n                ShareTinkerLog.e(TAG, \"getInfoLock Thread failed time:\" + LOCK_WAIT_EACH_TIME);\n            }\n\n            //it can just sleep 0, afraid of cpu scheduling\n            try {\n                Thread.sleep(LOCK_WAIT_EACH_TIME);\n            } catch (Exception ignore) {\n                ShareTinkerLog.e(TAG, \"getInfoLock Thread sleep exception\", ignore);\n            }\n        }\n\n        if (localFileLock == null) {\n            throw new IOException(\"Tinker Exception:FileLockHelper lock file failed: \" + lockFile.getAbsolutePath(), saveException);\n        }\n        fileLock = localFileLock;\n    }\n\n    public static ShareFileLockHelper getFileLock(File lockFile) throws IOException {\n        return new ShareFileLockHelper(lockFile);\n    }\n\n    @Override\n    public void close() throws IOException {\n        try {\n            if (fileLock != null) {\n                fileLock.release();\n            }\n        } finally {\n            if (outputStream != null) {\n                outputStream.close();\n            }","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/ShareFileLockHelper.java#L48-L84","documentation":"ShareFileLockHelper's constructor tries to acquire an exclusive FileLock on the lock file, retrying with Thread.sleep(LOCK_WAIT_EACH_TIME) up to a bounded number of attempts; the saveException from each try is kept. When all attempts fail it throws IOException('Tinker Exception:FileLockHelper lock file failed: <path>', saveException), exposing the last underlying failure (often OverlappingFileLockException, ClosedChannelException, or EMFILE too many open files).","triggerScenarios":"getFileLock(lockFile) called while another thread/process already holds the lock for longer than the total retry window; the lock file was deleted while held; the process ran out of file descriptors so the channel could not be opened; channel closed concurrently.","commonSituations":"Multiple processes (main + :patch + push) applying or loading patches simultaneously; a previous crash leaving the lock held; heavy FD usage leaking channels; tinker info file locking contended during patch apply on slow devices.","solutions":["Centralize patch apply/load operations in one process (e.g. only the main process or a dedicated :patch process) to remove lock contention.","Close every ShareFileLockHelper via try-with-resources/finally; leaked helpers hold locks and exhaust FDs.","Inspect the suppressed saveException cause: OverlappingFileLockException means same-JVM contention; Too many open files means an FD leak elsewhere in the app.","If a stale lock survives a crashed process, cleanPatch() or app restart releases it (FileLock releases on process death)."],"exampleFix":"// before (leaks lock, later callers fail)\nShareFileLockHelper fileLock = ShareFileLockHelper.getFileLock(lockFile);\nwriteInfo(info);\n// lock never closed\n\n// after\ntry (ShareFileLockHelper fileLock = ShareFileLockHelper.getFileLock(lockFile)) {\n    writeInfo(info);\n}","handlingStrategy":"fallback","validationCode":"public static void withLock(File lockFile, Callable<Void> body) throws IOException {\n    try (ShareFileLockHelper lock = ShareFileLockHelper.getFileLock(lockFile)) {\n        body.call();\n    } // always released\n}","typeGuard":null,"tryCatchPattern":"try (ShareFileLockHelper lock = ShareFileLockHelper.getFileLock(f)) {\n    doWork();\n} catch (IOException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"lock file failed\")) {\n        // contention or FD exhaustion: back off and retry later\n    }\n}","preventionTips":["Close every ShareFileLockHelper in finally / try-with-resources","Restrict patch operations to a single process","Watch for FD leaks (Too many open files as the saveException cause)"],"tags":["tinker","android","file-lock","concurrency","io"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}