Add protobuf-kotlin-lite and use new builders

This commit is contained in:
Torsten Grote 2024-09-06 10:48:10 -03:00
parent 897ae48b44
commit 8ce79f4195
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
19 changed files with 1112 additions and 181 deletions

View file

@ -9,6 +9,8 @@ android_app {
"app/src/main/java/**/*.kt", "app/src/main/java/**/*.kt",
"app/src/main/java/**/*.java", "app/src/main/java/**/*.java",
"app/src/main/proto/*.proto", "app/src/main/proto/*.proto",
// as of Android 15, there is no way to pass --kotlin_out to aprotoc compiler
"app/build/generated/source/proto/debug/kotlin/com/stevesoltys/seedvault/proto/*.kt",
], ],
resource_dirs: [ resource_dirs: [
"app/src/main/res", "app/src/main/res",
@ -33,6 +35,7 @@ android_app {
"kotlinx-coroutines-android", "kotlinx-coroutines-android",
"kotlinx-coroutines-core", "kotlinx-coroutines-core",
// app backup related libs // app backup related libs
"seedvault-lib-protobuf-kotlin-lite",
"seedvault-lib-kotlin-logging-jvm", "seedvault-lib-kotlin-logging-jvm",
"seedvault-lib-chunker", "seedvault-lib-chunker",
"seedvault-lib-zstd-jni", "seedvault-lib-zstd-jni",

View file

@ -111,6 +111,9 @@ android {
id("java") { id("java") {
option("lite") option("lite")
} }
id("kotlin") {
option("lite")
}
} }
} }
} }
@ -177,6 +180,9 @@ dependencies {
implementation(fileTree("${rootProject.rootDir}/libs/koin-android").include("*.jar")) implementation(fileTree("${rootProject.rootDir}/libs/koin-android").include("*.jar"))
implementation(fileTree("${rootProject.rootDir}/libs/koin-android").include("*.aar")) implementation(fileTree("${rootProject.rootDir}/libs/koin-android").include("*.aar"))
implementation(
fileTree("${rootProject.rootDir}/libs").include("protobuf-kotlin-lite-3.21.12.jar")
)
implementation(fileTree("${rootProject.rootDir}/libs").include("seedvault-chunker-0.1.jar")) implementation(fileTree("${rootProject.rootDir}/libs").include("seedvault-chunker-0.1.jar"))
implementation(fileTree("${rootProject.rootDir}/libs").include("zstd-jni-1.5.6-5.aar")) implementation(fileTree("${rootProject.rootDir}/libs").include("zstd-jni-1.5.6-5.aar"))
implementation(fileTree("${rootProject.rootDir}/libs").include("kotlin-bip39-jvm-1.0.6.jar")) implementation(fileTree("${rootProject.rootDir}/libs").include("kotlin-bip39-jvm-1.0.6.jar"))

View file

@ -0,0 +1,933 @@
//Generated by the protocol buffer compiler. DO NOT EDIT!
// source: snapshot.proto
package com.stevesoltys.seedvault.proto;
@kotlin.jvm.JvmName("-initializesnapshot")
public inline fun snapshot(block: com.stevesoltys.seedvault.proto.SnapshotKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot =
com.stevesoltys.seedvault.proto.SnapshotKt.Dsl._create(com.stevesoltys.seedvault.proto.Snapshot.newBuilder()).apply { block() }._build()
public object SnapshotKt {
@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.Builder
) {
public companion object {
@kotlin.jvm.JvmSynthetic
@kotlin.PublishedApi
internal fun _create(builder: com.stevesoltys.seedvault.proto.Snapshot.Builder): Dsl = Dsl(builder)
}
@kotlin.jvm.JvmSynthetic
@kotlin.PublishedApi
internal fun _build(): com.stevesoltys.seedvault.proto.Snapshot = _builder.build()
/**
* <code>uint32 version = 1;</code>
*/
public var version: kotlin.Int
@JvmName("getVersion")
get() = _builder.getVersion()
@JvmName("setVersion")
set(value) {
_builder.setVersion(value)
}
/**
* <code>uint32 version = 1;</code>
*/
public fun clearVersion() {
_builder.clearVersion()
}
/**
* <code>uint64 token = 2;</code>
*/
public var token: kotlin.Long
@JvmName("getToken")
get() = _builder.getToken()
@JvmName("setToken")
set(value) {
_builder.setToken(value)
}
/**
* <code>uint64 token = 2;</code>
*/
public fun clearToken() {
_builder.clearToken()
}
/**
* <code>string name = 3;</code>
*/
public var name: kotlin.String
@JvmName("getName")
get() = _builder.getName()
@JvmName("setName")
set(value) {
_builder.setName(value)
}
/**
* <code>string name = 3;</code>
*/
public fun clearName() {
_builder.clearName()
}
/**
* <code>string androidId = 4;</code>
*/
public var androidId: kotlin.String
@JvmName("getAndroidId")
get() = _builder.getAndroidId()
@JvmName("setAndroidId")
set(value) {
_builder.setAndroidId(value)
}
/**
* <code>string androidId = 4;</code>
*/
public fun clearAndroidId() {
_builder.clearAndroidId()
}
/**
* <code>uint32 sdkInt = 5;</code>
*/
public var sdkInt: kotlin.Int
@JvmName("getSdkInt")
get() = _builder.getSdkInt()
@JvmName("setSdkInt")
set(value) {
_builder.setSdkInt(value)
}
/**
* <code>uint32 sdkInt = 5;</code>
*/
public fun clearSdkInt() {
_builder.clearSdkInt()
}
/**
* <code>string androidIncremental = 6;</code>
*/
public var androidIncremental: kotlin.String
@JvmName("getAndroidIncremental")
get() = _builder.getAndroidIncremental()
@JvmName("setAndroidIncremental")
set(value) {
_builder.setAndroidIncremental(value)
}
/**
* <code>string androidIncremental = 6;</code>
*/
public fun clearAndroidIncremental() {
_builder.clearAndroidIncremental()
}
/**
* <code>bool d2d = 7;</code>
*/
public var d2D: kotlin.Boolean
@JvmName("getD2D")
get() = _builder.getD2D()
@JvmName("setD2D")
set(value) {
_builder.setD2D(value)
}
/**
* <code>bool d2d = 7;</code>
*/
public fun clearD2D() {
_builder.clearD2D()
}
/**
* An uninstantiable, behaviorless type to represent the field in
* generics.
*/
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
public class AppsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.App&gt; apps = 8;</code>
*/
public val apps: com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
@kotlin.jvm.JvmSynthetic
@JvmName("getAppsMap")
get() = com.google.protobuf.kotlin.DslMap(
_builder.getAppsMap()
)
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.App&gt; apps = 8;</code>
*/
@JvmName("putApps")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
.put(key: kotlin.String, value: com.stevesoltys.seedvault.proto.Snapshot.App) {
_builder.putApps(key, value)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.App&gt; apps = 8;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("setApps")
@Suppress("NOTHING_TO_INLINE")
public inline operator fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
.set(key: kotlin.String, value: com.stevesoltys.seedvault.proto.Snapshot.App) {
put(key, value)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.App&gt; apps = 8;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("removeApps")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
.remove(key: kotlin.String) {
_builder.removeApps(key)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.App&gt; apps = 8;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("putAllApps")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
.putAll(map: kotlin.collections.Map<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App>) {
_builder.putAllApps(map)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.App&gt; apps = 8;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("clearApps")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.App, AppsProxy>
.clear() {
_builder.clearApps()
}
/**
* An uninstantiable, behaviorless type to represent the field in
* generics.
*/
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
public class IconChunkIdsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
/**
* <code>repeated bytes iconChunkIds = 9;</code>
*/
public val iconChunkIds: com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>
@kotlin.jvm.JvmSynthetic
get() = com.google.protobuf.kotlin.DslList(
_builder.getIconChunkIdsList()
)
/**
* <code>repeated bytes iconChunkIds = 9;</code>
* @param value The iconChunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addIconChunkIds")
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>
* @param value The iconChunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("plusAssignIconChunkIds")
@Suppress("NOTHING_TO_INLINE")
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>
* @param values The iconChunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addAllIconChunkIds")
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>
* @param values The iconChunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("plusAssignAllIconChunkIds")
@Suppress("NOTHING_TO_INLINE")
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>
* @param index The index to set the value at.
* @param value The iconChunkIds to set.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("setIconChunkIds")
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>
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("clearIconChunkIds")
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, IconChunkIdsProxy>.clear() {
_builder.clearIconChunkIds()
}
/**
* An uninstantiable, behaviorless type to represent the field in
* generics.
*/
@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)
public class BlobsProxy private constructor() : com.google.protobuf.kotlin.DslProxy()
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.Blob&gt; blobs = 10;</code>
*/
public val blobs: com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
@kotlin.jvm.JvmSynthetic
@JvmName("getBlobsMap")
get() = com.google.protobuf.kotlin.DslMap(
_builder.getBlobsMap()
)
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.Blob&gt; blobs = 10;</code>
*/
@JvmName("putBlobs")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
.put(key: kotlin.String, value: com.stevesoltys.seedvault.proto.Snapshot.Blob) {
_builder.putBlobs(key, value)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.Blob&gt; blobs = 10;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("setBlobs")
@Suppress("NOTHING_TO_INLINE")
public inline operator fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
.set(key: kotlin.String, value: com.stevesoltys.seedvault.proto.Snapshot.Blob) {
put(key, value)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.Blob&gt; blobs = 10;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("removeBlobs")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
.remove(key: kotlin.String) {
_builder.removeBlobs(key)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.Blob&gt; blobs = 10;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("putAllBlobs")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
.putAll(map: kotlin.collections.Map<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob>) {
_builder.putAllBlobs(map)
}
/**
* <code>map&lt;string, .com.stevesoltys.seedvault.proto.Snapshot.Blob&gt; blobs = 10;</code>
*/
@kotlin.jvm.JvmSynthetic
@JvmName("clearBlobs")
public fun com.google.protobuf.kotlin.DslMap<kotlin.String, com.stevesoltys.seedvault.proto.Snapshot.Blob, BlobsProxy>
.clear() {
_builder.clearBlobs()
}
}
@kotlin.jvm.JvmName("-initializeapp")
public inline fun app(block: com.stevesoltys.seedvault.proto.SnapshotKt.AppKt.Dsl.() -> kotlin.Unit): com.stevesoltys.seedvault.proto.Snapshot.App =
com.stevesoltys.seedvault.proto.SnapshotKt.AppKt.Dsl._create(com.stevesoltys.seedvault.proto.Snapshot.App.newBuilder()).apply { block() }._build()
public object AppKt {
@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.App.Builder
) {
public companion object {
@kotlin.jvm.JvmSynthetic
@kotlin.PublishedApi
internal fun _create(builder: com.stevesoltys.seedvault.proto.Snapshot.App.Builder): Dsl = Dsl(builder)
}
@kotlin.jvm.JvmSynthetic
@kotlin.PublishedApi
internal fun _build(): com.stevesoltys.seedvault.proto.Snapshot.App = _builder.build()
/**
* <code>uint64 time = 1;</code>
*/
public var time: kotlin.Long
@JvmName("getTime")
get() = _builder.getTime()
@JvmName("setTime")
set(value) {
_builder.setTime(value)
}
/**
* <code>uint64 time = 1;</code>
*/
public fun clearTime() {
_builder.clearTime()
}
/**
* <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>
*/
public var type: com.stevesoltys.seedvault.proto.Snapshot.BackupType
@JvmName("getType")
get() = _builder.getType()
@JvmName("setType")
set(value) {
_builder.setType(value)
}
/**
* <code>.com.stevesoltys.seedvault.proto.Snapshot.BackupType type = 3;</code>
*/
public fun clearType() {
_builder.clearType()
}
/**
* <code>string name = 4;</code>
*/
public var name: kotlin.String
@JvmName("getName")
get() = _builder.getName()
@JvmName("setName")
set(value) {
_builder.setName(value)
}
/**
* <code>string name = 4;</code>
*/
public fun clearName() {
_builder.clearName()
}
/**
* <code>bool system = 5;</code>
*/
public var system: kotlin.Boolean
@JvmName("getSystem")
get() = _builder.getSystem()
@JvmName("setSystem")
set(value) {
_builder.setSystem(value)
}
/**
* <code>bool system = 5;</code>
*/
public fun clearSystem() {
_builder.clearSystem()
}
/**
* <code>bool launchableSystemApp = 6;</code>
*/
public var launchableSystemApp: kotlin.Boolean
@JvmName("getLaunchableSystemApp")
get() = _builder.getLaunchableSystemApp()
@JvmName("setLaunchableSystemApp")
set(value) {
_builder.setLaunchableSystemApp(value)
}
/**
* <code>bool launchableSystemApp = 6;</code>
*/
public fun clearLaunchableSystemApp() {
_builder.clearLaunchableSystemApp()
}
/**
* 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()
/**
* <code>repeated bytes chunkIds = 7;</code>
*/
public val chunkIds: com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>
@kotlin.jvm.JvmSynthetic
get() = com.google.protobuf.kotlin.DslList(
_builder.getChunkIdsList()
)
/**
* <code>repeated bytes chunkIds = 7;</code>
* @param value The chunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addChunkIds")
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>
* @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<com.google.protobuf.ByteString, ChunkIdsProxy>.plusAssign(value: com.google.protobuf.ByteString) {
add(value)
}/**
* <code>repeated bytes chunkIds = 7;</code>
* @param values The chunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addAllChunkIds")
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>
* @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<com.google.protobuf.ByteString, ChunkIdsProxy>.plusAssign(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
addAll(values)
}/**
* <code>repeated bytes chunkIds = 7;</code>
* @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<com.google.protobuf.ByteString, ChunkIdsProxy>.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
_builder.setChunkIds(index, value)
}/**
* <code>repeated bytes chunkIds = 7;</code>
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("clearChunkIds")
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.clear() {
_builder.clearChunkIds()
}
/**
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;</code>
*/
public var apk: com.stevesoltys.seedvault.proto.Snapshot.Apk
@JvmName("getApk")
get() = _builder.getApk()
@JvmName("setApk")
set(value) {
_builder.setApk(value)
}
/**
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;</code>
*/
public fun clearApk() {
_builder.clearApk()
}
/**
* <code>.com.stevesoltys.seedvault.proto.Snapshot.Apk apk = 8;</code>
* @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()
/**
* <pre>
**
* Attention: Has default value of 0
* </pre>
*
* <code>uint64 versionCode = 1;</code>
*/
public var versionCode: kotlin.Long
@JvmName("getVersionCode")
get() = _builder.getVersionCode()
@JvmName("setVersionCode")
set(value) {
_builder.setVersionCode(value)
}
/**
* <pre>
**
* Attention: Has default value of 0
* </pre>
*
* <code>uint64 versionCode = 1;</code>
*/
public fun clearVersionCode() {
_builder.clearVersionCode()
}
/**
* <code>string installer = 2;</code>
*/
public var installer: kotlin.String
@JvmName("getInstaller")
get() = _builder.getInstaller()
@JvmName("setInstaller")
set(value) {
_builder.setInstaller(value)
}
/**
* <code>string installer = 2;</code>
*/
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()
/**
* <code>repeated bytes signatures = 3;</code>
*/
public val signatures: com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, SignaturesProxy>
@kotlin.jvm.JvmSynthetic
get() = com.google.protobuf.kotlin.DslList(
_builder.getSignaturesList()
)
/**
* <code>repeated bytes signatures = 3;</code>
* @param value The signatures to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addSignatures")
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, SignaturesProxy>.add(value: com.google.protobuf.ByteString) {
_builder.addSignatures(value)
}/**
* <code>repeated bytes signatures = 3;</code>
* @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<com.google.protobuf.ByteString, SignaturesProxy>.plusAssign(value: com.google.protobuf.ByteString) {
add(value)
}/**
* <code>repeated bytes signatures = 3;</code>
* @param values The signatures to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addAllSignatures")
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, SignaturesProxy>.addAll(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
_builder.addAllSignatures(values)
}/**
* <code>repeated bytes signatures = 3;</code>
* @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<com.google.protobuf.ByteString, SignaturesProxy>.plusAssign(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
addAll(values)
}/**
* <code>repeated bytes signatures = 3;</code>
* @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<com.google.protobuf.ByteString, SignaturesProxy>.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
_builder.setSignatures(index, value)
}/**
* <code>repeated bytes signatures = 3;</code>
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("clearSignatures")
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, SignaturesProxy>.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()
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
*/
public val splits: com.google.protobuf.kotlin.DslList<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>
@kotlin.jvm.JvmSynthetic
get() = com.google.protobuf.kotlin.DslList(
_builder.getSplitsList()
)
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
* @param value The splits to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addSplits")
public fun com.google.protobuf.kotlin.DslList<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>.add(value: com.stevesoltys.seedvault.proto.Snapshot.Split) {
_builder.addSplits(value)
}
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
* @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<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>.plusAssign(value: com.stevesoltys.seedvault.proto.Snapshot.Split) {
add(value)
}
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
* @param values The splits to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addAllSplits")
public fun com.google.protobuf.kotlin.DslList<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>.addAll(values: kotlin.collections.Iterable<com.stevesoltys.seedvault.proto.Snapshot.Split>) {
_builder.addAllSplits(values)
}
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
* @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<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>.plusAssign(values: kotlin.collections.Iterable<com.stevesoltys.seedvault.proto.Snapshot.Split>) {
addAll(values)
}
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
* @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<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>.set(index: kotlin.Int, value: com.stevesoltys.seedvault.proto.Snapshot.Split) {
_builder.setSplits(index, value)
}
/**
* <code>repeated .com.stevesoltys.seedvault.proto.Snapshot.Split splits = 4;</code>
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("clearSplits")
public fun com.google.protobuf.kotlin.DslList<com.stevesoltys.seedvault.proto.Snapshot.Split, SplitsProxy>.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()
/**
* <code>string name = 1;</code>
*/
public var name: kotlin.String
@JvmName("getName")
get() = _builder.getName()
@JvmName("setName")
set(value) {
_builder.setName(value)
}
/**
* <code>string name = 1;</code>
*/
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()
/**
* <code>repeated bytes chunkIds = 2;</code>
*/
public val chunkIds: com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>
@kotlin.jvm.JvmSynthetic
get() = com.google.protobuf.kotlin.DslList(
_builder.getChunkIdsList()
)
/**
* <code>repeated bytes chunkIds = 2;</code>
* @param value The chunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addChunkIds")
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 = 2;</code>
* @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<com.google.protobuf.ByteString, ChunkIdsProxy>.plusAssign(value: com.google.protobuf.ByteString) {
add(value)
}/**
* <code>repeated bytes chunkIds = 2;</code>
* @param values The chunkIds to add.
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("addAllChunkIds")
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 = 2;</code>
* @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<com.google.protobuf.ByteString, ChunkIdsProxy>.plusAssign(values: kotlin.collections.Iterable<com.google.protobuf.ByteString>) {
addAll(values)
}/**
* <code>repeated bytes chunkIds = 2;</code>
* @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<com.google.protobuf.ByteString, ChunkIdsProxy>.set(index: kotlin.Int, value: com.google.protobuf.ByteString) {
_builder.setChunkIds(index, value)
}/**
* <code>repeated bytes chunkIds = 2;</code>
*/
@kotlin.jvm.JvmSynthetic
@kotlin.jvm.JvmName("clearChunkIds")
public fun com.google.protobuf.kotlin.DslList<com.google.protobuf.ByteString, ChunkIdsProxy>.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()
/**
* <code>bytes id = 1;</code>
*/
public var id: com.google.protobuf.ByteString
@JvmName("getId")
get() = _builder.getId()
@JvmName("setId")
set(value) {
_builder.setId(value)
}
/**
* <code>bytes id = 1;</code>
*/
public fun clearId() {
_builder.clearId()
}
/**
* <code>uint32 length = 2;</code>
*/
public var length: kotlin.Int
@JvmName("getLength")
get() = _builder.getLength()
@JvmName("setLength")
set(value) {
_builder.setLength(value)
}
/**
* <code>uint32 length = 2;</code>
*/
public fun clearLength() {
_builder.clearLength()
}
/**
* <code>uint32 uncompressedLength = 3;</code>
*/
public var uncompressedLength: kotlin.Int
@JvmName("getUncompressedLength")
get() = _builder.getUncompressedLength()
@JvmName("setUncompressedLength")
set(value) {
_builder.setUncompressedLength(value)
}
/**
* <code>uint32 uncompressedLength = 3;</code>
*/
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()

View file

@ -9,7 +9,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import com.google.protobuf.ByteString 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.AppBackupManager
import com.stevesoltys.seedvault.transport.backup.BackupData import com.stevesoltys.seedvault.transport.backup.BackupData
import com.stevesoltys.seedvault.transport.backup.BackupReceiver import com.stevesoltys.seedvault.transport.backup.BackupReceiver
@ -66,7 +66,7 @@ class IconManagerTest : KoinComponent {
val chunkId = Random.nextBytes(32).toHexString() val chunkId = Random.nextBytes(32).toHexString()
val chunkList = listOf(chunkId) val chunkList = listOf(chunkId)
val blobId = Random.nextBytes(32).toHexString() 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 // upload icons and capture plaintext bytes
coEvery { backupReceiver.addBytes(capture(output)) } just Runs coEvery { backupReceiver.addBytes(capture(output)) } just Runs

View file

@ -115,7 +115,7 @@ data class PackageMetadata(
system = app.system, system = app.system,
isLaunchableSystemApp = app.launchableSystemApp, isLaunchableSystemApp = app.launchableSystemApp,
version = app.apk.versionCode, version = app.apk.versionCode,
installer = app.apk.installer, installer = app.apk.installer.takeIf { it.isNotEmpty() },
baseApkChunkIds = run { baseApkChunkIds = run {
val baseChunk = app.apk.splitsList.find { it.name == BASE_SPLIT } val baseChunk = app.apk.splitsList.find { it.name == BASE_SPLIT }
if (baseChunk == null || baseChunk.chunkIdsCount == 0) { if (baseChunk == null || baseChunk.chunkIdsCount == 0) {

View file

@ -11,6 +11,7 @@ import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.crypto.Crypto import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.proto.Snapshot.Blob import com.stevesoltys.seedvault.proto.Snapshot.Blob
import com.stevesoltys.seedvault.proto.SnapshotKt.blob
import okio.Buffer import okio.Buffer
import okio.buffer import okio.buffer
import okio.sink import okio.sink
@ -43,10 +44,10 @@ internal class BlobCreator(
outputBuffer.flush() outputBuffer.flush()
length length
} }
return Blob.newBuilder() return blob {
.setId(ByteString.copyFrom(sha256ByteString.asByteBuffer())) id = ByteString.copyFrom(sha256ByteString.asByteBuffer())
.setLength(size.toInt()) length = size.toInt()
.setUncompressedLength(chunk.length) uncompressedLength = chunk.length
.build() }
} }
} }

View file

@ -15,6 +15,7 @@ import android.provider.Settings
import android.provider.Settings.Secure.ANDROID_ID import android.provider.Settings.Secure.ANDROID_ID
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
import com.stevesoltys.seedvault.Clock import com.stevesoltys.seedvault.Clock
import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.metadata.BackupType import com.stevesoltys.seedvault.metadata.BackupType
import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
import com.stevesoltys.seedvault.proto.Snapshot 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.App
import com.stevesoltys.seedvault.proto.Snapshot.Blob import com.stevesoltys.seedvault.proto.Snapshot.Blob
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager
import io.github.oshai.kotlinlogging.KotlinLogging
import org.calyxos.seedvault.core.backends.AppBackupFileType import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.toHexString import org.calyxos.seedvault.core.toHexString
@ -41,8 +43,8 @@ internal class SnapshotCreator(
private val settingsManager: SettingsManager, private val settingsManager: SettingsManager,
) { ) {
private val log = KotlinLogging.logger { }
private val snapshotBuilder = Snapshot.newBuilder() private val snapshotBuilder = Snapshot.newBuilder()
.setToken(clock.time())
private val appBuilderMap = mutableMapOf<String, App.Builder>() private val appBuilderMap = mutableMapOf<String, App.Builder>()
private val blobsMap = mutableMapOf<String, Blob>() private val blobsMap = mutableMapOf<String, Blob>()
@ -51,37 +53,41 @@ internal class SnapshotCreator(
} }
fun onApkBackedUp( fun onApkBackedUp(
packageName: String, packageInfo: PackageInfo,
apk: Apk, apk: Apk,
chunkMap: Map<String, Blob>, chunkMap: Map<String, Blob>,
) { ) {
val appBuilder = appBuilderMap.getOrPut(packageName) { appBuilderMap.getOrPut(packageInfo.packageName) {
App.newBuilder() App.newBuilder()
}.apply {
val label = packageInfo.applicationInfo?.loadLabel(context.packageManager)
if (label != null) name = label.toString()
setApk(apk)
} }
appBuilder.setApk(apk)
blobsMap.putAll(chunkMap) blobsMap.putAll(chunkMap)
} }
fun onPackageBackedUp( fun onPackageBackedUp(
packageInfo: PackageInfo, packageInfo: PackageInfo,
type: BackupType, backupType: BackupType,
backupData: BackupData, backupData: BackupData,
) { ) {
val packageName = packageInfo.packageName val packageName = packageInfo.packageName
val builder = appBuilderMap.getOrPut(packageName) {
App.newBuilder()
}
val isSystemApp = packageInfo.isSystemApp() val isSystemApp = packageInfo.isSystemApp()
val chunkIds = backupData.chunks.forProto() 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) 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) { fun onIconsBackedUp(backupData: BackupData) {
@ -90,6 +96,7 @@ internal class SnapshotCreator(
} }
fun finalizeSnapshot(): Snapshot { fun finalizeSnapshot(): Snapshot {
log.info { "finalizeSnapshot()" }
val userName = getUserName() val userName = getUserName()
val deviceName = if (userName == null) { val deviceName = if (userName == null) {
"${Build.MANUFACTURER} ${Build.MODEL}" "${Build.MANUFACTURER} ${Build.MODEL}"
@ -98,16 +105,17 @@ internal class SnapshotCreator(
} }
@SuppressLint("HardwareIds") @SuppressLint("HardwareIds")
val androidId = Settings.Secure.getString(context.contentResolver, ANDROID_ID) val snapshot = snapshotBuilder.apply {
val snapshot = snapshotBuilder version = VERSION.toInt()
.setName(deviceName) token = clock.time()
.setAndroidId(androidId) name = deviceName
.setSdkInt(Build.VERSION.SDK_INT) androidId = Settings.Secure.getString(context.contentResolver, ANDROID_ID)
.setAndroidIncremental(Build.VERSION.INCREMENTAL) sdkInt = Build.VERSION.SDK_INT
.setD2D(settingsManager.d2dBackupsEnabled()) androidIncremental = Build.VERSION.INCREMENTAL
.putAllApps(appBuilderMap.mapValues { it.value.build() }) d2D = settingsManager.d2dBackupsEnabled()
.putAllBlobs(blobsMap) putAllApps(appBuilderMap.mapValues { it.value.build() })
.build() putAllBlobs(this@SnapshotCreator.blobsMap)
}.build()
appBuilderMap.clear() appBuilderMap.clear()
snapshotBuilder.clear() snapshotBuilder.clear()
return snapshot return snapshot

View file

@ -14,6 +14,7 @@ import android.util.PackageUtils.computeSha256DigestBytes
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.proto.Snapshot import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.proto.SnapshotKt.split
import com.stevesoltys.seedvault.settings.SettingsManager import com.stevesoltys.seedvault.settings.SettingsManager
import com.stevesoltys.seedvault.transport.SnapshotManager import com.stevesoltys.seedvault.transport.SnapshotManager
import com.stevesoltys.seedvault.transport.backup.AppBackupManager import com.stevesoltys.seedvault.transport.backup.AppBackupManager
@ -108,10 +109,14 @@ internal class ApkBackup(
} }
// builder for Apk object // builder for Apk object
val apkBuilder = Snapshot.Apk.newBuilder() val apkBuilder = Snapshot.Apk.newBuilder().apply {
.setVersionCode(version) versionCode = version
.setInstaller(pm.getInstallSourceInfo(packageName).installingPackageName) pm.getInstallSourceInfo(packageName).installingPackageName?.let {
.addAllSignatures(signatures.forProto()) // protobuf doesn't support null values
installer = it
}
addAllSignatures(signatures.forProto())
}
// get an InputStream for the APK // get an InputStream for the APK
val sourceDir = packageInfo.applicationInfo?.sourceDir ?: return val sourceDir = packageInfo.applicationInfo?.sourceDir ?: return
@ -121,9 +126,10 @@ internal class ApkBackup(
} }
val backupData = backupReceiver.finalize() val backupData = backupReceiver.finalize()
// store base split in builder // store base split in builder
val baseSplit = Snapshot.Split.newBuilder() val baseSplit = split {
.setName(BASE_SPLIT) name = BASE_SPLIT
.addAllChunkIds(backupData.chunks.forProto()) chunkIds.addAll(backupData.chunks.forProto())
}
apkBuilder apkBuilder
.addSplits(baseSplit) .addSplits(baseSplit)
val chunkMap = backupData.chunkMap.toMutableMap() val chunkMap = backupData.chunkMap.toMutableMap()
@ -134,9 +140,8 @@ internal class ApkBackup(
} else { } else {
backupSplitApks(packageInfo, chunkMap) backupSplitApks(packageInfo, chunkMap)
} }
apkBuilder.addAllSplits(splits) val apk = apkBuilder.addAllSplits(splits).build()
val apk = apkBuilder.build() snapshotCreator.onApkBackedUp(packageInfo, apk, chunkMap)
snapshotCreator.onApkBackedUp(packageName, apk, chunkMap)
Log.d(TAG, "Backed up new APK of $packageName with version ${packageInfo.versionName}.") Log.d(TAG, "Backed up new APK of $packageName with version ${packageInfo.versionName}.")
} }

View file

@ -14,7 +14,6 @@ import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.BackupMetadata import com.stevesoltys.seedvault.metadata.BackupMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap import com.stevesoltys.seedvault.metadata.PackageMetadataMap
import com.stevesoltys.seedvault.proto.Snapshot
import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.ui.PACKAGE_NAME_CONTACTS import com.stevesoltys.seedvault.ui.PACKAGE_NAME_CONTACTS
import com.stevesoltys.seedvault.ui.PACKAGE_NAME_SETTINGS import com.stevesoltys.seedvault.ui.PACKAGE_NAME_SETTINGS
@ -29,7 +28,6 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.LegacyAppBackupFile import org.calyxos.seedvault.core.backends.LegacyAppBackupFile
import org.calyxos.seedvault.core.toHexString
import org.junit.Test import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertFalse
@ -61,12 +59,6 @@ internal class AppSelectionManagerTest : TransportTest() {
token = Random.nextLong(), token = Random.nextLong(),
salt = getRandomString(), 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( private val appSelectionManager = AppSelectionManager(
context = context, context = context,

View file

@ -14,13 +14,10 @@ import android.content.pm.Signature
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.util.PackageUtils import android.util.PackageUtils
import app.cash.turbine.test 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.BackupStateManager
import com.stevesoltys.seedvault.assertReadEquals import com.stevesoltys.seedvault.assertReadEquals
import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.backend.LegacyStoragePlugin import com.stevesoltys.seedvault.backend.LegacyStoragePlugin
import com.stevesoltys.seedvault.decodeBase64
import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap 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.SnapshotManager
import com.stevesoltys.seedvault.transport.TransportTest import com.stevesoltys.seedvault.transport.TransportTest
import com.stevesoltys.seedvault.transport.backup.AppBackupManager 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.BackupReceiver
import com.stevesoltys.seedvault.transport.backup.SnapshotCreator import com.stevesoltys.seedvault.transport.backup.SnapshotCreator
import com.stevesoltys.seedvault.transport.backup.hexFromProto import com.stevesoltys.seedvault.transport.backup.hexFromProto
import com.stevesoltys.seedvault.transport.restore.Loader import com.stevesoltys.seedvault.transport.restore.Loader
import com.stevesoltys.seedvault.transport.restore.RestorableBackup import com.stevesoltys.seedvault.transport.restore.RestorableBackup
import com.stevesoltys.seedvault.worker.ApkBackup import com.stevesoltys.seedvault.worker.ApkBackup
import com.stevesoltys.seedvault.worker.BASE_SPLIT
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every
@ -46,11 +41,10 @@ import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.slot import io.mockk.slot
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.AppBackupFileType import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.Backend 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.assertArrayEquals
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertFalse
@ -64,9 +58,7 @@ import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.InputStream import java.io.InputStream
import java.nio.file.Path import java.nio.file.Path
import kotlin.random.Random
@ExperimentalCoroutinesApi
internal class ApkBackupRestoreTest : TransportTest() { internal class ApkBackupRestoreTest : TransportTest() {
private val pm: PackageManager = mockk() private val pm: PackageManager = mockk()
@ -108,37 +100,6 @@ internal class ApkBackupRestoreTest : TransportTest() {
private val signatureBytes = byteArrayOf(0x01, 0x02, 0x03) private val signatureBytes = byteArrayOf(0x01, 0x02, 0x03)
private val signatureHash = byteArrayOf(0x03, 0x02, 0x01) private val signatureHash = byteArrayOf(0x03, 0x02, 0x01)
private val sigs = arrayOf(Signature(signatureBytes)) 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 = private val packageMetadataMap: PackageMetadataMap =
hashMapOf(packageName to PackageMetadata.fromSnapshot(app)) hashMapOf(packageName to PackageMetadata.fromSnapshot(app))
private val installerName = apk.installer private val installerName = apk.installer

View file

@ -17,19 +17,18 @@ import android.content.pm.PackageManager.NameNotFoundException
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import app.cash.turbine.TurbineTestContext import app.cash.turbine.TurbineTestContext
import app.cash.turbine.test import app.cash.turbine.test
import com.google.protobuf.ByteString import com.google.protobuf.ByteString.copyFrom
import com.google.protobuf.ByteString.copyFromUtf8
import com.google.protobuf.ByteString.fromHex import com.google.protobuf.ByteString.fromHex
import com.stevesoltys.seedvault.BackupStateManager import com.stevesoltys.seedvault.BackupStateManager
import com.stevesoltys.seedvault.backend.BackendManager 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.getRandomBase64
import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.ApkSplit import com.stevesoltys.seedvault.metadata.ApkSplit
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap 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.RestorableBackup
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP 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.QUEUED
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
import com.stevesoltys.seedvault.transport.TransportTest 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.backup.hexFromProto
import com.stevesoltys.seedvault.transport.restore.Loader import com.stevesoltys.seedvault.transport.restore.Loader
import com.stevesoltys.seedvault.worker.BASE_SPLIT
import io.mockk.Runs import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.every import io.mockk.every
@ -48,7 +45,6 @@ import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.verifyOrder import io.mockk.verifyOrder
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.AppBackupFileType import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend
@ -66,7 +62,6 @@ import java.io.IOException
import java.nio.file.Path import java.nio.file.Path
import kotlin.random.Random import kotlin.random.Random
@ExperimentalCoroutinesApi
internal class ApkRestoreTest : TransportTest() { internal class ApkRestoreTest : TransportTest() {
private val pm: PackageManager = mockk() private val pm: PackageManager = mockk()
@ -78,7 +73,6 @@ internal class ApkRestoreTest : TransportTest() {
private val backendManager: BackendManager = mockk() private val backendManager: BackendManager = mockk()
private val loader: Loader = mockk() private val loader: Loader = mockk()
private val backend: Backend = mockk() private val backend: Backend = mockk()
private val legacyStoragePlugin: LegacyStoragePlugin = mockk()
private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk() private val splitCompatChecker: ApkSplitCompatibilityChecker = mockk()
private val apkInstaller: ApkInstaller = mockk() private val apkInstaller: ApkInstaller = mockk()
private val installRestriction: InstallRestriction = mockk() private val installRestriction: InstallRestriction = mockk()
@ -89,8 +83,8 @@ internal class ApkRestoreTest : TransportTest() {
backupStateManager = backupStateManager, backupStateManager = backupStateManager,
backendManager = backendManager, backendManager = backendManager,
loader = loader, loader = loader,
legacyStoragePlugin = legacyStoragePlugin, legacyStoragePlugin = mockk(),
crypto = crypto, crypto = mockk(),
splitCompatChecker = splitCompatChecker, splitCompatChecker = splitCompatChecker,
apkInstaller = apkInstaller, apkInstaller = apkInstaller,
installRestriction = installRestriction, installRestriction = installRestriction,
@ -99,38 +93,24 @@ internal class ApkRestoreTest : TransportTest() {
private val icon: Drawable = mockk() private val icon: Drawable = mockk()
private val deviceName = metadata.deviceName private val deviceName = metadata.deviceName
private val packageName = packageInfo.packageName
private val apkBytes = byteArrayOf(0x04, 0x05, 0x06) private val apkBytes = byteArrayOf(0x04, 0x05, 0x06)
private val apkInputStream = ByteArrayInputStream(apkBytes) private val apkInputStream = ByteArrayInputStream(apkBytes)
private val appName = getRandomString() private val appName = getRandomString()
private val repoId = Random.nextBytes(32).toHexString() private val appNoSplit = app.copy { // tests that need splits bring their own
private val apkChunkId = Random.nextBytes(32).toHexString() this.apk = apk.copy {
private val apkBlob = splits.clear()
Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build() splits.add(baseSplit)
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) private val snapshotWithoutSplit = snapshot.copy {
.addAllChunkIds(listOf(fromHex(apkChunkId))).build() apps[packageName] = appNoSplit
private val apk = Snapshot.Apk.newBuilder() }
.setVersionCode(packageInfo.longVersionCode - 1) private val packageMetadata = PackageMetadata.fromSnapshot(appNoSplit)
.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 packageMetadataMap: PackageMetadataMap = hashMapOf(packageName to packageMetadata) private val packageMetadataMap: PackageMetadataMap = hashMapOf(packageName to packageMetadata)
private val installerName = packageMetadata.installer private val installerName = packageMetadata.installer
private val backup = RestorableBackup( private val backup = RestorableBackup(
repoId = repoId, repoId = repoId,
snapshot = snapshot, snapshot = snapshotWithoutSplit,
backupMetadata = metadata.copy(packageMetadataMap = packageMetadataMap), backupMetadata = metadata.copy(packageMetadataMap = packageMetadataMap),
) )
@ -472,7 +452,7 @@ internal class ApkRestoreTest : TransportTest() {
splits = listOf(split) splits = listOf(split)
) )
val blobHandle = AppBackupFileType.Blob(repoId, splitBlobId) 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 snapshot = snapshot.toBuilder().putBlobs(splitChunkId, splitBlob).build()
val backup = backup.copy(snapshot = snapshot) val backup = backup.copy(snapshot = snapshot)
@ -496,27 +476,31 @@ internal class ApkRestoreTest : TransportTest() {
@Test @Test
fun `splits get installed along with base APK`(@TempDir tmpDir: Path) = runBlocking { fun `splits get installed along with base APK`(@TempDir tmpDir: Path) = runBlocking {
// add one APK split to metadata // add one APK split to metadata
val split1Name = getRandomString()
val split2Name = getRandomString()
val splitChunkId1 = Random.nextBytes(32).toHexString() val splitChunkId1 = Random.nextBytes(32).toHexString()
val splitChunkId2 = Random.nextBytes(32).toHexString() val splitChunkId2 = Random.nextBytes(32).toHexString()
val apkSplit1 = Snapshot.Split.newBuilder().setName(split1Name) val apkSplit1 = split {
.addAllChunkIds(listOf(fromHex(splitChunkId1))).build() name = getRandomString()
val apkSplit2 = Snapshot.Split.newBuilder().setName(split2Name) chunkIds.add(fromHex(splitChunkId1))
.addAllChunkIds(listOf(fromHex(splitChunkId2))).build() }
val splitBlob1 = val apkSplit2 = split {
Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build() name = getRandomString()
val splitBlob2 = chunkIds.add(fromHex(splitChunkId2))
Snapshot.Blob.newBuilder().setId(ByteString.copyFrom(Random.nextBytes(32))).build() }
val apk = apk.toBuilder().addSplits(apkSplit1).addSplits(apkSplit2).build() val splitBlob1 = blob { id = copyFrom(Random.nextBytes(32)) }
val app = app.toBuilder().setApk(apk).build() val splitBlob2 = blob { id = copyFrom(Random.nextBytes(32)) }
val blobMap = apkBackupData.chunkMap + val blobMap = apkBackupData.chunkMap +
mapOf(splitChunkId1 to splitBlob1) + mapOf(splitChunkId1 to splitBlob1) +
mapOf(splitChunkId2 to splitBlob2) mapOf(splitChunkId2 to splitBlob2)
val snapshot = snapshot.toBuilder() val app = appNoSplit.copy {
.putApps(packageName, app) this.apk = apk.copy {
.putAllBlobs(blobMap) splits.clear()
.build() splits.addAll(listOf(baseSplit, apkSplit1, apkSplit2))
}
}
val snapshot = snapshotWithoutSplit.copy {
apps[packageName] = app
blobs.putAll(blobMap)
}
packageMetadataMap[packageName] = PackageMetadata.fromSnapshot(app) packageMetadataMap[packageName] = PackageMetadata.fromSnapshot(app)
val backup = backup.copy(snapshot = snapshot) val backup = backup.copy(snapshot = snapshot)
@ -528,7 +512,7 @@ internal class ApkRestoreTest : TransportTest() {
cacheBaseApkAndGetInfo(tmpDir) cacheBaseApkAndGetInfo(tmpDir)
every { every {
splitCompatChecker.isCompatible(deviceName, listOf(split1Name, split2Name)) splitCompatChecker.isCompatible(deviceName, listOf(apkSplit1.name, apkSplit2.name))
} returns true } returns true
// define bytes of splits and return them as stream (matches above hashes) // define bytes of splits and return them as stream (matches above hashes)

View file

@ -41,7 +41,6 @@ import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.verifyOrder import io.mockk.verifyOrder
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.calyxos.seedvault.core.backends.Backend import org.calyxos.seedvault.core.backends.Backend
import org.calyxos.seedvault.core.backends.LegacyAppBackupFile import org.calyxos.seedvault.core.backends.LegacyAppBackupFile
@ -57,7 +56,6 @@ import java.io.IOException
import java.nio.file.Path import java.nio.file.Path
import kotlin.random.Random import kotlin.random.Random
@ExperimentalCoroutinesApi
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
internal class ApkRestoreV1Test : TransportTest() { internal class ApkRestoreV1Test : TransportTest() {
@ -91,7 +89,6 @@ internal class ApkRestoreV1Test : TransportTest() {
private val icon: Drawable = mockk() private val icon: Drawable = mockk()
private val deviceName = metadata.deviceName private val deviceName = metadata.deviceName
private val packageName = packageInfo.packageName
private val packageMetadata = PackageMetadata( private val packageMetadata = PackageMetadata(
time = Random.nextLong(), time = Random.nextLong(),
version = packageInfo.longVersionCode - 1, version = packageInfo.longVersionCode - 1,

View file

@ -6,8 +6,6 @@
package com.stevesoltys.seedvault.transport package com.stevesoltys.seedvault.transport
import com.stevesoltys.seedvault.backend.BackendManager 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.proto.Snapshot
import com.stevesoltys.seedvault.transport.restore.Loader import com.stevesoltys.seedvault.transport.restore.Loader
import io.mockk.coEvery import io.mockk.coEvery
@ -31,9 +29,8 @@ import java.io.OutputStream
import java.security.MessageDigest import java.security.MessageDigest
import kotlin.random.Random import kotlin.random.Random
class SnapshotManagerTest { internal class SnapshotManagerTest : TransportTest() {
private val crypto: Crypto = mockk()
private val backendManager: BackendManager = mockk() private val backendManager: BackendManager = mockk()
private val backend: Backend = mockk() private val backend: Backend = mockk()
@ -43,14 +40,7 @@ class SnapshotManagerTest {
private val ad = Random.nextBytes(1) private val ad = Random.nextBytes(1)
private val passThroughOutputStream = slot<OutputStream>() private val passThroughOutputStream = slot<OutputStream>()
private val passThroughInputStream = slot<InputStream>() private val passThroughInputStream = slot<InputStream>()
private val repoId = Random.nextBytes(32).toHexString()
private val snapshotHandle = slot<AppBackupFileType.Snapshot>() private val snapshotHandle = slot<AppBackupFileType.Snapshot>()
private val snapshot = Snapshot.newBuilder()
.setToken(Random.nextLong())
.setName(getRandomString())
.setSdkInt(Random.nextInt())
.putAllBlobs(mapOf(getRandomString() to Snapshot.Blob.getDefaultInstance()))
.build()
@Test @Test
fun `test saving and loading`() = runBlocking { fun `test saving and loading`() = runBlocking {

View file

@ -12,9 +12,12 @@ import android.content.pm.ApplicationInfo.FLAG_INSTALLED
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.SigningInfo import android.content.pm.SigningInfo
import android.util.Log import android.util.Log
import com.google.protobuf.ByteString
import com.google.protobuf.ByteString.copyFromUtf8
import com.stevesoltys.seedvault.Clock import com.stevesoltys.seedvault.Clock
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.crypto.Crypto import com.stevesoltys.seedvault.crypto.Crypto
import com.stevesoltys.seedvault.decodeBase64
import com.stevesoltys.seedvault.getRandomBase64 import com.stevesoltys.seedvault.getRandomBase64
import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.metadata.BackupMetadata 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.MetadataManager
import com.stevesoltys.seedvault.metadata.PackageMetadata import com.stevesoltys.seedvault.metadata.PackageMetadata
import com.stevesoltys.seedvault.metadata.PackageMetadataMap 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.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.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.slot import io.mockk.slot
import org.calyxos.seedvault.core.backends.AppBackupFileType
import org.calyxos.seedvault.core.backends.LegacyAppBackupFile 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
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD
import kotlin.random.Random import kotlin.random.Random
@ -53,6 +65,7 @@ internal abstract class TransportTest {
applicationInfo = this@TransportTest.applicationInfo applicationInfo = this@TransportTest.applicationInfo
signingInfo = sigInfo signingInfo = sigInfo
} }
protected val packageName: String = packageInfo.packageName
protected val pmPackageInfo = PackageInfo().apply { protected val pmPackageInfo = PackageInfo().apply {
packageName = MAGIC_PACKAGE_MANAGER packageName = MAGIC_PACKAGE_MANAGER
} }
@ -76,6 +89,46 @@ internal abstract class TransportTest {
protected val storageProviderPackageName = getRandomString(23) protected val storageProviderPackageName = getRandomString(23)
protected val handle = LegacyAppBackupFile.Blob(token, name) 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 { init {
mockkStatic(Log::class) mockkStatic(Log::class)
val logTagSlot = slot<String>() val logTagSlot = slot<String>()

View file

@ -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_NON_INCREMENTAL_BACKUP_REQUIRED
import android.app.backup.BackupTransport.TRANSPORT_OK import android.app.backup.BackupTransport.TRANSPORT_OK
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE import com.stevesoltys.seedvault.header.MAX_KEY_LENGTH_SIZE
import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.header.VERSION
import com.stevesoltys.seedvault.header.getADForKV import com.stevesoltys.seedvault.header.getADForKV
import com.stevesoltys.seedvault.backend.BackendManager
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import io.mockk.CapturingSlot import io.mockk.CapturingSlot
import io.mockk.Runs import io.mockk.Runs
@ -55,7 +55,6 @@ internal class KVBackupTest : BackupTest() {
private val db = mockk<KVDb>() private val db = mockk<KVDb>()
private val backend = mockk<Backend>() private val backend = mockk<Backend>()
private val packageName = packageInfo.packageName
private val key = getRandomString(MAX_KEY_LENGTH_SIZE) private val key = getRandomString(MAX_KEY_LENGTH_SIZE)
private val dataValue = Random.nextBytes(23) private val dataValue = Random.nextBytes(23)
private val dbBytes = Random.nextBytes(42) private val dbBytes = Random.nextBytes(42)

View file

@ -73,7 +73,6 @@ internal class RestoreCoordinatorTest : TransportTest() {
PackageInfo().apply { packageName = "@pm@" }, PackageInfo().apply { packageName = "@pm@" },
packageInfo packageInfo
) )
private val packageName = packageInfo.packageName
private val storageName = getRandomString() private val storageName = getRandomString()
init { init {

View file

@ -13,10 +13,12 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.Signature import android.content.pm.Signature
import android.util.PackageUtils 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.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.getRandomString import com.stevesoltys.seedvault.getRandomString
import com.stevesoltys.seedvault.proto.Snapshot 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.SnapshotManager
import com.stevesoltys.seedvault.transport.backup.AppBackupManager import com.stevesoltys.seedvault.transport.backup.AppBackupManager
import com.stevesoltys.seedvault.transport.backup.BackupData import com.stevesoltys.seedvault.transport.backup.BackupData
@ -56,14 +58,6 @@ internal class ApkBackupTest : BackupTest() {
private val signatureBytes = byteArrayOf(0x01, 0x02, 0x03) private val signatureBytes = byteArrayOf(0x01, 0x02, 0x03)
private val signatureHash = byteArrayOf(0x03, 0x02, 0x01) private val signatureHash = byteArrayOf(0x03, 0x02, 0x01)
private val sigs = arrayOf(Signature(signatureBytes)) 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 { init {
mockkStatic(PackageUtils::class) mockkStatic(PackageUtils::class)
@ -113,8 +107,8 @@ internal class ApkBackupTest : BackupTest() {
@Test @Test
fun `does not back up the same version`() = runBlocking { fun `does not back up the same version`() = runBlocking {
packageInfo.applicationInfo!!.flags = FLAG_UPDATED_SYSTEM_APP packageInfo.applicationInfo!!.flags = FLAG_UPDATED_SYSTEM_APP
val apk = apk.toBuilder().setVersionCode(packageInfo.longVersionCode).build() val apk = apk.copy { versionCode = packageInfo.longVersionCode }
val app = Snapshot.App.newBuilder().setApk(apk).build() val app = app { this.apk = apk }
expectChecks(snapshot.toBuilder().putApps(packageInfo.packageName, app).build()) expectChecks(snapshot.toBuilder().putApps(packageInfo.packageName, app).build())
apkBackup.backupApkIfNecessary(packageInfo) apkBackup.backupApkIfNecessary(packageInfo)
@ -123,12 +117,12 @@ internal class ApkBackupTest : BackupTest() {
@Test @Test
fun `does back up the same version when signatures changes`() { fun `does back up the same version when signatures changes`() {
packageInfo.applicationInfo!!.sourceDir = "/tmp/doesNotExist" packageInfo.applicationInfo!!.sourceDir = "/tmp/doesNotExist"
val apk = apk.toBuilder() val apk = apk.copy {
.clearSignatures() signatures.clear()
.addSignatures(ByteString.copyFromUtf8("foo")) signatures.add(copyFromUtf8("foo"))
.setVersionCode(packageInfo.longVersionCode) versionCode = packageInfo.longVersionCode
.build() }
val app = Snapshot.App.newBuilder().setApk(apk).build() val app = app { this.apk = apk }
expectChecks(snapshot.toBuilder().putApps(packageInfo.packageName, app).build()) expectChecks(snapshot.toBuilder().putApps(packageInfo.packageName, app).build())
every { every {
pm.getInstallSourceInfo(packageInfo.packageName) pm.getInstallSourceInfo(packageInfo.packageName)

View file

@ -10,6 +10,12 @@ android_library_import {
extract_jni: true, extract_jni: true,
} }
java_import {
name: "seedvault-lib-protobuf-kotlin-lite",
jars: ["protobuf-kotlin-lite-3.21.12.jar"],
sdk_version: "current",
}
java_import { java_import {
name: "seedvault-lib-kotlin-bip39", name: "seedvault-lib-kotlin-bip39",
jars: ["kotlin-bip39-jvm-1.0.6.jar"], jars: ["kotlin-bip39-jvm-1.0.6.jar"],

Binary file not shown.