diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 22492ccd03732..94a4fde0131ec 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -403,7 +403,7 @@ public abstract class BackupAgent extends ContextWrapper { public void onFullBackup(FullBackupDataOutput data) throws IOException { FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this, mOperationType); - if (!isDeviceToDeviceMigration() && !backupScheme.isFullBackupContentEnabled()) { + if (!backupScheme.isFullBackupEnabled(data.getTransportFlags())) { return; } @@ -911,7 +911,7 @@ public abstract class BackupAgent extends ContextWrapper { } FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this, mOperationType); - if (!bs.isFullBackupContentEnabled()) { + if (!bs.isFullRestoreEnabled()) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { Log.v(FullBackup.TAG_XML_PARSER, "onRestoreFile \"" + destination.getCanonicalPath() diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index 829b6cd439345..9b543b571a449 100644 --- a/core/java/android/app/backup/FullBackup.java +++ b/core/java/android/app/backup/FullBackup.java @@ -99,6 +99,8 @@ public class FullBackup { public static final String FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER = "deviceToDeviceTransfer"; public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION = "fakeClientSideEncryption"; + private static final String FLAG_DISABLE_IF_NO_ENCRYPTION_CAPABILITIES + = "disableIfNoEncryptionCapabilities"; /** * When this change is enabled, include / exclude rules specified via @@ -307,6 +309,10 @@ public class FullBackup { // lazy initialized, only when needed private StorageVolume[] mVolumes = null; + // Properties the transport must have (e.g. encryption) for the operation to go ahead. + @Nullable private Integer mRequiredTransportFlags; + @Nullable private Boolean mIsUsingNewScheme; + /** * Parse out the semantic domains into the correct physical location. */ @@ -453,6 +459,35 @@ public class FullBackup { } } + boolean isFullBackupEnabled(int transportFlags) { + try { + if (isUsingNewScheme()) { + int requiredTransportFlags = getRequiredTransportFlags(); + // All bits that are set in requiredTransportFlags must be set in + // transportFlags. + return (transportFlags & requiredTransportFlags) == requiredTransportFlags; + } + } catch (IOException | XmlPullParserException e) { + Slog.w(TAG, "Failed to interpret the backup scheme: " + e); + return false; + } + + return isFullBackupContentEnabled(); + } + + boolean isFullRestoreEnabled() { + try { + if (isUsingNewScheme()) { + return true; + } + } catch (IOException | XmlPullParserException e) { + Slog.w(TAG, "Failed to interpret the backup scheme: " + e); + return false; + } + + return isFullBackupContentEnabled(); + } + boolean isFullBackupContentEnabled() { if (mFullBackupContent < 0) { // android:fullBackupContent="false", bail. @@ -491,10 +526,30 @@ public class FullBackup { return mExcludes; } + private synchronized int getRequiredTransportFlags() + throws IOException, XmlPullParserException { + if (mRequiredTransportFlags == null) { + maybeParseBackupSchemeLocked(); + } + + return mRequiredTransportFlags; + } + + private synchronized boolean isUsingNewScheme() + throws IOException, XmlPullParserException { + if (mIsUsingNewScheme == null) { + maybeParseBackupSchemeLocked(); + } + + return mIsUsingNewScheme; + } + private void maybeParseBackupSchemeLocked() throws IOException, XmlPullParserException { // This not being null is how we know that we've tried to parse the xml already. mIncludes = new ArrayMap>(); mExcludes = new ArraySet(); + mRequiredTransportFlags = 0; + mIsUsingNewScheme = false; if (mFullBackupContent == 0 && mDataExtractionRules == 0) { // No scheme specified via either new or legacy config, will copy everything. @@ -535,12 +590,14 @@ public class FullBackup { } if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) { // Found configuration in the new config, we will use it. + mIsUsingNewScheme = true; return; } } if (operationType == OperationType.MIGRATION && CompatChanges.isChangeEnabled(IGNORE_FULL_BACKUP_CONTENT_IN_D2D)) { + mIsUsingNewScheme = true; return; } @@ -584,13 +641,24 @@ public class FullBackup { continue; } - // TODO(b/180523028): Parse required attributes for rules (e.g. encryption). + parseRequiredTransportFlags(parser, configSection); parseRules(parser, excludes, includes, Optional.of(0), configSection); } logParsingResults(excludes, includes); } + private void parseRequiredTransportFlags(XmlPullParser parser, + @ConfigSection String configSection) { + if (ConfigSection.CLOUD_BACKUP.equals(configSection)) { + String encryptionAttribute = parser.getAttributeValue(/* namespace */ null, + FLAG_DISABLE_IF_NO_ENCRYPTION_CAPABILITIES); + if ("true".equals(encryptionAttribute)) { + mRequiredTransportFlags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED; + } + } + } + @VisibleForTesting public void parseBackupSchemeFromXmlLocked(XmlPullParser parser, Set excludes, diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java index 139c8e59a148e..63edc776b3cbe 100644 --- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java @@ -165,6 +165,9 @@ public class LocalTransport extends BackupTransport { if (mParameters.isDeviceTransfer()) { flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER; } + if (mParameters.isEncrypted()) { + flags |= BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED; + } return flags; } diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java index 2946db3cdcf0c..1ba1bc6bfec75 100644 --- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java @@ -28,10 +28,12 @@ public class LocalTransportParameters extends KeyValueSettingObserver { private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag"; private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only"; private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer"; + private static final String KEY_IS_ENCRYPTED = "is_encrypted"; private boolean mFakeEncryptionFlag; private boolean mIsNonIncrementalOnly; private boolean mIsDeviceTransfer; + private boolean mIsEncrypted; public LocalTransportParameters(Handler handler, ContentResolver resolver) { super(handler, resolver, Settings.Secure.getUriFor(SETTING)); @@ -49,6 +51,10 @@ public class LocalTransportParameters extends KeyValueSettingObserver { return mIsDeviceTransfer; } + boolean isEncrypted() { + return mIsEncrypted; + } + public String getSettingValue(ContentResolver resolver) { return Settings.Secure.getString(resolver, SETTING); } @@ -57,5 +63,6 @@ public class LocalTransportParameters extends KeyValueSettingObserver { mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false); mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false); + mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false); } }