Commit 91e33bab authored by Torne (Richard Coles)'s avatar Torne (Richard Coles) Committed by Commit Bot

Fix data dir lock handling on old OS versions.

Older versions of Android implement file locking incorrectly in the
Java standard library: they throw IOException instead of returning null
when the lock is already held by another process. This causes us to
crash when the lock is already held, without attempting to retry or
considering whether we're intending to crash vs warn.

Catch and ignore the exception when it comes from the tryLock call, and
only consider IOException fatal when it's thrown by the RandomAccessFile
constructor.

Bug: 558377
Fixed: 1048982
Change-Id: I66c5665a8e94e2713233b9799db6694ce5bfa077
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2050366
Commit-Queue: Richard Coles <torne@chromium.org>
Commit-Queue: Tobias Sargeant <tobiasjs@chromium.org>
Auto-Submit: Richard Coles <torne@chromium.org>
Reviewed-by: default avatarTobias Sargeant <tobiasjs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740287}
parent 9a0d3224
...@@ -48,32 +48,37 @@ abstract class AwDataDirLock { ...@@ -48,32 +48,37 @@ abstract class AwDataDirLock {
try { try {
// Note that the file is kept open intentionally. // Note that the file is kept open intentionally.
sLockFile = new RandomAccessFile(lockFile, "rw"); sLockFile = new RandomAccessFile(lockFile, "rw");
// Some Android versions may have a race where a new instance of an app process can
// be started while an existing one is still in the process of being killed. Retry
// the lock a few times to give the old process time to fully go away.
for (int attempts = 1; attempts <= LOCK_RETRIES; ++attempts) {
sExclusiveFileLock = sLockFile.getChannel().tryLock();
if (sExclusiveFileLock != null) {
// We got the lock; write out info for debugging.
writeCurrentProcessInfo(sLockFile);
recordLockAttempts(attempts);
return;
}
// If we're not out of retries, sleep and try again.
if (attempts == LOCK_RETRIES) break;
try {
Thread.sleep(LOCK_SLEEP_MS);
} catch (InterruptedException e) {
}
}
} catch (IOException e) { } catch (IOException e) {
// Failing to create the lock file is always fatal; even if multiple processes are // Failing to create the lock file is always fatal; even if multiple processes are
// using the same data directory we should always be able to access the file itself. // using the same data directory we should always be able to access the file itself.
throw new RuntimeException("Failed to create lock file " + lockFile, e); throw new RuntimeException("Failed to create lock file " + lockFile, e);
} }
// Some Android versions may have a race where a new instance of an app process can
// be started while an existing one is still in the process of being killed. Retry
// the lock a few times to give the old process time to fully go away.
for (int attempts = 1; attempts <= LOCK_RETRIES; ++attempts) {
try {
sExclusiveFileLock = sLockFile.getChannel().tryLock();
} catch (IOException e) {
// Older versions of Android incorrectly throw IOException when the flock()
// call fails with EAGAIN, instead of returning null. Just ignore it.
}
if (sExclusiveFileLock != null) {
// We got the lock; write out info for debugging.
writeCurrentProcessInfo(sLockFile);
recordLockAttempts(attempts);
return;
}
// If we're not out of retries, sleep and try again.
if (attempts == LOCK_RETRIES) break;
try {
Thread.sleep(LOCK_SLEEP_MS);
} catch (InterruptedException e) {
}
}
// We failed to get the lock even after retrying. // We failed to get the lock even after retrying.
// Many existing apps rely on this even though it's known to be unsafe. // Many existing apps rely on this even though it's known to be unsafe.
// Make it fatal when on P for apps that target P or higher // Make it fatal when on P for apps that target P or higher
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment