Use the BlobProvider in the contact and group sync jobs.

This commit is contained in:
Greyson Parrelli 2020-06-30 08:17:29 -07:00 committed by GitHub
parent 5c0cb425a6
commit 904cb01067
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 35 deletions

View file

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.ContactsContract;
import androidx.annotation.NonNull;
@ -20,6 +21,7 @@ import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
@ -44,6 +46,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -122,10 +127,10 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
private void generateSingleContactUpdate(@NonNull RecipientId recipientId)
throws IOException, UntrustedIdentityException, NetworkException
{
File contactDataFile = createTempFile("multidevice-contact-update");
WriteDetails writeDetails = createTempFile();
try {
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
DeviceContactsOutputStream out = new DeviceContactsOutputStream(writeDetails.outputStream);
Recipient recipient = Recipient.resolved(recipientId);
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getId());
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
@ -145,12 +150,18 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
archived.contains(recipientId)));
out.close();
sendUpdate(ApplicationDependencies.getSignalServiceMessageSender(), contactDataFile, false);
long length = BlobProvider.getInstance().calculateFileSize(context, writeDetails.uri);
sendUpdate(ApplicationDependencies.getSignalServiceMessageSender(),
BlobProvider.getInstance().getStream(context, writeDetails.uri),
length,
false);
} catch(InvalidNumberException e) {
Log.w(TAG, e);
} finally {
if (contactDataFile != null) contactDataFile.delete();
BlobProvider.getInstance().delete(context, writeDetails.uri);
}
}
@ -171,10 +182,10 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
TextSecurePreferences.setLastFullContactSyncTime(context, System.currentTimeMillis());
TextSecurePreferences.setNeedsFullContactSync(context, false);
File contactDataFile = createTempFile("multidevice-contact-update");
WriteDetails writeDetails = createTempFile();
try {
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
DeviceContactsOutputStream out = new DeviceContactsOutputStream(writeDetails.outputStream);
List<Recipient> recipients = DatabaseFactory.getRecipientDatabase(context).getRecipientsForMultiDeviceSync();
Map<RecipientId, Integer> inboxPositions = DatabaseFactory.getThreadDatabase(context).getInboxPositions();
Set<RecipientId> archived = DatabaseFactory.getThreadDatabase(context).getArchivedRecipients();
@ -219,11 +230,17 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
}
out.close();
sendUpdate(ApplicationDependencies.getSignalServiceMessageSender(), contactDataFile, true);
long length = BlobProvider.getInstance().calculateFileSize(context, writeDetails.uri);
sendUpdate(ApplicationDependencies.getSignalServiceMessageSender(),
BlobProvider.getInstance().getStream(context, writeDetails.uri),
length,
true);
} catch(InvalidNumberException e) {
Log.w(TAG, e);
} finally {
if (contactDataFile != null) contactDataFile.delete();
BlobProvider.getInstance().delete(context, writeDetails.uri);
}
}
@ -238,15 +255,14 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
}
private void sendUpdate(SignalServiceMessageSender messageSender, File contactsFile, boolean complete)
throws IOException, UntrustedIdentityException, NetworkException
private void sendUpdate(SignalServiceMessageSender messageSender, InputStream stream, long length, boolean complete)
throws UntrustedIdentityException, NetworkException
{
if (contactsFile.length() > 0) {
FileInputStream contactsFileStream = new FileInputStream(contactsFile);
if (length > 0) {
SignalServiceAttachmentStream attachmentStream = SignalServiceAttachment.newStreamBuilder()
.withStream(contactsFileStream)
.withStream(stream)
.withContentType("application/octet-stream")
.withLength(contactsFile.length())
.withLength(length)
.build();
try {
@ -255,6 +271,8 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
} catch (IOException ioe) {
throw new NetworkException(ioe);
}
} else {
Log.w(TAG, "Nothing to write!");
}
}
@ -360,11 +378,17 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
return Optional.of(new VerifiedMessage(destination, identityKey, state, System.currentTimeMillis()));
}
private File createTempFile(String prefix) throws IOException {
File file = File.createTempFile(prefix, "tmp", context.getCacheDir());
file.deleteOnExit();
private @NonNull WriteDetails createTempFile() throws IOException {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]);
Uri uri = BlobProvider.getInstance()
.forData(inputStream, 0)
.withFileName("multidevice-contact-update")
.createForSingleSessionOnDiskAsync(context,
() -> Log.i(TAG, "Write successful."),
e -> Log.w(TAG, "Error during write.", e));
return file;
return new WriteDetails(uri, new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]));
}
private static class NetworkException extends Exception {
@ -374,6 +398,16 @@ public class MultiDeviceContactUpdateJob extends BaseJob {
}
}
private static class WriteDetails {
private final Uri uri;
private final OutputStream outputStream;
private WriteDetails(@NonNull Uri uri, @NonNull OutputStream outputStream) {
this.uri = uri;
this.outputStream = outputStream;
}
}
public static final class Factory implements Job.Factory<MultiDeviceContactUpdateJob> {
@Override
public @NonNull MultiDeviceContactUpdateJob create(@NonNull Parameters parameters, @NonNull Data data) {

View file

@ -1,5 +1,8 @@
package org.thoughtcrime.securesms.jobs;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -12,6 +15,7 @@ import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
@ -32,6 +36,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -74,15 +79,20 @@ public class MultiDeviceGroupUpdateJob extends BaseJob {
return;
}
File contactDataFile = createTempFile("multidevice-contact-update");
GroupDatabase.Reader reader = null;
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]);
Uri uri = BlobProvider.getInstance()
.forData(inputStream, 0)
.withFileName("multidevice-group-update")
.createForSingleSessionOnDiskAsync(context,
() -> Log.i(TAG, "Write successful."),
e -> Log.w(TAG, "Error during write.", e));
GroupDatabase.GroupRecord record;
try (GroupDatabase.Reader reader = DatabaseFactory.getGroupDatabase(context).getGroups()) {
DeviceGroupsOutputStream out = new DeviceGroupsOutputStream(new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]));
boolean hasData = false;
try {
DeviceGroupsOutputStream out = new DeviceGroupsOutputStream(new FileOutputStream(contactDataFile));
reader = DatabaseFactory.getGroupDatabase(context).getGroups();
GroupDatabase.GroupRecord record;
while ((record = reader.getNext()) != null) {
if (record.isV1Group()) {
@ -108,22 +118,25 @@ public class MultiDeviceGroupUpdateJob extends BaseJob {
recipient.isBlocked(),
Optional.fromNullable(inboxPositions.get(recipientId)),
archived.contains(recipientId)));
hasData = true;
}
}
out.close();
if (contactDataFile.exists() && contactDataFile.length() > 0) {
sendUpdate(ApplicationDependencies.getSignalServiceMessageSender(), contactDataFile);
if (hasData) {
long length = BlobProvider.getInstance().calculateFileSize(context, uri);
sendUpdate(ApplicationDependencies.getSignalServiceMessageSender(),
BlobProvider.getInstance().getStream(context, uri),
length);
} else {
Log.w(TAG, "No groups present for sync message...");
}
} finally {
if (contactDataFile != null) contactDataFile.delete();
if (reader != null) reader.close();
BlobProvider.getInstance().delete(context, uri);
}
}
@Override
@ -137,14 +150,13 @@ public class MultiDeviceGroupUpdateJob extends BaseJob {
}
private void sendUpdate(SignalServiceMessageSender messageSender, File contactsFile)
private void sendUpdate(SignalServiceMessageSender messageSender, InputStream stream, long length)
throws IOException, UntrustedIdentityException
{
FileInputStream contactsFileStream = new FileInputStream(contactsFile);
SignalServiceAttachmentStream attachmentStream = SignalServiceAttachment.newStreamBuilder()
.withStream(contactsFileStream)
.withStream(stream)
.withContentType("application/octet-stream")
.withLength(contactsFile.length())
.withLength(length)
.build();
messageSender.sendMessage(SignalServiceSyncMessage.forGroups(attachmentStream),

View file

@ -215,6 +215,20 @@ public class BlobProvider {
return null;
}
@WorkerThread
public long calculateFileSize(@NonNull Context context, @NonNull Uri uri) {
if (!isAuthority(uri)) {
return 0;
}
try (InputStream stream = getStream(context, uri)) {
return Util.getStreamLength(stream);
} catch (IOException e) {
Log.w(TAG, e);
return 0;
}
}
public static boolean isAuthority(@NonNull Uri uri) {
return URI_MATCHER.match(uri) == MATCH;
}