diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index 37460cc9b..0a9804d26 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -9,8 +9,10 @@ import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.logging.PersistentLogManager; import java.io.File; +import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -20,17 +22,21 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.inject.Inject; +import static android.content.Context.MODE_PRIVATE; import static android.os.Build.VERSION.SDK_INT; import static java.util.Arrays.asList; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir; +import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logFileOrDir; class AndroidAccountManager extends AccountManagerImpl implements AccountManager { private static final Logger LOG = - Logger.getLogger(AndroidAccountManager.class.getName()); + getLogger(AndroidAccountManager.class.getName()); /** * Directories that shouldn't be deleted when deleting the user's account. @@ -40,13 +46,16 @@ class AndroidAccountManager extends AccountManagerImpl protected final Context appContext; private final SharedPreferences prefs; + private final PersistentLogManager logManager; @Inject AndroidAccountManager(DatabaseConfig databaseConfig, CryptoComponent crypto, IdentityManager identityManager, - SharedPreferences prefs, Application app) { + SharedPreferences prefs, PersistentLogManager logManager, + Application app) { super(databaseConfig, crypto, identityManager); this.prefs = prefs; + this.logManager = logManager; appContext = app.getApplicationContext(); } @@ -74,6 +83,7 @@ class AndroidAccountManager extends AccountManagerImpl LOG.info("Contents of account directory after deleting:"); logFileOrDir(LOG, INFO, getDataDir()); } + replacePersistentLogger(); } } @@ -134,4 +144,13 @@ class AndroidAccountManager extends AccountManagerImpl private void addIfNotNull(Set files, @Nullable File file) { if (file != null) files.add(file); } + + private void replacePersistentLogger() { + File logDir = appContext.getDir("log", MODE_PRIVATE); + try { + logManager.addLogHandler(logDir, getLogger("")); + } catch (IOException e) { + logException(LOG, WARNING, e); + } + } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/logging/PersistentLogManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/logging/PersistentLogManager.java index a26c714c2..d3c81c33e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/logging/PersistentLogManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/logging/PersistentLogManager.java @@ -7,6 +7,7 @@ import java.io.File; import java.io.IOException; import java.util.List; import java.util.logging.Handler; +import java.util.logging.Logger; @NotNullByDefault public interface PersistentLogManager { @@ -24,11 +25,16 @@ public interface PersistentLogManager { /** * Creates and returns a persistent log handler that stores its logs in * the given directory. - *

- * This method should only be called once. */ Handler createLogHandler(File dir) throws IOException; + /** + * Creates a persistent log handler that stores its logs in the given + * directory and adds the handler to the given logger, replacing any + * existing persistent log handler. + */ + void addLogHandler(File dir, Logger logger) throws IOException; + /** * Loads and returns the persistent log entries stored in the given * directory, or an empty list if no log entries are found. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/logging/PersistentLogManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/logging/PersistentLogManagerImpl.java index 5e82664a9..4af59b262 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/logging/PersistentLogManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/logging/PersistentLogManagerImpl.java @@ -27,7 +27,7 @@ import java.util.List; import java.util.Scanner; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Logger; @@ -62,7 +62,8 @@ class PersistentLogManagerImpl implements PersistentLogManager, private final StreamWriterFactory streamWriterFactory; private final Formatter formatter; private final SecretKey logKey; - private final AtomicBoolean handlerCreated = new AtomicBoolean(false); + private final AtomicReference shutdownHookHandle = + new AtomicReference<>(); @Nullable private volatile SecretKey oldLogKey = null; @@ -103,7 +104,6 @@ class PersistentLogManagerImpl implements PersistentLogManager, @Override public Handler createLogHandler(File dir) throws IOException { - if (handlerCreated.getAndSet(true)) throw new IllegalStateException(); File logFile = new File(dir, LOG_FILE); File oldLogFile = new File(dir, OLD_LOG_FILE); if (oldLogFile.exists() && !oldLogFile.delete()) @@ -117,7 +117,7 @@ class PersistentLogManagerImpl implements PersistentLogManager, StreamHandler handler = new FlushingStreamHandler(scheduler, ioExecutor, writer.getOutputStream(), formatter); // Flush the log and terminate the stream at shutdown - shutdownManager.addShutdownHook(() -> { + Runnable shutdownHook = () -> { LOG.info("Shutting down"); handler.flush(); try { @@ -125,13 +125,27 @@ class PersistentLogManagerImpl implements PersistentLogManager, } catch (IOException e) { logException(LOG, WARNING, e); } - }); + }; + int handle = shutdownManager.addShutdownHook(shutdownHook); + // If a previous handler registered a shutdown hook, remove it + Integer oldHandle = shutdownHookHandle.getAndSet(handle); + if (oldHandle != null) { + shutdownManager.removeShutdownHook(oldHandle); + } return handler; } catch (SecurityException e) { throw new IOException(e); } } + @Override + public void addLogHandler(File dir, Logger logger) throws IOException { + for (Handler h : logger.getHandlers()) { + if (h instanceof FlushingStreamHandler) logger.removeHandler(h); + } + logger.addHandler(createLogHandler(dir)); + } + @Override public List getPersistedLog(File dir, boolean old) throws IOException { diff --git a/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java index eb1e2faaa..14ebd77a6 100644 --- a/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java +++ b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java @@ -6,6 +6,7 @@ import android.content.SharedPreferences; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.logging.PersistentLogManager; import org.briarproject.briar.R; import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.util.UiUtils; @@ -17,8 +18,8 @@ class BriarAccountManager extends AndroidAccountManager { @Inject BriarAccountManager(DatabaseConfig databaseConfig, CryptoComponent crypto, IdentityManager identityManager, SharedPreferences prefs, - Application app) { - super(databaseConfig, crypto, identityManager, prefs, app); + PersistentLogManager logManager, Application app) { + super(databaseConfig, crypto, identityManager, prefs, logManager, app); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java index a8ecb8bf9..867a78bea 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java @@ -32,7 +32,6 @@ import org.briarproject.briar.android.util.UiUtils; import java.io.File; import java.io.IOException; import java.util.Collection; -import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.Logger; @@ -130,12 +129,9 @@ public class BriarApplicationImpl extends Application PersistentLogManager logManager = applicationComponent.persistentLogManager(); - Formatter formatter = applicationComponent.formatter(); + File logDir = getDir("log", MODE_PRIVATE); try { - File logDir = getDir("log", MODE_PRIVATE); - Handler handler = logManager.createLogHandler(logDir); - handler.setFormatter(formatter); - rootLogger.addHandler(handler); + rootLogger.addHandler(logManager.createLogHandler(logDir)); } catch (IOException e) { logException(LOG, WARNING, e); }