1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org
.chromium
.incrementalinstall
;
7 import android
.util
.Log
;
10 import java
.io
.FileOutputStream
;
11 import java
.io
.IOException
;
12 import java
.nio
.channels
.FileLock
;
13 import java
.util
.concurrent
.Callable
;
16 * Helpers for dealing with .lock files used during install / first run.
18 final class LockFile
{
19 private static final String TAG
= "cr.incrementalinstall";
21 private final File mFile
;
22 private final FileOutputStream mOutputStream
;
23 private final FileLock mFileLock
;
25 private LockFile(File file
, FileOutputStream outputStream
, FileLock fileLock
) {
27 mOutputStream
= outputStream
;
32 * Clears the lock file by writing to it (making it non-zero in length);
34 static void clearInstallerLock(File lockFile
) throws IOException
{
35 Log
.i(TAG
, "Clearing " + lockFile
);
36 // On Android M+, we can't delete files in /data/local/tmp, so we write to it instead.
37 FileOutputStream os
= new FileOutputStream(lockFile
);
43 * Waits for the given file to be non-zero in length.
45 static void waitForInstallerLock(final File file
, long timeoutMs
) {
46 pollingWait(new Callable
<Boolean
>() {
47 @Override public Boolean
call() {
48 return !installerLockExists(file
);
54 * Waits for the given file to be non-zero in length.
56 private static void pollingWait(Callable
<Boolean
> func
, File file
, long timeoutMs
) {
57 long pollIntervalMs
= 200;
58 for (int i
= 0; i
< timeoutMs
/ pollIntervalMs
; i
++) {
62 Log
.i(TAG
, "Finished waiting on lock file: " + file
);
66 Log
.i(TAG
, "Waiting on lock file: " + file
);
68 } catch (Exception e
) {
69 throw new RuntimeException(e
);
72 Thread
.sleep(pollIntervalMs
);
73 } catch (InterruptedException e
) {
74 // Should never happen.
77 throw new RuntimeException("Timed out waiting for lock file: " + file
);
81 * Returns whether the given lock file is missing or is in the locked state.
83 static boolean installerLockExists(File file
) {
84 return !file
.exists() || file
.length() == 0;
88 * Attempts to acquire a lock for the given file.
89 * @return Returns the FileLock if it was acquired, or null otherwise.
91 static LockFile
acquireRuntimeLock(File file
) {
93 FileOutputStream outputStream
= new FileOutputStream(file
);
94 FileLock lock
= outputStream
.getChannel().tryLock();
96 Log
.i(TAG
, "Created lock file: " + file
);
97 return new LockFile(file
, outputStream
, lock
);
100 } catch (IOException e
) {
101 // Do nothing. We didn't get the lock.
107 * Waits for the given file to not exist.
109 static void waitForRuntimeLock(final File file
, long timeoutMs
) {
110 pollingWait(new Callable
<Boolean
>() {
111 @Override public Boolean
call() {
112 return !file
.exists();
118 * Releases and deletes the lock file.
120 void release() throws IOException
{
121 Log
.i(TAG
, "Deleting lock file: " + mFile
);
123 mOutputStream
.close();
124 if (!mFile
.delete()) {
125 throw new IOException("Failed to delete lock file: " + mFile
);