summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/persistentlog
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/persistentlog')
-rw-r--r--java/com/android/dialer/persistentlog/PersistentLogFileHandler.java61
-rw-r--r--java/com/android/dialer/persistentlog/PersistentLogger.java15
2 files changed, 72 insertions, 4 deletions
diff --git a/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java b/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java
index 5c7a28c5b..8bd8335a2 100644
--- a/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java
+++ b/java/com/android/dialer/persistentlog/PersistentLogFileHandler.java
@@ -27,6 +27,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.support.v4.os.UserManagerCompat;
+import com.android.dialer.common.LogUtil;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -58,6 +59,16 @@ final class PersistentLogFileHandler {
private static final String LOG_DIRECTORY = "persistent_log";
private static final String NEXT_FILE_INDEX_PREFIX = "persistent_long_next_file_index_";
+ private static final byte[] ENTRY_PREFIX = {'P'};
+ private static final byte[] ENTRY_POSTFIX = {'L'};
+
+ private static class LogCorruptionException extends Exception {
+
+ public LogCorruptionException(String message) {
+ super(message);
+ }
+ };
+
private File logDirectory;
private final String subfolder;
private final int fileSizeLimit;
@@ -106,8 +117,10 @@ final class PersistentLogFileHandler {
try (DataOutputStream outputStream =
new DataOutputStream(new FileOutputStream(outputFile, true))) {
for (byte[] log : logs) {
+ outputStream.write(ENTRY_PREFIX);
outputStream.writeInt(log.length);
outputStream.write(log);
+ outputStream.write(ENTRY_POSTFIX);
}
outputStream.close();
if (outputFile.length() > fileSizeLimit) {
@@ -116,6 +129,21 @@ final class PersistentLogFileHandler {
}
}
+ void writeRawLogsForTest(byte[] data) throws IOException {
+ if (outputFile == null) {
+ selectNextFileToWrite();
+ }
+ outputFile.createNewFile();
+ try (DataOutputStream outputStream =
+ new DataOutputStream(new FileOutputStream(outputFile, true))) {
+ outputStream.write(data);
+ outputStream.close();
+ if (outputFile.length() > fileSizeLimit) {
+ selectNextFileToWrite();
+ }
+ }
+ }
+
/** Concatenate all log files in chronicle order and return a byte array. */
@WorkerThread
@NonNull
@@ -149,10 +177,21 @@ final class PersistentLogFileHandler {
logs.add(log);
log = readLog(input);
}
+ } catch (LogCorruptionException e) {
+ LogUtil.e("PersistentLogFileHandler.getLogs", "logs corrupted, deleting", e);
+ deleteLogs();
+ return new ArrayList<>();
}
return logs;
}
+ private void deleteLogs() throws IOException {
+ for (File file : getLogFiles()) {
+ file.delete();
+ }
+ selectNextFileToWrite();
+ }
+
@WorkerThread
private void selectNextFileToWrite() throws IOException {
File[] files = getLogFiles();
@@ -186,10 +225,28 @@ final class PersistentLogFileHandler {
@Nullable
@WorkerThread
- private static byte[] readLog(DataInputStream inputStream) throws IOException {
+ private byte[] readLog(DataInputStream inputStream) throws IOException, LogCorruptionException {
try {
- byte[] data = new byte[inputStream.readInt()];
+ byte[] prefix = new byte[ENTRY_PREFIX.length];
+ if (inputStream.read(prefix) == -1) {
+ // EOF
+ return null;
+ }
+ if (!Arrays.equals(prefix, ENTRY_PREFIX)) {
+ throw new LogCorruptionException("entry prefix mismatch");
+ }
+ int dataLength = inputStream.readInt();
+ if (dataLength > fileSizeLimit) {
+ throw new LogCorruptionException("data length over max size");
+ }
+ byte[] data = new byte[dataLength];
inputStream.read(data);
+
+ byte[] postfix = new byte[ENTRY_POSTFIX.length];
+ inputStream.read(postfix);
+ if (!Arrays.equals(postfix, ENTRY_POSTFIX)) {
+ throw new LogCorruptionException("entry postfix mismatch");
+ }
return data;
} catch (EOFException e) {
return null;
diff --git a/java/com/android/dialer/persistentlog/PersistentLogger.java b/java/com/android/dialer/persistentlog/PersistentLogger.java
index cf43b8ca8..5fdefd174 100644
--- a/java/com/android/dialer/persistentlog/PersistentLogger.java
+++ b/java/com/android/dialer/persistentlog/PersistentLogger.java
@@ -26,6 +26,7 @@ import android.support.annotation.WorkerThread;
import android.support.v4.os.UserManagerCompat;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.strictmode.DialerStrictMode;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -43,7 +44,7 @@ import java.util.concurrent.LinkedBlockingQueue;
* com.google.android.apps.dialer.crashreporter.SilentCrashReporter} is expected to handle such
* cases.
*
- * <p>{@link #logText(String, String)} should be used to log ad-hoc text logs. TODO: switch
+ * <p>{@link #logText(String, String)} should be used to log ad-hoc text logs. TODO(twyen): switch
* to structured logging
*/
public final class PersistentLogger {
@@ -110,6 +111,16 @@ public final class PersistentLogger {
loggerThreadHandler.sendEmptyMessageDelayed(MESSAGE_FLUSH, FLUSH_DELAY_MILLIS);
}
+ @VisibleForTesting
+ /** write raw bytes directly to the log file, likely corrupting it. */
+ static void rawLogForTest(byte[] data) {
+ try {
+ fileHandler.writeRawLogsForTest(data);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/** Dump the log as human readable string. Blocks until the dump is finished. */
@NonNull
@WorkerThread
@@ -167,7 +178,7 @@ public final class PersistentLogger {
}
private static byte[] buildTextLog(String tag, String string) {
- Calendar c = Calendar.getInstance();
+ Calendar c = DialerStrictMode.bypass(() -> Calendar.getInstance());
return String.format("%tm-%td %tH:%tM:%tS.%tL - %s - %s", c, c, c, c, c, c, tag, string)
.getBytes(StandardCharsets.UTF_8);
}