Fixing RealtimeSleepTimer to work in concurrent threads.

master
theBoatman 2019-11-08 22:18:12 +01:00 committed by Alan Evans
parent dfa08d1356
commit e3b66dc7e8
2 changed files with 100 additions and 2 deletions

View File

@ -23,13 +23,13 @@ import org.thoughtcrime.securesms.push.SecurityEventListener;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.recipients.LiveRecipientCache;
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
import org.thoughtcrime.securesms.util.AlarmSleepTimer;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.RealtimeSleepTimer;
import org.whispersystems.signalservice.api.util.SleepTimer;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.websocket.ConnectivityListener;
@ -72,7 +72,7 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
@Override
public @NonNull SignalServiceMessageReceiver provideSignalServiceMessageReceiver() {
SleepTimer sleepTimer = TextSecurePreferences.isFcmDisabled(context) ? new RealtimeSleepTimer(context)
SleepTimer sleepTimer = TextSecurePreferences.isFcmDisabled(context) ? new AlarmSleepTimer(context)
: new UptimeSleepTimer();
return new SignalServiceMessageReceiver(networkAccess.getConfiguration(context),
new DynamicCredentialsProvider(context),

View File

@ -0,0 +1,98 @@
package org.thoughtcrime.securesms.util;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;
import java.util.concurrent.ConcurrentSkipListSet;
import org.whispersystems.signalservice.api.util.SleepTimer;
/**
* A sleep timer that is based on elapsed realtime, so
* that it works properly, even in low-power sleep modes.
*
*/
public class AlarmSleepTimer implements SleepTimer {
private static final String TAG = AlarmSleepTimer.class.getSimpleName();
private static ConcurrentSkipListSet<Integer> actionIdList = new ConcurrentSkipListSet<>();
private final Context context;
public AlarmSleepTimer(Context context) {
this.context = context;
}
@Override
public void sleep(long millis) {
final AlarmReceiver alarmReceiver = new AlarmSleepTimer.AlarmReceiver();
int actionId = 0;
while (!actionIdList.add(actionId)){
actionId++;
}
try {
context.registerReceiver(alarmReceiver,
new IntentFilter(AlarmReceiver.WAKE_UP_THREAD_ACTION + "." + actionId));
final long startTime = System.currentTimeMillis();
alarmReceiver.setAlarm(millis, AlarmReceiver.WAKE_UP_THREAD_ACTION + "." + actionId);
while (System.currentTimeMillis() - startTime < millis) {
try {
synchronized (this) {
wait(millis - System.currentTimeMillis() + startTime);
}
} catch (InterruptedException e) {
Log.w(TAG, e);
}
}
context.unregisterReceiver(alarmReceiver);
} catch(Exception e) {
Log.w(TAG, "Exception during sleep ...",e);
}finally {
actionIdList.remove(actionId);
}
}
private class AlarmReceiver extends BroadcastReceiver {
private static final String WAKE_UP_THREAD_ACTION = "org.thoughtcrime.securesms.util.AlarmSleepTimer.AlarmReceiver.WAKE_UP_THREAD";
private void setAlarm(long millis, String action) {
final Intent intent = new Intent(action);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
final AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Log.w(TAG, "Setting alarm to wake up in " + millis + "ms.");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + millis,
pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + millis,
pendingIntent);
} else {
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + millis,
pendingIntent);
}
}
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "Waking up.");
synchronized (AlarmSleepTimer.this) {
AlarmSleepTimer.this.notifyAll();
}
}
}
}