mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Hold a wake lock during app startup and shutdown.
This commit is contained in:
@@ -19,12 +19,15 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
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.R;
|
||||||
import org.briarproject.briar.android.logout.HideUiActivity;
|
import org.briarproject.briar.android.logout.HideUiActivity;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.LockManager;
|
import org.briarproject.briar.api.android.LockManager;
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -48,6 +51,7 @@ import static java.util.logging.Level.INFO;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
|
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||||
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_NOTIFICATION_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_NOTIFICATION_ID;
|
||||||
@@ -80,6 +84,11 @@ public class BriarService extends Service {
|
|||||||
AccountManager accountManager;
|
AccountManager accountManager;
|
||||||
@Inject
|
@Inject
|
||||||
LockManager lockManager;
|
LockManager lockManager;
|
||||||
|
@Inject
|
||||||
|
AndroidWakeLockManager wakeLockManager;
|
||||||
|
@Inject
|
||||||
|
@WakefulIoExecutor
|
||||||
|
Executor wakefulIoExecutor;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
@@ -108,54 +117,57 @@ public class BriarService extends Service {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create notification channels
|
// Hold a wake lock during startup
|
||||||
if (SDK_INT >= 26) {
|
wakeLockManager.runWakefully(() -> {
|
||||||
NotificationManager nm = (NotificationManager)
|
// Create notification channels
|
||||||
getSystemService(NOTIFICATION_SERVICE);
|
if (SDK_INT >= 26) {
|
||||||
NotificationChannel ongoingChannel = new NotificationChannel(
|
NotificationManager nm = (NotificationManager)
|
||||||
ONGOING_CHANNEL_ID,
|
requireNonNull(getSystemService(NOTIFICATION_SERVICE));
|
||||||
getString(R.string.ongoing_notification_title),
|
NotificationChannel ongoingChannel = new NotificationChannel(
|
||||||
IMPORTANCE_NONE);
|
ONGOING_CHANNEL_ID,
|
||||||
ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
getString(R.string.ongoing_notification_title),
|
||||||
nm.createNotificationChannel(ongoingChannel);
|
IMPORTANCE_NONE);
|
||||||
NotificationChannel failureChannel = new NotificationChannel(
|
ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||||
FAILURE_CHANNEL_ID,
|
nm.createNotificationChannel(ongoingChannel);
|
||||||
getString(R.string.startup_failed_notification_title),
|
NotificationChannel failureChannel = new NotificationChannel(
|
||||||
IMPORTANCE_DEFAULT);
|
FAILURE_CHANNEL_ID,
|
||||||
failureChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
getString(R.string.startup_failed_notification_title),
|
||||||
nm.createNotificationChannel(failureChannel);
|
IMPORTANCE_DEFAULT);
|
||||||
}
|
failureChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||||
Notification foregroundNotification =
|
nm.createNotificationChannel(failureChannel);
|
||||||
notificationManager.getForegroundNotification();
|
|
||||||
startForeground(ONGOING_NOTIFICATION_ID, foregroundNotification);
|
|
||||||
// Start the services in a background thread
|
|
||||||
new Thread(() -> {
|
|
||||||
StartResult result = lifecycleManager.startServices(dbKey);
|
|
||||||
if (result == SUCCESS) {
|
|
||||||
started = true;
|
|
||||||
} else if (result == ALREADY_RUNNING) {
|
|
||||||
LOG.info("Already running");
|
|
||||||
stopSelf();
|
|
||||||
} else {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.warning("Startup failed: " + result);
|
|
||||||
showStartupFailureNotification(result);
|
|
||||||
stopSelf();
|
|
||||||
}
|
}
|
||||||
}).start();
|
Notification foregroundNotification =
|
||||||
// Register for device shutdown broadcasts
|
notificationManager.getForegroundNotification();
|
||||||
receiver = new BroadcastReceiver() {
|
startForeground(ONGOING_NOTIFICATION_ID, foregroundNotification);
|
||||||
@Override
|
// Start the services in a background thread
|
||||||
public void onReceive(Context context, Intent intent) {
|
wakefulIoExecutor.execute(() -> {
|
||||||
LOG.info("Device is shutting down");
|
StartResult result = lifecycleManager.startServices(dbKey);
|
||||||
shutdownFromBackground();
|
if (result == SUCCESS) {
|
||||||
}
|
started = true;
|
||||||
};
|
} else if (result == ALREADY_RUNNING) {
|
||||||
IntentFilter filter = new IntentFilter();
|
LOG.info("Already running");
|
||||||
filter.addAction(ACTION_SHUTDOWN);
|
stopSelf();
|
||||||
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
|
} else {
|
||||||
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
|
if (LOG.isLoggable(WARNING))
|
||||||
registerReceiver(receiver, filter);
|
LOG.warning("Startup failed: " + result);
|
||||||
|
showStartupFailureNotification(result);
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Register for device shutdown broadcasts
|
||||||
|
receiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
LOG.info("Device is shutting down");
|
||||||
|
shutdownFromBackground();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(ACTION_SHUTDOWN);
|
||||||
|
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
|
||||||
|
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
|
||||||
|
registerReceiver(receiver, filter);
|
||||||
|
}, "LifecycleStartup");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -179,8 +191,8 @@ public class BriarService extends Service {
|
|||||||
i.putExtra(EXTRA_NOTIFICATION_ID, FAILURE_NOTIFICATION_ID);
|
i.putExtra(EXTRA_NOTIFICATION_ID, FAILURE_NOTIFICATION_ID);
|
||||||
b.setContentIntent(PendingIntent.getActivity(BriarService.this,
|
b.setContentIntent(PendingIntent.getActivity(BriarService.this,
|
||||||
0, i, FLAG_UPDATE_CURRENT));
|
0, i, FLAG_UPDATE_CURRENT));
|
||||||
Object o = getSystemService(NOTIFICATION_SERVICE);
|
NotificationManager nm = (NotificationManager)
|
||||||
NotificationManager nm = (NotificationManager) o;
|
requireNonNull(getSystemService(NOTIFICATION_SERVICE));
|
||||||
nm.notify(FAILURE_NOTIFICATION_ID, b.build());
|
nm.notify(FAILURE_NOTIFICATION_ID, b.build());
|
||||||
// Bring the dashboard to the front to clear the back stack
|
// Bring the dashboard to the front to clear the back stack
|
||||||
i = new Intent(BriarService.this, ENTRY_ACTIVITY);
|
i = new Intent(BriarService.this, ENTRY_ACTIVITY);
|
||||||
@@ -205,14 +217,17 @@ public class BriarService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
// Hold a wake lock during shutdown
|
||||||
LOG.info("Destroyed");
|
wakeLockManager.runWakefully(() -> {
|
||||||
stopForeground(true);
|
super.onDestroy();
|
||||||
if (receiver != null) unregisterReceiver(receiver);
|
LOG.info("Destroyed");
|
||||||
// Stop the services in a background thread
|
stopForeground(true);
|
||||||
new Thread(() -> {
|
if (receiver != null) unregisterReceiver(receiver);
|
||||||
if (started) lifecycleManager.stopServices();
|
// Stop the services in a background thread
|
||||||
}).start();
|
wakefulIoExecutor.execute(() -> {
|
||||||
|
if (started) lifecycleManager.stopServices();
|
||||||
|
});
|
||||||
|
}, "LifecycleShutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -257,20 +272,23 @@ public class BriarService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void shutdownFromBackground() {
|
private void shutdownFromBackground() {
|
||||||
// Stop the service
|
// Hold a wake lock during shutdown
|
||||||
stopSelf();
|
wakeLockManager.runWakefully(() -> {
|
||||||
// Hide the UI
|
// Stop the service
|
||||||
hideUi();
|
stopSelf();
|
||||||
// Wait for shutdown to complete, then exit
|
// Hide the UI
|
||||||
new Thread(() -> {
|
hideUi();
|
||||||
try {
|
// Wait for shutdown to complete, then exit
|
||||||
if (started) lifecycleManager.waitForShutdown();
|
wakefulIoExecutor.execute(() -> {
|
||||||
} catch (InterruptedException e) {
|
try {
|
||||||
LOG.info("Interrupted while waiting for shutdown");
|
if (started) lifecycleManager.waitForShutdown();
|
||||||
}
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Exiting");
|
LOG.info("Interrupted while waiting for shutdown");
|
||||||
System.exit(0);
|
}
|
||||||
}).start();
|
LOG.info("Exiting");
|
||||||
|
System.exit(0);
|
||||||
|
});
|
||||||
|
}, "BackgroundShutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user