Polish SnapshotCreator and write tests
This commit is contained in:
parent
463fc33230
commit
7702fb7bd8
8 changed files with 252 additions and 120 deletions
|
@ -74,7 +74,24 @@ public object SnapshotKt {
|
|||
}
|
||||
|
||||
/**
|
||||
* <code>string androidId = 4;</code>
|
||||
* <code>string user = 4;</code>
|
||||
*/
|
||||
public var user: kotlin.String
|
||||
@JvmName("getUser")
|
||||
get() = _builder.getUser()
|
||||
@JvmName("setUser")
|
||||
set(value) {
|
||||
_builder.setUser(value)
|
||||
}
|
||||
/**
|
||||
* <code>string user = 4;</code>
|
||||
*/
|
||||
public fun clearUser() {
|
||||
_builder.clearUser()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>string androidId = 5;</code>
|
||||
*/
|
||||
public var androidId: kotlin.String
|
||||
@JvmName("getAndroidId")
|
||||
|
@ -84,14 +101,14 @@ public object SnapshotKt {
|
|||
_builder.setAndroidId(value)
|
||||
}
|
||||
/**
|
||||
* <code>string androidId = 4;</code>
|
||||
* <code>string androidId = 5;</code>
|
||||
*/
|
||||
public fun clearAndroidId() {
|
||||
_builder.clearAndroidId()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>uint32 sdkInt = 5;</code>
|
||||
* <code>uint32 sdkInt = 6;</code>
|
||||
*/
|
||||
public var sdkInt: kotlin.Int
|
||||
@JvmName("getSdkInt")
|
||||
|
@ -101,14 +118,14 @@ public object SnapshotKt {
|
|||
_builder.setSdkInt(value)
|
||||
}
|
||||
/**
|
||||
* <code>uint32 sdkInt = 5;</code>
|
||||
* <code>uint32 sdkInt = 6;</code>
|
||||
*/
|
||||
public fun clearSdkInt() {
|
||||
_builder.clearSdkInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>string androidIncremental = 6;</code>
|
||||
* <code>string androidIncremental = 7;</code>
|
||||
*/
|
||||
public var androidIncremental: kotlin.String
|
||||
@JvmName("getAndroidIncremental")
|
||||
|
@ -118,14 +135,14 @@ public object SnapshotKt {
|
|||
_builder.setAndroidIncremental(value)
|
||||
}
|
||||
/**
|
||||
* <code>string androidIncremental = 6;</code>
|
||||
* <code>string androidIncremental = 7;</code>
|
||||
*/
|
||||
public fun clearAndroidIncremental() {
|
||||
_builder.clearAndroidIncremental()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>bool d2d = 7;</code>
|
||||
* <code>bool d2d = 8;</code>
|
||||
*/
|
||||
public var d2D: kotlin.Boolean
|
||||
@JvmName("getD2D")
|
||||
|
@ -135,7 +152,7 @@ public object SnapshotKt {
|
|||
_builder.setD2D(value)
|
||||
}
|
||||
/**
|
||||
* <code>bool d2d = 7;</code>
|
||||
* <code>bool d2d = 8;</code>
|
||||
*/
|
||||
public fun clearD2D() {
|
||||
_builder.clearD2D()
|
||||
|
@ -148,7 +165,7 @@ public object SnapshotKt {
|
|||
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
|
||||
public class AppsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 8;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 9;</code>
|
||||
*/
|
||||
public val apps: com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -157,7 +174,7 @@ public object SnapshotKt {
|
|||
_builder.getAppsMap()
|
||||
)
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 8;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 9;</code>
|
||||
*/
|
||||
@JvmName("putApps")
|
||||
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
|
||||
|
@ -165,7 +182,7 @@ public object SnapshotKt {
|
|||
_builder.putApps(key, value)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 8;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 9;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("setApps")
|
||||
|
@ -175,7 +192,7 @@ public object SnapshotKt {
|
|||
put(key, value)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 8;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 9;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("removeApps")
|
||||
|
@ -184,7 +201,7 @@ public object SnapshotKt {
|
|||
_builder.removeApps(key)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 8;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 9;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("putAllApps")
|
||||
|
@ -193,7 +210,7 @@ public object SnapshotKt {
|
|||
_builder.putAllApps(map)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 8;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.App> apps = 9;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("clearApps")
|
||||
|
@ -209,7 +226,7 @@ public object SnapshotKt {
|
|||
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
|
||||
public class IconChunkIdsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
|
||||
/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
*/
|
||||
public val iconChunkIds: com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -217,7 +234,7 @@ public object SnapshotKt {
|
|||
_builder.getIconChunkIdsList()
|
||||
)
|
||||
/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
* @param value The iconChunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -225,7 +242,7 @@ public object SnapshotKt {
|
|||
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>.add(value: com.google.protobuf.ByteString) {
|
||||
_builder.addIconChunkIds(value)
|
||||
}/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
* @param value The iconChunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -234,7 +251,7 @@ public object SnapshotKt {
|
|||
public inline operator fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>.plusAssign(value: com.google.protobuf.ByteString) {
|
||||
add(value)
|
||||
}/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
* @param values The iconChunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -242,7 +259,7 @@ public object SnapshotKt {
|
|||
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>.addAll(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
|
||||
_builder.addAllIconChunkIds(values)
|
||||
}/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
* @param values The iconChunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -251,7 +268,7 @@ public object SnapshotKt {
|
|||
public inline operator fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>.plusAssign(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
|
||||
addAll(values)
|
||||
}/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
* @param index The index to set the value at.
|
||||
* @param value The iconChunkIds to set.
|
||||
*/
|
||||
|
@ -260,7 +277,7 @@ public object SnapshotKt {
|
|||
public operator fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
|
||||
_builder.setIconChunkIds(index, value)
|
||||
}/**
|
||||
* <code>repeated bytes iconChunkIds = 9;</code>
|
||||
* <code>repeated bytes iconChunkIds = 10;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@kotlin.jvm.JvmName("clearIconChunkIds")
|
||||
|
@ -274,7 +291,7 @@ public object SnapshotKt {
|
|||
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
|
||||
public class BlobsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 10;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 11;</code>
|
||||
*/
|
||||
public val blobs: com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -283,7 +300,7 @@ public object SnapshotKt {
|
|||
_builder.getBlobsMap()
|
||||
)
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 10;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 11;</code>
|
||||
*/
|
||||
@JvmName("putBlobs")
|
||||
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
|
||||
|
@ -291,7 +308,7 @@ public object SnapshotKt {
|
|||
_builder.putBlobs(key, value)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 10;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 11;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("setBlobs")
|
||||
|
@ -301,7 +318,7 @@ public object SnapshotKt {
|
|||
put(key, value)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 10;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 11;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("removeBlobs")
|
||||
|
@ -310,7 +327,7 @@ public object SnapshotKt {
|
|||
_builder.removeBlobs(key)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 10;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 11;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("putAllBlobs")
|
||||
|
@ -319,7 +336,7 @@ public object SnapshotKt {
|
|||
_builder.putAllBlobs(map)
|
||||
}
|
||||
/**
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 10;</code>
|
||||
* <code>map<string, .com.stevesoltys.seedvault.proto.Snapshot.Blob> blobs = 11;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@JvmName("clearBlobs")
|
||||
|
@ -365,24 +382,7 @@ public object SnapshotKt {
|
|||
}
|
||||
|
||||
/**
|
||||
* <code>string state = 2;</code>
|
||||
*/
|
||||
public var state: kotlin.String
|
||||
@JvmName("getState")
|
||||
get() = _builder.getState()
|
||||
@JvmName("setState")
|
||||
set(value) {
|
||||
_builder.setState(value)
|
||||
}
|
||||
/**
|
||||
* <code>string state = 2;</code>
|
||||
*/
|
||||
public fun clearState() {
|
||||
_builder.clearState()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.BackupType type = 3;</code>
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.BackupType type = 2;</code>
|
||||
*/
|
||||
public var type: com.stevesoltys.seedvault.proto.Snapshot.BackupType
|
||||
@JvmName("getType")
|
||||
|
@ -392,14 +392,14 @@ public object SnapshotKt {
|
|||
_builder.setType(value)
|
||||
}
|
||||
/**
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.BackupType type = 3;</code>
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.BackupType type = 2;</code>
|
||||
*/
|
||||
public fun clearType() {
|
||||
_builder.clearType()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>string name = 4;</code>
|
||||
* <code>string name = 3;</code>
|
||||
*/
|
||||
public var name: kotlin.String
|
||||
@JvmName("getName")
|
||||
|
@ -409,14 +409,14 @@ public object SnapshotKt {
|
|||
_builder.setName(value)
|
||||
}
|
||||
/**
|
||||
* <code>string name = 4;</code>
|
||||
* <code>string name = 3;</code>
|
||||
*/
|
||||
public fun clearName() {
|
||||
_builder.clearName()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>bool system = 5;</code>
|
||||
* <code>bool system = 4;</code>
|
||||
*/
|
||||
public var system: kotlin.Boolean
|
||||
@JvmName("getSystem")
|
||||
|
@ -426,14 +426,14 @@ public object SnapshotKt {
|
|||
_builder.setSystem(value)
|
||||
}
|
||||
/**
|
||||
* <code>bool system = 5;</code>
|
||||
* <code>bool system = 4;</code>
|
||||
*/
|
||||
public fun clearSystem() {
|
||||
_builder.clearSystem()
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>bool launchableSystemApp = 6;</code>
|
||||
* <code>bool launchableSystemApp = 5;</code>
|
||||
*/
|
||||
public var launchableSystemApp: kotlin.Boolean
|
||||
@JvmName("getLaunchableSystemApp")
|
||||
|
@ -443,7 +443,7 @@ public object SnapshotKt {
|
|||
_builder.setLaunchableSystemApp(value)
|
||||
}
|
||||
/**
|
||||
* <code>bool launchableSystemApp = 6;</code>
|
||||
* <code>bool launchableSystemApp = 5;</code>
|
||||
*/
|
||||
public fun clearLaunchableSystemApp() {
|
||||
_builder.clearLaunchableSystemApp()
|
||||
|
@ -456,7 +456,7 @@ public object SnapshotKt {
|
|||
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
|
||||
public class ChunkIdsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
|
||||
/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
*/
|
||||
public val chunkIds: com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -464,7 +464,7 @@ public object SnapshotKt {
|
|||
_builder.getChunkIdsList()
|
||||
)
|
||||
/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
* @param value The chunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -472,7 +472,7 @@ public object SnapshotKt {
|
|||
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.add(value: com.google.protobuf.ByteString) {
|
||||
_builder.addChunkIds(value)
|
||||
}/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
* @param value The chunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -481,7 +481,7 @@ public object SnapshotKt {
|
|||
public inline operator fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.plusAssign(value: com.google.protobuf.ByteString) {
|
||||
add(value)
|
||||
}/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
* @param values The chunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -489,7 +489,7 @@ public object SnapshotKt {
|
|||
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.addAll(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
|
||||
_builder.addAllChunkIds(values)
|
||||
}/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
* @param values The chunkIds to add.
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
|
@ -498,7 +498,7 @@ public object SnapshotKt {
|
|||
public inline operator fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.plusAssign(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
|
||||
addAll(values)
|
||||
}/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
* @param index The index to set the value at.
|
||||
* @param value The chunkIds to set.
|
||||
*/
|
||||
|
@ -507,7 +507,7 @@ public object SnapshotKt {
|
|||
public operator fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
|
||||
_builder.setChunkIds(index, value)
|
||||
}/**
|
||||
* <code>repeated bytes chunkIds = 7;</code>
|
||||
* <code>repeated bytes chunkIds = 6;</code>
|
||||
*/
|
||||
@kotlin.jvm.JvmSynthetic
|
||||
@kotlin.jvm.JvmName("clearChunkIds")
|
||||
|
@ -515,7 +515,7 @@ public object SnapshotKt {
|
|||
_builder.clearChunkIds()
|
||||
}
|
||||
/**
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;</code>
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 7;</code>
|
||||
*/
|
||||
public var apk: com.stevesoltys.seedvault.proto.Snapshot.Apk
|
||||
@JvmName("getApk")
|
||||
|
@ -525,13 +525,13 @@ public object SnapshotKt {
|
|||
_builder.setApk(value)
|
||||
}
|
||||
/**
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;</code>
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 7;</code>
|
||||
*/
|
||||
public fun clearApk() {
|
||||
_builder.clearApk()
|
||||
}
|
||||
/**
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;</code>
|
||||
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 7;</code>
|
||||
* @return Whether the apk field is set.
|
||||
*/
|
||||
public fun hasApk(): kotlin.Boolean {
|
||||
|
|
|
@ -39,7 +39,7 @@ data class BackupMetadata(
|
|||
time = s.token,
|
||||
androidVersion = s.sdkInt,
|
||||
androidIncremental = s.androidIncremental,
|
||||
deviceName = s.name,
|
||||
deviceName = "${s.name} - ${s.user}",
|
||||
d2dBackup = s.d2D,
|
||||
packageMetadataMap = s.appsMap.mapValues { (_, app) ->
|
||||
PackageMetadata.fromSnapshot(app)
|
||||
|
@ -121,7 +121,6 @@ data class PackageMetadata(
|
|||
companion object {
|
||||
fun fromSnapshot(app: Snapshot.App) = PackageMetadata(
|
||||
time = app.time,
|
||||
state = if (app.state.isBlank()) UNKNOWN_ERROR else PackageState.valueOf(app.state),
|
||||
backupType = when (app.type) {
|
||||
Snapshot.BackupType.FULL -> BackupType.FULL
|
||||
Snapshot.BackupType.KV -> BackupType.KV
|
||||
|
|
|
@ -13,8 +13,6 @@ import androidx.annotation.VisibleForTesting
|
|||
import androidx.annotation.WorkerThread
|
||||
import com.stevesoltys.seedvault.Clock
|
||||
import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
|
||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
@ -31,7 +29,6 @@ internal class MetadataManager(
|
|||
private val clock: Clock,
|
||||
private val metadataWriter: MetadataWriter,
|
||||
private val metadataReader: MetadataReader,
|
||||
private val packageService: PackageService,
|
||||
) {
|
||||
|
||||
private val uninitializedMetadata = BackupMetadata(token = -42L, salt = "foo bar")
|
||||
|
@ -52,10 +49,6 @@ internal class MetadataManager(
|
|||
return field
|
||||
}
|
||||
|
||||
private val launchableSystemApps by lazy {
|
||||
packageService.launchableSystemApps.map { it.activityInfo.packageName }.toSet()
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after a package has been backed up successfully.
|
||||
*
|
||||
|
@ -75,15 +68,11 @@ internal class MetadataManager(
|
|||
modifyCachedMetadata {
|
||||
val now = clock.time()
|
||||
metadata.packageMetadataMap.getOrPut(packageName) {
|
||||
val isSystemApp = packageInfo.isSystemApp()
|
||||
PackageMetadata(
|
||||
time = now,
|
||||
state = APK_AND_DATA,
|
||||
backupType = type,
|
||||
size = size,
|
||||
system = isSystemApp,
|
||||
isLaunchableSystemApp = isSystemApp &&
|
||||
launchableSystemApps.contains(packageName),
|
||||
)
|
||||
}.apply {
|
||||
time = now
|
||||
|
@ -111,15 +100,11 @@ internal class MetadataManager(
|
|||
check(packageState != APK_AND_DATA) { "Backup Error with non-error package state." }
|
||||
modifyCachedMetadata {
|
||||
metadata.packageMetadataMap.getOrPut(packageInfo.packageName) {
|
||||
val isSystemApp = packageInfo.isSystemApp()
|
||||
PackageMetadata(
|
||||
time = 0L,
|
||||
state = packageState,
|
||||
backupType = backupType,
|
||||
name = packageInfo.applicationInfo?.loadLabel(context.packageManager),
|
||||
system = isSystemApp,
|
||||
isLaunchableSystemApp = isSystemApp &&
|
||||
launchableSystemApps.contains(packageInfo.packageName),
|
||||
)
|
||||
}.state = packageState
|
||||
}
|
||||
|
@ -137,14 +122,10 @@ internal class MetadataManager(
|
|||
packageState: PackageState,
|
||||
) = modifyCachedMetadata {
|
||||
metadata.packageMetadataMap.getOrPut(packageInfo.packageName) {
|
||||
val isSystemApp = packageInfo.isSystemApp()
|
||||
PackageMetadata(
|
||||
time = 0L,
|
||||
state = packageState,
|
||||
name = packageInfo.applicationInfo?.loadLabel(context.packageManager),
|
||||
system = isSystemApp,
|
||||
isLaunchableSystemApp = isSystemApp &&
|
||||
launchableSystemApps.contains(packageInfo.packageName),
|
||||
)
|
||||
}.apply {
|
||||
state = packageState
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.koin.android.ext.koin.androidContext
|
|||
import org.koin.dsl.module
|
||||
|
||||
val metadataModule = module {
|
||||
single { MetadataManager(androidContext(), get(), get(), get(), get()) }
|
||||
single { MetadataManager(androidContext(), get(), get(), get()) }
|
||||
single<MetadataWriter> { MetadataWriterImpl() }
|
||||
single<MetadataReader> { MetadataReaderImpl(get()) }
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package com.stevesoltys.seedvault.transport.backup
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageInfo
|
||||
|
@ -18,7 +19,6 @@ import com.stevesoltys.seedvault.Clock
|
|||
import com.stevesoltys.seedvault.header.VERSION
|
||||
import com.stevesoltys.seedvault.metadata.BackupType
|
||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||
import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
|
||||
import com.stevesoltys.seedvault.proto.Snapshot
|
||||
import com.stevesoltys.seedvault.proto.Snapshot.Apk
|
||||
import com.stevesoltys.seedvault.proto.Snapshot.App
|
||||
|
@ -28,6 +28,9 @@ import io.github.oshai.kotlinlogging.KotlinLogging
|
|||
import org.calyxos.seedvault.core.backends.AppBackupFileType
|
||||
import org.calyxos.seedvault.core.toHexString
|
||||
|
||||
/**
|
||||
* Creates a new [SnapshotCreator], because one is only valid for a single backup run.
|
||||
*/
|
||||
internal class SnapshotCreatorFactory(
|
||||
private val context: Context,
|
||||
private val clock: Clock,
|
||||
|
@ -39,6 +42,10 @@ internal class SnapshotCreatorFactory(
|
|||
SnapshotCreator(context, clock, packageService, settingsManager, metadataManager)
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles snapshot information over the course of a single backup run
|
||||
* and creates a [Snapshot] object in the end by calling [finalizeSnapshot].
|
||||
*/
|
||||
internal class SnapshotCreator(
|
||||
private val context: Context,
|
||||
private val clock: Clock,
|
||||
|
@ -48,14 +55,21 @@ internal class SnapshotCreator(
|
|||
) {
|
||||
|
||||
private val log = KotlinLogging.logger { }
|
||||
|
||||
private val snapshotBuilder = Snapshot.newBuilder()
|
||||
private val appBuilderMap = mutableMapOf<String, App.Builder>()
|
||||
private val blobsMap = mutableMapOf<String, Blob>()
|
||||
|
||||
private val launchableSystemApps by lazy {
|
||||
// as we can't ask [PackageInfo] for this, we keep a set of packages around
|
||||
packageService.launchableSystemApps.map { it.activityInfo.packageName }.toSet()
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after all blobs for the given [apk] have been saved to the backend.
|
||||
* The [apk] must contain the ordered list of chunk IDs
|
||||
* and the given [blobMap] must have one [Blob] per chunk ID.
|
||||
*/
|
||||
fun onApkBackedUp(
|
||||
packageInfo: PackageInfo,
|
||||
apk: Apk,
|
||||
|
@ -71,6 +85,14 @@ internal class SnapshotCreator(
|
|||
blobsMap.putAll(blobMap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after all blobs for the package identified by the given [packageInfo]
|
||||
* have been saved to the backend.
|
||||
* The given [backupData] must contain the full ordered list of [BackupData.chunkIds]
|
||||
* and the [BackupData.blobMap] must have one [Blob] per chunk ID.
|
||||
*
|
||||
* Failure to call this method results in the package effectively not getting backed up.
|
||||
*/
|
||||
fun onPackageBackedUp(
|
||||
packageInfo: PackageInfo,
|
||||
backupType: BackupType,
|
||||
|
@ -83,7 +105,6 @@ internal class SnapshotCreator(
|
|||
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()
|
||||
|
@ -95,26 +116,31 @@ internal class SnapshotCreator(
|
|||
metadataManager.onPackageBackedUp(packageInfo, backupType, backupData.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after all blobs for the app icons have been saved to the backend.
|
||||
*/
|
||||
fun onIconsBackedUp(backupData: BackupData) {
|
||||
snapshotBuilder.addAllIconChunkIds(backupData.chunkIds.forProto())
|
||||
blobsMap.putAll(backupData.blobMap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Must get called after all backup data was saved to the backend.
|
||||
* Returns the assembled [Snapshot] which must be saved to the backend as well
|
||||
* to complete the current backup run.
|
||||
*
|
||||
* Internal state will be cleared to free up memory.
|
||||
* Still, it isn't safe to re-use an instance of this class, after it has been finalized.
|
||||
*/
|
||||
fun finalizeSnapshot(): Snapshot {
|
||||
log.info { "finalizeSnapshot()" }
|
||||
val userName = getUserName()
|
||||
val deviceName = if (userName == null) {
|
||||
"${Build.MANUFACTURER} ${Build.MODEL}"
|
||||
} else {
|
||||
"${Build.MANUFACTURER} ${Build.MODEL} - $userName"
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
val snapshot = snapshotBuilder.apply {
|
||||
version = VERSION.toInt()
|
||||
token = clock.time()
|
||||
name = deviceName
|
||||
androidId = Settings.Secure.getString(context.contentResolver, ANDROID_ID)
|
||||
name = "${Build.MANUFACTURER} ${Build.MODEL}"
|
||||
user = getUserName() ?: ""
|
||||
androidId = Settings.Secure.getString(context.contentResolver, ANDROID_ID) ?: ""
|
||||
sdkInt = Build.VERSION.SDK_INT
|
||||
androidIncremental = Build.VERSION.INCREMENTAL
|
||||
d2D = settingsManager.d2dBackupsEnabled()
|
||||
|
@ -123,11 +149,13 @@ internal class SnapshotCreator(
|
|||
}.build()
|
||||
appBuilderMap.clear()
|
||||
snapshotBuilder.clear()
|
||||
blobsMap.clear()
|
||||
return snapshot
|
||||
}
|
||||
|
||||
private fun getUserName(): String? {
|
||||
val perm = "android.permission.QUERY_USERS"
|
||||
@Suppress("UNRESOLVED_REFERENCE") // hidden AOSP API
|
||||
val perm = Manifest.permission.QUERY_USERS
|
||||
return if (context.checkSelfPermission(perm) == PERMISSION_GRANTED) {
|
||||
val userManager = context.getSystemService(UserManager::class.java) ?: return null
|
||||
userManager.userName
|
||||
|
|
|
@ -8,23 +8,23 @@ message Snapshot {
|
|||
uint32 version = 1;
|
||||
uint64 token = 2;
|
||||
string name = 3;
|
||||
string androidId = 4;
|
||||
uint32 sdkInt = 5;
|
||||
string androidIncremental = 6;
|
||||
bool d2d = 7;
|
||||
map<string, App> apps = 8;
|
||||
repeated bytes iconChunkIds = 9;
|
||||
map<string, Blob> blobs = 10;
|
||||
string user = 4;
|
||||
string androidId = 5;
|
||||
uint32 sdkInt = 6;
|
||||
string androidIncremental = 7;
|
||||
bool d2d = 8;
|
||||
map<string, App> apps = 9;
|
||||
repeated bytes iconChunkIds = 10;
|
||||
map<string, Blob> blobs = 11;
|
||||
|
||||
message App {
|
||||
uint64 time = 1;
|
||||
string state = 2;
|
||||
BackupType type = 3;
|
||||
string name = 4;
|
||||
bool system = 5;
|
||||
bool launchableSystemApp = 6;
|
||||
repeated bytes chunkIds = 7;
|
||||
Apk apk = 8;
|
||||
BackupType type = 2;
|
||||
string name = 3;
|
||||
bool system = 4;
|
||||
bool launchableSystemApp = 5;
|
||||
repeated bytes chunkIds = 6;
|
||||
Apk apk = 7;
|
||||
}
|
||||
|
||||
enum BackupType {
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.content.Context
|
|||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ApplicationInfo.FLAG_ALLOW_BACKUP
|
||||
import android.content.pm.ApplicationInfo.FLAG_SYSTEM
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
@ -23,7 +22,6 @@ import com.stevesoltys.seedvault.metadata.PackageState.NOT_ALLOWED
|
|||
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
|
||||
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED
|
||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
|
@ -37,7 +35,6 @@ import org.junit.Test
|
|||
import org.junit.runner.RunWith
|
||||
import org.koin.core.context.stopKoin
|
||||
import org.robolectric.annotation.Config
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import kotlin.random.Random
|
||||
|
@ -53,7 +50,6 @@ class MetadataManagerTest {
|
|||
private val clock: Clock = mockk()
|
||||
private val metadataWriter: MetadataWriter = mockk()
|
||||
private val metadataReader: MetadataReader = mockk()
|
||||
private val packageService: PackageService = mockk()
|
||||
private val settingsManager: SettingsManager = mockk()
|
||||
|
||||
private val manager = MetadataManager(
|
||||
|
@ -61,7 +57,6 @@ class MetadataManagerTest {
|
|||
clock = clock,
|
||||
metadataWriter = metadataWriter,
|
||||
metadataReader = metadataReader,
|
||||
packageService = packageService,
|
||||
)
|
||||
|
||||
private val packageManager: PackageManager = mockk()
|
||||
|
@ -76,7 +71,6 @@ class MetadataManagerTest {
|
|||
private val saltBytes = Random.nextBytes(METADATA_SALT_SIZE)
|
||||
private val salt = saltBytes.encodeBase64()
|
||||
private val initialMetadata = BackupMetadata(token = token, salt = salt)
|
||||
private val storageOutputStream = ByteArrayOutputStream()
|
||||
private val cacheOutputStream: FileOutputStream = mockk()
|
||||
private val cacheInputStream: FileInputStream = mockk()
|
||||
private val encodedMetadata = getRandomByteArray()
|
||||
|
@ -93,7 +87,6 @@ class MetadataManagerTest {
|
|||
|
||||
@Test
|
||||
fun `test onPackageBackedUp()`() {
|
||||
packageInfo.applicationInfo!!.flags = FLAG_SYSTEM
|
||||
val updatedMetadata = initialMetadata.copy(
|
||||
time = time,
|
||||
packageMetadataMap = PackageMetadataMap() // otherwise this isn't copied, but referenced
|
||||
|
@ -103,7 +96,6 @@ class MetadataManagerTest {
|
|||
updatedMetadata.packageMetadataMap[packageName] = packageMetadata
|
||||
|
||||
every { context.packageManager } returns packageManager
|
||||
every { packageService.launchableSystemApps } returns emptyList()
|
||||
expectReadFromCache()
|
||||
every { clock.time() } returns time
|
||||
expectWriteToCache(initialMetadata)
|
||||
|
@ -115,8 +107,6 @@ class MetadataManagerTest {
|
|||
state = APK_AND_DATA,
|
||||
backupType = BackupType.FULL,
|
||||
size = size,
|
||||
system = true,
|
||||
isLaunchableSystemApp = false,
|
||||
),
|
||||
manager.getPackageMetadata(packageName)
|
||||
)
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 The Calyx Institute
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.stevesoltys.seedvault.transport.backup
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ApplicationInfo.FLAG_SYSTEM
|
||||
import android.content.pm.ResolveInfo
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.stevesoltys.seedvault.TestApp
|
||||
import com.stevesoltys.seedvault.header.VERSION
|
||||
import com.stevesoltys.seedvault.metadata.BackupType
|
||||
import com.stevesoltys.seedvault.proto.Snapshot
|
||||
import com.stevesoltys.seedvault.transport.TransportTest
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.annotation.Config
|
||||
import kotlin.random.Random
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@Config(
|
||||
sdk = [34], // TODO: Drop once robolectric supports 35
|
||||
application = TestApp::class
|
||||
)
|
||||
internal class SnapshotCreatorTest : TransportTest() {
|
||||
|
||||
private val ctx: Context = ApplicationProvider.getApplicationContext()
|
||||
private val packageService: PackageService = mockk()
|
||||
private val snapshotCreator =
|
||||
SnapshotCreator(ctx, clock, packageService, settingsManager, metadataManager)
|
||||
|
||||
@Test
|
||||
fun `test onApkBackedUp`() {
|
||||
every { applicationInfo.loadLabel(any()) } returns name
|
||||
every { clock.time() } returns token
|
||||
every { settingsManager.d2dBackupsEnabled() } returns Random.nextBoolean()
|
||||
|
||||
snapshotCreator.onApkBackedUp(packageInfo, apk, blobMap)
|
||||
val s = snapshotCreator.finalizeSnapshot()
|
||||
|
||||
assertEquals(apk, s.appsMap[packageName]?.apk)
|
||||
assertEquals(name, s.appsMap[packageName]?.name)
|
||||
assertEquals(blobMap, s.blobsMap)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test onPackageBackedUp`() {
|
||||
val size = apkBackupData.size
|
||||
val isSystem = Random.nextBoolean()
|
||||
val appInfo = mockk<ApplicationInfo> {
|
||||
flags = if (isSystem) FLAG_SYSTEM else 0
|
||||
}
|
||||
packageInfo.applicationInfo = appInfo
|
||||
val resolveInfo = ResolveInfo().apply { // if isSystem, then it will be launchable
|
||||
activityInfo = ActivityInfo().apply {
|
||||
packageName = this@SnapshotCreatorTest.packageName
|
||||
}
|
||||
}
|
||||
every { appInfo.loadLabel(any()) } returns name
|
||||
every { metadataManager.onPackageBackedUp(packageInfo, BackupType.FULL, size) } just Runs
|
||||
every { clock.time() } returns token andThen token + 1
|
||||
every { settingsManager.d2dBackupsEnabled() } returns Random.nextBoolean()
|
||||
every { packageService.launchableSystemApps } returns listOf(resolveInfo)
|
||||
|
||||
snapshotCreator.onPackageBackedUp(packageInfo, BackupType.FULL, apkBackupData)
|
||||
val s = snapshotCreator.finalizeSnapshot()
|
||||
|
||||
assertEquals(name, s.appsMap[packageName]?.name)
|
||||
assertEquals(token, s.appsMap[packageName]?.time)
|
||||
assertEquals(Snapshot.BackupType.FULL, s.appsMap[packageName]?.type)
|
||||
assertEquals(isSystem, s.appsMap[packageName]?.system)
|
||||
assertEquals(isSystem, s.appsMap[packageName]?.launchableSystemApp)
|
||||
assertEquals(apkBackupData.chunkIds.forProto(), s.appsMap[packageName]?.chunkIdsList)
|
||||
assertEquals(apkBackupData.blobMap, s.blobsMap)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test onPackageBackedUp handles no application info`() {
|
||||
packageInfo.applicationInfo = null
|
||||
|
||||
val size = apkBackupData.size
|
||||
every { metadataManager.onPackageBackedUp(packageInfo, BackupType.FULL, size) } just Runs
|
||||
every { clock.time() } returns token andThen token + 1
|
||||
every { settingsManager.d2dBackupsEnabled() } returns Random.nextBoolean()
|
||||
every { packageService.launchableSystemApps } returns emptyList()
|
||||
|
||||
snapshotCreator.onPackageBackedUp(packageInfo, BackupType.FULL, apkBackupData)
|
||||
snapshotCreator.finalizeSnapshot()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test onIconsBackedUp`() {
|
||||
every { clock.time() } returns token andThen token + 1
|
||||
every { settingsManager.d2dBackupsEnabled() } returns Random.nextBoolean()
|
||||
|
||||
snapshotCreator.onIconsBackedUp(apkBackupData)
|
||||
val s = snapshotCreator.finalizeSnapshot()
|
||||
|
||||
assertEquals(apkBackupData.chunkIds.forProto(), s.iconChunkIdsList)
|
||||
assertEquals(apkBackupData.blobMap, s.blobsMap)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test finalize`() {
|
||||
val d2d = Random.nextBoolean()
|
||||
every { clock.time() } returns token
|
||||
every { settingsManager.d2dBackupsEnabled() } returns d2d
|
||||
|
||||
val s = snapshotCreator.finalizeSnapshot()
|
||||
|
||||
assertEquals(VERSION, s.version.toByte())
|
||||
assertEquals(token, s.token)
|
||||
assertEquals("robolectric robolectric", s.name)
|
||||
assertEquals("", s.user) // no perm
|
||||
assertEquals("", s.androidId) // not mocked
|
||||
assertEquals(34, s.sdkInt) // as per config above, needs bump once possible
|
||||
assertEquals("unknown", s.androidIncremental)
|
||||
assertEquals(d2d, s.d2D)
|
||||
assertEquals(0, s.appsCount)
|
||||
assertEquals(0, s.iconChunkIdsCount)
|
||||
assertEquals(emptyMap<String, Snapshot.Blob>(), s.blobsMap)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue