mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Avoid creating an in-memory copy of the log where possible.
This helps to avoid OOMs on low-memory devices.
This commit is contained in:
@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.settings.Settings;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.Scanner;
|
||||||
import java.util.logging.Handler;
|
import java.util.logging.Handler;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -36,11 +36,11 @@ public interface PersistentLogManager {
|
|||||||
void addLogHandler(File dir, Logger logger) throws IOException;
|
void addLogHandler(File dir, Logger logger) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads and returns the persistent log entries stored in the given
|
* Returns a {@link Scanner} for reading the persistent log entries stored
|
||||||
* directory, or an empty list if no log entries are found.
|
* in the given directory.
|
||||||
*
|
*
|
||||||
* @param old True if the previous session's log should be loaded, or false
|
* @param old True if the previous session's log should be loaded, or false
|
||||||
* if the current session's log should be loaded
|
* if the current session's log should be loaded
|
||||||
*/
|
*/
|
||||||
List<String> getPersistedLog(File dir, boolean old) throws IOException;
|
Scanner getPersistedLog(File dir, boolean old) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,13 @@ import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
|||||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@@ -37,7 +36,6 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
@@ -52,7 +50,6 @@ class PersistentLogManagerImpl implements PersistentLogManager,
|
|||||||
|
|
||||||
private static final String LOG_FILE = "briar.log";
|
private static final String LOG_FILE = "briar.log";
|
||||||
private static final String OLD_LOG_FILE = "briar.log.old";
|
private static final String OLD_LOG_FILE = "briar.log.old";
|
||||||
private static final int MAX_LINES_TO_RETURN = 10_000;
|
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
@@ -147,13 +144,13 @@ class PersistentLogManagerImpl implements PersistentLogManager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getPersistedLog(File dir, boolean old)
|
public Scanner getPersistedLog(File dir, boolean old)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (old) {
|
if (old) {
|
||||||
SecretKey oldLogKey = this.oldLogKey;
|
SecretKey oldLogKey = this.oldLogKey;
|
||||||
if (oldLogKey == null) {
|
if (oldLogKey == null) {
|
||||||
LOG.info("Old log key has not been loaded");
|
LOG.info("Old log key has not been loaded");
|
||||||
return emptyList();
|
return emptyScanner();
|
||||||
}
|
}
|
||||||
return getPersistedLog(new File(dir, OLD_LOG_FILE), oldLogKey);
|
return getPersistedLog(new File(dir, OLD_LOG_FILE), oldLogKey);
|
||||||
} else {
|
} else {
|
||||||
@@ -161,31 +158,20 @@ class PersistentLogManagerImpl implements PersistentLogManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getPersistedLog(File logFile, SecretKey key)
|
private Scanner getPersistedLog(File logFile, SecretKey key)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (logFile.exists()) {
|
if (logFile.exists()) {
|
||||||
LOG.info("Reading log file");
|
LOG.info("Reading log file");
|
||||||
LinkedList<String> lines = new LinkedList<>();
|
|
||||||
int numLines = 0;
|
|
||||||
InputStream in = new FileInputStream(logFile);
|
InputStream in = new FileInputStream(logFile);
|
||||||
//noinspection TryFinallyCanBeTryWithResources
|
return new Scanner(streamReaderFactory.createLogStreamReader(in,
|
||||||
try {
|
key));
|
||||||
InputStream reader = streamReaderFactory
|
|
||||||
.createLogStreamReader(in, key);
|
|
||||||
Scanner s = new Scanner(reader);
|
|
||||||
while (s.hasNextLine()) {
|
|
||||||
lines.add(s.nextLine());
|
|
||||||
if (numLines == MAX_LINES_TO_RETURN) lines.poll();
|
|
||||||
else numLines++;
|
|
||||||
}
|
|
||||||
s.close();
|
|
||||||
return lines;
|
|
||||||
} finally {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Log file does not exist");
|
LOG.info("Log file does not exist");
|
||||||
return emptyList();
|
return emptyScanner();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Scanner emptyScanner() {
|
||||||
|
return new Scanner(new ByteArrayInputStream(new byte[0]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
@@ -54,6 +56,8 @@ import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
|||||||
|
|
||||||
public class BriarReportPrimer implements ReportPrimer {
|
public class BriarReportPrimer implements ReportPrimer {
|
||||||
|
|
||||||
|
private static final int MAX_PERSISTED_LOG_LINES = 1_000;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void primeReport(@NonNull Context ctx,
|
public void primeReport(@NonNull Context ctx,
|
||||||
@NonNull ReportBuilder builder) {
|
@NonNull ReportBuilder builder) {
|
||||||
@@ -271,9 +275,16 @@ public class BriarReportPrimer implements ReportPrimer {
|
|||||||
File logDir = ctx.getDir("log", MODE_PRIVATE);
|
File logDir = ctx.getDir("log", MODE_PRIVATE);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
for (String line : logManager.getPersistedLog(logDir, old)) {
|
Scanner scanner = logManager.getPersistedLog(logDir, old);
|
||||||
sb.append(line).append('\n');
|
LinkedList<String> lines = new LinkedList<>();
|
||||||
|
int numLines = 0;
|
||||||
|
while (scanner.hasNextLine()) {
|
||||||
|
lines.add(scanner.nextLine());
|
||||||
|
if (numLines == MAX_PERSISTED_LOG_LINES) lines.pollFirst();
|
||||||
|
else numLines++;
|
||||||
}
|
}
|
||||||
|
scanner.close();
|
||||||
|
for (String line : lines) sb.append(line).append('\n');
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
sb.append("Could not recover persisted log: ").append(e);
|
sb.append("Could not recover persisted log: ").append(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.List;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -106,18 +106,19 @@ public class SettingsActivity extends BriarActivity {
|
|||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
File logDir = getApplication().getDir("log", MODE_PRIVATE);
|
File logDir = getApplication().getDir("log", MODE_PRIVATE);
|
||||||
List<String> lines = logManager.getPersistedLog(logDir, old);
|
Scanner scanner = logManager.getPersistedLog(logDir, old);
|
||||||
if (lines.isEmpty()) {
|
if (!scanner.hasNextLine()) {
|
||||||
|
scanner.close();
|
||||||
runOnUiThreadUnlessDestroyed(() ->
|
runOnUiThreadUnlessDestroyed(() ->
|
||||||
Toast.makeText(getApplication(), "Log is empty",
|
Toast.makeText(getApplication(), "Log is empty",
|
||||||
LENGTH_LONG).show());
|
LENGTH_LONG).show());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PrintWriter w = new PrintWriter(osp.getOutputStream());
|
PrintWriter w = new PrintWriter(osp.getOutputStream());
|
||||||
for (String line : lines) {
|
while (scanner.hasNextLine()) w.println(scanner.nextLine());
|
||||||
w.println(line);
|
w.flush();
|
||||||
}
|
|
||||||
w.close();
|
w.close();
|
||||||
|
scanner.close();
|
||||||
runOnUiThreadUnlessDestroyed(() ->
|
runOnUiThreadUnlessDestroyed(() ->
|
||||||
Toast.makeText(getApplication(), "Log exported",
|
Toast.makeText(getApplication(), "Log exported",
|
||||||
LENGTH_LONG).show());
|
LENGTH_LONG).show());
|
||||||
|
|||||||
Reference in New Issue
Block a user