Merge "Add a lock when writing temporary files in BootReceiver" into main
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 7d016c8..926d7a4 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -62,6 +62,7 @@
import java.nio.file.attribute.PosixFilePermissions;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -328,9 +329,11 @@
* @param tombstone path to the tombstone
* @param proto whether the tombstone is stored as proto
* @param processName the name of the process corresponding to the tombstone
+ * @param tmpFileLock the lock for reading/writing tmp files
*/
public static void addTombstoneToDropBox(
- Context ctx, File tombstone, boolean proto, String processName) {
+ Context ctx, File tombstone, boolean proto, String processName,
+ ReentrantLock tmpFileLock) {
final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
if (db == null) {
Slog.e(TAG, "Can't log tombstone: DropBoxManager not available");
@@ -351,39 +354,11 @@
// due to rate limiting. Do this by enclosing the proto tombsstone in a
// container proto that has the dropped entry count and the proto tombstone as
// bytes (to avoid the complexity of reading and writing nested protos).
-
- // Read the proto tombstone file as bytes.
- final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath());
-
- final File tombstoneProtoWithHeaders = File.createTempFile(
- tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
- Files.setPosixFilePermissions(
- tombstoneProtoWithHeaders.toPath(),
- PosixFilePermissions.fromString("rw-rw----"));
-
- // Write the new proto container proto with headers.
- try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- tombstoneProtoWithHeaders, MODE_READ_WRITE)) {
- ProtoOutputStream protoStream = new ProtoOutputStream(
- pfd.getFileDescriptor());
- protoStream.write(TombstoneWithHeadersProto.TOMBSTONE, tombstoneBytes);
- protoStream.write(
- TombstoneWithHeadersProto.DROPPED_COUNT,
- rateLimitResult.droppedCountSinceRateLimitActivated());
- protoStream.flush();
-
- // Add the proto to dropbox.
- db.addFile(TAG_TOMBSTONE_PROTO_WITH_HEADERS, tombstoneProtoWithHeaders, 0);
- } catch (FileNotFoundException ex) {
- Slog.e(TAG, "failed to open for write: " + tombstoneProtoWithHeaders, ex);
- throw ex;
- } catch (IOException ex) {
- Slog.e(TAG, "IO exception during write: " + tombstoneProtoWithHeaders, ex);
+ tmpFileLock.lock();
+ try {
+ addAugmentedProtoToDropbox(tombstone, db, rateLimitResult);
} finally {
- // Remove the temporary file.
- if (tombstoneProtoWithHeaders != null) {
- tombstoneProtoWithHeaders.delete();
- }
+ tmpFileLock.unlock();
}
}
} else {
@@ -399,6 +374,44 @@
writeTimestamps(timestamps);
}
+ private static void addAugmentedProtoToDropbox(
+ File tombstone, DropBoxManager db,
+ DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException {
+ // Read the proto tombstone file as bytes.
+ final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath());
+
+ final File tombstoneProtoWithHeaders = File.createTempFile(
+ tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
+ Files.setPosixFilePermissions(
+ tombstoneProtoWithHeaders.toPath(),
+ PosixFilePermissions.fromString("rw-rw----"));
+
+ // Write the new proto container proto with headers.
+ try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ tombstoneProtoWithHeaders, MODE_READ_WRITE)) {
+ ProtoOutputStream protoStream =
+ new ProtoOutputStream(pfd.getFileDescriptor());
+ protoStream.write(TombstoneWithHeadersProto.TOMBSTONE, tombstoneBytes);
+ protoStream.write(
+ TombstoneWithHeadersProto.DROPPED_COUNT,
+ rateLimitResult.droppedCountSinceRateLimitActivated());
+ protoStream.flush();
+
+ // Add the proto to dropbox.
+ db.addFile(TAG_TOMBSTONE_PROTO_WITH_HEADERS, tombstoneProtoWithHeaders, 0);
+ } catch (FileNotFoundException ex) {
+ Slog.e(TAG, "failed to open for write: " + tombstoneProtoWithHeaders, ex);
+ throw ex;
+ } catch (IOException ex) {
+ Slog.e(TAG, "IO exception during write: " + tombstoneProtoWithHeaders, ex);
+ } finally {
+ // Remove the temporary file and unlock the lock.
+ if (tombstoneProtoWithHeaders != null) {
+ tombstoneProtoWithHeaders.delete();
+ }
+ }
+ }
+
private static void addLastkToDropBox(
DropBoxManager db, HashMap<String, Long> timestamps,
String headers, String footers, String filename, int maxSize,
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index e5616d0..ab0d0d2 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -61,6 +61,7 @@
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
/**
* A class to manage native tombstones.
@@ -74,6 +75,8 @@
private final Handler mHandler;
private final TombstoneWatcher mWatcher;
+ private final ReentrantLock mTmpFileLock = new ReentrantLock();
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -112,7 +115,12 @@
// Clean up temporary files if they made it this far (e.g. if system server crashes).
if (filename.endsWith(".tmp")) {
- path.delete();
+ mTmpFileLock.lock();
+ try {
+ path.delete();
+ } finally {
+ mTmpFileLock.unlock();
+ }
return;
}
@@ -128,7 +136,7 @@
if (parsedTombstone.isPresent()) {
processName = parsedTombstone.get().getProcessName();
}
- BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName);
+ BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName, mTmpFileLock);
}
private Optional<TombstoneFile> handleProtoTombstone(File path, boolean addToList) {