From 08931e64cbfbcb502e7dab003d94e619a8c59123 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Fri, 15 Jun 2018 12:04:12 +0100
Subject: [PATCH] Use System.nanoTime() for timing measurements.

---
 .../briarproject/bramble/util/TimeUtils.java  | 14 +++++++++
 .../briarproject/bramble/PoliteExecutor.java  |  5 ++--
 .../bramble/TimeLoggingExecutor.java          |  7 +++--
 .../bramble/crypto/CryptoComponentImpl.java   |  5 ++--
 .../bramble/crypto/ScryptKdf.java             |  5 ++--
 .../bramble/crypto/Sec1KeyParser.java         |  9 +++---
 .../bramble/db/DatabaseComponentImpl.java     |  5 ++--
 .../lifecycle/LifecycleManagerImpl.java       | 29 ++++++++++---------
 .../bramble/plugin/PluginManagerImpl.java     |  9 +++---
 .../briar/android/NetworkUsageLogger.java     | 10 +++----
 .../android/blog/BaseControllerImpl.java      | 17 ++++++-----
 .../android/blog/BlogControllerImpl.java      |  9 +++---
 .../android/blog/FeedControllerImpl.java      |  9 +++---
 .../android/blog/WriteBlogPostActivity.java   |  4 +--
 .../android/contact/ContactListFragment.java  |  5 ++--
 .../android/contact/ConversationActivity.java | 21 +++++++-------
 .../android/forum/CreateForumActivity.java    |  5 ++--
 .../android/forum/ForumListFragment.java      |  9 +++---
 .../android/login/PasswordControllerImpl.java |  5 ++--
 .../list/GroupListControllerImpl.java         |  9 +++---
 .../android/settings/SettingsFragment.java    | 17 ++++++-----
 .../sharing/InvitationControllerImpl.java     |  5 ++--
 .../threaded/ThreadListControllerImpl.java    | 25 ++++++++--------
 23 files changed, 136 insertions(+), 102 deletions(-)
 create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/util/TimeUtils.java

diff --git a/bramble-api/src/main/java/org/briarproject/bramble/util/TimeUtils.java b/bramble-api/src/main/java/org/briarproject/bramble/util/TimeUtils.java
new file mode 100644
index 0000000000..34420a346c
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/util/TimeUtils.java
@@ -0,0 +1,14 @@
+package org.briarproject.bramble.util;
+
+public class TimeUtils {
+
+	private static final int NANOS_PER_MILLI = 1000 * 1000;
+
+	/**
+	 * Returns the elapsed time in milliseconds since some arbitrary
+	 * starting time. This is only useful for measuring elapsed time.
+	 */
+	public static long now() {
+		return System.nanoTime() / NANOS_PER_MILLI;
+	}
+}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/PoliteExecutor.java b/bramble-core/src/main/java/org/briarproject/bramble/PoliteExecutor.java
index 518845953b..2ab5e032df 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/PoliteExecutor.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/PoliteExecutor.java
@@ -10,6 +10,7 @@ import java.util.logging.Logger;
 import javax.annotation.concurrent.GuardedBy;
 
 import static java.util.logging.Level.FINE;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 /**
  * An {@link Executor} that delegates its tasks to another {@link Executor}
@@ -46,10 +47,10 @@ public class PoliteExecutor implements Executor {
 
 	@Override
 	public void execute(Runnable r) {
-		long submitted = System.currentTimeMillis();
+		long submitted = now();
 		Runnable wrapped = () -> {
 			if (log.isLoggable(FINE)) {
-				long queued = System.currentTimeMillis() - submitted;
+				long queued = now() - submitted;
 				log.fine("Queue time " + queued + " ms");
 			}
 			try {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java b/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java
index e79b032142..8f5e861a8f 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java
@@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.logging.Logger;
 
 import static java.util.logging.Level.FINE;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @NotNullByDefault
 public class TimeLoggingExecutor extends ThreadPoolExecutor {
@@ -27,13 +28,13 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor {
 	@Override
 	public void execute(Runnable r) {
 		if (log.isLoggable(FINE)) {
-			long submitted = System.currentTimeMillis();
+			long submitted = now();
 			super.execute(() -> {
-				long started = System.currentTimeMillis();
+				long started = now();
 				long queued = started - submitted;
 				log.fine("Queue time " + queued + " ms");
 				r.run();
-				long executing = System.currentTimeMillis() - started;
+				long executing = now() - started;
 				log.fine("Execution time " + executing + " ms");
 			});
 		} else {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
index e4e9e87113..d6ee52a0fa 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoComponentImpl.java
@@ -33,6 +33,7 @@ import javax.inject.Inject;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.INFO;
 import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @NotNullByDefault
 class CryptoComponentImpl implements CryptoComponent {
@@ -128,14 +129,14 @@ class CryptoComponentImpl implements CryptoComponent {
 			throw new IllegalArgumentException();
 		if (!(pub instanceof Curve25519PublicKey))
 			throw new IllegalArgumentException();
-		long now = System.currentTimeMillis();
+		long start = now();
 		byte[] secret = curve25519.calculateAgreement(pub.getEncoded(),
 				priv.getEncoded());
 		// If the shared secret is all zeroes, the public key is invalid
 		byte allZero = 0;
 		for (byte b : secret) allZero |= b;
 		if (allZero == 0) throw new GeneralSecurityException();
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Deriving shared secret took " + duration + " ms");
 		return secret;
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/ScryptKdf.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/ScryptKdf.java
index b3ece21ae1..c9726ea5e0 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/ScryptKdf.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/ScryptKdf.java
@@ -11,6 +11,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.INFO;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 class ScryptKdf implements PasswordBasedKdf {
 
@@ -51,11 +52,11 @@ class ScryptKdf implements PasswordBasedKdf {
 
 	@Override
 	public SecretKey deriveKey(String password, byte[] salt, int cost) {
-		long start = System.currentTimeMillis();
+		long start = now();
 		byte[] passwordBytes = StringUtils.toUtf8(password);
 		SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
 				BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH));
-		long duration = System.currentTimeMillis() - start;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Deriving key from password took " + duration + " ms");
 		return k;
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/Sec1KeyParser.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/Sec1KeyParser.java
index 2cfc47e4f0..f1c3220944 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/Sec1KeyParser.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/Sec1KeyParser.java
@@ -17,6 +17,7 @@ import java.util.logging.Logger;
 import javax.annotation.concurrent.Immutable;
 
 import static java.util.logging.Level.FINE;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 /**
  * A key parser that uses the encoding defined in "SEC 1: Elliptic Curve
@@ -48,7 +49,7 @@ class Sec1KeyParser implements KeyParser {
 			throws GeneralSecurityException {
 		// The validation procedure comes from SEC 1, section 3.2.2.1. Note
 		// that SEC 1 parameter names are used below, not RFC 5639 names
-		long now = System.currentTimeMillis();
+		long start = now();
 		if (encodedKey.length != publicKeyBytes)
 			throw new GeneralSecurityException();
 		// The first byte must be 0x04
@@ -80,7 +81,7 @@ class Sec1KeyParser implements KeyParser {
 		// Construct a public key from the point (x, y) and the params
 		ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
 		PublicKey p = new Sec1PublicKey(k);
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Parsing public key took " + duration + " ms");
 		return p;
@@ -89,7 +90,7 @@ class Sec1KeyParser implements KeyParser {
 	@Override
 	public PrivateKey parsePrivateKey(byte[] encodedKey)
 			throws GeneralSecurityException {
-		long now = System.currentTimeMillis();
+		long start = now();
 		if (encodedKey.length != privateKeyBytes)
 			throw new GeneralSecurityException();
 		BigInteger d = new BigInteger(1, encodedKey); // Positive signum
@@ -99,7 +100,7 @@ class Sec1KeyParser implements KeyParser {
 		// Construct a private key from the private value and the params
 		ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
 		PrivateKey p = new Sec1PrivateKey(k, keyBits);
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Parsing private key took " + duration + " ms");
 		return p;
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
index 6f54b32199..0b478e1199 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
@@ -75,6 +75,7 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
 import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
 import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
 import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @ThreadSafe
 @NotNullByDefault
@@ -125,11 +126,11 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 		// Don't allow reentrant locking
 		if (lock.getReadHoldCount() > 0) throw new IllegalStateException();
 		if (lock.getWriteHoldCount() > 0) throw new IllegalStateException();
-		long start = System.currentTimeMillis();
+		long start = now();
 		if (readOnly) lock.readLock().lock();
 		else lock.writeLock().lock();
 		if (LOG.isLoggable(FINE)) {
-			long duration = System.currentTimeMillis() - start;
+			long duration = now() - start;
 			if (readOnly) LOG.fine("Waited " + duration + " ms for read lock");
 			else LOG.fine("Waited " + duration + " ms for write lock");
 		}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java
index 8462f05844..fa3d31ce5a 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java
@@ -44,6 +44,7 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResul
 import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
 import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
 import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @ThreadSafe
 @NotNullByDefault
@@ -102,22 +103,22 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 	}
 
 	private LocalAuthor createLocalAuthor(String nickname) {
-		long now = System.currentTimeMillis();
+		long start = now();
 		KeyPair keyPair = crypto.generateSignatureKeyPair();
 		byte[] publicKey = keyPair.getPublic().getEncoded();
 		byte[] privateKey = keyPair.getPrivate().getEncoded();
 		LocalAuthor localAuthor = authorFactory
 				.createLocalAuthor(nickname, publicKey, privateKey);
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Creating local author took " + duration + " ms");
 		return localAuthor;
 	}
 
 	private void registerLocalAuthor(LocalAuthor author) throws DbException {
-		long now = System.currentTimeMillis();
+		long start = now();
 		identityManager.registerLocalAuthor(author);
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Registering local author took " + duration + " ms");
 	}
@@ -130,10 +131,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 		}
 		try {
 			LOG.info("Starting services");
-			long start = System.currentTimeMillis();
+			long start = now();
 
 			boolean reopened = db.open(this);
-			long duration = System.currentTimeMillis() - start;
+			long duration = now() - start;
 			if (LOG.isLoggable(FINE)) {
 				if (reopened)
 					LOG.fine("Reopening database took " + duration + " ms");
@@ -151,9 +152,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 			Transaction txn = db.startTransaction(false);
 			try {
 				for (Client c : clients) {
-					start = System.currentTimeMillis();
+					start = now();
 					c.createLocalState(txn);
-					duration = System.currentTimeMillis() - start;
+					duration = now() - start;
 					if (LOG.isLoggable(FINE)) {
 						LOG.fine("Starting client "
 								+ c.getClass().getSimpleName()
@@ -165,9 +166,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 				db.endTransaction(txn);
 			}
 			for (Service s : services) {
-				start = System.currentTimeMillis();
+				start = now();
 				s.startService();
-				duration = System.currentTimeMillis() - start;
+				duration = now() - start;
 				if (LOG.isLoggable(FINE)) {
 					LOG.fine("Starting service " + s.getClass().getSimpleName()
 							+ " took " + duration + " ms");
@@ -214,9 +215,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 			state = STOPPING;
 			eventBus.broadcast(new LifecycleEvent(STOPPING));
 			for (Service s : services) {
-				long start = System.currentTimeMillis();
+				long start = now();
 				s.stopService();
-				long duration = System.currentTimeMillis() - start;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE)) {
 					LOG.fine("Stopping service " + s.getClass().getSimpleName()
 							+ " took " + duration + " ms");
@@ -229,9 +230,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
 				}
 				e.shutdownNow();
 			}
-			long start = System.currentTimeMillis();
+			long start = now();
 			db.close();
-			long duration = System.currentTimeMillis() - start;
+			long duration = now() - start;
 			if (LOG.isLoggable(FINE))
 				LOG.fine("Closing database took " + duration + " ms");
 			shutdownLatch.countDown();
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java
index b79170d0ed..726539fa94 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java
@@ -52,6 +52,7 @@ import javax.inject.Inject;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @ThreadSafe
 @NotNullByDefault
@@ -206,9 +207,9 @@ class PluginManagerImpl implements PluginManager, Service {
 		@Override
 		public void run() {
 			try {
-				long start = System.currentTimeMillis();
+				long start = now();
 				plugin.start();
-				long duration = System.currentTimeMillis() - start;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE)) {
 					LOG.fine("Starting plugin " + plugin.getId() + " took " +
 							duration + " ms");
@@ -244,9 +245,9 @@ class PluginManagerImpl implements PluginManager, Service {
 				// Wait for the plugin to finish starting
 				startLatch.await();
 				// Stop the plugin
-				long start = System.currentTimeMillis();
+				long start = now();
 				plugin.stop();
-				long duration = System.currentTimeMillis() - start;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE)) {
 					LOG.fine("Stopping plugin " + plugin.getId()
 							+ " took " + duration + " ms");
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/NetworkUsageLogger.java b/briar-android/src/main/java/org/briarproject/briar/android/NetworkUsageLogger.java
index dcf500cbf6..5e700baccc 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/NetworkUsageLogger.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/NetworkUsageLogger.java
@@ -4,11 +4,11 @@ import android.net.TrafficStats;
 import android.os.Process;
 
 import org.briarproject.bramble.api.lifecycle.Service;
-import org.briarproject.bramble.api.lifecycle.ServiceException;
 
 import java.util.logging.Logger;
 
 import static java.util.logging.Level.INFO;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 class NetworkUsageLogger implements Service {
 
@@ -18,17 +18,17 @@ class NetworkUsageLogger implements Service {
 	private volatile long startTime, rxBytes, txBytes;
 
 	@Override
-	public void startService() throws ServiceException {
-		startTime = System.currentTimeMillis();
+	public void startService() {
+		startTime = now();
 		int uid = Process.myUid();
 		rxBytes = TrafficStats.getUidRxBytes(uid);
 		txBytes = TrafficStats.getUidTxBytes(uid);
 	}
 
 	@Override
-	public void stopService() throws ServiceException {
+	public void stopService() {
 		if (LOG.isLoggable(INFO)) {
-			long sessionDuration = System.currentTimeMillis() - startTime;
+			long sessionDuration = now() - startTime;
 			int uid = Process.myUid();
 			long rx = TrafficStats.getUidRxBytes(uid) - rxBytes;
 			long tx = TrafficStats.getUidTxBytes(uid) - txBytes;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java
index 77ba1bc583..1ddb16ba6e 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BaseControllerImpl.java
@@ -34,6 +34,7 @@ import javax.annotation.Nullable;
 
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.util.HtmlUtils.ARTICLE;
 
 @MethodsNotNullByDefault
@@ -109,20 +110,20 @@ abstract class BaseControllerImpl extends DbControllerImpl
 	}
 
 	Collection<BlogPostItem> loadItems(GroupId groupId) throws DbException {
-		long now = System.currentTimeMillis();
+		long start = now();
 		Collection<BlogPostHeader> headers =
 				blogManager.getPostHeaders(groupId);
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Loading headers took " + duration + " ms");
 		Collection<BlogPostItem> items = new ArrayList<>(headers.size());
-		now = System.currentTimeMillis();
+		start = now();
 		for (BlogPostHeader h : headers) {
 			headerCache.put(h.getId(), h);
 			BlogPostItem item = getItem(h);
 			items.add(item);
 		}
-		duration = System.currentTimeMillis() - now;
+		duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Loading bodies took " + duration + " ms");
 		return items;
@@ -140,9 +141,9 @@ abstract class BaseControllerImpl extends DbControllerImpl
 		}
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				BlogPostItem item = getItem(header);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading body took " + duration + " ms");
 				handler.onResult(item);
@@ -166,10 +167,10 @@ abstract class BaseControllerImpl extends DbControllerImpl
 		}
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				BlogPostHeader header1 = getPostHeader(g, m);
 				BlogPostItem item = getItem(header1);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading post took " + duration + " ms");
 				handler.onResult(item);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java
index 5a0be438de..f3030553e3 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/BlogControllerImpl.java
@@ -37,6 +37,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @MethodsNotNullByDefault
 @ParametersNotNullByDefault
@@ -154,13 +155,13 @@ class BlogControllerImpl extends BaseControllerImpl
 		if (groupId == null) throw new IllegalStateException();
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				LocalAuthor a = identityManager.getLocalAuthor();
 				Blog b = blogManager.getBlog(groupId);
 				boolean ours = a.getId().equals(b.getAuthor().getId());
 				boolean removable = blogManager.canBeRemoved(b);
 				BlogItem blog = new BlogItem(b, ours, removable);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading blog took " + duration + " ms");
 				handler.onResult(blog);
@@ -177,10 +178,10 @@ class BlogControllerImpl extends BaseControllerImpl
 		if (groupId == null) throw new IllegalStateException();
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Blog b = blogManager.getBlog(groupId);
 				blogManager.removeBlog(b);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Removing blog took " + duration + " ms");
 				handler.onResult(null);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedControllerImpl.java
index 7cfc0ecb97..1b2aa49db2 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/FeedControllerImpl.java
@@ -28,6 +28,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
 
 @MethodsNotNullByDefault
@@ -99,7 +100,7 @@ class FeedControllerImpl extends BaseControllerImpl
 			ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Collection<BlogPostItem> posts = new ArrayList<>();
 				for (Blog b : blogManager.getBlogs()) {
 					try {
@@ -109,7 +110,7 @@ class FeedControllerImpl extends BaseControllerImpl
 							LOG.log(WARNING, e.toString(), e);
 					}
 				}
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading all posts took " + duration + " ms");
 				handler.onResult(posts);
@@ -125,10 +126,10 @@ class FeedControllerImpl extends BaseControllerImpl
 			ResultExceptionHandler<Blog, DbException> handler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Author a = identityManager.getLocalAuthor();
 				Blog b = blogManager.getPersonalBlog(a);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading blog took " + duration + " ms");
 				handler.onResult(b);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java
index 918c6def21..7f11558e05 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java
@@ -142,11 +142,11 @@ public class WriteBlogPostActivity extends BriarActivity
 
 	private void storePost(String body) {
 		runOnDbThread(() -> {
-			long now = System.currentTimeMillis();
+			long timestamp = System.currentTimeMillis();
 			try {
 				LocalAuthor author = identityManager.getLocalAuthor();
 				BlogPost p = blogPostFactory
-						.createBlogPost(groupId, now, null, author, body);
+						.createBlogPost(groupId, timestamp, null, author, body);
 				blogManager.addLocalPost(p);
 				postPublished();
 			} catch (DbException | GeneralSecurityException
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java
index fbf5247349..3b821fdaa1 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java
@@ -61,6 +61,7 @@ import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAn
 import static android.support.v4.view.ViewCompat.getTransitionName;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
 
 @MethodsNotNullByDefault
@@ -194,7 +195,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 		int revision = adapter.getRevision();
 		listener.runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				List<ContactListItem> contacts = new ArrayList<>();
 				for (Contact c : contactManager.getActiveContacts()) {
 					try {
@@ -208,7 +209,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 						// Continue
 					}
 				}
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Full load took " + duration + " ms");
 				displayContacts(revision, contacts);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java
index 71c7a9cbeb..c3ff017820 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java
@@ -107,6 +107,7 @@ import static android.widget.Toast.LENGTH_SHORT;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_INTRODUCTION;
 import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
 import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
@@ -291,13 +292,13 @@ public class ConversationActivity extends BriarActivity
 	private void loadContactDetailsAndMessages() {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				if (contactName == null || contactAuthorId == null) {
 					Contact contact = contactManager.getContact(contactId);
 					contactName = contact.getAuthor().getName();
 					contactAuthorId = contact.getAuthor().getId();
 				}
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading contact took " + duration + " ms");
 				loadMessages();
@@ -341,7 +342,7 @@ public class ConversationActivity extends BriarActivity
 		int revision = adapter.getRevision();
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Collection<PrivateMessageHeader> headers =
 						messagingManager.getMessageHeaders(contactId);
 				Collection<IntroductionMessage> introductions =
@@ -358,7 +359,7 @@ public class ConversationActivity extends BriarActivity
 				invitations.addAll(forumInvitations);
 				invitations.addAll(blogInvitations);
 				invitations.addAll(groupInvitations);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading messages took " + duration + " ms");
 				displayMessages(revision, headers, introductions, invitations);
@@ -439,9 +440,9 @@ public class ConversationActivity extends BriarActivity
 	private void loadMessageBody(MessageId m) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				String body = messagingManager.getMessageBody(m);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading body took " + duration + " ms");
 				displayMessageBody(m, body);
@@ -690,9 +691,9 @@ public class ConversationActivity extends BriarActivity
 	private void storeMessage(PrivateMessage m, String body) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				messagingManager.addLocalMessage(m);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Storing message took " + duration + " ms");
 				Message message = m.getMessage();
@@ -817,9 +818,9 @@ public class ConversationActivity extends BriarActivity
 	private void markMessageRead(GroupId g, MessageId m) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				messagingManager.setReadFlag(g, m, true);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Marking read took " + duration + " ms");
 			} catch (DbException e) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/CreateForumActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/CreateForumActivity.java
index 05224ef745..89097376ee 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/forum/CreateForumActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/CreateForumActivity.java
@@ -30,6 +30,7 @@ import static android.view.View.VISIBLE;
 import static android.widget.Toast.LENGTH_LONG;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
 
 @MethodsNotNullByDefault
@@ -122,9 +123,9 @@ public class CreateForumActivity extends BriarActivity {
 	private void storeForum(String name) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Forum f = forumManager.addForum(name);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Storing forum took " + duration + " ms");
 				displayForum(f);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java
index e5cad06ada..83ba45564f 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java
@@ -46,6 +46,7 @@ import javax.inject.Inject;
 import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
 
 @MethodsNotNullByDefault
@@ -157,7 +158,7 @@ public class ForumListFragment extends BaseEventFragment implements
 		int revision = adapter.getRevision();
 		listener.runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Collection<ForumListItem> forums = new ArrayList<>();
 				for (Forum f : forumManager.getForums()) {
 					try {
@@ -168,7 +169,7 @@ public class ForumListFragment extends BaseEventFragment implements
 						// Continue
 					}
 				}
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Full load took " + duration + " ms");
 				displayForums(revision, forums);
@@ -194,9 +195,9 @@ public class ForumListFragment extends BaseEventFragment implements
 	private void loadAvailableForums() {
 		listener.runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				int available = forumSharingManager.getInvitations().size();
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading available took " + duration + " ms");
 				displayAvailableForums(available);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java
index dcee51a9dd..8ba74434cb 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java
@@ -18,6 +18,7 @@ import java.util.logging.Logger;
 import javax.inject.Inject;
 
 import static java.util.logging.Level.FINE;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @NotNullByDefault
 public class PasswordControllerImpl extends ConfigControllerImpl
@@ -86,9 +87,9 @@ public class PasswordControllerImpl extends ConfigControllerImpl
 
 	@CryptoExecutor
 	String encryptDatabaseKey(SecretKey key, String password) {
-		long now = System.currentTimeMillis();
+		long start = now();
 		byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
-		long duration = System.currentTimeMillis() - now;
+		long duration = now() - start;
 		if (LOG.isLoggable(FINE))
 			LOG.fine("Key derivation took " + duration + " ms");
 		return StringUtils.toHexString(encrypted);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java
index c632e64ee5..aa1c1f2207 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java
@@ -38,6 +38,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
 
 @MethodsNotNullByDefault
@@ -147,7 +148,7 @@ class GroupListControllerImpl extends DbControllerImpl
 			ResultExceptionHandler<Collection<GroupItem>, DbException> handler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Collection<PrivateGroup> groups =
 						groupManager.getPrivateGroups();
 				List<GroupItem> items = new ArrayList<>(groups.size());
@@ -161,7 +162,7 @@ class GroupListControllerImpl extends DbControllerImpl
 						// Continue
 					}
 				}
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading groups took " + duration + " ms");
 				handler.onResult(items);
@@ -176,9 +177,9 @@ class GroupListControllerImpl extends DbControllerImpl
 	public void removeGroup(GroupId g, ExceptionHandler<DbException> handler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				groupManager.removePrivateGroup(g);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Removing group took " + duration + " ms");
 			} catch (DbException e) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
index 94f61f762d..91977a72db 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
@@ -65,6 +65,7 @@ import static java.util.logging.Level.WARNING;
 import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE;
 import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK;
 import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS;
+import static org.briarproject.bramble.util.TimeUtils.now;
 import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
 import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE;
 import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT;
@@ -243,12 +244,12 @@ public class SettingsFragment extends PreferenceFragmentCompat
 	private void loadSettings() {
 		listener.runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
 				Settings btSettings = settingsManager.getSettings(BT_NAMESPACE);
 				Settings torSettings =
 						settingsManager.getSettings(TOR_NAMESPACE);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading settings took " + duration + " ms");
 				boolean btSetting =
@@ -436,9 +437,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
 			try {
 				Settings s = new Settings();
 				s.putInt(PREF_TOR_NETWORK, torSetting);
-				long now = System.currentTimeMillis();
+				long start = now();
 				settingsManager.mergeSettings(s, TOR_NAMESPACE);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Merging settings took " + duration + " ms");
 			} catch (DbException e) {
@@ -452,9 +453,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
 			try {
 				Settings s = new Settings();
 				s.putBoolean(PREF_BT_ENABLE, btSetting);
-				long now = System.currentTimeMillis();
+				long start = now();
 				settingsManager.mergeSettings(s, BT_NAMESPACE);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Merging settings took " + duration + " ms");
 			} catch (DbException e) {
@@ -466,9 +467,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
 	private void storeSettings(Settings settings) {
 		listener.runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Merging settings took " + duration + " ms");
 			} catch (DbException e) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/InvitationControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/InvitationControllerImpl.java
index 9d8ae48ed1..1a8d73c31a 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/InvitationControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/InvitationControllerImpl.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
 
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @MethodsNotNullByDefault
 @ParametersNotNullByDefault
@@ -95,9 +96,9 @@ public abstract class InvitationControllerImpl<I extends InvitationItem>
 			ResultExceptionHandler<Collection<I>, DbException> handler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				Collection<I> invitations = new ArrayList<>(getInvitations());
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading invitations took " + duration + " ms");
 				handler.onResult(invitations);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java
index f12b2ee18d..21ae3891f3 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java
@@ -37,6 +37,7 @@ import java.util.logging.Logger;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.TimeUtils.now;
 
 @MethodsNotNullByDefault
 @ParametersNotNullByDefault
@@ -132,9 +133,9 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 		checkGroupId();
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				G groupItem = loadNamedGroup();
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading group took " + duration + " ms");
 				handler.onResult(groupItem);
@@ -156,21 +157,21 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 		runOnDbThread(() -> {
 			try {
 				// Load headers
-				long now = System.currentTimeMillis();
+				long start = now();
 				Collection<H> headers = loadHeaders();
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading headers took " + duration + " ms");
 
 				// Load bodies into cache
-				now = System.currentTimeMillis();
+				start = now();
 				for (H header : headers) {
 					if (!bodyCache.containsKey(header.getId())) {
 						bodyCache.put(header.getId(),
 								loadMessageBody(header));
 					}
 				}
-				duration = System.currentTimeMillis() - now;
+				duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Loading bodies took " + duration + " ms");
 
@@ -198,11 +199,11 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 	public void markItemsRead(Collection<I> items) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				for (I i : items) {
 					markRead(i.getId());
 				}
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Marking read took " + duration + " ms");
 			} catch (DbException e) {
@@ -218,10 +219,10 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 			ResultExceptionHandler<I, DbException> resultHandler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				H header = addLocalMessage(msg);
 				bodyCache.put(msg.getMessage().getId(), body);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Storing message took " + duration + " ms");
 				resultHandler.onResult(buildItem(header, body));
@@ -239,10 +240,10 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 	public void deleteNamedGroup(ExceptionHandler<DbException> handler) {
 		runOnDbThread(() -> {
 			try {
-				long now = System.currentTimeMillis();
+				long start = now();
 				G groupItem = loadNamedGroup();
 				deleteNamedGroup(groupItem);
-				long duration = System.currentTimeMillis() - now;
+				long duration = now() - start;
 				if (LOG.isLoggable(FINE))
 					LOG.fine("Removing group took " + duration + " ms");
 			} catch (DbException e) {
-- 
GitLab