Include user profile name in backup name

so it is easier to identify the right backup if more users backup to the same storage medium.

Change-Id: I56fa93899da3764e20b6aee40adfd52722a05a9f
This commit is contained in:
Torsten Grote 2024-02-12 12:01:38 -03:00 committed by Chirayu Desai
parent 6e63d9bac0
commit 87db20e45f
5 changed files with 65 additions and 2 deletions

View file

@ -46,6 +46,7 @@ It uses the same internal APIs as `adb backup` which is deprecated and thus need
* `android.permission.MANAGE_USB` to access the serial number of USB mass storage devices. * `android.permission.MANAGE_USB` to access the serial number of USB mass storage devices.
* `android.permission.WRITE_SECURE_SETTINGS` to change system backup settings and enable call log backup. * `android.permission.WRITE_SECURE_SETTINGS` to change system backup settings and enable call log backup.
* `android.permission.QUERY_ALL_PACKAGES` to get information about all installed apps for backup. * `android.permission.QUERY_ALL_PACKAGES` to get information about all installed apps for backup.
* `android.permission.QUERY_USERS` to get the name of the user profile that gets backed up.
* `android.permission.INSTALL_PACKAGES` to re-install apps when restoring from backup. * `android.permission.INSTALL_PACKAGES` to re-install apps when restoring from backup.
* `android.permission.MANAGE_EXTERNAL_STORAGE` to backup and restore files from device storage. * `android.permission.MANAGE_EXTERNAL_STORAGE` to backup and restore files from device storage.
* `android.permission.ACCESS_MEDIA_LOCATION` to backup original media files e.g. without stripped EXIF metadata. * `android.permission.ACCESS_MEDIA_LOCATION` to backup original media files e.g. without stripped EXIF metadata.

View file

@ -64,6 +64,10 @@
android:name="android.permission.READ_LOGS" android:name="android.permission.READ_LOGS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
<!-- Used to get the name of the current profile -->
<uses-permission android:name="android.permission.QUERY_USERS"
tools:ignore="ProtectedPermissions" />
<!-- Used for periodic storage backups --> <!-- Used for periodic storage backups -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

View file

@ -3,6 +3,9 @@ package com.stevesoltys.seedvault.metadata
import android.content.Context import android.content.Context
import android.content.Context.MODE_PRIVATE import android.content.Context.MODE_PRIVATE
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Build
import android.os.UserManager
import android.util.Log import android.util.Log
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
@ -67,7 +70,16 @@ internal class MetadataManager(
fun onDeviceInitialization(token: Long) { fun onDeviceInitialization(token: Long) {
val salt = crypto.getRandomBytes(METADATA_SALT_SIZE).encodeBase64() val salt = crypto.getRandomBytes(METADATA_SALT_SIZE).encodeBase64()
modifyCachedMetadata { modifyCachedMetadata {
metadata = BackupMetadata(token = token, salt = salt) val userName = getUserName()
metadata = BackupMetadata(
token = token,
salt = salt,
deviceName = if (userName == null) {
"${Build.MANUFACTURER} ${Build.MODEL}"
} else {
"${Build.MANUFACTURER} ${Build.MODEL} - $userName"
},
)
} }
} }
@ -297,4 +309,12 @@ internal class MetadataManager(
} }
} }
private fun getUserName(): String? {
val perm = "android.permission.QUERY_USERS"
return if (context.checkSelfPermission(perm) == PERMISSION_GRANTED) {
val userManager = context.getSystemService(UserManager::class.java)
userManager.userName
} else null
}
} }

View file

@ -6,6 +6,8 @@ import android.content.pm.ApplicationInfo
import android.content.pm.ApplicationInfo.FLAG_ALLOW_BACKUP import android.content.pm.ApplicationInfo.FLAG_ALLOW_BACKUP
import android.content.pm.ApplicationInfo.FLAG_SYSTEM import android.content.pm.ApplicationInfo.FLAG_SYSTEM
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.UserManager
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.stevesoltys.seedvault.Clock import com.stevesoltys.seedvault.Clock
import com.stevesoltys.seedvault.TestApp import com.stevesoltys.seedvault.TestApp
@ -94,12 +96,16 @@ class MetadataManagerTest {
} }
@Test @Test
fun `test onDeviceInitialization()`() { fun `test onDeviceInitialization() without user permission`() {
every { clock.time() } returns time every { clock.time() } returns time
every { crypto.getRandomBytes(METADATA_SALT_SIZE) } returns saltBytes every { crypto.getRandomBytes(METADATA_SALT_SIZE) } returns saltBytes
expectReadFromCache() expectReadFromCache()
expectModifyMetadata(initialMetadata) expectModifyMetadata(initialMetadata)
every {
context.checkSelfPermission("android.permission.QUERY_USERS")
} returns PackageManager.PERMISSION_DENIED
manager.onDeviceInitialization(token) manager.onDeviceInitialization(token)
assertEquals(token, manager.getBackupToken()) assertEquals(token, manager.getBackupToken())
@ -111,6 +117,37 @@ class MetadataManagerTest {
} }
} }
@Test
fun `test onDeviceInitialization() with user permission`() {
val userManager: UserManager = mockk()
val userName = getRandomString()
val newMetadata = initialMetadata.copy(
deviceName = initialMetadata.deviceName + " - $userName",
)
every { clock.time() } returns time
every { crypto.getRandomBytes(METADATA_SALT_SIZE) } returns saltBytes
expectReadFromCache()
expectModifyMetadata(newMetadata)
every {
context.checkSelfPermission("android.permission.QUERY_USERS")
} returns PackageManager.PERMISSION_GRANTED
every { context.getSystemService(UserManager::class.java) } returns userManager
every { userManager.userName } returns userName
manager.onDeviceInitialization(token)
assertEquals(token, manager.getBackupToken())
assertEquals(0L, manager.getLastBackupTime())
verify {
cacheInputStream.close()
cacheOutputStream.close()
userManager.userName
}
}
@Test @Test
fun `test onApkBackedUp() with no prior package metadata`() { fun `test onApkBackedUp() with no prior package metadata`() {
val packageMetadata = PackageMetadata( val packageMetadata = PackageMetadata(

View file

@ -5,6 +5,7 @@
<permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MANAGE_USB"/>
<permission name="android.permission.INSTALL_PACKAGES"/> <permission name="android.permission.INSTALL_PACKAGES"/>
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/> <permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<permission name="android.permission.QUERY_USERS" />
<permission name="android.permission.READ_LOGS"/> <permission name="android.permission.READ_LOGS"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/> <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>