Throttle background contact syncs to once every 6 hours.

Unfortunately, there's apps out there that trigger contact changes
very frequently. Because we listen to the system for contact
changes to tell us when to sync, that could result in us sending
an abundance of contact syncs to linked desktop instances.

This throttles contact sync requests using the following methodology:

- By default, throttle contact syncs to 6 hrs while the app is
  backgrounded.
- If a sync is throttled in the background, we set a dirty flag and
  will execute the sync the next time the app is foregrounded.
- Syncs explicitly requested by desktop are never throttled.
This commit is contained in:
Greyson Parrelli
2018-07-06 17:28:58 -07:00
parent 7960a5785d
commit bf692e8da3
5 changed files with 89 additions and 6 deletions

View File

@@ -11,6 +11,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
import org.thoughtcrime.securesms.crypto.MasterSecret;
@@ -45,6 +46,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@@ -54,15 +56,27 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
private static final String TAG = MultiDeviceContactUpdateJob.class.getSimpleName();
private static final long FULL_SYNC_TIME = TimeUnit.HOURS.toMillis(6);
@Inject transient SignalServiceMessageSender messageSender;
private final @Nullable String address;
private boolean forceSync;
public MultiDeviceContactUpdateJob(@NonNull Context context) {
this(context, null);
this(context, false);
}
public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) {
this(context, null, forceSync);
}
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address) {
this(context, address, true);
}
public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address, boolean forceSync) {
super(context, JobParameters.newBuilder()
.withRequirement(new NetworkRequirement(context))
.withRequirement(new MasterSecretRequirement(context))
@@ -70,6 +84,8 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
.withPersistence()
.create());
this.forceSync = forceSync;
if (address != null) this.address = address.serialize();
else this.address = null;
}
@@ -126,7 +142,21 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
Log.w(TAG, "No contact permissions, skipping multi-device contact update...");
return;
}
boolean isAppVisible = ApplicationContext.getInstance(context).isAppVisible();
long timeSinceLastSync = System.currentTimeMillis() - TextSecurePreferences.getLastFullContactSyncTime(context);
Log.d(TAG, "Requesting a full contact sync. forced = " + forceSync + ", appVisible = " + isAppVisible + ", timeSinceLastSync = " + timeSinceLastSync + " ms");
if (!forceSync && !isAppVisible && timeSinceLastSync < FULL_SYNC_TIME) {
Log.i(TAG, "App is backgrounded and the last contact sync was too soon (" + timeSinceLastSync + " ms ago). Marking that we need a sync. Skipping multi-device contact update...");
TextSecurePreferences.setNeedsFullContactSync(context, true);
return;
}
TextSecurePreferences.setLastFullContactSyncTime(context, System.currentTimeMillis());
TextSecurePreferences.setNeedsFullContactSync(context, false);
File contactDataFile = createTempFile("multidevice-contact-update");
try {

View File

@@ -479,7 +479,7 @@ public class PushDecryptJob extends ContextJob {
if (message.isContactsRequest()) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceContactUpdateJob(getContext()));
.add(new MultiDeviceContactUpdateJob(getContext(), true));
}
if (message.isGroupsRequest()) {