mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-26 20:55:10 +00:00
Add additional debug info for the backups alpha.
This commit is contained in:
committed by
Alex Hart
parent
869b5aa3d5
commit
dc8e93a9d3
@@ -29,12 +29,14 @@ import org.signal.core.util.bytes
|
||||
import org.signal.core.util.concurrent.LimitedWorker
|
||||
import org.signal.core.util.concurrent.SignalDispatchers
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.decodeOrNull
|
||||
import org.signal.core.util.forceForeignKeyConstraintsEnabled
|
||||
import org.signal.core.util.fullWalCheckpoint
|
||||
import org.signal.core.util.getAllIndexDefinitions
|
||||
import org.signal.core.util.getAllTableDefinitions
|
||||
import org.signal.core.util.getAllTriggerDefinitions
|
||||
import org.signal.core.util.getForeignKeyViolations
|
||||
import org.signal.core.util.isNotEmpty
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.money.FiatMoney
|
||||
import org.signal.core.util.requireIntOrNull
|
||||
@@ -62,6 +64,7 @@ import org.thoughtcrime.securesms.backup.v2.processor.ChatItemArchiveProcessor
|
||||
import org.thoughtcrime.securesms.backup.v2.processor.NotificationProfileProcessor
|
||||
import org.thoughtcrime.securesms.backup.v2.processor.RecipientArchiveProcessor
|
||||
import org.thoughtcrime.securesms.backup.v2.processor.StickerArchiveProcessor
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.BackupDebugInfo
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.BackupInfo
|
||||
import org.thoughtcrime.securesms.backup.v2.stream.BackupExportWriter
|
||||
import org.thoughtcrime.securesms.backup.v2.stream.BackupImportReader
|
||||
@@ -104,6 +107,7 @@ import org.thoughtcrime.securesms.keyvalue.BackupValues.ArchiveServiceCredential
|
||||
import org.thoughtcrime.securesms.keyvalue.KeyValueStore
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.keyvalue.isDecisionPending
|
||||
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogRepository
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||
@@ -147,7 +151,10 @@ import java.io.OutputStream
|
||||
import java.time.ZonedDateTime
|
||||
import java.util.Currency
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -798,7 +805,8 @@ object BackupRepository {
|
||||
version = VERSION,
|
||||
backupTimeMs = exportState.backupTime,
|
||||
mediaRootBackupKey = SignalStore.backup.mediaRootBackupKey.value.toByteString(),
|
||||
firstAppVersion = SignalStore.backup.firstAppVersion
|
||||
firstAppVersion = SignalStore.backup.firstAppVersion,
|
||||
debugInfo = buildDebugInfo()
|
||||
)
|
||||
)
|
||||
frameCount++
|
||||
@@ -1211,6 +1219,7 @@ object BackupRepository {
|
||||
stopwatch.split("group-jobs")
|
||||
|
||||
SignalStore.backup.firstAppVersion = header.firstAppVersion
|
||||
SignalStore.internal.importedBackupDebugInfo = header.debugInfo.let { BackupDebugInfo.ADAPTER.decodeOrNull(it.toByteArray()) }
|
||||
|
||||
Log.d(TAG, "[import] Finished! ${eventTimer.stop().summary}")
|
||||
stopwatch.stop(TAG)
|
||||
@@ -1846,6 +1855,38 @@ object BackupRepository {
|
||||
return RemoteRestoreResult.Success
|
||||
}
|
||||
|
||||
private fun buildDebugInfo(): ByteString {
|
||||
if (!RemoteConfig.internalUser) {
|
||||
return ByteString.EMPTY
|
||||
}
|
||||
|
||||
var debuglogUrl: String? = null
|
||||
|
||||
if (SignalStore.internal.includeDebuglogInBackup) {
|
||||
Log.i(TAG, "User has debuglog inclusion enabled. Generating a debuglog.")
|
||||
val latch = CountDownLatch(1)
|
||||
SubmitDebugLogRepository().buildAndSubmitLog { url ->
|
||||
debuglogUrl = url.getOrNull()
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
try {
|
||||
val success = latch.await(10, TimeUnit.SECONDS)
|
||||
if (!success) {
|
||||
Log.w(TAG, "Timed out waiting for debuglog!")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Hit an error while generating the debuglog!")
|
||||
}
|
||||
}
|
||||
|
||||
return BackupDebugInfo(
|
||||
debuglogUrl = debuglogUrl ?: "",
|
||||
attachmentDetails = SignalDatabase.attachments.debugAttachmentStatsForBackupProto(),
|
||||
usingPaidTier = SignalStore.backup.backupTier == MessageBackupTier.PAID
|
||||
).encodeByteString()
|
||||
}
|
||||
|
||||
interface ExportProgressListener {
|
||||
fun onAccount()
|
||||
fun onRecipient()
|
||||
|
||||
@@ -171,7 +171,7 @@ private fun BackupsSettingsContent(
|
||||
|
||||
is BackupState.ActiveFree, is BackupState.ActivePaid, is BackupState.Canceled -> {
|
||||
ActiveBackupsRow(
|
||||
backupState = backupsSettingsState.backupState,
|
||||
backupState = backupsSettingsState.backupState as BackupState.WithTypeAndRenewalTime,
|
||||
onBackupsRowClick = onBackupsRowClick,
|
||||
lastBackupAt = backupsSettingsState.lastBackupAt
|
||||
)
|
||||
@@ -524,7 +524,8 @@ private fun BackupsSettingsContentPreview() {
|
||||
),
|
||||
renewalTime = 0.seconds,
|
||||
price = FiatMoney(BigDecimal.valueOf(4), Currency.getInstance("CAD"))
|
||||
)
|
||||
),
|
||||
lastBackupAt = 0.seconds
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -536,7 +537,8 @@ private fun BackupsSettingsContentNotAvailablePreview() {
|
||||
Previews.Preview {
|
||||
BackupsSettingsContent(
|
||||
backupsSettingsState = BackupsSettingsState(
|
||||
backupState = BackupState.NotAvailable
|
||||
backupState = BackupState.NotAvailable,
|
||||
lastBackupAt = 0.seconds
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -550,7 +552,8 @@ private fun BackupsSettingsContentBackupTierInternalOverridePreview() {
|
||||
backupsSettingsState = BackupsSettingsState(
|
||||
backupState = BackupState.None,
|
||||
showBackupTierInternalOverride = true,
|
||||
backupTierInternalOverride = null
|
||||
backupTierInternalOverride = null,
|
||||
lastBackupAt = 0.seconds
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -279,6 +279,10 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
|
||||
requireActivity().finish()
|
||||
requireActivity().startActivity(AppSettingsActivity.manageStorage(requireActivity()))
|
||||
}
|
||||
|
||||
override fun onIncludeDebuglogClick(newState: Boolean) {
|
||||
viewModel.setIncludeDebuglog(newState)
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayBackupKey() {
|
||||
@@ -368,6 +372,7 @@ private interface ContentCallbacks {
|
||||
fun onDisplayProgressDialog() = Unit
|
||||
fun onDisplayDownloadingBackupDialog() = Unit
|
||||
fun onManageStorageClick() = Unit
|
||||
fun onIncludeDebuglogClick(newState: Boolean) = Unit
|
||||
|
||||
object Empty : ContentCallbacks
|
||||
}
|
||||
@@ -512,6 +517,7 @@ private fun RemoteBackupsSettingsContent(
|
||||
canBackUpUsingCellular = state.canBackUpUsingCellular,
|
||||
canRestoreUsingCellular = state.canRestoreUsingCellular,
|
||||
canBackUpNow = !state.isOutOfStorageSpace,
|
||||
includeDebuglog = state.includeDebuglog,
|
||||
contentCallbacks = contentCallbacks
|
||||
)
|
||||
} else {
|
||||
@@ -815,6 +821,7 @@ private fun LazyListScope.appendBackupDetailsItems(
|
||||
canBackUpUsingCellular: Boolean,
|
||||
canRestoreUsingCellular: Boolean,
|
||||
canBackUpNow: Boolean,
|
||||
includeDebuglog: Boolean?,
|
||||
contentCallbacks: ContentCallbacks
|
||||
) {
|
||||
item {
|
||||
@@ -843,6 +850,12 @@ private fun LazyListScope.appendBackupDetailsItems(
|
||||
}
|
||||
}
|
||||
|
||||
if (includeDebuglog != null) {
|
||||
item {
|
||||
IncludeDebuglogRow(includeDebuglog) { contentCallbacks.onIncludeDebuglogClick(it) }
|
||||
}
|
||||
}
|
||||
|
||||
if (backupProgress == null || backupProgress.state == ArchiveUploadProgressState.State.None || backupProgress.state == ArchiveUploadProgressState.State.UserCanceled) {
|
||||
item {
|
||||
LastBackupRow(
|
||||
@@ -1421,6 +1434,19 @@ private fun getBackupUploadPhaseProgressString(state: ArchiveUploadProgressState
|
||||
return stringResource(R.string.RemoteBackupsSettingsFragment__uploading_s_of_s_d, formattedUploadedBytes, formattedTotalBytes, percent)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IncludeDebuglogRow(
|
||||
enabled: Boolean,
|
||||
onToggle: (Boolean) -> Unit
|
||||
) {
|
||||
Rows.ToggleRow(
|
||||
checked = enabled,
|
||||
text = "[INTERNAL ONLY] Include debuglog?",
|
||||
label = "If enabled, we will capture a debuglog and include it in the backup file.",
|
||||
onCheckChanged = onToggle
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LastBackupRow(
|
||||
lastBackupTimestamp: Long,
|
||||
@@ -1748,6 +1774,36 @@ private fun RemoteBackupsSettingsContentPreview() {
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun RemoteBackupsSettingsInternalUserContentPreview() {
|
||||
Previews.Preview {
|
||||
RemoteBackupsSettingsContent(
|
||||
state = RemoteBackupsSettingsState(
|
||||
backupsEnabled = true,
|
||||
lastBackupTimestamp = -1,
|
||||
canBackUpUsingCellular = false,
|
||||
canRestoreUsingCellular = false,
|
||||
backupsFrequency = BackupFrequency.MANUAL,
|
||||
dialog = RemoteBackupsSettingsState.Dialog.NONE,
|
||||
snackbar = RemoteBackupsSettingsState.Snackbar.NONE,
|
||||
backupMediaSize = 2300000,
|
||||
backupState = BackupState.ActiveFree(
|
||||
messageBackupsType = MessageBackupsType.Free(mediaRetentionDays = 30)
|
||||
),
|
||||
hasRedemptionError = false,
|
||||
isOutOfStorageSpace = false,
|
||||
includeDebuglog = true
|
||||
),
|
||||
statusBarColorNestedScrollConnection = null,
|
||||
backupDeleteState = DeletionState.NONE,
|
||||
backupRestoreState = BackupRestoreState.FromBackupStatusData(BackupStatusData.CouldNotCompleteBackup),
|
||||
contentCallbacks = ContentCallbacks.Empty,
|
||||
backupProgress = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun RedemptionErrorAlertPreview() {
|
||||
|
||||
@@ -9,6 +9,9 @@ import org.thoughtcrime.securesms.backup.v2.BackupFrequency
|
||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||
import org.thoughtcrime.securesms.components.settings.app.backups.BackupState
|
||||
|
||||
/**
|
||||
* @param includeDebuglog The state for whether or not we should include a debuglog in the backup. If `null`, hide the setting.
|
||||
*/
|
||||
data class RemoteBackupsSettingsState(
|
||||
val tier: MessageBackupTier? = null,
|
||||
val backupsEnabled: Boolean,
|
||||
@@ -23,7 +26,8 @@ data class RemoteBackupsSettingsState(
|
||||
val backupsFrequency: BackupFrequency = BackupFrequency.DAILY,
|
||||
val lastBackupTimestamp: Long = 0,
|
||||
val dialog: Dialog = Dialog.NONE,
|
||||
val snackbar: Snackbar = Snackbar.NONE
|
||||
val snackbar: Snackbar = Snackbar.NONE,
|
||||
val includeDebuglog: Boolean? = null
|
||||
) {
|
||||
|
||||
enum class Dialog {
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.jobs.BackupMessagesJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.keyvalue.protos.ArchiveUploadProgressState
|
||||
import org.thoughtcrime.securesms.service.MessageBackupListener
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@@ -66,7 +67,8 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||
lastBackupTimestamp = SignalStore.backup.lastBackupTime,
|
||||
backupsFrequency = SignalStore.backup.backupFrequency,
|
||||
canBackUpUsingCellular = SignalStore.backup.backupWithCellular,
|
||||
canRestoreUsingCellular = SignalStore.backup.restoreWithCellular
|
||||
canRestoreUsingCellular = SignalStore.backup.restoreWithCellular,
|
||||
includeDebuglog = SignalStore.internal.includeDebuglogInBackup.takeIf { RemoteConfig.internalUser }
|
||||
)
|
||||
)
|
||||
|
||||
@@ -214,6 +216,11 @@ class RemoteBackupsSettingsViewModel : ViewModel() {
|
||||
ArchiveUploadProgress.cancel()
|
||||
}
|
||||
|
||||
fun setIncludeDebuglog(includeDebuglog: Boolean) {
|
||||
SignalStore.internal.includeDebuglogInBackup = includeDebuglog
|
||||
_state.update { it.copy(includeDebuglog = includeDebuglog) }
|
||||
}
|
||||
|
||||
private suspend fun refreshState(lastPurchase: InAppPaymentTable.InAppPayment?) {
|
||||
try {
|
||||
Log.i(TAG, "Performing a state refresh.")
|
||||
|
||||
@@ -70,16 +70,12 @@ import org.thoughtcrime.securesms.attachments.Cdn
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.attachments.WallpaperAttachment
|
||||
import org.thoughtcrime.securesms.audio.AudioHash
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.BackupDebugInfo
|
||||
import org.thoughtcrime.securesms.blurhash.BlurHash
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret
|
||||
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream
|
||||
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream
|
||||
import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.COPY_PENDING
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.FINISHED
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.NONE
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.PERMANENT_FAILURE
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.UPLOAD_IN_PROGRESS
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.Companion.DATA_FILE
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.Companion.DATA_HASH_END
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable.Companion.PREUPLOAD_MESSAGE_ID
|
||||
@@ -926,7 +922,7 @@ class AttachmentTable(
|
||||
fun deleteAttachments(toDelete: List<SyncAttachmentId>): List<SyncMessageId> {
|
||||
val unhandled = mutableListOf<SyncMessageId>()
|
||||
for (syncAttachmentId in toDelete) {
|
||||
val messageId = SignalDatabase.messages.getMessageIdOrNull(syncAttachmentId.syncMessageId)
|
||||
val messageId = messages.getMessageIdOrNull(syncAttachmentId.syncMessageId)
|
||||
if (messageId != null) {
|
||||
val attachments = readableDatabase
|
||||
.select(ID, ATTACHMENT_UUID, REMOTE_DIGEST, DATA_HASH_END)
|
||||
@@ -949,7 +945,7 @@ class AttachmentTable(
|
||||
val attachmentToDelete = (byUuid ?: byDigest ?: byPlaintext)?.id
|
||||
if (attachmentToDelete != null) {
|
||||
if (attachments.size == 1) {
|
||||
SignalDatabase.messages.deleteMessage(messageId)
|
||||
messages.deleteMessage(messageId)
|
||||
} else {
|
||||
deleteAttachment(attachmentToDelete)
|
||||
}
|
||||
@@ -2463,7 +2459,7 @@ class AttachmentTable(
|
||||
transferProgress = cursor.requireInt(TRANSFER_STATE),
|
||||
size = cursor.requireLong(DATA_SIZE),
|
||||
fileName = cursor.requireString(FILE_NAME),
|
||||
cdn = cursor.requireObject(CDN_NUMBER, Cdn.Serializer),
|
||||
cdn = cursor.requireObject(CDN_NUMBER, Cdn),
|
||||
location = cursor.requireString(REMOTE_LOCATION),
|
||||
key = cursor.requireString(REMOTE_KEY),
|
||||
digest = cursor.requireBlob(REMOTE_DIGEST),
|
||||
@@ -2621,6 +2617,27 @@ class AttachmentTable(
|
||||
)
|
||||
}
|
||||
|
||||
fun debugAttachmentStatsForBackupProto(): BackupDebugInfo.AttachmentDetails {
|
||||
val archiveStateCounts = ArchiveTransferState
|
||||
.entries.associateWith {
|
||||
readableDatabase
|
||||
.count()
|
||||
.from(TABLE_NAME)
|
||||
.where("$ARCHIVE_TRANSFER_STATE = ${it.value} AND $DATA_HASH_END NOT NULL AND $REMOTE_KEY NOT NULL")
|
||||
.run()
|
||||
.readToSingleLong(-1L)
|
||||
}
|
||||
|
||||
return BackupDebugInfo.AttachmentDetails(
|
||||
notStartedCount = archiveStateCounts[ArchiveTransferState.NONE]?.toInt() ?: 0,
|
||||
uploadInProgressCount = archiveStateCounts[ArchiveTransferState.UPLOAD_IN_PROGRESS]?.toInt() ?: 0,
|
||||
copyPendingCount = archiveStateCounts[ArchiveTransferState.COPY_PENDING]?.toInt() ?: 0,
|
||||
finishedCount = archiveStateCounts[ArchiveTransferState.FINISHED]?.toInt() ?: 0,
|
||||
permanentFailureCount = archiveStateCounts[ArchiveTransferState.PERMANENT_FAILURE]?.toInt() ?: 0,
|
||||
temporaryFailureCount = archiveStateCounts[ArchiveTransferState.TEMPORARY_FAILURE]?.toInt() ?: 0
|
||||
)
|
||||
}
|
||||
|
||||
class DataFileWriteResult(
|
||||
val file: File,
|
||||
val length: Long,
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.core.app.NotificationManagerCompat
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.signal.core.util.Base64.decodeBase64OrThrow
|
||||
import org.signal.core.util.PendingIntentFlags
|
||||
import org.signal.core.util.isNotNullOrBlank
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.libsignal.protocol.InvalidMacException
|
||||
import org.signal.libsignal.protocol.InvalidMessageException
|
||||
@@ -302,22 +303,32 @@ class RestoreAttachmentJob private constructor(
|
||||
Log.w(TAG, e.message)
|
||||
markFailed(attachmentId)
|
||||
} catch (e: NonSuccessfulResponseCodeException) {
|
||||
if (SignalStore.backup.backsUpMedia) {
|
||||
if (e.code == 404 && !forceTransitTier && attachment.remoteLocation?.isNotBlank() == true) {
|
||||
Log.i(TAG, "[$attachmentId] Failed to download attachment from archive! Should only happen for recent attachments in a narrow window. Retrying download from transit CDN.")
|
||||
if (RemoteConfig.internalUser) {
|
||||
postFailedToDownloadFromArchiveNotification()
|
||||
}
|
||||
when (e.code) {
|
||||
404 -> {
|
||||
if (forceTransitTier) {
|
||||
Log.w(TAG, "[$attachmentId] Completely failed to restore an attachment! Failed downloading from both the archive and transit CDN.")
|
||||
maybePostFailedToDownloadFromArchiveAndTransitNotification()
|
||||
} else if (SignalStore.backup.backsUpMedia && attachment.remoteLocation.isNotNullOrBlank()) {
|
||||
Log.w(TAG, "[$attachmentId] Failed to download attachment from the archive CDN! Retrying download from transit CDN.")
|
||||
maybePostFailedToDownloadFromArchiveNotification()
|
||||
|
||||
retrieveAttachment(messageId, attachmentId, attachment, true)
|
||||
return
|
||||
} else if (e.code == 401 && useArchiveCdn) {
|
||||
SignalStore.backup.mediaCredentials.cdnReadCredentials = null
|
||||
SignalStore.backup.cachedMediaCdnPath = null
|
||||
throw RetryLaterException(e)
|
||||
} else if (e.code == 404 && attachment.remoteLocation?.isNotBlank() == true) {
|
||||
Log.i(TAG, "Failed to download attachment from transit tier. Scheduling retry.")
|
||||
throw e
|
||||
return retrieveAttachment(messageId, attachmentId, attachment, forceTransitTier = true)
|
||||
} else if (SignalStore.backup.backsUpMedia) {
|
||||
Log.w(TAG, "[$attachmentId] Completely failed to restore an attachment! Failed to download from archive CDN, and there's not transit CDN info.")
|
||||
maybePostFailedToDownloadFromArchiveAndTransitNotification()
|
||||
} else if (attachment.remoteLocation.isNotNullOrBlank()) {
|
||||
Log.w(TAG, "[$attachmentId] Failed to restore an attachment for a free tier user. Likely just older than 45 days.")
|
||||
}
|
||||
}
|
||||
401 -> {
|
||||
if (useArchiveCdn) {
|
||||
Log.w(TAG, "[$attachmentId] Had a credential issue when downloading an attachment. Clearing credentials and retrying.")
|
||||
SignalStore.backup.mediaCredentials.cdnReadCredentials = null
|
||||
SignalStore.backup.cachedMediaCdnPath = null
|
||||
throw RetryLaterException(e)
|
||||
} else {
|
||||
Log.w(TAG, "[$attachmentId] Unexpected 401 response for transit CDN restore.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,10 +359,29 @@ class RestoreAttachmentJob private constructor(
|
||||
SignalDatabase.attachments.setRestoreTransferState(attachmentId, AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE)
|
||||
}
|
||||
|
||||
private fun postFailedToDownloadFromArchiveNotification() {
|
||||
private fun maybePostFailedToDownloadFromArchiveNotification() {
|
||||
if (!RemoteConfig.internalUser || !SignalStore.backup.backsUpMedia) {
|
||||
return
|
||||
}
|
||||
|
||||
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setContentTitle("[Internal-only] Failed to download attachment from archive!")
|
||||
.setContentTitle("[Internal-only] Failed to restore attachment from Archive CDN!")
|
||||
.setContentText("Tap to send a debug log")
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, SubmitDebugLogActivity::class.java), PendingIntentFlags.mutable()))
|
||||
.build()
|
||||
|
||||
NotificationManagerCompat.from(context).notify(NotificationIds.INTERNAL_ERROR, notification)
|
||||
}
|
||||
|
||||
private fun maybePostFailedToDownloadFromArchiveAndTransitNotification() {
|
||||
if (!RemoteConfig.internalUser || !SignalStore.backup.backsUpMedia) {
|
||||
return
|
||||
}
|
||||
|
||||
val notification: Notification = NotificationCompat.Builder(context, NotificationChannels.getInstance().FAILURES)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setContentTitle("[Internal-only] Completely failed to restore attachment!")
|
||||
.setContentText("Tap to send a debug log")
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, SubmitDebugLogActivity::class.java), PendingIntentFlags.mutable()))
|
||||
.build()
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.keyvalue
|
||||
|
||||
import org.signal.ringrtc.CallManager.DataMode
|
||||
import org.thoughtcrime.securesms.BuildConfig
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.BackupDebugInfo
|
||||
import org.thoughtcrime.securesms.util.Environment.Calling.defaultSfuUrl
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
|
||||
@@ -34,6 +35,8 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
const val LARGE_SCREEN_UI: String = "internal.large.screen.ui"
|
||||
const val FORCE_SPLIT_PANE_ON_COMPACT_LANDSCAPE: String = "internal.force.split.pane.on.compact.landscape.ui"
|
||||
const val SHOW_ARCHIVE_STATE_HINT: String = "internal.show_archive_state_hint"
|
||||
const val INCLUDE_DEBUGLOG_IN_BACKUP: String = "internal.include_debuglog_in_backup"
|
||||
const val IMPORTED_BACKUP_DEBUG_INFO: String = "internal.imported_backup_debug_info"
|
||||
}
|
||||
|
||||
public override fun onFirstEverAppLaunch() = Unit
|
||||
@@ -181,6 +184,12 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
|
||||
|
||||
var showArchiveStateHint by booleanValue(SHOW_ARCHIVE_STATE_HINT, false).defaultForExternalUsers()
|
||||
|
||||
/** Whether or not we should include a debuglog in the backup debug info when generating a backup. */
|
||||
var includeDebuglogInBackup by booleanValue(INCLUDE_DEBUGLOG_IN_BACKUP, true).falseForExternalUsers()
|
||||
|
||||
/** Any [BackupDebugInfo] that was imported during the last backup restore, if any. */
|
||||
var importedBackupDebugInfo: BackupDebugInfo? by protoValue(IMPORTED_BACKUP_DEBUG_INFO, BackupDebugInfo.ADAPTER).defaultForExternalUsers()
|
||||
|
||||
private fun <T> SignalStoreValueDelegate<T>.defaultForExternalUsers(): SignalStoreValueDelegate<T> {
|
||||
return this.withPrecondition { RemoteConfig.internalUser }
|
||||
}
|
||||
|
||||
@@ -55,7 +55,23 @@ class LogSectionRemoteBackups : LogSection {
|
||||
output.append("IAP error type (or null): ${inAppPayment.data.error?.type}\n")
|
||||
output.append("IAP cancellation reason (or null): ${inAppPayment.data.cancellation?.reason}\n")
|
||||
} else {
|
||||
output.append("No in-app payment data available.")
|
||||
output.append("No in-app payment data available.\n")
|
||||
}
|
||||
|
||||
output.append("\n -- Imported DebugInfo\n")
|
||||
if (SignalStore.internal.importedBackupDebugInfo != null) {
|
||||
val info = SignalStore.internal.importedBackupDebugInfo!!
|
||||
output.append("Debuglog : ${info.debuglogUrl}\n")
|
||||
output.append("Using Paid Tier : ${info.usingPaidTier}\n")
|
||||
output.append("Attachment Details:\n")
|
||||
output.append(" NONE : ${info.attachmentDetails?.notStartedCount ?: "N/A"}\n")
|
||||
output.append(" UPLOAD_IN_PROGRESS: ${info.attachmentDetails?.uploadInProgressCount ?: "N/A"}\n")
|
||||
output.append(" COPY_PENDING : ${info.attachmentDetails?.copyPendingCount ?: "N/A"}\n")
|
||||
output.append(" FINISHED : ${info.attachmentDetails?.finishedCount ?: "N/A"}\n")
|
||||
output.append(" PERMANENT_FAILURE : ${info.attachmentDetails?.permanentFailureCount ?: "N/A"}\n")
|
||||
output.append(" TEMPORARY_FAILURE : ${info.attachmentDetails?.temporaryFailureCount ?: "N/A"}\n")
|
||||
} else {
|
||||
output.append("None\n")
|
||||
}
|
||||
|
||||
return output
|
||||
|
||||
Reference in New Issue
Block a user