diff --git a/README.md b/README.md index 3f97ac35..b396a5a5 100644 --- a/README.md +++ b/README.md @@ -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.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_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.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. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c3bd194c..f2278814 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -64,6 +64,10 @@ android:name="android.permission.READ_LOGS" tools:ignore="ProtectedPermissions" /> + + + diff --git a/app/src/main/java/com/stevesoltys/seedvault/metadata/MetadataManager.kt b/app/src/main/java/com/stevesoltys/seedvault/metadata/MetadataManager.kt index 6c09ac8f..2346adb6 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/metadata/MetadataManager.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/metadata/MetadataManager.kt @@ -3,6 +3,9 @@ package com.stevesoltys.seedvault.metadata import android.content.Context import android.content.Context.MODE_PRIVATE 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 androidx.annotation.VisibleForTesting import androidx.annotation.WorkerThread @@ -67,7 +70,16 @@ internal class MetadataManager( fun onDeviceInitialization(token: Long) { val salt = crypto.getRandomBytes(METADATA_SALT_SIZE).encodeBase64() 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 + } + } diff --git a/app/src/test/java/com/stevesoltys/seedvault/metadata/MetadataManagerTest.kt b/app/src/test/java/com/stevesoltys/seedvault/metadata/MetadataManagerTest.kt index 62300e76..308f9105 100644 --- a/app/src/test/java/com/stevesoltys/seedvault/metadata/MetadataManagerTest.kt +++ b/app/src/test/java/com/stevesoltys/seedvault/metadata/MetadataManagerTest.kt @@ -6,6 +6,8 @@ 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 android.os.UserManager import androidx.test.ext.junit.runners.AndroidJUnit4 import com.stevesoltys.seedvault.Clock import com.stevesoltys.seedvault.TestApp @@ -94,12 +96,16 @@ class MetadataManagerTest { } @Test - fun `test onDeviceInitialization()`() { + fun `test onDeviceInitialization() without user permission`() { every { clock.time() } returns time every { crypto.getRandomBytes(METADATA_SALT_SIZE) } returns saltBytes expectReadFromCache() expectModifyMetadata(initialMetadata) + every { + context.checkSelfPermission("android.permission.QUERY_USERS") + } returns PackageManager.PERMISSION_DENIED + manager.onDeviceInitialization(token) 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 fun `test onApkBackedUp() with no prior package metadata`() { val packageMetadata = PackageMetadata( diff --git a/permissions_com.stevesoltys.seedvault.xml b/permissions_com.stevesoltys.seedvault.xml index cb85ca60..f6b63de3 100644 --- a/permissions_com.stevesoltys.seedvault.xml +++ b/permissions_com.stevesoltys.seedvault.xml @@ -5,6 +5,7 @@ +