Add support for d2d
Change-Id: I61d88a511a0f81e6d384e3650f6797725da79814
This commit is contained in:
parent
72c8460864
commit
4a98667162
7 changed files with 73 additions and 25 deletions
|
|
@ -67,6 +67,12 @@
|
|||
android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
|
||||
<!-- This is needed to read if the IGNORE_ALLOW_BACKUP_IN_D2D -->
|
||||
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
|
||||
|
||||
<!-- This is needed to read if the -->
|
||||
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:allowBackup="false"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.app.Application
|
|||
import android.app.backup.BackupManager.PACKAGE_MANAGER_SENTINEL
|
||||
import android.app.backup.IBackupManager
|
||||
import android.content.Context
|
||||
import android.content.Context.BACKUP_SERVICE
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.os.Build
|
||||
import android.os.ServiceManager.getService
|
||||
|
|
@ -118,6 +117,8 @@ open class App : Application() {
|
|||
|
||||
}
|
||||
|
||||
const val PLATFORM_PACKAGE_NAME = "android"
|
||||
const val SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup"
|
||||
const val MAGIC_PACKAGE_MANAGER = PACKAGE_MANAGER_SENTINEL
|
||||
const val ANCESTRAL_RECORD_KEY = "@ancestral_record@"
|
||||
const val GLOBAL_METADATA_KEY = "@meta@"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ data class BackupMetadata(
|
|||
internal var time: Long = 0L,
|
||||
internal val androidVersion: Int = Build.VERSION.SDK_INT,
|
||||
internal val androidIncremental: String = Build.VERSION.INCREMENTAL,
|
||||
internal val deviceName: String = "${Build.MANUFACTURER} ${Build.MODEL}",
|
||||
internal val deviceName: String = "D2D",
|
||||
internal val packageMetadataMap: PackageMetadataMap = PackageMetadataMap(),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,12 +15,16 @@ import android.content.Context
|
|||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.util.Log
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.annotation.VisibleForTesting.PRIVATE
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.stevesoltys.seedvault.Clock
|
||||
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
||||
import com.stevesoltys.seedvault.PLATFORM_PACKAGE_NAME
|
||||
import com.stevesoltys.seedvault.SHARED_BACKUP_AGENT_PACKAGE
|
||||
import com.stevesoltys.seedvault.metadata.BackupType
|
||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||
import com.stevesoltys.seedvault.metadata.PackageState
|
||||
|
|
@ -143,12 +147,26 @@ internal class BackupCoordinator(
|
|||
@Suppress("UNUSED_PARAMETER") isFullBackup: Boolean,
|
||||
): Boolean {
|
||||
val packageName = targetPackage.packageName
|
||||
val applicationInfo = targetPackage.applicationInfo
|
||||
// This must be kept in sync with frameworks/base/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
|
||||
if (!targetPackage.allowsBackup(context, UserHandle.myUserId())
|
||||
|| (UserHandle.isCore(applicationInfo.uid) &&
|
||||
(applicationInfo.backupAgentName == null ||
|
||||
(!UserManager.get(context).isSystemUser &&
|
||||
(packageName == MAGIC_PACKAGE_MANAGER
|
||||
|| packageName == PLATFORM_PACKAGE_NAME))))
|
||||
|| packageName == SHARED_BACKUP_AGENT_PACKAGE
|
||||
|| applicationInfo.isInstantApp
|
||||
|| targetPackage.isStopped()
|
||||
|| !applicationInfo.enabled) {
|
||||
return false
|
||||
}
|
||||
// Check that the app is not blacklisted by the user
|
||||
val enabled = settingsManager.isBackupEnabled(packageName)
|
||||
if (!enabled) Log.w(TAG, "Backup of $packageName disabled by user.")
|
||||
// We need to exclude the DocumentsProvider used to store backup data.
|
||||
// Otherwise, it gets killed when we back it up, terminating our backup.
|
||||
return enabled && targetPackage.packageName != plugin.providerPackageName
|
||||
return enabled && packageName != plugin.providerPackageName
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ val backupModule = module {
|
|||
single { InputFactory() }
|
||||
single {
|
||||
PackageService(
|
||||
context = androidContext(),
|
||||
backupManager = get()
|
||||
context = androidContext()
|
||||
)
|
||||
}
|
||||
single {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.stevesoltys.seedvault.transport.backup
|
||||
|
||||
import android.app.backup.IBackupManager
|
||||
import android.Manifest
|
||||
import android.app.compat.CompatChanges
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo.FLAG_ALLOW_BACKUP
|
||||
import android.content.pm.ApplicationInfo.FLAG_STOPPED
|
||||
|
|
@ -22,13 +23,15 @@ private val TAG = PackageService::class.java.simpleName
|
|||
|
||||
private const val LOG_MAX_PACKAGES = 100
|
||||
|
||||
// This must be kept in sync with frameworks/base/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
|
||||
private const val IGNORE_ALLOW_BACKUP_IN_D2D = 183147249L
|
||||
|
||||
/**
|
||||
* @author Steve Soltys
|
||||
* @author Torsten Grote
|
||||
*/
|
||||
internal class PackageService(
|
||||
private val context: Context,
|
||||
private val backupManager: IBackupManager,
|
||||
) {
|
||||
|
||||
private val packageManager: PackageManager = context.packageManager
|
||||
|
|
@ -50,17 +53,14 @@ internal class PackageService(
|
|||
}
|
||||
}
|
||||
|
||||
val eligibleApps =
|
||||
backupManager.filterAppsEligibleForBackupForUser(myUserId, packages.toTypedArray())
|
||||
|
||||
// log eligible packages
|
||||
if (Log.isLoggable(TAG, INFO)) {
|
||||
Log.i(TAG, "Filtering left ${eligibleApps.size} eligible packages:")
|
||||
logPackages(eligibleApps.toList())
|
||||
}
|
||||
// val eligiblePackages = packages.filter { packageInfo ->
|
||||
// isAppEligibleForBackup(packageInfo,
|
||||
// if (packageInfo.applicationInfo.backupAgentName != null)
|
||||
// pkg.applicationInfo.flags and FLAG_FULL_BACKUP_ONLY != 0 else true)
|
||||
// }
|
||||
|
||||
// add magic @pm@ package (PACKAGE_MANAGER_SENTINEL) which holds package manager data
|
||||
val packageArray = eligibleApps.toMutableList()
|
||||
val packageArray = packages.toMutableList()
|
||||
packageArray.add(MAGIC_PACKAGE_MANAGER)
|
||||
|
||||
return packageArray.toTypedArray()
|
||||
|
|
@ -73,7 +73,7 @@ internal class PackageService(
|
|||
// because the package info is used by [ApkBackup] which needs signing info.
|
||||
return packageManager.getInstalledPackages(GET_SIGNING_CERTIFICATES)
|
||||
.filter { packageInfo ->
|
||||
packageInfo.doesNotGetBackedUp() && // only apps that do not allow backup
|
||||
packageInfo.doesNotGetBackedUp(context, myUserId) && // only apps that do not allow backup
|
||||
!packageInfo.isNotUpdatedSystemApp() && // and are not vanilla system apps
|
||||
packageInfo.packageName != context.packageName // not this app
|
||||
}.sortedBy { packageInfo ->
|
||||
|
|
@ -94,7 +94,7 @@ internal class PackageService(
|
|||
val userApps: List<PackageInfo>
|
||||
@WorkerThread
|
||||
get() = packageManager.getInstalledPackages(GET_INSTRUMENTATION).filter { packageInfo ->
|
||||
packageInfo.isUserVisible(context) && packageInfo.allowsBackup()
|
||||
packageInfo.isUserVisible(context) && packageInfo.allowsBackup(context, myUserId)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -103,7 +103,7 @@ internal class PackageService(
|
|||
val userNotAllowedApps: List<PackageInfo>
|
||||
@WorkerThread
|
||||
get() = packageManager.getInstalledPackages(0).filter { packageInfo ->
|
||||
!packageInfo.allowsBackup() && !packageInfo.isSystemApp()
|
||||
!packageInfo.allowsBackup(context, myUserId) && !packageInfo.isSystemApp()
|
||||
}
|
||||
|
||||
val expectedAppTotals: ExpectedAppTotals
|
||||
|
|
@ -114,7 +114,7 @@ internal class PackageService(
|
|||
packageManager.getInstalledPackages(GET_INSTRUMENTATION).forEach { packageInfo ->
|
||||
if (packageInfo.isUserVisible(context)) {
|
||||
appsTotal++
|
||||
if (packageInfo.doesNotGetBackedUp()) {
|
||||
if (packageInfo.doesNotGetBackedUp(context, myUserId)) {
|
||||
appsOptOut++
|
||||
}
|
||||
}
|
||||
|
|
@ -157,9 +157,20 @@ internal fun PackageInfo.isSystemApp(): Boolean {
|
|||
return applicationInfo.flags and FLAG_SYSTEM != 0
|
||||
}
|
||||
|
||||
internal fun PackageInfo.allowsBackup(): Boolean {
|
||||
internal fun PackageInfo.allowsBackup(context: Context, userId: Int): Boolean {
|
||||
if (packageName == MAGIC_PACKAGE_MANAGER || applicationInfo == null) return false
|
||||
return applicationInfo.flags and FLAG_ALLOW_BACKUP != 0
|
||||
|
||||
// This must be kept in sync with frameworks/base/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
|
||||
val isSystemApp = applicationInfo.flags and FLAG_SYSTEM != 0
|
||||
val ignoreAllowBackup = !isSystemApp
|
||||
&& (context.checkSelfPermission(Manifest.permission.LOG_COMPAT_CHANGE)
|
||||
== PackageManager.PERMISSION_GRANTED)
|
||||
&& (context.checkSelfPermission(Manifest.permission.READ_COMPAT_CHANGE_CONFIG)
|
||||
== PackageManager.PERMISSION_GRANTED)
|
||||
&& CompatChanges.isChangeEnabled(IGNORE_ALLOW_BACKUP_IN_D2D, packageName,
|
||||
UserHandle.of(userId))
|
||||
val allowBackup = applicationInfo.flags and FLAG_ALLOW_BACKUP != 0
|
||||
return ignoreAllowBackup || allowBackup
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -173,10 +184,21 @@ internal fun PackageInfo.isNotUpdatedSystemApp(): Boolean {
|
|||
return isSystemApp && !isUpdatedSystemApp
|
||||
}
|
||||
|
||||
internal fun PackageInfo.doesNotGetBackedUp(): Boolean {
|
||||
internal fun PackageInfo.doesNotGetBackedUp(context: Context, userId: Int): Boolean {
|
||||
if (packageName == MAGIC_PACKAGE_MANAGER || applicationInfo == null) return true
|
||||
return applicationInfo.flags and FLAG_ALLOW_BACKUP == 0 || // does not allow backup
|
||||
applicationInfo.flags and FLAG_STOPPED != 0 // is stopped
|
||||
|
||||
// This must be kept in sync with frameworks/base/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
|
||||
val isSystemApp = applicationInfo.flags and FLAG_SYSTEM != 0
|
||||
val ignoreAllowBackup = !isSystemApp
|
||||
&& (context.checkSelfPermission(Manifest.permission.LOG_COMPAT_CHANGE)
|
||||
== PackageManager.PERMISSION_GRANTED)
|
||||
&& (context.checkSelfPermission(Manifest.permission.READ_COMPAT_CHANGE_CONFIG)
|
||||
== PackageManager.PERMISSION_GRANTED)
|
||||
&& CompatChanges.isChangeEnabled(IGNORE_ALLOW_BACKUP_IN_D2D, packageName,
|
||||
UserHandle.of(userId))
|
||||
val allowBackup = applicationInfo.flags and FLAG_ALLOW_BACKUP != 0
|
||||
val stopped = applicationInfo.flags and FLAG_STOPPED != 0
|
||||
return (!ignoreAllowBackup && !allowBackup) || stopped
|
||||
}
|
||||
|
||||
internal fun PackageInfo.isStopped(): Boolean {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
<permission name="android.permission.MANAGE_USB"/>
|
||||
<permission name="android.permission.INSTALL_PACKAGES"/>
|
||||
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
|
||||
<permission name="android.permission.LOG_COMPAT_CHANGE"/>
|
||||
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
|
||||
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
<permission name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue