Fix backup fails when running in background.
This commit is contained in:
parent
7759ad283d
commit
59de56439a
7 changed files with 85 additions and 36 deletions
|
@ -5,6 +5,7 @@ import android.annotation.SuppressLint;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.documentfile.provider.DocumentFileHelper;
|
import androidx.documentfile.provider.DocumentFileHelper;
|
||||||
|
@ -93,14 +94,23 @@ public final class LocalBackupJobApi29 extends BaseJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressUpdater updater = new ProgressUpdater(context.getString(R.string.LocalBackupJob_verifying_signal_backup));
|
ProgressUpdater updater = new ProgressUpdater(context.getString(R.string.LocalBackupJob_verifying_signal_backup));
|
||||||
try (NotificationController notification = GenericForegroundService.startForegroundTask(context,
|
|
||||||
context.getString(R.string.LocalBackupJob_creating_signal_backup),
|
NotificationController notification = null;
|
||||||
NotificationChannels.BACKUPS,
|
try {
|
||||||
R.drawable.ic_signal_backup))
|
notification = GenericForegroundService.startForegroundTask(context,
|
||||||
{
|
context.getString(R.string.LocalBackupJob_creating_signal_backup),
|
||||||
|
NotificationChannels.BACKUPS,
|
||||||
|
R.drawable.ic_signal_backup);
|
||||||
|
} catch (GenericForegroundService.UnableToStartException e) {
|
||||||
|
Log.w(TAG, "Unable to start foreground backup service, continuing without service");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
updater.setNotification(notification);
|
updater.setNotification(notification);
|
||||||
EventBus.getDefault().register(updater);
|
EventBus.getDefault().register(updater);
|
||||||
notification.setIndeterminateProgress();
|
if (notification != null) {
|
||||||
|
notification.setIndeterminateProgress();
|
||||||
|
}
|
||||||
|
|
||||||
String backupPassword = BackupPassphrase.get(context);
|
String backupPassword = BackupPassphrase.get(context);
|
||||||
DocumentFile backupDirectory = DocumentFile.fromTreeUri(context, backupDirectoryUri);
|
DocumentFile backupDirectory = DocumentFile.fromTreeUri(context, backupDirectoryUri);
|
||||||
|
@ -171,10 +181,10 @@ public final class LocalBackupJobApi29 extends BaseJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupUtil.deleteOldBackups();
|
BackupUtil.deleteOldBackups();
|
||||||
} catch (GenericForegroundService.UnableToStartException e) {
|
|
||||||
Log.w(TAG, "Unable to start foreground backup service", e);
|
|
||||||
BackupFileIOError.UNKNOWN.postNotification(context);
|
|
||||||
} finally {
|
} finally {
|
||||||
|
if (notification != null) {
|
||||||
|
notification.close();
|
||||||
|
}
|
||||||
EventBus.getDefault().unregister(updater);
|
EventBus.getDefault().unregister(updater);
|
||||||
updater.setNotification(null);
|
updater.setNotification(null);
|
||||||
}
|
}
|
||||||
|
@ -266,7 +276,7 @@ public final class LocalBackupJobApi29 extends BaseJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNotification(NotificationController notification) {
|
public void setNotification(@Nullable NotificationController notification) {
|
||||||
this.notification = notification;
|
this.notification = notification;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,6 @@ public class DirectoryRefreshListener extends PersistentAlarmManagerListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void schedule(Context context) {
|
public static void schedule(Context context) {
|
||||||
new DirectoryRefreshListener().onReceive(context, new Intent());
|
new DirectoryRefreshListener().onReceive(context, getScheduleIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.service;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -20,7 +19,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
|
||||||
private static final long INTERVAL = TimeUnit.DAYS.toMillis(1);
|
private static final long INTERVAL = TimeUnit.DAYS.toMillis(1);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean scheduleExact() {
|
protected boolean shouldScheduleExact() {
|
||||||
return Build.VERSION.SDK_INT >= 31;
|
return Build.VERSION.SDK_INT >= 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
|
||||||
@Override
|
@Override
|
||||||
protected long onAlarm(Context context, long scheduledTime) {
|
protected long onAlarm(Context context, long scheduledTime) {
|
||||||
if (SignalStore.settings().isBackupEnabled()) {
|
if (SignalStore.settings().isBackupEnabled()) {
|
||||||
LocalBackupJob.enqueue(scheduleExact());
|
LocalBackupJob.enqueue(shouldScheduleExact());
|
||||||
}
|
}
|
||||||
|
|
||||||
return setNextBackupTimeToIntervalFromNow(context);
|
return setNextBackupTimeToIntervalFromNow(context);
|
||||||
|
@ -40,7 +39,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
|
||||||
|
|
||||||
public static void schedule(Context context) {
|
public static void schedule(Context context) {
|
||||||
if (SignalStore.settings().isBackupEnabled()) {
|
if (SignalStore.settings().isBackupEnabled()) {
|
||||||
new LocalBackupListener().onReceive(context, new Intent());
|
new LocalBackupListener().onReceive(context, getScheduleIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,49 +8,89 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.signal.core.util.PendingIntentFlags;
|
import org.signal.core.util.PendingIntentFlags;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
|
|
||||||
public abstract class PersistentAlarmManagerListener extends BroadcastReceiver {
|
public abstract class PersistentAlarmManagerListener extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(PersistentAlarmManagerListener.class);
|
private static final String TAG = Log.tag(PersistentAlarmManagerListener.class);
|
||||||
|
private static final String ACTION_SCHEDULE = "signal.ACTION_SCHEDULE";
|
||||||
|
|
||||||
|
protected static @NonNull Intent getScheduleIntent() {
|
||||||
|
Intent scheduleIntent = new Intent();
|
||||||
|
scheduleIntent.setAction(ACTION_SCHEDULE);
|
||||||
|
return scheduleIntent;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract long getNextScheduledExecutionTime(Context context);
|
protected abstract long getNextScheduledExecutionTime(Context context);
|
||||||
|
|
||||||
protected abstract long onAlarm(Context context, long scheduledTime);
|
protected abstract long onAlarm(Context context, long scheduledTime);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Log.i(TAG, String.format("%s#onReceive(%s)", getClass().getSimpleName(), intent.getAction()));
|
info(String.format("onReceive(%s)", intent.getAction()));
|
||||||
|
|
||||||
long scheduledTime = getNextScheduledExecutionTime(context);
|
long scheduledTime = getNextScheduledExecutionTime(context);
|
||||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||||
Intent alarmIntent = new Intent(context, getClass());
|
Intent alarmIntent = new Intent(context, getClass());
|
||||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntentFlags.immutable());
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntentFlags.immutable());
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() >= scheduledTime && canRunDuringSchedule(intent.getAction())) {
|
||||||
if (System.currentTimeMillis() >= scheduledTime) {
|
info("onAlarm(): scheduled: " + scheduledTime + " actual: " + System.currentTimeMillis());
|
||||||
scheduledTime = onAlarm(context, scheduledTime);
|
scheduledTime = onAlarm(context, scheduledTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, getClass() + " scheduling for: " + scheduledTime + " action: " + intent.getAction());
|
if (pendingIntent == null) {
|
||||||
|
info("PendingIntent somehow null, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pendingIntent != null) {
|
alarmManager.cancel(pendingIntent);
|
||||||
alarmManager.cancel(pendingIntent);
|
|
||||||
if (scheduleExact() && Build.VERSION.SDK_INT >= 31) {
|
if (shouldScheduleExact()) {
|
||||||
if (alarmManager.canScheduleExactAlarms()) {
|
scheduleExact(alarmManager, scheduledTime, pendingIntent);
|
||||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Unable to schedule exact alarm, permissionAllowed: " + alarmManager.canScheduleExactAlarms());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, "PendingIntent somehow null, skipping");
|
info("scheduling alarm for: " + scheduledTime);
|
||||||
|
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean scheduleExact() {
|
private boolean canRunDuringSchedule(@NonNull String action) {
|
||||||
|
return !shouldScheduleExact() || !ACTION_SCHEDULE.equals(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleExact(AlarmManager alarmManager, long scheduledTime, PendingIntent pendingIntent) {
|
||||||
|
boolean hasManagerPermission = Build.VERSION.SDK_INT < 31 || alarmManager.canScheduleExactAlarms();
|
||||||
|
|
||||||
|
info("scheduling exact alarm for: " + scheduledTime + " hasManagerPermission: " + hasManagerPermission);
|
||||||
|
if (hasManagerPermission) {
|
||||||
|
try {
|
||||||
|
alarmManager.setExact(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
warn(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warn("Unable to schedule exact alarm, falling back to inexact alarm, scheduling alarm for: " + scheduledTime);
|
||||||
|
alarmManager.set(AlarmManager.RTC_WAKEUP, scheduledTime, pendingIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldScheduleExact() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void info(String message) {
|
||||||
|
Log.i(TAG, "[" + getClass().getSimpleName() + "] " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void warn(String message) {
|
||||||
|
Log.w(TAG, "[" + getClass().getSimpleName() + "] " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void warn(Throwable t) {
|
||||||
|
Log.w(TAG, "[" + getClass().getSimpleName() + "]", t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class RotateSenderCertificateListener extends PersistentAlarmManagerListe
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void schedule(Context context) {
|
public static void schedule(Context context) {
|
||||||
new RotateSenderCertificateListener().onReceive(context, new Intent());
|
new RotateSenderCertificateListener().onReceive(context, getScheduleIntent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,6 @@ public class RotateSignedPreKeyListener extends PersistentAlarmManagerListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void schedule(Context context) {
|
public static void schedule(Context context) {
|
||||||
new RotateSignedPreKeyListener().onReceive(context, new Intent());
|
new RotateSignedPreKeyListener().onReceive(context, getScheduleIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class UpdateApkRefreshListener extends PersistentAlarmManagerListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void schedule(Context context) {
|
public static void schedule(Context context) {
|
||||||
new UpdateApkRefreshListener().onReceive(context, new Intent());
|
new UpdateApkRefreshListener().onReceive(context, getScheduleIntent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue