From 49f10e7e8250b751ab1caf5f9f78c9bca841c6b5 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 27 Mar 2023 13:56:53 +0100 Subject: [PATCH] Move wake lock code to dont-kill-me-lib. --- bramble-android/build.gradle | 2 + .../wakelock/AndroidWakeLockModule.java | 17 +++ .../bramble/BrambleAndroidModule.java | 2 + .../bramble/api/system/AndroidWakeLock.java | 19 --- .../api/system/AndroidWakeLockManager.java | 38 ----- .../AndroidBluetoothConnectionFactory.java | 2 +- .../AndroidBluetoothPluginFactory.java | 2 +- .../AndroidBluetoothTransportConnection.java | 4 +- .../plugin/tor/AndroidTorPluginFactory.java | 2 +- .../plugin/tor/wrapper/AndroidTorWrapper.java | 24 +++- .../bramble/system/AndroidSystemModule.java | 8 -- .../bramble/system/AndroidTaskScheduler.java | 2 +- .../system/AndroidTaskSchedulerModule.java | 2 +- .../bramble/system/AndroidWakeLockImpl.java | 74 ---------- .../system/AndroidWakeLockManagerImpl.java | 125 ----------------- .../AndroidWakefulIoExecutorModule.java | 2 +- .../bramble/system/RenewableWakeLock.java | 130 ------------------ .../bramble/system/SharedWakeLock.java | 22 --- bramble-android/witness.gradle | 7 +- .../plugin/tor/wrapper/UnixTorWrapper.java | 18 +++ .../plugin/tor/wrapper/WindowsTorWrapper.java | 18 +++ briar-android/build.gradle | 1 - .../briar/android/AndroidComponent.java | 2 +- .../briar/android/BriarService.java | 2 +- .../briar/android/activity/BriarActivity.java | 2 +- .../controller/BriarControllerImpl.java | 2 +- .../splash/ExpiredOldAndroidActivity.java | 2 +- briar-android/witness.gradle | 6 +- 28 files changed, 99 insertions(+), 438 deletions(-) create mode 100644 bramble-android/src/main/java/org/briarproject/android/dontkillmelib/wakelock/AndroidWakeLockModule.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java delete mode 100644 bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java diff --git a/bramble-android/build.gradle b/bramble-android/build.gradle index 719309088..4a3083747 100644 --- a/bramble-android/build.gradle +++ b/bramble-android/build.gradle @@ -40,6 +40,8 @@ configurations { } dependencies { + api 'org.briarproject:dont-kill-me-lib:0.2.6' + // In theory this dependency shouldn't be needed, but without it Android Studio's linter will // complain about unresolved symbols for bramble-api test classes in bramble-android tests, // even though the bramble-api test classes are provided by the testImplementation dependency diff --git a/bramble-android/src/main/java/org/briarproject/android/dontkillmelib/wakelock/AndroidWakeLockModule.java b/bramble-android/src/main/java/org/briarproject/android/dontkillmelib/wakelock/AndroidWakeLockModule.java new file mode 100644 index 000000000..a8dba5dd1 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/android/dontkillmelib/wakelock/AndroidWakeLockModule.java @@ -0,0 +1,17 @@ +package org.briarproject.android.dontkillmelib.wakelock; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class AndroidWakeLockModule { + + @Provides + @Singleton + AndroidWakeLockManager provideWakeLockManager( + AndroidWakeLockManagerImpl wakeLockManager) { + return wakeLockManager; + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java index 7859bd652..4e4a49f86 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java @@ -1,5 +1,6 @@ package org.briarproject.bramble; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockModule; import org.briarproject.bramble.battery.AndroidBatteryModule; import org.briarproject.bramble.io.DnsModule; import org.briarproject.bramble.network.AndroidNetworkModule; @@ -19,6 +20,7 @@ import dagger.Module; AndroidSystemModule.class, AndroidTaskSchedulerModule.class, AndroidWakefulIoExecutorModule.class, + AndroidWakeLockModule.class, DefaultThreadFactoryModule.class, CircumventionModule.class, DnsModule.class, diff --git a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java deleted file mode 100644 index 2ef13da48..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLock.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.briarproject.bramble.api.system; - -import org.briarproject.nullsafety.NotNullByDefault; - -@NotNullByDefault -public interface AndroidWakeLock { - - /** - * Acquires the wake lock. This has no effect if the wake lock has already - * been acquired. - */ - void acquire(); - - /** - * Releases the wake lock. This has no effect if the wake lock has already - * been released. - */ - void release(); -} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java b/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java deleted file mode 100644 index a44a088a5..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/api/system/AndroidWakeLockManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.briarproject.bramble.api.system; - -import org.briarproject.nullsafety.NotNullByDefault; - -import java.util.concurrent.Executor; - -@NotNullByDefault -public interface AndroidWakeLockManager { - - /** - * Creates a wake lock with the given tag. The tag is only used for - * logging; the underlying OS wake lock will use its own tag. - */ - AndroidWakeLock createWakeLock(String tag); - - /** - * Runs the given task while holding a wake lock. - */ - void runWakefully(Runnable r, String tag); - - /** - * Submits the given task to the given executor while holding a wake lock. - * The lock is released when the task completes, or if an exception is - * thrown while submitting or running the task. - */ - void executeWakefully(Runnable r, Executor executor, String tag); - - /** - * Starts a dedicated thread to run the given task asynchronously. A wake - * lock is acquired before starting the thread and released when the task - * completes, or if an exception is thrown while starting the thread or - * running the task. - *

- * This method should only be used for lifecycle management tasks that - * can't be run on an executor. - */ - void executeWakefully(Runnable r, String tag); -} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java index ecc468258..3ad518fb4 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothConnectionFactory.java @@ -2,10 +2,10 @@ package org.briarproject.bramble.plugin.bluetooth; import android.bluetooth.BluetoothSocket; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.nullsafety.NotNullByDefault; import java.io.IOException; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java index 6ea75cb27..2e3a2ac69 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPluginFactory.java @@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.bluetooth; import android.app.Application; import android.bluetooth.BluetoothSocket; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.lifecycle.IoExecutor; @@ -13,7 +14,6 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.system.AndroidExecutor; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.WakefulIoExecutor; import org.briarproject.nullsafety.NotNullByDefault; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java index 297c11021..fbfee2791 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothTransportConnection.java @@ -2,11 +2,11 @@ package org.briarproject.bramble.plugin.bluetooth; import android.bluetooth.BluetoothSocket; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLock; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.io.TimeoutMonitor; import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection; -import org.briarproject.bramble.api.system.AndroidWakeLock; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.nullsafety.NotNullByDefault; import java.io.IOException; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java index 34621a1af..497ea7f43 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPluginFactory.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.tor; import android.app.Application; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.battery.BatteryManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.event.EventBus; @@ -14,7 +15,6 @@ import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.TorControlPort; import org.briarproject.bramble.api.plugin.TorDirectory; import org.briarproject.bramble.api.plugin.TorSocksPort; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.WakefulIoExecutor; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/AndroidTorWrapper.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/AndroidTorWrapper.java index 36b8ced24..b07b4e147 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/AndroidTorWrapper.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/AndroidTorWrapper.java @@ -7,8 +7,8 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.os.Build; -import org.briarproject.bramble.api.system.AndroidWakeLock; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLock; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.nullsafety.NotNullByDefault; import java.io.File; @@ -29,6 +29,9 @@ import static java.util.Arrays.asList; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; +/** + * A Tor wrapper for the Android operating system. + */ @NotNullByDefault public class AndroidTorWrapper extends AbstractTorWrapper { @@ -46,6 +49,23 @@ public class AndroidTorWrapper extends AbstractTorWrapper { private final AndroidWakeLock wakeLock; private final File torLib, obfs4Lib, snowflakeLib; + /** + * @param app The application instance. + * @param wakeLockManager The interface for managing a shared wake lock. + * @param ioExecutor The wrapper will use this executor to run IO tasks, + * some of which may run for the lifetime of the wrapper, so the executor + * should have an unlimited thread pool. + * @param eventExecutor The wrapper will use this executor to call + * {@link StateObserver#observeState(TorState)}. To ensure that state + * changes are observed in the order they occur, this executor should have + * a single thread (eg the app's main thread). + * @param architecture The processor architecture of the Tor and pluggable + * transport binaries. + * @param torDirectory The directory where the Tor process should keep its + * state. + * @param torSocksPort The port number to use for Tor's SOCKS port. + * @param torControlPort The port number to use for Tor's control port. + */ public AndroidTorWrapper(Application app, AndroidWakeLockManager wakeLockManager, Executor ioExecutor, diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java index 714d1ab83..96aadb506 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidSystemModule.java @@ -3,7 +3,6 @@ package org.briarproject.bramble.system; import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.system.AndroidExecutor; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.api.system.ResourceProvider; import org.briarproject.bramble.api.system.SecureRandomProvider; @@ -69,11 +68,4 @@ public class AndroidSystemModule { ResourceProvider provideResourceProvider(AndroidResourceProvider provider) { return provider; } - - @Provides - @Singleton - AndroidWakeLockManager provideWakeLockManager( - AndroidWakeLockManagerImpl wakeLockManager) { - return wakeLockManager; - } } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java index 92fb8c4d5..22f8d0df6 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java @@ -8,10 +8,10 @@ import android.content.Intent; import android.os.Process; import android.os.SystemClock; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.Cancellable; import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.bramble.api.system.AlarmListener; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.TaskScheduler; import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.nullsafety.NotNullByDefault; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskSchedulerModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskSchedulerModule.java index 2dcbb551c..403fd8f9d 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskSchedulerModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskSchedulerModule.java @@ -2,9 +2,9 @@ package org.briarproject.bramble.system; import android.app.Application; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.system.AlarmListener; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.TaskScheduler; import java.util.concurrent.ScheduledExecutorService; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java deleted file mode 100644 index 5da499d1e..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.briarproject.bramble.system; - -import org.briarproject.bramble.api.system.AndroidWakeLock; -import org.briarproject.nullsafety.NotNullByDefault; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Logger; - -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.ThreadSafe; - -import static java.util.logging.Level.FINE; -import static java.util.logging.Logger.getLogger; - -/** - * A wrapper around a {@link SharedWakeLock} that provides the more convenient - * semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release() - * don't need to be balanced). - */ -@ThreadSafe -@NotNullByDefault -class AndroidWakeLockImpl implements AndroidWakeLock { - - private static final Logger LOG = - getLogger(AndroidWakeLockImpl.class.getName()); - - private static final AtomicInteger INSTANCE_ID = new AtomicInteger(0); - - private final SharedWakeLock sharedWakeLock; - private final String tag; - - private final Object lock = new Object(); - @GuardedBy("lock") - private boolean held = false; - - AndroidWakeLockImpl(SharedWakeLock sharedWakeLock, String tag) { - this.sharedWakeLock = sharedWakeLock; - this.tag = tag + "_" + INSTANCE_ID.getAndIncrement(); - } - - @Override - public void acquire() { - synchronized (lock) { - if (held) { - if (LOG.isLoggable(FINE)) { - LOG.fine(tag + " already acquired"); - } - } else { - if (LOG.isLoggable(FINE)) { - LOG.fine(tag + " acquiring shared wake lock"); - } - held = true; - sharedWakeLock.acquire(); - } - } - } - - @Override - public void release() { - synchronized (lock) { - if (held) { - if (LOG.isLoggable(FINE)) { - LOG.fine(tag + " releasing shared wake lock"); - } - held = false; - sharedWakeLock.release(); - } else { - if (LOG.isLoggable(FINE)) { - LOG.fine(tag + " already released"); - } - } - } - } -} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java deleted file mode 100644 index 8c0f444e0..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.briarproject.bramble.system; - -import android.app.Application; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.PowerManager; - -import org.briarproject.bramble.api.system.AndroidWakeLock; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; -import org.briarproject.nullsafety.NotNullByDefault; - -import java.util.concurrent.Executor; -import java.util.concurrent.ScheduledExecutorService; - -import javax.inject.Inject; - -import static android.content.Context.POWER_SERVICE; -import static android.os.PowerManager.PARTIAL_WAKE_LOCK; -import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.briarproject.nullsafety.NullSafety.requireNonNull; - -@NotNullByDefault -class AndroidWakeLockManagerImpl implements AndroidWakeLockManager { - - /** - * How often to replace the wake lock. - */ - private static final long LOCK_DURATION_MS = MINUTES.toMillis(1); - - /** - * Automatically release the lock this many milliseconds after it's due - * to have been replaced and released. - */ - private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(30); - - private final SharedWakeLock sharedWakeLock; - - @Inject - AndroidWakeLockManagerImpl(Application app, - ScheduledExecutorService scheduledExecutorService) { - PowerManager powerManager = (PowerManager) - requireNonNull(app.getSystemService(POWER_SERVICE)); - String tag = getWakeLockTag(app); - sharedWakeLock = new RenewableWakeLock(powerManager, - scheduledExecutorService, PARTIAL_WAKE_LOCK, tag, - LOCK_DURATION_MS, SAFETY_MARGIN_MS); - } - - @Override - public AndroidWakeLock createWakeLock(String tag) { - return new AndroidWakeLockImpl(sharedWakeLock, tag); - } - - @Override - public void runWakefully(Runnable r, String tag) { - AndroidWakeLock wakeLock = createWakeLock(tag); - wakeLock.acquire(); - try { - r.run(); - } finally { - wakeLock.release(); - } - } - - @Override - public void executeWakefully(Runnable r, Executor executor, String tag) { - AndroidWakeLock wakeLock = createWakeLock(tag); - wakeLock.acquire(); - try { - executor.execute(() -> { - try { - r.run(); - } finally { - // Release the wake lock if the task throws an exception - wakeLock.release(); - } - }); - } catch (Exception e) { - // Release the wake lock if the executor throws an exception when - // we submit the task (in which case the release() call above won't - // happen) - wakeLock.release(); - throw e; - } - } - - @Override - public void executeWakefully(Runnable r, String tag) { - AndroidWakeLock wakeLock = createWakeLock(tag); - wakeLock.acquire(); - try { - new Thread(() -> { - try { - r.run(); - } finally { - wakeLock.release(); - } - }).start(); - } catch (Exception e) { - wakeLock.release(); - throw e; - } - } - - private String getWakeLockTag(Context ctx) { - PackageManager pm = ctx.getPackageManager(); - if (isInstalled(pm, "com.huawei.powergenie")) { - return "LocationManagerService"; - } else if (isInstalled(pm, "com.evenwell.PowerMonitor")) { - return "AudioIn"; - } - return ctx.getPackageName(); - } - - private boolean isInstalled(PackageManager pm, String packageName) { - try { - pm.getPackageInfo(packageName, 0); - return true; - } catch (PackageManager.NameNotFoundException e) { - return false; - } - } - -} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakefulIoExecutorModule.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakefulIoExecutorModule.java index 994b50483..d8048d0ba 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakefulIoExecutorModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakefulIoExecutorModule.java @@ -1,7 +1,7 @@ package org.briarproject.bramble.system; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.lifecycle.IoExecutor; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.WakefulIoExecutor; import java.util.concurrent.Executor; diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java deleted file mode 100644 index 498c3e8d4..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/RenewableWakeLock.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.briarproject.bramble.system; - -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; - -import org.briarproject.nullsafety.NotNullByDefault; - -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.logging.Logger; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.ThreadSafe; - -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.logging.Level.FINE; -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.nullsafety.NullSafety.requireNonNull; - -@ThreadSafe -@NotNullByDefault -class RenewableWakeLock implements SharedWakeLock { - - private static final Logger LOG = - getLogger(RenewableWakeLock.class.getName()); - - private final PowerManager powerManager; - private final ScheduledExecutorService scheduledExecutorService; - private final int levelAndFlags; - private final String tag; - private final long durationMs, safetyMarginMs; - - private final Object lock = new Object(); - @GuardedBy("lock") - @Nullable - private WakeLock wakeLock; - @GuardedBy("lock") - @Nullable - private Future future; - @GuardedBy("lock") - private int refCount = 0; - @GuardedBy("lock") - private long acquired = 0; - - RenewableWakeLock(PowerManager powerManager, - ScheduledExecutorService scheduledExecutorService, - int levelAndFlags, - String tag, - long durationMs, - long safetyMarginMs) { - this.powerManager = powerManager; - this.scheduledExecutorService = scheduledExecutorService; - this.levelAndFlags = levelAndFlags; - this.tag = tag; - this.durationMs = durationMs; - this.safetyMarginMs = safetyMarginMs; - } - - @Override - public void acquire() { - synchronized (lock) { - refCount++; - if (refCount == 1) { - if (LOG.isLoggable(INFO)) { - LOG.info("Acquiring wake lock " + tag); - } - wakeLock = powerManager.newWakeLock(levelAndFlags, tag); - // We do our own reference counting so we can replace the lock - // TODO: Check whether using a ref-counted wake lock affects - // power management apps - wakeLock.setReferenceCounted(false); - wakeLock.acquire(durationMs + safetyMarginMs); - future = scheduledExecutorService.schedule(this::renew, - durationMs, MILLISECONDS); - acquired = android.os.SystemClock.elapsedRealtime(); - } else if (LOG.isLoggable(FINE)) { - LOG.fine("Wake lock " + tag + " has " + refCount + " holders"); - } - } - } - - private void renew() { - if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag); - synchronized (lock) { - if (wakeLock == null) { - LOG.info("Already released"); - return; - } - if (LOG.isLoggable(FINE)) { - LOG.fine("Wake lock " + tag + " has " + refCount + " holders"); - } - long now = android.os.SystemClock.elapsedRealtime(); - long expiry = acquired + durationMs + safetyMarginMs; - if (now > expiry && LOG.isLoggable(WARNING)) { - LOG.warning("Wake lock expired " + (now - expiry) + " ms ago"); - } - WakeLock oldWakeLock = wakeLock; - wakeLock = powerManager.newWakeLock(levelAndFlags, tag); - wakeLock.setReferenceCounted(false); - wakeLock.acquire(durationMs + safetyMarginMs); - oldWakeLock.release(); - future = scheduledExecutorService.schedule(this::renew, durationMs, - MILLISECONDS); - acquired = now; - } - } - - @Override - public void release() { - synchronized (lock) { - refCount--; - if (refCount == 0) { - if (LOG.isLoggable(INFO)) { - LOG.info("Releasing wake lock " + tag); - } - requireNonNull(future).cancel(false); - future = null; - requireNonNull(wakeLock).release(); - wakeLock = null; - acquired = 0; - } else if (LOG.isLoggable(FINE)) { - LOG.fine("Wake lock " + tag + " has " + refCount + " holders"); - } - } - } -} - diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java b/bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java deleted file mode 100644 index d8c430eec..000000000 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/SharedWakeLock.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.briarproject.bramble.system; - -import org.briarproject.bramble.api.system.AndroidWakeLock; -import org.briarproject.nullsafety.NotNullByDefault; - -@NotNullByDefault -interface SharedWakeLock { - - /** - * Acquires the wake lock. This increments the wake lock's reference count, - * so unlike {@link AndroidWakeLock#acquire()} every call to this method - * must be followed by a balancing call to {@link #release()}. - */ - void acquire(); - - /** - * Releases the wake lock. This decrements the wake lock's reference count, - * so unlike {@link AndroidWakeLock#release()} every call to this method - * must follow a balancing call to {@link #acquire()}. - */ - void release(); -} diff --git a/bramble-android/witness.gradle b/bramble-android/witness.gradle index 62fadac3f..f87138d64 100644 --- a/bramble-android/witness.gradle +++ b/bramble-android/witness.gradle @@ -24,6 +24,8 @@ dependencyVerification { 'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0', 'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd', 'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047', + 'org.briarproject:dont-kill-me-lib:0.2.6:dont-kill-me-lib-0.2.6.aar:8a4cc201143227c0865c2edfba035f71109bf02e1ab26444fa3e42d3c569960f', + 'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011', 'org.briarproject:obfs4proxy-android:0.0.14-tor2:obfs4proxy-android-0.0.14-tor2.jar:a0a93770d6760ce57d9dbd31cc7177687374e00c3361dac22ab75e3b6e0f289e', 'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87', 'org.briarproject:tor-android:0.4.7.13-2:tor-android-0.4.7.13-2.jar:453fd463b234a2104edd7f0d02d0649cbb5c5efbe47a76df3828f55a3f90f8b5', @@ -37,11 +39,12 @@ dependencyVerification { 'org.jacoco:org.jacoco.core:0.8.7:org.jacoco.core-0.8.7.jar:ad7739b5fb5969aa1a8aead3d74ed54dc82ed012f1f10f336bd1b96e71c1a13c', 'org.jacoco:org.jacoco.report:0.8.7:org.jacoco.report-0.8.7.jar:cc89258623700a6c932592153cb528785876b6da183d5431f97efbba6f020e5b', 'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10:kotlin-stdlib-common-1.7.10.jar:19f102efe9629f8eabc63853ad15c533e47c47f91fca09285c5bde86e59f91d4', + 'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0:kotlin-stdlib-common-1.8.0.jar:78ef93b59e603cc0fe51def9bd4c037b07cbace3b3b7806d1a490a42bc1f4cb2', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239', + 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0:kotlin-stdlib-jdk7-1.8.0.jar:4c889d1d9803f5f2eb6c1592a6b7e62369ac7660c9eee15aba16fec059163666', 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b', 'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05', - 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10:kotlin-stdlib-1.7.10.jar:e771fe74250a943e8f6346713201ff1d8cb95c3a5d1a91a22b65a9e04f6a8901', + 'org.jetbrains.kotlin:kotlin-stdlib:1.8.0:kotlin-stdlib-1.8.0.jar:c77bef8774640b9fb9d6e217459ff220dae59878beb7d2e4b430506feffc654e', 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', 'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09', diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/UnixTorWrapper.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/UnixTorWrapper.java index 14c3c5773..d01550c67 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/UnixTorWrapper.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/UnixTorWrapper.java @@ -8,9 +8,27 @@ import org.briarproject.nullsafety.NotNullByDefault; import java.io.File; import java.util.concurrent.Executor; +/** + * A Tor wrapper for Unix-like operating systems. + */ @NotNullByDefault public class UnixTorWrapper extends JavaTorWrapper { + /** + * @param ioExecutor The wrapper will use this executor to run IO tasks, + * some of which may run for the lifetime of the wrapper, so the executor + * should have an unlimited thread pool. + * @param eventExecutor The wrapper will use this executor to call + * {@link StateObserver#observeState(TorState)}. To ensure that state + * changes are observed in the order they occur, this executor should have + * a single thread (eg the app's main thread). + * @param architecture The processor architecture of the Tor and pluggable + * transport binaries. + * @param torDirectory The directory where the Tor process should keep its + * state. + * @param torSocksPort The port number to use for Tor's SOCKS port. + * @param torControlPort The port number to use for Tor's control port. + */ public UnixTorWrapper(Executor ioExecutor, Executor eventExecutor, String architecture, diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/WindowsTorWrapper.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/WindowsTorWrapper.java index 8c31a1b5c..fb1169411 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/WindowsTorWrapper.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/tor/wrapper/WindowsTorWrapper.java @@ -13,9 +13,27 @@ import java.util.concurrent.Executor; import static java.util.logging.Level.INFO; +/** + * A Tor wrapper for the Windows operating system. + */ @NotNullByDefault public class WindowsTorWrapper extends JavaTorWrapper { + /** + * @param ioExecutor The wrapper will use this executor to run IO tasks, + * some of which may run for the lifetime of the wrapper, so the executor + * should have an unlimited thread pool. + * @param eventExecutor The wrapper will use this executor to call + * {@link StateObserver#observeState(TorState)}. To ensure that state + * changes are observed in the order they occur, this executor should have + * a single thread (eg the app's main thread). + * @param architecture The processor architecture of the Tor and pluggable + * transport binaries. + * @param torDirectory The directory where the Tor process should keep its + * state. + * @param torSocksPort The port number to use for Tor's SOCKS port. + * @param torControlPort The port number to use for Tor's control port. + */ public WindowsTorWrapper(Executor ioExecutor, Executor eventExecutor, String architecture, diff --git a/briar-android/build.gradle b/briar-android/build.gradle index d05cbd064..dec9db1c1 100644 --- a/briar-android/build.gradle +++ b/briar-android/build.gradle @@ -116,7 +116,6 @@ dependencies { implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.recyclerview:recyclerview-selection:1.1.0' - implementation 'org.briarproject:dont-kill-me-lib:0.2.5' implementation "com.squareup.okhttp3:okhttp:$okhttp_version" implementation "org.jsoup:jsoup:$jsoup_version" implementation 'info.guardianproject.panic:panic:1.0' diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 468782cd4..6d23ec95f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.BrambleAndroidEagerSingletons; import org.briarproject.bramble.BrambleAndroidModule; import org.briarproject.bramble.BrambleAppComponent; @@ -25,7 +26,6 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.api.system.AndroidExecutor; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.LocationUtils; import org.briarproject.bramble.mailbox.ModularMailboxModule; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index 3fab62163..87f866021 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -15,12 +15,12 @@ import android.os.IBinder; import com.bumptech.glide.Glide; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult; import org.briarproject.bramble.api.system.AndroidExecutor; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.R; import org.briarproject.briar.android.logout.HideUiActivity; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java index 8c72093ba..9873748a4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java @@ -5,7 +5,7 @@ import android.transition.Transition; import android.view.Window; import android.widget.CheckBox; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.briar.R; import org.briarproject.briar.android.BriarApplication; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java index 47dfa1ba8..34f4edcee 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java @@ -4,13 +4,13 @@ import android.app.Activity; import android.content.Intent; import android.os.IBinder; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.BriarService; import org.briarproject.briar.android.BriarService.BriarServiceConnection; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/splash/ExpiredOldAndroidActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/splash/ExpiredOldAndroidActivity.java index c9fe83229..a5e7d271c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/splash/ExpiredOldAndroidActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/splash/ExpiredOldAndroidActivity.java @@ -3,7 +3,7 @@ package org.briarproject.briar.android.splash; import android.content.Intent; import android.os.Bundle; -import org.briarproject.bramble.api.system.AndroidWakeLockManager; +import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BaseActivity; diff --git a/briar-android/witness.gradle b/briar-android/witness.gradle index 198bc6e14..5795fc5a2 100644 --- a/briar-android/witness.gradle +++ b/briar-android/witness.gradle @@ -120,7 +120,6 @@ dependencyVerification { 'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd', 'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047', 'org.bouncycastle:bcprov-jdk15on:1.65:bcprov-jdk15on-1.65.jar:e78f96eb59066c94c94fb2d6b5eb80f52feac6f5f9776898634f8addec6e2137', - 'org.briarproject:dont-kill-me-lib:0.2.5:dont-kill-me-lib-0.2.5.aar:55cd9d511b7016ab573905d64bc54e222e2633144d36389192b8b34485b31b9d', 'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a', 'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a', 'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb', @@ -136,12 +135,11 @@ dependencyVerification { 'org.jacoco:org.jacoco.core:0.8.7:org.jacoco.core-0.8.7.jar:ad7739b5fb5969aa1a8aead3d74ed54dc82ed012f1f10f336bd1b96e71c1a13c', 'org.jacoco:org.jacoco.report:0.8.7:org.jacoco.report-0.8.7.jar:cc89258623700a6c932592153cb528785876b6da183d5431f97efbba6f020e5b', 'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10:kotlin-stdlib-common-1.7.10.jar:19f102efe9629f8eabc63853ad15c533e47c47f91fca09285c5bde86e59f91d4', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.20:kotlin-stdlib-jdk7-1.6.20.jar:aa2fa2e81355c4d98dd97da2169bf401f842261378f5b1cbea1aa11855d67620', + 'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0:kotlin-stdlib-common-1.8.0.jar:78ef93b59e603cc0fe51def9bd4c037b07cbace3b3b7806d1a490a42bc1f4cb2', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239', 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b', 'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05', - 'org.jetbrains.kotlin:kotlin-stdlib:1.7.10:kotlin-stdlib-1.7.10.jar:e771fe74250a943e8f6346713201ff1d8cb95c3a5d1a91a22b65a9e04f6a8901', + 'org.jetbrains.kotlin:kotlin-stdlib:1.8.0:kotlin-stdlib-1.8.0.jar:c77bef8774640b9fb9d6e217459ff220dae59878beb7d2e4b430506feffc654e', 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1:kotlinx-coroutines-android-1.4.1.jar:d4cadb673b2101f1ee5fbc147956ac78b1cfd9cc255fb53d3aeb88dff11d99ca', 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.1:kotlinx-coroutines-core-jvm-1.4.1.jar:6d2f87764b6638f27aff12ed380db4b63c9d46ba55dc32683a650598fa5a3e22', 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',