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 index 0ebf256a2..b1cad4377 100644 --- 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 @@ -24,4 +24,12 @@ public interface AndroidWakeLockManager { * 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. + */ + void executeWakefully(Runnable r, String tag); } 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 index bf80c5fc0..f976e518d 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidWakeLockManagerImpl.java @@ -86,6 +86,24 @@ class AndroidWakeLockManagerImpl implements AndroidWakeLockManager { } } + @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(); for (PackageInfo info : pm.getInstalledPackages(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 0c4de76ee..fedf33ba3 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 @@ -24,6 +24,7 @@ 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.plugin.tor.CircumventionProvider; @@ -166,6 +167,8 @@ public interface AndroidComponent FeatureFlags featureFlags(); + AndroidWakeLockManager wakeLockManager(); + void inject(SignInReminderReceiver briarService); void inject(BriarService briarService); 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 952664002..a949161e9 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 @@ -20,14 +20,12 @@ 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.WakefulIoExecutor; import org.briarproject.briar.R; import org.briarproject.briar.android.logout.HideUiActivity; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.LockManager; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; @@ -86,9 +84,6 @@ public class BriarService extends Service { LockManager lockManager; @Inject AndroidWakeLockManager wakeLockManager; - @Inject - @WakefulIoExecutor - Executor wakefulIoExecutor; // Fields that are accessed from background threads must be volatile @Inject @@ -140,7 +135,7 @@ public class BriarService extends Service { notificationManager.getForegroundNotification(); startForeground(ONGOING_NOTIFICATION_ID, foregroundNotification); // Start the services in a background thread - wakefulIoExecutor.execute(() -> { + wakeLockManager.executeWakefully(() -> { StartResult result = lifecycleManager.startServices(dbKey); if (result == SUCCESS) { started = true; @@ -153,7 +148,7 @@ public class BriarService extends Service { showStartupFailureNotification(result); stopSelf(); } - }); + }, "LifecycleStartup"); // Register for device shutdown broadcasts receiver = new BroadcastReceiver() { @Override @@ -224,9 +219,9 @@ public class BriarService extends Service { stopForeground(true); if (receiver != null) unregisterReceiver(receiver); // Stop the services in a background thread - wakefulIoExecutor.execute(() -> { + wakeLockManager.executeWakefully(() -> { if (started) lifecycleManager.stopServices(); - }); + }, "LifecycleShutdown"); }, "LifecycleShutdown"); } @@ -279,7 +274,7 @@ public class BriarService extends Service { // Hide the UI hideUi(); // Wait for shutdown to complete, then exit - wakefulIoExecutor.execute(() -> { + wakeLockManager.executeWakefully(() -> { try { if (started) lifecycleManager.waitForShutdown(); } catch (InterruptedException e) { @@ -287,7 +282,7 @@ public class BriarService extends Service { } LOG.info("Exiting"); System.exit(0); - }); + }, "BackgroundShutdown"); }, "BackgroundShutdown"); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 60edec57d..02c18b341 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -82,13 +82,19 @@ import org.briarproject.briar.android.test.TestDataActivity; import dagger.Component; @ActivityScope -@Component( - modules = {ActivityModule.class, ForumModule.class, SharingModule.class, - BlogModule.class, ContactModule.class, GroupListModule.class, - CreateGroupModule.class, GroupInvitationModule.class, - GroupConversationModule.class, GroupMemberModule.class, - GroupRevealModule.class}, - dependencies = AndroidComponent.class) +@Component(modules = { + ActivityModule.class, + BlogModule.class, + ContactModule.class, + CreateGroupModule.class, + ForumModule.class, + GroupInvitationModule.class, + GroupConversationModule.class, + GroupListModule.class, + GroupMemberModule.class, + GroupRevealModule.class, + SharingModule.class +}, dependencies = AndroidComponent.class) public interface ActivityComponent { Activity activity(); 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 15de79805..e8ce42f32 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 @@ -7,6 +7,8 @@ import android.widget.CheckBox; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.system.AndroidWakeLockManager; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.briar.R; import org.briarproject.briar.android.account.UnlockActivity; import org.briarproject.briar.android.controller.BriarController; @@ -32,6 +34,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Build.VERSION.SDK_INT; import static java.util.logging.Level.INFO; +import static java.util.logging.Logger.getLogger; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_UNLOCK; @@ -47,7 +50,7 @@ public abstract class BriarActivity extends BaseActivity { public static final String GROUP_NAME = "briar.GROUP_NAME"; private static final Logger LOG = - Logger.getLogger(BriarActivity.class.getName()); + getLogger(BriarActivity.class.getName()); @Inject BriarController briarController; @@ -56,6 +59,8 @@ public abstract class BriarActivity extends BaseActivity { DbController dbController; @Inject protected LockManager lockManager; + @Inject + AndroidWakeLockManager wakeLockManager; @Override public void onStart() { @@ -130,6 +135,7 @@ public abstract class BriarActivity extends BaseActivity { /** * Sets the transition animations. + * * @param enterTransition used to move views into initial positions * @param exitTransition used to move views out when starting a new activity. * @param returnTransition used when window is closing, because the activity is finishing. @@ -197,22 +203,29 @@ public abstract class BriarActivity extends BaseActivity { protected void signOut(boolean removeFromRecentApps, boolean deleteAccount) { - if (briarController.accountSignedIn()) { - // Don't use UiResultHandler because we want the result even if - // this activity has been destroyed - briarController.signOut(result -> runOnUiThread( - () -> exit(removeFromRecentApps)), deleteAccount); - } else { - if (deleteAccount) briarController.deleteAccount(); - exit(removeFromRecentApps); - } + // Hold a wake lock to ensure we exit before the device goes to sleep + wakeLockManager.runWakefully(() -> { + if (briarController.accountSignedIn()) { + // Don't use UiResultHandler because we want the result even if + // this activity has been destroyed + briarController.signOut(result -> + wakeLockManager.executeWakefully(() -> + exit(removeFromRecentApps), + this::runOnUiThread, "SignOut"), deleteAccount); + } else { + if (deleteAccount) briarController.deleteAccount(); + exit(removeFromRecentApps); + } + }, "SignOut"); } + @Wakeful private void exit(boolean removeFromRecentApps) { if (removeFromRecentApps) startExitActivity(); else finishAndExit(); } + @Wakeful private void startExitActivity() { Intent i = new Intent(this, ExitActivity.class); i.addFlags(FLAG_ACTIVITY_NEW_TASK @@ -222,6 +235,7 @@ public abstract class BriarActivity extends BaseActivity { startActivity(i); } + @Wakeful private void finishAndExit() { if (SDK_INT >= 21) finishAndRemoveTask(); else supportFinishAfterTransition(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java index c86e6f905..33cbb9e64 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java @@ -1,7 +1,10 @@ package org.briarproject.briar.android.controller; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.system.Wakeful; import org.briarproject.briar.android.controller.handler.ResultHandler; +@NotNullByDefault public interface BriarController extends ActivityLifecycleController { void startAndBindService(); @@ -16,7 +19,8 @@ public interface BriarController extends ActivityLifecycleController { void doNotAskAgainForDozeWhiteListing(); - void signOut(ResultHandler eventHandler, boolean deleteAccount); + @Wakeful + void signOut(ResultHandler handler, boolean deleteAccount); void deleteAccount(); 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 2e4479716..65c3efec4 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 @@ -8,8 +8,10 @@ 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.nullsafety.NotNullByDefault; 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.BriarService; import org.briarproject.briar.android.BriarService.BriarServiceConnection; import org.briarproject.briar.android.controller.handler.ResultHandler; @@ -23,15 +25,17 @@ import javax.inject.Inject; import androidx.annotation.CallSuper; import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting; +@NotNullByDefault public class BriarControllerImpl implements BriarController { private static final Logger LOG = - Logger.getLogger(BriarControllerImpl.class.getName()); + getLogger(BriarControllerImpl.class.getName()); public static final String DOZE_ASK_AGAIN = "dozeAskAgain"; @@ -41,6 +45,7 @@ public class BriarControllerImpl implements BriarController { private final Executor databaseExecutor; private final SettingsManager settingsManager; private final DozeWatchdog dozeWatchdog; + private final AndroidWakeLockManager wakeLockManager; private final Activity activity; private boolean bound = false; @@ -50,7 +55,9 @@ public class BriarControllerImpl implements BriarController { AccountManager accountManager, LifecycleManager lifecycleManager, @DatabaseExecutor Executor databaseExecutor, - SettingsManager settingsManager, DozeWatchdog dozeWatchdog, + SettingsManager settingsManager, + DozeWatchdog dozeWatchdog, + AndroidWakeLockManager wakeLockManager, Activity activity) { this.serviceConnection = serviceConnection; this.accountManager = accountManager; @@ -58,6 +65,7 @@ public class BriarControllerImpl implements BriarController { this.databaseExecutor = databaseExecutor; this.settingsManager = settingsManager; this.dozeWatchdog = dozeWatchdog; + this.wakeLockManager = wakeLockManager; this.activity = activity; } @@ -127,9 +135,8 @@ public class BriarControllerImpl implements BriarController { } @Override - public void signOut(ResultHandler eventHandler, - boolean deleteAccount) { - new Thread(() -> { + public void signOut(ResultHandler handler, boolean deleteAccount) { + wakeLockManager.executeWakefully(() -> { try { // Wait for the service to finish starting up IBinder binder = serviceConnection.waitForBinder(); @@ -145,8 +152,8 @@ public class BriarControllerImpl implements BriarController { } finally { if (deleteAccount) accountManager.deleteAccount(); } - eventHandler.onResult(null); - }).start(); + handler.onResult(null); + }, "SignOut"); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java index b1ca57ee6..1491e3659 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java @@ -4,17 +4,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; -import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; import java.util.logging.Logger; import javax.annotation.Nullable; -import javax.inject.Inject; import androidx.preference.PreferenceManager; import info.guardianproject.GuardianProjectRSA4096; @@ -23,6 +20,7 @@ import info.guardianproject.panic.PanicResponder; import info.guardianproject.trustedintents.TrustedIntents; import static android.os.Build.VERSION.SDK_INT; +import static java.util.logging.Logger.getLogger; import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_LOCK; import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_PURGE; @@ -31,12 +29,7 @@ import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_ public class PanicResponderActivity extends BriarActivity { private static final Logger LOG = - Logger.getLogger(PanicResponderActivity.class.getName()); - - @Inject - protected LifecycleManager lifecycleManager; - @Inject - protected AndroidExecutor androidExecutor; + getLogger(PanicResponderActivity.class.getName()); @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -63,11 +56,14 @@ public class PanicResponderActivity extends BriarActivity { // Performing panic responses if (sharedPref.getBoolean(KEY_PURGE, false)) { LOG.info("Purging all data..."); - deleteAllData(); + signOut(true, true); + } else { + LOG.info("Signing out..."); + signOut(true, false); } - } - // non-destructive actions are allowed by non-connected trusted apps - if (sharedPref.getBoolean(KEY_LOCK, true)) { + } else if (sharedPref.getBoolean(KEY_LOCK, true)) { + // non-destructive actions are allowed by non-connected + // trusted apps LOG.info("Signing out..."); signOut(true, false); } @@ -85,11 +81,4 @@ public class PanicResponderActivity extends BriarActivity { public void injectActivity(ActivityComponent component) { component.inject(this); } - - private void deleteAllData() { - androidExecutor.runOnBackgroundThread(() -> { - LOG.info("Signing out..."); - signOut(true, true); - }); - } }