summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorRuslan Tkhakokhov <rthakohov@google.com>2021-02-24 23:20:54 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-02-24 23:20:54 +0000
commitc3bf79a2cd92634cc18a2983e63b5f5c9193cdfd (patch)
tree156baab0bb8b2b9d7c3522b9457f605ebea136c3 /core/java/android
parentf7bc904f444b6b7286454220213a91dc9ead1821 (diff)
parent6751d29041620384e8384d60cc245c64e1b82c20 (diff)
Merge "Parse include / exclude config specified by dataExtractionRules" into sc-dev
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/backup/FullBackup.java118
1 files changed, 100 insertions, 18 deletions
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index f7ed6f1f2feb..3701ea825933 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -19,8 +19,10 @@ package android.app.backup;
import static android.app.backup.BackupManager.OperationType;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.os.ParcelFileDescriptor;
@@ -33,6 +35,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -93,6 +96,15 @@ public class FullBackup {
public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
"fakeClientSideEncryption";
+ @StringDef({
+ ConfigSection.CLOUD_BACKUP,
+ ConfigSection.DEVICE_TRANSFER
+ })
+ private @interface ConfigSection {
+ String CLOUD_BACKUP = "cloud-backup";
+ String DEVICE_TRANSFER = "device-transfer";
+ }
+
/**
* Identify {@link BackupScheme} object by package and operation type
* (see {@link OperationType}) it corresponds to.
@@ -273,6 +285,7 @@ public class FullBackup {
private final static String TAG_INCLUDE = "include";
private final static String TAG_EXCLUDE = "exclude";
+ final int mDataExtractionRules;
final int mFullBackupContent;
@OperationType final int mOperationType;
final PackageManager mPackageManager;
@@ -394,7 +407,10 @@ public class FullBackup {
ArraySet<PathWithRequiredFlags> mExcludes;
BackupScheme(Context context, @OperationType int operationType) {
- mFullBackupContent = context.getApplicationInfo().fullBackupContent;
+ ApplicationInfo applicationInfo = context.getApplicationInfo();
+
+ mDataExtractionRules = applicationInfo.dataExtractionRulesRes;
+ mFullBackupContent = applicationInfo.fullBackupContent;
mOperationType = operationType;
mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
mPackageManager = context.getPackageManager();
@@ -468,34 +484,98 @@ public class FullBackup {
mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
mExcludes = new ArraySet<PathWithRequiredFlags>();
- if (mFullBackupContent == 0) {
- // android:fullBackupContent="true" which means that we'll do everything.
+ if (mFullBackupContent == 0 && mDataExtractionRules == 0) {
+ // No scheme specified via either new or legacy config, will copy everything.
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(FullBackup.TAG_XML_PARSER, "android:fullBackupContent - \"true\"");
}
} else {
- // android:fullBackupContent="@xml/some_resource".
+ // Scheme is present.
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
- Log.v(FullBackup.TAG_XML_PARSER,
- "android:fullBackupContent - found xml resource");
+ Log.v(FullBackup.TAG_XML_PARSER, "Found xml scheme: "
+ + "android:fullBackupContent=" + mFullBackupContent
+ + "; android:dataExtractionRules=" + mDataExtractionRules);
}
- XmlResourceParser parser = null;
+
try {
- parser = mPackageManager
- .getResourcesForApplication(mPackageName)
- .getXml(mFullBackupContent);
- parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
+ parseSchemeForOperationType(mOperationType);
} catch (PackageManager.NameNotFoundException e) {
// Throw it as an IOException
throw new IOException(e);
- } finally {
- if (parser != null) {
- parser.close();
- }
}
}
}
+ private void parseSchemeForOperationType(@OperationType int operationType)
+ throws PackageManager.NameNotFoundException, IOException, XmlPullParserException {
+ String configSection = getConfigSectionForOperationType(operationType);
+ if (configSection == null) {
+ Slog.w(TAG, "Given operation type isn't supported by backup scheme: "
+ + operationType);
+ return;
+ }
+
+ if (mDataExtractionRules != 0) {
+ // New config is present. Use it if it has configuration for this operation
+ // type.
+ try (XmlResourceParser parser = getParserForResource(mDataExtractionRules)) {
+ parseNewBackupSchemeFromXmlLocked(parser, configSection, mExcludes, mIncludes);
+ }
+ if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
+ // Found configuration in the new config, we will use it.
+ return;
+ }
+ }
+
+ // TODO(b/180523564): Ignore the old config for apps targeting Android S+ during D2D.
+
+ if (mFullBackupContent != 0) {
+ // Fall back to the old config.
+ try (XmlResourceParser parser = getParserForResource(mFullBackupContent)) {
+ parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
+ }
+ }
+ }
+
+ @Nullable
+ private String getConfigSectionForOperationType(@OperationType int operationType) {
+ switch (operationType) {
+ case OperationType.BACKUP:
+ return ConfigSection.CLOUD_BACKUP;
+ case OperationType.MIGRATION:
+ return ConfigSection.DEVICE_TRANSFER;
+ default:
+ return null;
+ }
+ }
+
+ private XmlResourceParser getParserForResource(int resourceId)
+ throws PackageManager.NameNotFoundException {
+ return mPackageManager
+ .getResourcesForApplication(mPackageName)
+ .getXml(resourceId);
+ }
+
+ private void parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
+ @ConfigSection String configSection,
+ Set<PathWithRequiredFlags> excludes,
+ Map<String, Set<PathWithRequiredFlags>> includes)
+ throws IOException, XmlPullParserException {
+ verifyTopLevelTag(parser, "data-extraction-rules");
+
+ int event;
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (event != XmlPullParser.START_TAG || !configSection.equals(parser.getName())) {
+ continue;
+ }
+
+ // TODO(b/180523028): Parse required attributes for rules (e.g. encryption).
+ parseRules(parser, excludes, includes, Optional.of(0), configSection);
+ }
+
+ logParsingResults(excludes, includes);
+ }
+
@VisibleForTesting
public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
Set<PathWithRequiredFlags> excludes,
@@ -503,7 +583,7 @@ public class FullBackup {
throws IOException, XmlPullParserException {
verifyTopLevelTag(parser, "full-backup-content");
- parseRules(parser, excludes, includes, Optional.empty());
+ parseRules(parser, excludes, includes, Optional.empty(), "full-backup-content");
logParsingResults(excludes, includes);
}
@@ -532,10 +612,12 @@ public class FullBackup {
private void parseRules(XmlPullParser parser,
Set<PathWithRequiredFlags> excludes,
Map<String, Set<PathWithRequiredFlags>> includes,
- Optional<Integer> maybeRequiredFlags)
+ Optional<Integer> maybeRequiredFlags,
+ String endingTag)
throws IOException, XmlPullParserException {
int event;
- while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
+ && !parser.getName().equals(endingTag)) {
switch (event) {
case XmlPullParser.START_TAG:
validateInnerTagContents(parser);