.clear() {
+ _builder.clearChunkIds()
+ }
+ /**
+ * .com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;
+ */
+ public var apk: com.stevesoltys.seedvault.proto.Snapshot.Apk
+ @JvmName("getApk")
+ get() = _builder.getApk()
+ @JvmName("setApk")
+ set(value) {
+ _builder.setApk(value)
+ }
+ /**
+ * .com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;
+ */
+ public fun clearApk() {
+ _builder.clearApk()
+ }
+ /**
+ * .com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;
+ * @return Whether the apk field is set.
+ */
+ public fun hasApk(): kotlin.Boolean {
+ return _builder.hasApk()
+ }
+ }
+ }
+ @kotlin.jvm.JvmName("-initializeapk")
+ public inline fun apk(block: com.stevesoltys.seedvault.proto.SnapshotKt.ApkKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.Apk =
+ com.stevesoltys.seedvault.proto.SnapshotKt.ApkKt.Dsl._create(com.stevesoltys.seedvault.proto.Snapshot.Apk.newBuilder()).apply { block() }._build()
+ public object ApkKt {
+ @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
+ @com.google.protobuf.kotlin.ProtoDslMarker
+ public class Dsl private constructor(
+ private val _builder: com.stevesoltys.seedvault.proto.Snapshot.Apk.Builder
+ ) {
+ public companion object {
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.PublishedApi
+ internal fun _create(builder: com.stevesoltys.seedvault.proto.Snapshot.Apk.Builder): Dsl = Dsl(builder)
+ }
+
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.PublishedApi
+ internal fun _build(): com.stevesoltys.seedvault.proto.Snapshot.Apk = _builder.build()
+
+ /**
+ *
+ **
+ * Attention: Has default value of 0
+ *
+ *
+ * uint64 versionCode = 1;
+ */
+ public var versionCode: kotlin.Long
+ @JvmName("getVersionCode")
+ get() = _builder.getVersionCode()
+ @JvmName("setVersionCode")
+ set(value) {
+ _builder.setVersionCode(value)
+ }
+ /**
+ *
+ **
+ * Attention: Has default value of 0
+ *
+ *
+ * uint64 versionCode = 1;
+ */
+ public fun clearVersionCode() {
+ _builder.clearVersionCode()
+ }
+
+ /**
+ * string installer = 2;
+ */
+ public var installer: kotlin.String
+ @JvmName("getInstaller")
+ get() = _builder.getInstaller()
+ @JvmName("setInstaller")
+ set(value) {
+ _builder.setInstaller(value)
+ }
+ /**
+ * string installer = 2;
+ */
+ public fun clearInstaller() {
+ _builder.clearInstaller()
+ }
+
+ /**
+ * An uninstantiable, behaviorless type to represent the field in
+ * generics.
+ */
+ @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
+ public class SignaturesProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
+ /**
+ * repeated bytes signatures = 3;
+ */
+ public val signatures: com.google.protobuf.kotlin.DslList
+ @kotlin.jvm.JvmSynthetic
+ get() = com.google.protobuf.kotlin.DslList(
+ _builder.getSignaturesList()
+ )
+ /**
+ * repeated bytes signatures = 3;
+ * @param value The signatures to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("addSignatures")
+ public fun com.google.protobuf.kotlin.DslList.add(value: com.google.protobuf.ByteString) {
+ _builder.addSignatures(value)
+ }/**
+ * repeated bytes signatures = 3;
+ * @param value The signatures to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("plusAssignSignatures")
+ @Suppress("NOTHING_TO_INLINE")
+ public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(value: com.google.protobuf.ByteString) {
+ add(value)
+ }/**
+ * repeated bytes signatures = 3;
+ * @param values The signatures to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("addAllSignatures")
+ public fun com.google.protobuf.kotlin.DslList.addAll(values: kotlin.collections.Iterable) {
+ _builder.addAllSignatures(values)
+ }/**
+ * repeated bytes signatures = 3;
+ * @param values The signatures to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("plusAssignAllSignatures")
+ @Suppress("NOTHING_TO_INLINE")
+ public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(values: kotlin.collections.Iterable) {
+ addAll(values)
+ }/**
+ * repeated bytes signatures = 3;
+ * @param index The index to set the value at.
+ * @param value The signatures to set.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("setSignatures")
+ public operator fun com.google.protobuf.kotlin.DslList.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
+ _builder.setSignatures(index, value)
+ }/**
+ * repeated bytes signatures = 3;
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("clearSignatures")
+ public fun com.google.protobuf.kotlin.DslList.clear() {
+ _builder.clearSignatures()
+ }
+ /**
+ * An uninstantiable, behaviorless type to represent the field in
+ * generics.
+ */
+ @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
+ public class SplitsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ */
+ public val splits: com.google.protobuf.kotlin.DslList
+ @kotlin.jvm.JvmSynthetic
+ get() = com.google.protobuf.kotlin.DslList(
+ _builder.getSplitsList()
+ )
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ * @param value The splits to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("addSplits")
+ public fun com.google.protobuf.kotlin.DslList.add(value: com.stevesoltys.seedvault.proto.Snapshot.Split) {
+ _builder.addSplits(value)
+ }
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ * @param value The splits to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("plusAssignSplits")
+ @Suppress("NOTHING_TO_INLINE")
+ public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(value: com.stevesoltys.seedvault.proto.Snapshot.Split) {
+ add(value)
+ }
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ * @param values The splits to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("addAllSplits")
+ public fun com.google.protobuf.kotlin.DslList.addAll(values: kotlin.collections.Iterable) {
+ _builder.addAllSplits(values)
+ }
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ * @param values The splits to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("plusAssignAllSplits")
+ @Suppress("NOTHING_TO_INLINE")
+ public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(values: kotlin.collections.Iterable) {
+ addAll(values)
+ }
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ * @param index The index to set the value at.
+ * @param value The splits to set.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("setSplits")
+ public operator fun com.google.protobuf.kotlin.DslList.set(index: kotlin.Int, value: com.stevesoltys.seedvault.proto.Snapshot.Split) {
+ _builder.setSplits(index, value)
+ }
+ /**
+ * repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("clearSplits")
+ public fun com.google.protobuf.kotlin.DslList.clear() {
+ _builder.clearSplits()
+ }
+ }
+ }
+ @kotlin.jvm.JvmName("-initializesplit")
+ public inline fun split(block: com.stevesoltys.seedvault.proto.SnapshotKt.SplitKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.Split =
+ com.stevesoltys.seedvault.proto.SnapshotKt.SplitKt.Dsl._create(com.stevesoltys.seedvault.proto.Snapshot.Split.newBuilder()).apply { block() }._build()
+ public object SplitKt {
+ @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
+ @com.google.protobuf.kotlin.ProtoDslMarker
+ public class Dsl private constructor(
+ private val _builder: com.stevesoltys.seedvault.proto.Snapshot.Split.Builder
+ ) {
+ public companion object {
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.PublishedApi
+ internal fun _create(builder: com.stevesoltys.seedvault.proto.Snapshot.Split.Builder): Dsl = Dsl(builder)
+ }
+
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.PublishedApi
+ internal fun _build(): com.stevesoltys.seedvault.proto.Snapshot.Split = _builder.build()
+
+ /**
+ * string name = 1;
+ */
+ public var name: kotlin.String
+ @JvmName("getName")
+ get() = _builder.getName()
+ @JvmName("setName")
+ set(value) {
+ _builder.setName(value)
+ }
+ /**
+ * string name = 1;
+ */
+ public fun clearName() {
+ _builder.clearName()
+ }
+
+ /**
+ * An uninstantiable, behaviorless type to represent the field in
+ * generics.
+ */
+ @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
+ public class ChunkIdsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
+ /**
+ * repeated bytes chunkIds = 2;
+ */
+ public val chunkIds: com.google.protobuf.kotlin.DslList
+ @kotlin.jvm.JvmSynthetic
+ get() = com.google.protobuf.kotlin.DslList(
+ _builder.getChunkIdsList()
+ )
+ /**
+ * repeated bytes chunkIds = 2;
+ * @param value The chunkIds to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("addChunkIds")
+ public fun com.google.protobuf.kotlin.DslList.add(value: com.google.protobuf.ByteString) {
+ _builder.addChunkIds(value)
+ }/**
+ * repeated bytes chunkIds = 2;
+ * @param value The chunkIds to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("plusAssignChunkIds")
+ @Suppress("NOTHING_TO_INLINE")
+ public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(value: com.google.protobuf.ByteString) {
+ add(value)
+ }/**
+ * repeated bytes chunkIds = 2;
+ * @param values The chunkIds to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("addAllChunkIds")
+ public fun com.google.protobuf.kotlin.DslList.addAll(values: kotlin.collections.Iterable) {
+ _builder.addAllChunkIds(values)
+ }/**
+ * repeated bytes chunkIds = 2;
+ * @param values The chunkIds to add.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("plusAssignAllChunkIds")
+ @Suppress("NOTHING_TO_INLINE")
+ public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(values: kotlin.collections.Iterable) {
+ addAll(values)
+ }/**
+ * repeated bytes chunkIds = 2;
+ * @param index The index to set the value at.
+ * @param value The chunkIds to set.
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("setChunkIds")
+ public operator fun com.google.protobuf.kotlin.DslList.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
+ _builder.setChunkIds(index, value)
+ }/**
+ * repeated bytes chunkIds = 2;
+ */
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmName("clearChunkIds")
+ public fun com.google.protobuf.kotlin.DslList.clear() {
+ _builder.clearChunkIds()
+ }}
+ }
+ @kotlin.jvm.JvmName("-initializeblob")
+ public inline fun blob(block: com.stevesoltys.seedvault.proto.SnapshotKt.BlobKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.Blob =
+ com.stevesoltys.seedvault.proto.SnapshotKt.BlobKt.Dsl._create(com.stevesoltys.seedvault.proto.Snapshot.Blob.newBuilder()).apply { block() }._build()
+ public object BlobKt {
+ @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
+ @com.google.protobuf.kotlin.ProtoDslMarker
+ public class Dsl private constructor(
+ private val _builder: com.stevesoltys.seedvault.proto.Snapshot.Blob.Builder
+ ) {
+ public companion object {
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.PublishedApi
+ internal fun _create(builder: com.stevesoltys.seedvault.proto.Snapshot.Blob.Builder): Dsl = Dsl(builder)
+ }
+
+ @kotlin.jvm.JvmSynthetic
+ @kotlin.PublishedApi
+ internal fun _build(): com.stevesoltys.seedvault.proto.Snapshot.Blob = _builder.build()
+
+ /**
+ * bytes id = 1;
+ */
+ public var id: com.google.protobuf.ByteString
+ @JvmName("getId")
+ get() = _builder.getId()
+ @JvmName("setId")
+ set(value) {
+ _builder.setId(value)
+ }
+ /**
+ * bytes id = 1;
+ */
+ public fun clearId() {
+ _builder.clearId()
+ }
+
+ /**
+ * uint32 length = 2;
+ */
+ public var length: kotlin.Int
+ @JvmName("getLength")
+ get() = _builder.getLength()
+ @JvmName("setLength")
+ set(value) {
+ _builder.setLength(value)
+ }
+ /**
+ * uint32 length = 2;
+ */
+ public fun clearLength() {
+ _builder.clearLength()
+ }
+
+ /**
+ * uint32 uncompressedLength = 3;
+ */
+ public var uncompressedLength: kotlin.Int
+ @JvmName("getUncompressedLength")
+ get() = _builder.getUncompressedLength()
+ @JvmName("setUncompressedLength")
+ set(value) {
+ _builder.setUncompressedLength(value)
+ }
+ /**
+ * uint32 uncompressedLength = 3;
+ */
+ public fun clearUncompressedLength() {
+ _builder.clearUncompressedLength()
+ }
+ }
+ }
+}
+public inline fun com.stevesoltys.seedvault.proto.Snapshot.copy(block: com.stevesoltys.seedvault.proto.SnapshotKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot =
+ com.stevesoltys.seedvault.proto.SnapshotKt.Dsl._create(this.toBuilder()).apply { block() }._build()
+
+public inline fun com.stevesoltys.seedvault.proto.Snapshot.App.copy(block: com.stevesoltys.seedvault.proto.SnapshotKt.AppKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.App =
+ com.stevesoltys.seedvault.proto.SnapshotKt.AppKt.Dsl._create(this.toBuilder()).apply { block() }._build()
+
+public val com.stevesoltys.seedvault.proto.Snapshot.AppOrBuilder.apkOrNull: com.stevesoltys.seedvault.proto.Snapshot.Apk?
+ get() = if (hasApk()) getApk() else null
+
+public inline fun com.stevesoltys.seedvault.proto.Snapshot.Apk.copy(block: com.stevesoltys.seedvault.proto.SnapshotKt.ApkKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.Apk =
+ com.stevesoltys.seedvault.proto.SnapshotKt.ApkKt.Dsl._create(this.toBuilder()).apply { block() }._build()
+
+public inline fun com.stevesoltys.seedvault.proto.Snapshot.Split.copy(block: com.stevesoltys.seedvault.proto.SnapshotKt.SplitKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.Split =
+ com.stevesoltys.seedvault.proto.SnapshotKt.SplitKt.Dsl._create(this.toBuilder()).apply { block() }._build()
+
+public inline fun com.stevesoltys.seedvault.proto.Snapshot.Blob.copy(block: com.stevesoltys.seedvault.proto.SnapshotKt.BlobKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.Blob =
+ com.stevesoltys.seedvault.proto.SnapshotKt.BlobKt.Dsl._create(this.toBuilder()).apply { block() }._build()
+
diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/worker/IconManagerTest.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/worker/IconManagerTest.kt
index a16413e3..aec46369 100644
--- a/app/src/androidTest/java/com/stevesoltys/seedvault/worker/IconManagerTest.kt
+++ b/app/src/androidTest/java/com/stevesoltys/seedvault/worker/IconManagerTest.kt
@@ -9,7 +9,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry
import com.google.protobuf.ByteString
-import com.stevesoltys.seedvault.proto.Snapshot
+import com.stevesoltys.seedvault.proto.SnapshotKt.blob
import com.stevesoltys.seedvault.transport.backup.AppBackupManager
import com.stevesoltys.seedvault.transport.backup.BackupData
import com.stevesoltys.seedvault.transport.backup.BackupReceiver
@@ -66,7 +66,7 @@ class IconManagerTest : KoinComponent {
val chunkId = Random.nextBytes(32).toHexString()
val chunkList = listOf(chunkId)
val blobId = Random.nextBytes(32).toHexString()
- val blob = Snapshot.Blob.newBuilder().setId(ByteString.fromHex(blobId)).build()
+ val blob = blob { id = ByteString.fromHex(blobId) }
// upload icons and capture plaintext bytes
coEvery { backupReceiver.addBytes(capture(output)) } just Runs
diff --git a/app/src/main/java/com/stevesoltys/seedvault/metadata/Metadata.kt b/app/src/main/java/com/stevesoltys/seedvault/metadata/Metadata.kt
index 4311dc8f..ccf3d6ca 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/metadata/Metadata.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/metadata/Metadata.kt
@@ -115,7 +115,7 @@ data class PackageMetadata(
system = app.system,
isLaunchableSystemApp = app.launchableSystemApp,
version = app.apk.versionCode,
- installer = app.apk.installer,
+ installer = app.apk.installer.takeIf { it.isNotEmpty() },
baseApkChunkIds = run {
val baseChunk = app.apk.splitsList.find { it.name == BASE_SPLIT }
if (baseChunk == null || baseChunk.chunkIdsCount == 0) {
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BlobCreator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BlobCreator.kt
index 1a86158b..59ebeefb 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BlobCreator.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BlobCreator.kt
@@ -11,6 +11,7 @@ import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.proto.Snapshot.Blob
+import com.stevesoltys.seedvault.proto.SnapshotKt.blob
import okio.Buffer
import okio.buffer
import okio.sink
@@ -43,10 +44,10 @@ internal class BlobCreator(
outputBuffer.flush()
length
}
- return Blob.newBuilder()
- .setId(ByteString.copyFrom(sha256ByteString.asByteBuffer()))
- .setLength(size.toInt())
- .setUncompressedLength(chunk.length)
- .build()
+ return blob {
+ id = ByteString.copyFrom(sha256ByteString.asByteBuffer())
+ length = size.toInt()
+ uncompressedLength = chunk.length
+ }
}
}
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/SnapshotCreator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/SnapshotCreator.kt
index b5151552..4c5ad3d6 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/SnapshotCreator.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/SnapshotCreator.kt
@@ -15,6 +15,7 @@ import android.provider.Settings
import android.provider.Settings.Secure.ANDROID_ID
import com.google.protobuf.ByteString
import com.stevesoltys.seedvault.Clock
+import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.metadata.BackupType
import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
import com.stevesoltys.seedvault.proto.Snapshot
@@ -22,6 +23,7 @@ import com.stevesoltys.seedvault.proto.Snapshot.Apk
import com.stevesoltys.seedvault.proto.Snapshot.App
import com.stevesoltys.seedvault.proto.Snapshot.Blob
import com.stevesoltys.seedvault.settings.SettingsManager
+import io.github.oshai.kotlinlogging.KotlinLogging
import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.toHexString
@@ -41,8 +43,8 @@ internal class SnapshotCreator(
private val settingsManager: SettingsManager,
) {
+ private val log = KotlinLogging.logger { }
private val snapshotBuilder = Snapshot.newBuilder()
- .setToken(clock.time())
private val appBuilderMap = mutableMapOf()
private val blobsMap = mutableMapOf()
@@ -51,37 +53,41 @@ internal class SnapshotCreator(
}
fun onApkBackedUp(
- packageName: String,
+ packageInfo: PackageInfo,
apk: Apk,
chunkMap: Map,
) {
- val appBuilder = appBuilderMap.getOrPut(packageName) {
+ appBuilderMap.getOrPut(packageInfo.packageName) {
App.newBuilder()
+ }.apply {
+ val label = packageInfo.applicationInfo?.loadLabel(context.packageManager)
+ if (label != null) name = label.toString()
+ setApk(apk)
}
- appBuilder.setApk(apk)
blobsMap.putAll(chunkMap)
}
fun onPackageBackedUp(
packageInfo: PackageInfo,
- type: BackupType,
+ backupType: BackupType,
backupData: BackupData,
) {
val packageName = packageInfo.packageName
- val builder = appBuilderMap.getOrPut(packageName) {
- App.newBuilder()
- }
val isSystemApp = packageInfo.isSystemApp()
val chunkIds = backupData.chunks.forProto()
+ appBuilderMap.getOrPut(packageName) {
+ App.newBuilder()
+ }.apply {
+ time = clock.time()
+ state = APK_AND_DATA.name // TODO review those states and their usefulness for snapshot
+ type = backupType.forSnapshot()
+ val label = packageInfo.applicationInfo?.loadLabel(context.packageManager)
+ if (label != null) name = label.toString()
+ system = isSystemApp
+ launchableSystemApp = isSystemApp && launchableSystemApps.contains(packageName)
+ addAllChunkIds(chunkIds)
+ }
blobsMap.putAll(backupData.chunkMap)
- builder
- .setTime(clock.time())
- .setState(APK_AND_DATA.name)
- .setType(type.forSnapshot())
- .setName(packageInfo.applicationInfo?.loadLabel(context.packageManager)?.toString())
- .setSystem(isSystemApp)
- .setLaunchableSystemApp(isSystemApp && launchableSystemApps.contains(packageName))
- .addAllChunkIds(chunkIds)
}
fun onIconsBackedUp(backupData: BackupData) {
@@ -90,6 +96,7 @@ internal class SnapshotCreator(
}
fun finalizeSnapshot(): Snapshot {
+ log.info { "finalizeSnapshot()" }
val userName = getUserName()
val deviceName = if (userName == null) {
"${Build.MANUFACTURER} ${Build.MODEL}"
@@ -98,16 +105,17 @@ internal class SnapshotCreator(
}
@SuppressLint("HardwareIds")
- val androidId = Settings.Secure.getString(context.contentResolver, ANDROID_ID)
- val snapshot = snapshotBuilder
- .setName(deviceName)
- .setAndroidId(androidId)
- .setSdkInt(Build.VERSION.SDK_INT)
- .setAndroidIncremental(Build.VERSION.INCREMENTAL)
- .setD2D(settingsManager.d2dBackupsEnabled())
- .putAllApps(appBuilderMap.mapValues { it.value.build() })
- .putAllBlobs(blobsMap)
- .build()
+ val snapshot = snapshotBuilder.apply {
+ version = VERSION.toInt()
+ token = clock.time()
+ name = deviceName
+ androidId = Settings.Secure.getString(context.contentResolver, ANDROID_ID)
+ sdkInt = Build.VERSION.SDK_INT
+ androidIncremental = Build.VERSION.INCREMENTAL
+ d2D = settingsManager.d2dBackupsEnabled()
+ putAllApps(appBuilderMap.mapValues { it.value.build() })
+ putAllBlobs(this@SnapshotCreator.blobsMap)
+ }.build()
appBuilderMap.clear()
snapshotBuilder.clear()
return snapshot
diff --git a/app/src/main/java/com/stevesoltys/seedvault/worker/ApkBackup.kt b/app/src/main/java/com/stevesoltys/seedvault/worker/ApkBackup.kt
index 898cb193..1d282982 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/worker/ApkBackup.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/worker/ApkBackup.kt
@@ -14,6 +14,7 @@ import android.util.PackageUtils.computeSha256DigestBytes
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.proto.Snapshot
+import com.stevesoltys.seedvault.proto.SnapshotKt.split
import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.SnapshotManager
import com.stevesoltys.seedvault.transport.backup.AppBackupManager
@@ -108,10 +109,14 @@ internal class ApkBackup(
}
// builder for Apk object
- val apkBuilder = Snapshot.Apk.newBuilder()
- .setVersionCode(version)
- .setInstaller(pm.getInstallSourceInfo(packageName).installingPackageName)
- .addAllSignatures(signatures.forProto())
+ val apkBuilder = Snapshot.Apk.newBuilder().apply {
+ versionCode = version
+ pm.getInstallSourceInfo(packageName).installingPackageName?.let {
+ // protobuf doesn't support null values
+ installer = it
+ }
+ addAllSignatures(signatures.forProto())
+ }
// get an InputStream for the APK
val sourceDir = packageInfo.applicationInfo?.sourceDir ?: return
@@ -121,9 +126,10 @@ internal class ApkBackup(
}
val backupData = backupReceiver.finalize()
// store base split in builder
- val baseSplit = Snapshot.Split.newBuilder()
- .setName(BASE_SPLIT)
- .addAllChunkIds(backupData.chunks.forProto())
+ val baseSplit = split {
+ name = BASE_SPLIT
+ chunkIds.addAll(backupData.chunks.forProto())
+ }
apkBuilder
.addSplits(baseSplit)
val chunkMap = backupData.chunkMap.toMutableMap()
@@ -134,9 +140,8 @@ internal class ApkBackup(
} else {
backupSplitApks(packageInfo, chunkMap)
}
- apkBuilder.addAllSplits(splits)
- val apk = apkBuilder.build()
- snapshotCreator.onApkBackedUp(packageName, apk, chunkMap)
+ val apk = apkBuilder.addAllSplits(splits).build()
+ snapshotCreator.onApkBackedUp(packageInfo, apk, chunkMap)
Log.d(TAG, "Backed up new APK of $packageName with version ${packageInfo.versionName}.")
}
diff --git a/app/src/test/java/com/stevesoltys/seedvault/restore/AppSelectionManagerTest.kt b/app/src/test/java/com/stevesoltys/seedvault/restore/AppSelectionManagerTest.kt
index 1f00e1a8..3768f501 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/restore/AppSelectionManagerTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/restore/AppSelectionManagerTest.kt
@@ -14,7 +14,6 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.BackupMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
-import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.ui.PACKAGE_NAME_CONTACTS
import com.stevesoltys.seedvault.ui.PACKAGE_NAME_SETTINGS
@@ -29,7 +28,6 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.LegacyAppBackupFile
-import org.calyxos.seedvault.core.toHexString
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
@@ -61,12 +59,6 @@ internal class AppSelectionManagerTest : TransportTest() {
token = Random.nextLong(),
salt = getRandomString(),
)
- private val repoId = Random.nextBytes(32).toHexString()
- private val snapshot = Snapshot.newBuilder()
- .setToken(token)
- .putApps(packageInfo.packageName, Snapshot.App.getDefaultInstance())
- .putAllBlobs(emptyMap())
- .build()
private val appSelectionManager = AppSelectionManager(
context = context,
diff --git a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt
index 1be5ab32..f613fbf8 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkBackupRestoreTest.kt
@@ -14,13 +14,10 @@ import android.content.pm.Signature
import android.graphics.drawable.Drawable
import android.util.PackageUtils
import app.cash.turbine.test
-import com.google.protobuf.ByteString
-import com.google.protobuf.ByteString.copyFromUtf8
import com.stevesoltys.seedvault.BackupStateManager
import com.stevesoltys.seedvault.assertReadEquals
import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.backend.LegacyStoragePlugin
-import com.stevesoltys.seedvault.decodeBase64
import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
@@ -31,14 +28,12 @@ import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.SnapshotManager
import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.transport.backup.AppBackupManager
-import com.stevesoltys.seedvault.transport.backup.BackupData
import com.stevesoltys.seedvault.transport.backup.BackupReceiver
import com.stevesoltys.seedvault.transport.backup.SnapshotCreator
import com.stevesoltys.seedvault.transport.backup.hexFromProto
import com.stevesoltys.seedvault.transport.restore.Loader
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import com.stevesoltys.seedvault.worker.ApkBackup
-import com.stevesoltys.seedvault.worker.BASE_SPLIT
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.every
@@ -46,11 +41,10 @@ import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.slot
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+
import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.Backend
-import org.calyxos.seedvault.core.toHexString
import org.junit.jupiter.api.Assertions.assertArrayEquals
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
@@ -64,9 +58,7 @@ import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.nio.file.Path
-import kotlin.random.Random
-@ExperimentalCoroutinesApi
internal class ApkBackupRestoreTest : TransportTest() {
private val pm: PackageManager = mockk()
@@ -108,37 +100,6 @@ internal class ApkBackupRestoreTest : TransportTest() {
private val signatureBytes = byteArrayOf(0x01, 0x02, 0x03)
private val signatureHash = byteArrayOf(0x03, 0x02, 0x01)
private val sigs = arrayOf(Signature(signatureBytes))
- private val packageName: String = packageInfo.packageName
- private val splitName = getRandomString()
- private val splitBytes = byteArrayOf(0x07, 0x08, 0x09)
- private val apkChunkId = Random.nextBytes(32).toHexString()
- private val splitChunkId = Random.nextBytes(32).toHexString()
- private val apkBlob =
- Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build()
- private val splitBlob =
- Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build()
- private val apkBackupData = BackupData(listOf(apkChunkId), mapOf(apkChunkId to apkBlob))
- private val splitBackupData = BackupData(listOf(splitChunkId), mapOf(splitChunkId to splitBlob))
- private val chunkMap = apkBackupData.chunkMap + splitBackupData.chunkMap
- private val baseSplit = Snapshot.Split.newBuilder().setName(BASE_SPLIT)
- .addAllChunkIds(listOf(ByteString.fromHex(apkChunkId))).build()
- private val apkSplit = Snapshot.Split.newBuilder().setName(splitName)
- .addAllChunkIds(listOf(ByteString.fromHex(splitChunkId))).build()
- private val apk = Snapshot.Apk.newBuilder()
- .setVersionCode(packageInfo.longVersionCode - 1)
- .setInstaller(getRandomString())
- .addAllSignatures(mutableListOf(copyFromUtf8("AwIB".decodeBase64())))
- .addSplits(baseSplit)
- .addSplits(apkSplit)
- .build()
- private val app = Snapshot.App.newBuilder()
- .setApk(apk)
- .build()
- private val snapshot = Snapshot.newBuilder()
- .setToken(token)
- .putApps(packageName, app)
- .putAllBlobs(chunkMap)
- .build()
private val packageMetadataMap: PackageMetadataMap =
hashMapOf(packageName to PackageMetadata.fromSnapshot(app))
private val installerName = apk.installer
diff --git a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt
index 93bceb56..9765c35f 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreTest.kt
@@ -17,19 +17,18 @@ import android.content.pm.PackageManager.NameNotFoundException
import android.graphics.drawable.Drawable
import app.cash.turbine.TurbineTestContext
import app.cash.turbine.test
-import com.google.protobuf.ByteString
-import com.google.protobuf.ByteString.copyFromUtf8
+import com.google.protobuf.ByteString.copyFrom
import com.google.protobuf.ByteString.fromHex
import com.stevesoltys.seedvault.BackupStateManager
import com.stevesoltys.seedvault.backend.BackendManager
-import com.stevesoltys.seedvault.backend.LegacyStoragePlugin
-import com.stevesoltys.seedvault.decodeBase64
import com.stevesoltys.seedvault.getRandomBase64
import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
-import com.stevesoltys.seedvault.proto.Snapshot
+import com.stevesoltys.seedvault.proto.SnapshotKt.blob
+import com.stevesoltys.seedvault.proto.SnapshotKt.split
+import com.stevesoltys.seedvault.proto.copy
import com.stevesoltys.seedvault.restore.RestorableBackup
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
@@ -37,10 +36,8 @@ import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.TransportTest
-import com.stevesoltys.seedvault.transport.backup.BackupData
import com.stevesoltys.seedvault.transport.backup.hexFromProto
import com.stevesoltys.seedvault.transport.restore.Loader
-import com.stevesoltys.seedvault.worker.BASE_SPLIT
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.every
@@ -48,7 +45,6 @@ import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verifyOrder
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.Backend
@@ -66,7 +62,6 @@ import java.io.IOException
import java.nio.file.Path
import kotlin.random.Random
-@ExperimentalCoroutinesApi
internal class ApkRestoreTest : TransportTest() {
private val pm: PackageManager = mockk()
@@ -78,7 +73,6 @@ internal class ApkRestoreTest : TransportTest() {
private val backendManager: BackendManager = mockk()
private val loader: Loader = mockk()
private val backend: Backend = mockk()
- private val legacyStoragePlugin: LegacyStoragePlugin = mockk()
private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk()
private val apkInstaller: ApkInstaller = mockk()
private val installRestriction: InstallRestriction = mockk()
@@ -89,8 +83,8 @@ internal class ApkRestoreTest : TransportTest() {
backupStateManager = backupStateManager,
backendManager = backendManager,
loader = loader,
- legacyStoragePlugin = legacyStoragePlugin,
- crypto = crypto,
+ legacyStoragePlugin = mockk(),
+ crypto = mockk(),
splitCompatChecker = splitCompatChecker,
apkInstaller = apkInstaller,
installRestriction = installRestriction,
@@ -99,38 +93,24 @@ internal class ApkRestoreTest : TransportTest() {
private val icon: Drawable = mockk()
private val deviceName = metadata.deviceName
- private val packageName = packageInfo.packageName
private val apkBytes = byteArrayOf(0x04, 0x05, 0x06)
private val apkInputStream = ByteArrayInputStream(apkBytes)
private val appName = getRandomString()
- private val repoId = Random.nextBytes(32).toHexString()
- private val apkChunkId = Random.nextBytes(32).toHexString()
- private val apkBlob =
- Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build()
- private val apkBlobHandle = AppBackupFileType.Blob(repoId, apkBlob.id.hexFromProto())
- private val apkBackupData = BackupData(listOf(apkChunkId), mapOf(apkChunkId to apkBlob))
- private val baseSplit = Snapshot.Split.newBuilder().setName(BASE_SPLIT)
- .addAllChunkIds(listOf(fromHex(apkChunkId))).build()
- private val apk = Snapshot.Apk.newBuilder()
- .setVersionCode(packageInfo.longVersionCode - 1)
- .setInstaller(getRandomString())
- .addAllSignatures(mutableListOf(copyFromUtf8("AwIB".decodeBase64())))
- .addSplits(baseSplit)
- .build()
- private val app = Snapshot.App.newBuilder()
- .setApk(apk)
- .build()
- private val snapshot = Snapshot.newBuilder()
- .setToken(token)
- .putApps(packageName, app)
- .putAllBlobs(apkBackupData.chunkMap)
- .build()
- private val packageMetadata = PackageMetadata.fromSnapshot(app)
+ private val appNoSplit = app.copy { // tests that need splits bring their own
+ this.apk = apk.copy {
+ splits.clear()
+ splits.add(baseSplit)
+ }
+ }
+ private val snapshotWithoutSplit = snapshot.copy {
+ apps[packageName] = appNoSplit
+ }
+ private val packageMetadata = PackageMetadata.fromSnapshot(appNoSplit)
private val packageMetadataMap: PackageMetadataMap = hashMapOf(packageName to packageMetadata)
private val installerName = packageMetadata.installer
private val backup = RestorableBackup(
repoId = repoId,
- snapshot = snapshot,
+ snapshot = snapshotWithoutSplit,
backupMetadata = metadata.copy(packageMetadataMap = packageMetadataMap),
)
@@ -472,7 +452,7 @@ internal class ApkRestoreTest : TransportTest() {
splits = listOf(split)
)
val blobHandle = AppBackupFileType.Blob(repoId, splitBlobId)
- val splitBlob = Snapshot.Blob.newBuilder().setId(fromHex(splitBlobId)).build()
+ val splitBlob = blob { id = fromHex(splitBlobId) }
val snapshot = snapshot.toBuilder().putBlobs(splitChunkId, splitBlob).build()
val backup = backup.copy(snapshot = snapshot)
@@ -496,27 +476,31 @@ internal class ApkRestoreTest : TransportTest() {
@Test
fun `splits get installed along with base APK`(@TempDir tmpDir: Path) = runBlocking {
// add one APK split to metadata
- val split1Name = getRandomString()
- val split2Name = getRandomString()
val splitChunkId1 = Random.nextBytes(32).toHexString()
val splitChunkId2 = Random.nextBytes(32).toHexString()
- val apkSplit1 = Snapshot.Split.newBuilder().setName(split1Name)
- .addAllChunkIds(listOf(fromHex(splitChunkId1))).build()
- val apkSplit2 = Snapshot.Split.newBuilder().setName(split2Name)
- .addAllChunkIds(listOf(fromHex(splitChunkId2))).build()
- val splitBlob1 =
- Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build()
- val splitBlob2 =
- Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build()
- val apk = apk.toBuilder().addSplits(apkSplit1).addSplits(apkSplit2).build()
- val app = app.toBuilder().setApk(apk).build()
+ val apkSplit1 = split {
+ name = getRandomString()
+ chunkIds.add(fromHex(splitChunkId1))
+ }
+ val apkSplit2 = split {
+ name = getRandomString()
+ chunkIds.add(fromHex(splitChunkId2))
+ }
+ val splitBlob1 = blob { id = copyFrom(Random.nextBytes(32)) }
+ val splitBlob2 = blob { id = copyFrom(Random.nextBytes(32)) }
val blobMap = apkBackupData.chunkMap +
mapOf(splitChunkId1 to splitBlob1) +
mapOf(splitChunkId2 to splitBlob2)
- val snapshot = snapshot.toBuilder()
- .putApps(packageName, app)
- .putAllBlobs(blobMap)
- .build()
+ val app = appNoSplit.copy {
+ this.apk = apk.copy {
+ splits.clear()
+ splits.addAll(listOf(baseSplit, apkSplit1, apkSplit2))
+ }
+ }
+ val snapshot = snapshotWithoutSplit.copy {
+ apps[packageName] = app
+ blobs.putAll(blobMap)
+ }
packageMetadataMap[packageName] = PackageMetadata.fromSnapshot(app)
val backup = backup.copy(snapshot = snapshot)
@@ -528,7 +512,7 @@ internal class ApkRestoreTest : TransportTest() {
cacheBaseApkAndGetInfo(tmpDir)
every {
- splitCompatChecker.isCompatible(deviceName, listOf(split1Name, split2Name))
+ splitCompatChecker.isCompatible(deviceName, listOf(apkSplit1.name, apkSplit2.name))
} returns true
// define bytes of splits and return them as stream (matches above hashes)
diff --git a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreV1Test.kt b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreV1Test.kt
index b04351be..3abfca1d 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreV1Test.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/restore/install/ApkRestoreV1Test.kt
@@ -41,7 +41,6 @@ import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verifyOrder
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.LegacyAppBackupFile
@@ -57,7 +56,6 @@ import java.io.IOException
import java.nio.file.Path
import kotlin.random.Random
-@ExperimentalCoroutinesApi
@Suppress("DEPRECATION")
internal class ApkRestoreV1Test : TransportTest() {
@@ -91,7 +89,6 @@ internal class ApkRestoreV1Test : TransportTest() {
private val icon: Drawable = mockk()
private val deviceName = metadata.deviceName
- private val packageName = packageInfo.packageName
private val packageMetadata = PackageMetadata(
time = Random.nextLong(),
version = packageInfo.longVersionCode - 1,
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/SnapshotManagerTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/SnapshotManagerTest.kt
index e1a1652b..61b8cee7 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/SnapshotManagerTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/SnapshotManagerTest.kt
@@ -6,8 +6,6 @@
package com.stevesoltys.seedvault.transport
import com.stevesoltys.seedvault.backend.BackendManager
-import com.stevesoltys.seedvault.crypto.Crypto
-import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.transport.restore.Loader
import io.mockk.coEvery
@@ -31,9 +29,8 @@ import java.io.OutputStream
import java.security.MessageDigest
import kotlin.random.Random
-class SnapshotManagerTest {
+internal class SnapshotManagerTest : TransportTest() {
- private val crypto: Crypto = mockk()
private val backendManager: BackendManager = mockk()
private val backend: Backend = mockk()
@@ -43,14 +40,7 @@ class SnapshotManagerTest {
private val ad = Random.nextBytes(1)
private val passThroughOutputStream = slot()
private val passThroughInputStream = slot()
- private val repoId = Random.nextBytes(32).toHexString()
private val snapshotHandle = slot()
- private val snapshot = Snapshot.newBuilder()
- .setToken(Random.nextLong())
- .setName(getRandomString())
- .setSdkInt(Random.nextInt())
- .putAllBlobs(mapOf(getRandomString() to Snapshot.Blob.getDefaultInstance()))
- .build()
@Test
fun `test saving and loading`() = runBlocking {
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt
index ee0e99d7..ef14a346 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/TransportTest.kt
@@ -12,9 +12,12 @@ import android.content.pm.ApplicationInfo.FLAG_INSTALLED
import android.content.pm.PackageInfo
import android.content.pm.SigningInfo
import android.util.Log
+import com.google.protobuf.ByteString
+import com.google.protobuf.ByteString.copyFromUtf8
import com.stevesoltys.seedvault.Clock
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.crypto.Crypto
+import com.stevesoltys.seedvault.decodeBase64
import com.stevesoltys.seedvault.getRandomBase64
import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.BackupMetadata
@@ -23,12 +26,21 @@ import com.stevesoltys.seedvault.metadata.METADATA_SALT_SIZE
import com.stevesoltys.seedvault.metadata.MetadataManager
import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
+import com.stevesoltys.seedvault.proto.SnapshotKt
+import com.stevesoltys.seedvault.proto.SnapshotKt.blob
+import com.stevesoltys.seedvault.proto.SnapshotKt.split
+import com.stevesoltys.seedvault.proto.snapshot
import com.stevesoltys.seedvault.settings.SettingsManager
+import com.stevesoltys.seedvault.transport.backup.BackupData
+import com.stevesoltys.seedvault.transport.backup.hexFromProto
+import com.stevesoltys.seedvault.worker.BASE_SPLIT
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.slot
+import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.LegacyAppBackupFile
+import org.calyxos.seedvault.core.toHexString
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD
import kotlin.random.Random
@@ -53,6 +65,7 @@ internal abstract class TransportTest {
applicationInfo = this@TransportTest.applicationInfo
signingInfo = sigInfo
}
+ protected val packageName: String = packageInfo.packageName
protected val pmPackageInfo = PackageInfo().apply {
packageName = MAGIC_PACKAGE_MANAGER
}
@@ -76,6 +89,46 @@ internal abstract class TransportTest {
protected val storageProviderPackageName = getRandomString(23)
protected val handle = LegacyAppBackupFile.Blob(token, name)
+ protected val repoId = Random.nextBytes(32).toHexString()
+ protected val splitName = getRandomString()
+ protected val splitBytes = byteArrayOf(0x07, 0x08, 0x09)
+ protected val apkChunkId = Random.nextBytes(32).toHexString()
+ protected val splitChunkId = Random.nextBytes(32).toHexString()
+ protected val apkBlob = blob {
+ id = ByteString.copyFrom(Random.nextBytes(32))
+ }
+ protected val splitBlob = blob {
+ id = ByteString.copyFrom(Random.nextBytes(32))
+ }
+ protected val apkBlobHandle = AppBackupFileType.Blob(repoId, apkBlob.id.hexFromProto())
+ protected val apkBackupData = BackupData(listOf(apkChunkId), mapOf(apkChunkId to apkBlob))
+ protected val splitBackupData =
+ BackupData(listOf(splitChunkId), mapOf(splitChunkId to splitBlob))
+ protected val chunkMap = apkBackupData.chunkMap + splitBackupData.chunkMap
+ protected val baseSplit = split {
+ name = BASE_SPLIT
+ chunkIds.add(ByteString.fromHex(apkChunkId))
+ }
+ protected val apkSplit = split {
+ name = splitName
+ chunkIds.add(ByteString.fromHex(splitChunkId))
+ }
+ protected val apk = SnapshotKt.apk {
+ versionCode = packageInfo.longVersionCode - 1
+ installer = getRandomString()
+ signatures.add(copyFromUtf8("AwIB".decodeBase64()))
+ splits.add(baseSplit)
+ splits.add(apkSplit)
+ }
+ protected val app = SnapshotKt.app {
+ apk = this@TransportTest.apk
+ }
+ protected val snapshot = snapshot {
+ token = this@TransportTest.token
+ apps[packageName] = app
+ blobs.putAll(chunkMap)
+ }
+
init {
mockkStatic(Log::class)
val logTagSlot = slot()
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt
index 422bf71d..5c83cee0 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/backup/KVBackupTest.kt
@@ -13,11 +13,11 @@ import android.app.backup.BackupTransport.TRANSPORT_ERROR
import android.app.backup.BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED
import android.app.backup.BackupTransport.TRANSPORT_OK
import android.content.pm.PackageInfo
+import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForKV
-import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import io.mockk.CapturingSlot
import io.mockk.Runs
@@ -55,7 +55,6 @@ internal class KVBackupTest : BackupTest() {
private val db = mockk()
private val backend = mockk()
- private val packageName = packageInfo.packageName
private val key = getRandomString(MAX_KEY_LENGTH_SIZE)
private val dataValue = Random.nextBytes(23)
private val dbBytes = Random.nextBytes(42)
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
index f187ad00..23773189 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
@@ -73,7 +73,6 @@ internal class RestoreCoordinatorTest : TransportTest() {
PackageInfo().apply { packageName = "@pm@" },
packageInfo
)
- private val packageName = packageInfo.packageName
private val storageName = getRandomString()
init {
diff --git a/app/src/test/java/com/stevesoltys/seedvault/worker/ApkBackupTest.kt b/app/src/test/java/com/stevesoltys/seedvault/worker/ApkBackupTest.kt
index 27ca16df..a2c012dc 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/worker/ApkBackupTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/worker/ApkBackupTest.kt
@@ -13,10 +13,12 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.util.PackageUtils
-import com.google.protobuf.ByteString
+import com.google.protobuf.ByteString.copyFromUtf8
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.proto.Snapshot
+import com.stevesoltys.seedvault.proto.SnapshotKt.app
+import com.stevesoltys.seedvault.proto.copy
import com.stevesoltys.seedvault.transport.SnapshotManager
import com.stevesoltys.seedvault.transport.backup.AppBackupManager
import com.stevesoltys.seedvault.transport.backup.BackupData
@@ -56,14 +58,6 @@ internal class ApkBackupTest : BackupTest() {
private val signatureBytes = byteArrayOf(0x01, 0x02, 0x03)
private val signatureHash = byteArrayOf(0x03, 0x02, 0x01)
private val sigs = arrayOf(Signature(signatureBytes))
- private val apk = Snapshot.Apk.newBuilder()
- .setVersionCode(packageInfo.longVersionCode - 1)
- .addSignatures(ByteString.copyFrom(signatureHash))
- .build()
- private val snapshot = Snapshot.newBuilder()
- .setToken(token)
- .putApps(packageInfo.packageName, Snapshot.App.newBuilder().setApk(apk).build())
- .build()
init {
mockkStatic(PackageUtils::class)
@@ -113,8 +107,8 @@ internal class ApkBackupTest : BackupTest() {
@Test
fun `does not back up the same version`() = runBlocking {
packageInfo.applicationInfo!!.flags = FLAG_UPDATED_SYSTEM_APP
- val apk = apk.toBuilder().setVersionCode(packageInfo.longVersionCode).build()
- val app = Snapshot.App.newBuilder().setApk(apk).build()
+ val apk = apk.copy { versionCode = packageInfo.longVersionCode }
+ val app = app { this.apk = apk }
expectChecks(snapshot.toBuilder().putApps(packageInfo.packageName, app).build())
apkBackup.backupApkIfNecessary(packageInfo)
@@ -123,12 +117,12 @@ internal class ApkBackupTest : BackupTest() {
@Test
fun `does back up the same version when signatures changes`() {
packageInfo.applicationInfo!!.sourceDir = "/tmp/doesNotExist"
- val apk = apk.toBuilder()
- .clearSignatures()
- .addSignatures(ByteString.copyFromUtf8("foo"))
- .setVersionCode(packageInfo.longVersionCode)
- .build()
- val app = Snapshot.App.newBuilder().setApk(apk).build()
+ val apk = apk.copy {
+ signatures.clear()
+ signatures.add(copyFromUtf8("foo"))
+ versionCode = packageInfo.longVersionCode
+ }
+ val app = app { this.apk = apk }
expectChecks(snapshot.toBuilder().putApps(packageInfo.packageName, app).build())
every {
pm.getInstallSourceInfo(packageInfo.packageName)
diff --git a/libs/Android.bp b/libs/Android.bp
index ae63f75a..957fd446 100644
--- a/libs/Android.bp
+++ b/libs/Android.bp
@@ -10,6 +10,12 @@ android_library_import {
extract_jni: true,
}
+java_import {
+ name: "seedvault-lib-protobuf-kotlin-lite",
+ jars: ["protobuf-kotlin-lite-3.21.12.jar"],
+ sdk_version: "current",
+}
+
java_import {
name: "seedvault-lib-kotlin-bip39",
jars: ["kotlin-bip39-jvm-1.0.6.jar"],
diff --git a/libs/protobuf-kotlin-lite-3.21.12.jar b/libs/protobuf-kotlin-lite-3.21.12.jar
new file mode 100644
index 00000000..a16c4cab
Binary files /dev/null and b/libs/protobuf-kotlin-lite-3.21.12.jar differ