Skip to content

Commit e3375f2

Browse files
committed
fixed a leak when cross process locking didn't close a file
An intermediate RandomAccessFile created while acquiring the lock was not closed. Also pulled the cross process locking logic out into a separate class.
1 parent f801a7e commit e3375f2

File tree

2 files changed

+59
-29
lines changed

2 files changed

+59
-29
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.installations;
16+
17+
import android.content.Context;
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.io.RandomAccessFile;
21+
import java.nio.channels.FileChannel;
22+
import java.nio.channels.FileLock;
23+
24+
/** Use file locking to acquire a lock that will also block other processes. */
25+
class CrossProcessLock {
26+
private final FileChannel channel;
27+
private final FileLock lock;
28+
29+
private CrossProcessLock(FileChannel channel, FileLock lock) {
30+
this.channel = channel;
31+
this.lock = lock;
32+
}
33+
34+
static CrossProcessLock acquire(Context appContext, String lockName) {
35+
try {
36+
File file = new File(appContext.getFilesDir(), lockName);
37+
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
38+
// Use the file channel to create a lock on the file.
39+
// This method blocks until it can retrieve the lock.
40+
FileLock lock = channel.lock();
41+
return new CrossProcessLock(channel, lock);
42+
} catch (IOException e) {
43+
throw new IllegalStateException("exception while using file locks, should never happen", e);
44+
}
45+
}
46+
47+
/** Release a previously acquired lock and free any underlying resources. */
48+
void releaseAndClose() {
49+
try {
50+
lock.release();
51+
channel.close();
52+
} catch (IOException e) {
53+
throw new IllegalStateException("exception while using file locks, should never happen", e);
54+
}
55+
}
56+
}

firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@
3333
import com.google.firebase.installations.remote.InstallationResponse;
3434
import com.google.firebase.installations.remote.TokenResult;
3535
import com.google.firebase.platforminfo.UserAgentPublisher;
36-
import java.io.File;
3736
import java.io.IOException;
38-
import java.io.RandomAccessFile;
39-
import java.nio.channels.FileChannel;
40-
import java.nio.channels.FileLock;
4137
import java.util.ArrayList;
4238
import java.util.Calendar;
4339
import java.util.Iterator;
@@ -311,7 +307,8 @@ private final void doRegistrationInternal(boolean forceRefresh) {
311307
* been persisted.
312308
*/
313309
private PersistedInstallationEntry getPrefsWithGeneratedIdMultiProcessSafe() {
314-
FileLock fileLock = getCrossProcessLock();
310+
CrossProcessLock lock = CrossProcessLock
311+
.acquire(firebaseApp.getApplicationContext(), LOCKFILE_NAME_GENERATE_FID);
315312
try {
316313
synchronized (lockGenerateFid) {
317314
PersistedInstallationEntry prefs =
@@ -332,30 +329,7 @@ private PersistedInstallationEntry getPrefsWithGeneratedIdMultiProcessSafe() {
332329
}
333330

334331
} finally {
335-
releaseCrossProcessLock(fileLock);
336-
}
337-
}
338-
339-
/** Use file locking to acquire a lock that will also block other processes. */
340-
FileLock getCrossProcessLock() {
341-
try {
342-
File file =
343-
new File(firebaseApp.getApplicationContext().getFilesDir(), LOCKFILE_NAME_GENERATE_FID);
344-
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
345-
// Use the file channel to create a lock on the file.
346-
// This method blocks until it can retrieve the lock.
347-
return channel.lock();
348-
} catch (IOException e) {
349-
throw new IllegalStateException("exception while using file locks, should never happen", e);
350-
}
351-
}
352-
353-
/** Release a previously acquired lock. */
354-
void releaseCrossProcessLock(FileLock fileLock) {
355-
try {
356-
fileLock.release();
357-
} catch (IOException e) {
358-
throw new IllegalStateException("exception while using file locks, should never happen", e);
332+
lock.releaseAndClose();
359333
}
360334
}
361335

0 commit comments

Comments
 (0)