mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-22 18:55:12 +00:00
Fix infinite export loop and improve general error handling.
This commit is contained in:
@@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.video.EncryptedMediaDataSource;
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -204,7 +205,13 @@ public class AttachmentDatabase extends Database {
|
||||
public @NonNull InputStream getAttachmentStream(AttachmentId attachmentId, long offset)
|
||||
throws IOException
|
||||
{
|
||||
InputStream dataStream = getDataStream(attachmentId, DATA, offset);
|
||||
InputStream dataStream;
|
||||
|
||||
try {
|
||||
dataStream = getDataStream(attachmentId, DATA, offset);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IOException("No stream for: " + attachmentId, e);
|
||||
}
|
||||
|
||||
if (dataStream == null) throw new IOException("No stream for: " + attachmentId);
|
||||
else return dataStream;
|
||||
@@ -1019,8 +1026,8 @@ public class AttachmentDatabase extends Database {
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@VisibleForTesting
|
||||
protected @Nullable InputStream getDataStream(AttachmentId attachmentId, String dataType, long offset)
|
||||
private @Nullable InputStream getDataStream(AttachmentId attachmentId, String dataType, long offset)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
DataInfo dataInfo = getAttachmentDataFileInfo(attachmentId, dataType);
|
||||
|
||||
@@ -1042,6 +1049,9 @@ public class AttachmentDatabase extends Database {
|
||||
|
||||
return stream;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.database.documents.Document;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||
@@ -398,7 +399,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
|
||||
}
|
||||
|
||||
public int getUnexportedInsecureMessagesCount(long threadId) {
|
||||
try (Cursor cursor = getWritableDatabase().query(getTableName(), SqlUtil.COUNT, getInsecureMessageClause(threadId) + " AND NOT " + EXPORTED, null, null, null, null)) {
|
||||
try (Cursor cursor = getWritableDatabase().query(getTableName(), SqlUtil.COUNT, getInsecureMessageClause(threadId) + " AND " + EXPORTED + " < ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED), null, null, null)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return cursor.getInt(0);
|
||||
}
|
||||
@@ -407,6 +408,19 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the exported status (not state) to the default for clearing errors.
|
||||
*/
|
||||
public void clearInsecureMessageExportedErrorStatus() {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(EXPORTED, MessageExportStatus.UNEXPORTED.getCode());
|
||||
|
||||
SQLiteDatabaseExtensionsKt.update(getWritableDatabase(), getTableName())
|
||||
.values(values)
|
||||
.where(EXPORTED + " < ?", MessageExportStatus.UNEXPORTED.getCode())
|
||||
.run();
|
||||
}
|
||||
|
||||
public void setReactionsSeen(long threadId, long sinceTimestamp) {
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
@@ -52,6 +52,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailureSet;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.Mention;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||
@@ -205,7 +206,8 @@ public class MmsDatabase extends MessageDatabase {
|
||||
"CREATE INDEX IF NOT EXISTS mms_is_story_index ON " + TABLE_NAME + " (" + STORY_TYPE + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON " + TABLE_NAME + " (" + PARENT_STORY_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + "," + STORY_TYPE + "," + PARENT_STORY_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");"
|
||||
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");"
|
||||
};
|
||||
|
||||
private static final String[] MMS_PROJECTION = new String[] {
|
||||
@@ -2466,13 +2468,13 @@ public class MmsDatabase extends MessageDatabase {
|
||||
beginTransaction();
|
||||
try {
|
||||
List<Long> threadsToUpdate = new LinkedList<>();
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(1), THREAD_ID, null, null, null)) {
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED), THREAD_ID, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
threadsToUpdate.add(CursorUtil.requireLong(cursor, THREAD_ID));
|
||||
}
|
||||
}
|
||||
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(1));
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED));
|
||||
|
||||
for (final long threadId : threadsToUpdate) {
|
||||
SignalDatabase.threads().update(threadId, false);
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.MessageUpdate;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState;
|
||||
@@ -671,7 +672,16 @@ public class MmsSmsDatabase extends Database {
|
||||
String table = messageId.isMms() ? MmsDatabase.TABLE_NAME : SmsDatabase.TABLE_NAME;
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
|
||||
contentValues.put(MmsSmsColumns.EXPORTED, 1);
|
||||
contentValues.put(MmsSmsColumns.EXPORTED, MessageExportStatus.EXPORTED.getCode());
|
||||
|
||||
getWritableDatabase().update(table, contentValues, ID_WHERE, SqlUtil.buildArgs(messageId.getId()));
|
||||
}
|
||||
|
||||
public void markMessageExportFailed(@NonNull MessageId messageId) {
|
||||
String table = messageId.isMms() ? MmsDatabase.TABLE_NAME : SmsDatabase.TABLE_NAME;
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
|
||||
contentValues.put(MmsSmsColumns.EXPORTED, MessageExportStatus.ERROR.getCode());
|
||||
|
||||
getWritableDatabase().update(table, contentValues, ID_WHERE, SqlUtil.buildArgs(messageId.getId()));
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||
@@ -146,7 +147,8 @@ public class SmsDatabase extends MessageDatabase {
|
||||
"CREATE INDEX IF NOT EXISTS sms_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ", " + RECIPIENT_ID + ", " + THREAD_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_date_server_index ON " + TABLE_NAME + " (" + DATE_SERVER + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_thread_date_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");"
|
||||
"CREATE INDEX IF NOT EXISTS sms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");"
|
||||
};
|
||||
|
||||
private static final String[] MESSAGE_PROJECTION = new String[] {
|
||||
@@ -924,13 +926,13 @@ public class SmsDatabase extends MessageDatabase {
|
||||
beginTransaction();
|
||||
try {
|
||||
List<Long> threadsToUpdate = new LinkedList<>();
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(1), THREAD_ID, null, null, null)) {
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED), THREAD_ID, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
threadsToUpdate.add(CursorUtil.requireLong(cursor, THREAD_ID));
|
||||
}
|
||||
}
|
||||
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(1));
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED));
|
||||
|
||||
for (final long threadId : threadsToUpdate) {
|
||||
SignalDatabase.threads().update(threadId, false);
|
||||
|
||||
@@ -14,13 +14,14 @@ import org.thoughtcrime.securesms.database.helpers.migration.V156_RecipientUnreg
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V157_RecipeintHiddenMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V158_GroupsLastForceUpdateTimestampMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V159_ThreadUnreadSelfMentionCount
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V160_SmsMmsExportedIndexMigration
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
*/
|
||||
object SignalDatabaseMigrations {
|
||||
|
||||
const val DATABASE_VERSION = 159
|
||||
const val DATABASE_VERSION = 160
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -67,6 +68,10 @@ object SignalDatabaseMigrations {
|
||||
if (oldVersion < 159) {
|
||||
V159_ThreadUnreadSelfMentionCount.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 160) {
|
||||
V160_SmsMmsExportedIndexMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
object V160_SmsMmsExportedIndexMigration : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS sms_exported_index ON sms (exported)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_exported_index ON mms (exported)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.thoughtcrime.securesms.database.model
|
||||
|
||||
import org.signal.core.util.DatabaseId
|
||||
import org.signal.core.util.IntSerializer
|
||||
|
||||
/**
|
||||
* Export status for a message.
|
||||
*/
|
||||
enum class MessageExportStatus(val code: Int) : DatabaseId {
|
||||
UNEXPORTED(0),
|
||||
EXPORTED(1),
|
||||
ERROR(-1);
|
||||
|
||||
override fun serialize(): String {
|
||||
return Serializer.serialize(this).toString()
|
||||
}
|
||||
|
||||
companion object Serializer : IntSerializer<MessageExportStatus> {
|
||||
override fun serialize(data: MessageExportStatus): Int {
|
||||
return data.code
|
||||
}
|
||||
|
||||
override fun deserialize(data: Int): MessageExportStatus {
|
||||
return when (data) {
|
||||
UNEXPORTED.code -> UNEXPORTED
|
||||
EXPORTED.code -> EXPORTED
|
||||
ERROR.code -> ERROR
|
||||
else -> throw AssertionError("Unknown message export status: $data")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||
import org.thoughtcrime.securesms.notifications.v2.NotificationPendingIntentHelper
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
@@ -79,6 +80,11 @@ class SignalSmsExportService : SmsExportService() {
|
||||
)
|
||||
}
|
||||
|
||||
override fun prepareForExport() {
|
||||
SignalDatabase.sms.clearInsecureMessageExportedErrorStatus()
|
||||
SignalDatabase.mms.clearInsecureMessageExportedErrorStatus()
|
||||
}
|
||||
|
||||
override fun getUnexportedMessageCount(): Int {
|
||||
ensureReader()
|
||||
return reader!!.getCount()
|
||||
@@ -107,6 +113,8 @@ class SignalSmsExportService : SmsExportService() {
|
||||
SignalDatabase.mmsSms.updateMessageExportState(exportableMessage.getMessageId()) {
|
||||
it.toBuilder().setProgress(MessageExportState.Progress.INIT).build()
|
||||
}
|
||||
|
||||
SignalDatabase.mmsSms.markMessageExportFailed(exportableMessage.getMessageId())
|
||||
}
|
||||
|
||||
override fun onMessageIdCreated(exportableMessage: ExportableMessage, messageId: Long) {
|
||||
@@ -153,6 +161,7 @@ class SignalSmsExportService : SmsExportService() {
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun getInputStream(part: ExportableMessage.Mms.Part): InputStream {
|
||||
return SignalDatabase.attachments.getAttachmentStream(JsonUtils.fromJson(part.contentId, AttachmentId::class.java), 0)
|
||||
}
|
||||
|
||||
@@ -14,12 +14,13 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
*/
|
||||
class ExportSmsCompleteFragment : Fragment(R.layout.export_sms_complete_fragment) {
|
||||
|
||||
val args: ExportSmsCompleteFragmentArgs by navArgs()
|
||||
private val args: ExportSmsCompleteFragmentArgs by navArgs()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val binding = ExportSmsCompleteFragmentBinding.bind(view)
|
||||
val exportSuccessCount = args.exportMessageCount - args.exportMessageFailureCount
|
||||
|
||||
val binding = ExportSmsCompleteFragmentBinding.bind(view)
|
||||
binding.exportCompleteNext.setOnClickListener { findNavController().safeNavigate(ExportSmsCompleteFragmentDirections.actionExportingSmsMessagesFragmentToChooseANewDefaultSmsAppFragment()) }
|
||||
binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, args.exportMessageCount, args.exportMessageCount)
|
||||
binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, exportSuccessCount, args.exportMessageCount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class ExportYourSmsMessagesFragment : Fragment(R.layout.export_your_sms_messages
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it is SmsExportProgress.Done) {
|
||||
findNavController().safeNavigate(SmsExportDirections.actionDirectToExportSmsCompleteFragment(it.progress))
|
||||
findNavController().safeNavigate(SmsExportDirections.actionDirectToExportSmsCompleteFragment(it.errorCount, it.total))
|
||||
} else if (it is SmsExportProgress.InProgress) {
|
||||
findNavController().safeNavigate(ExportYourSmsMessagesFragmentDirections.actionExportYourSmsMessagesFragmentToExportingSmsMessagesFragment())
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class ExportingSmsMessagesFragment : Fragment(R.layout.exporting_sms_messages_fr
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it is SmsExportProgress.Done) {
|
||||
findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsCompleteFragment(it.progress))
|
||||
findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsCompleteFragment(it.total, it.errorCount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user