Merge "Parse include / exclude config specified by dataExtractionRules" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c3bf79a2cd
@@ -19,8 +19,10 @@ package android.app.backup;
|
|||||||
import static android.app.backup.BackupManager.OperationType;
|
import static android.app.backup.BackupManager.OperationType;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.StringDef;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.XmlResourceParser;
|
import android.content.res.XmlResourceParser;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
@@ -33,6 +35,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
@@ -93,6 +96,15 @@ public class FullBackup {
|
|||||||
public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
|
public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
|
||||||
"fakeClientSideEncryption";
|
"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
|
* Identify {@link BackupScheme} object by package and operation type
|
||||||
* (see {@link OperationType}) it corresponds to.
|
* (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_INCLUDE = "include";
|
||||||
private final static String TAG_EXCLUDE = "exclude";
|
private final static String TAG_EXCLUDE = "exclude";
|
||||||
|
|
||||||
|
final int mDataExtractionRules;
|
||||||
final int mFullBackupContent;
|
final int mFullBackupContent;
|
||||||
@OperationType final int mOperationType;
|
@OperationType final int mOperationType;
|
||||||
final PackageManager mPackageManager;
|
final PackageManager mPackageManager;
|
||||||
@@ -394,7 +407,10 @@ public class FullBackup {
|
|||||||
ArraySet<PathWithRequiredFlags> mExcludes;
|
ArraySet<PathWithRequiredFlags> mExcludes;
|
||||||
|
|
||||||
BackupScheme(Context context, @OperationType int operationType) {
|
BackupScheme(Context context, @OperationType int operationType) {
|
||||||
mFullBackupContent = context.getApplicationInfo().fullBackupContent;
|
ApplicationInfo applicationInfo = context.getApplicationInfo();
|
||||||
|
|
||||||
|
mDataExtractionRules = applicationInfo.dataExtractionRulesRes;
|
||||||
|
mFullBackupContent = applicationInfo.fullBackupContent;
|
||||||
mOperationType = operationType;
|
mOperationType = operationType;
|
||||||
mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||||
mPackageManager = context.getPackageManager();
|
mPackageManager = context.getPackageManager();
|
||||||
@@ -468,34 +484,98 @@ public class FullBackup {
|
|||||||
mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
|
mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
|
||||||
mExcludes = new ArraySet<PathWithRequiredFlags>();
|
mExcludes = new ArraySet<PathWithRequiredFlags>();
|
||||||
|
|
||||||
if (mFullBackupContent == 0) {
|
if (mFullBackupContent == 0 && mDataExtractionRules == 0) {
|
||||||
// android:fullBackupContent="true" which means that we'll do everything.
|
// No scheme specified via either new or legacy config, will copy everything.
|
||||||
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
|
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
|
||||||
Log.v(FullBackup.TAG_XML_PARSER, "android:fullBackupContent - \"true\"");
|
Log.v(FullBackup.TAG_XML_PARSER, "android:fullBackupContent - \"true\"");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// android:fullBackupContent="@xml/some_resource".
|
// Scheme is present.
|
||||||
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
|
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
|
||||||
Log.v(FullBackup.TAG_XML_PARSER,
|
Log.v(FullBackup.TAG_XML_PARSER, "Found xml scheme: "
|
||||||
"android:fullBackupContent - found xml resource");
|
+ "android:fullBackupContent=" + mFullBackupContent
|
||||||
|
+ "; android:dataExtractionRules=" + mDataExtractionRules);
|
||||||
}
|
}
|
||||||
XmlResourceParser parser = null;
|
|
||||||
try {
|
try {
|
||||||
parser = mPackageManager
|
parseSchemeForOperationType(mOperationType);
|
||||||
.getResourcesForApplication(mPackageName)
|
|
||||||
.getXml(mFullBackupContent);
|
|
||||||
parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
// Throw it as an IOException
|
// Throw it as an IOException
|
||||||
throw new IOException(e);
|
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
|
@VisibleForTesting
|
||||||
public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
|
public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
|
||||||
Set<PathWithRequiredFlags> excludes,
|
Set<PathWithRequiredFlags> excludes,
|
||||||
@@ -503,7 +583,7 @@ public class FullBackup {
|
|||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException {
|
||||||
verifyTopLevelTag(parser, "full-backup-content");
|
verifyTopLevelTag(parser, "full-backup-content");
|
||||||
|
|
||||||
parseRules(parser, excludes, includes, Optional.empty());
|
parseRules(parser, excludes, includes, Optional.empty(), "full-backup-content");
|
||||||
|
|
||||||
logParsingResults(excludes, includes);
|
logParsingResults(excludes, includes);
|
||||||
}
|
}
|
||||||
@@ -532,10 +612,12 @@ public class FullBackup {
|
|||||||
private void parseRules(XmlPullParser parser,
|
private void parseRules(XmlPullParser parser,
|
||||||
Set<PathWithRequiredFlags> excludes,
|
Set<PathWithRequiredFlags> excludes,
|
||||||
Map<String, Set<PathWithRequiredFlags>> includes,
|
Map<String, Set<PathWithRequiredFlags>> includes,
|
||||||
Optional<Integer> maybeRequiredFlags)
|
Optional<Integer> maybeRequiredFlags,
|
||||||
|
String endingTag)
|
||||||
throws IOException, XmlPullParserException {
|
throws IOException, XmlPullParserException {
|
||||||
int event;
|
int event;
|
||||||
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||||
|
&& !parser.getName().equals(endingTag)) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case XmlPullParser.START_TAG:
|
case XmlPullParser.START_TAG:
|
||||||
validateInnerTagContents(parser);
|
validateInnerTagContents(parser);
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
|
|||||||
private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
|
private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
|
||||||
private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
|
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_NON_INCREMENTAL_ONLY = "non_incremental_only";
|
||||||
|
private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
|
||||||
|
|
||||||
private boolean mFakeEncryptionFlag;
|
private boolean mFakeEncryptionFlag;
|
||||||
private boolean mIsNonIncrementalOnly;
|
private boolean mIsNonIncrementalOnly;
|
||||||
|
private boolean mIsDeviceTransfer;
|
||||||
|
|
||||||
public LocalTransportParameters(Handler handler, ContentResolver resolver) {
|
public LocalTransportParameters(Handler handler, ContentResolver resolver) {
|
||||||
super(handler, resolver, Settings.Secure.getUriFor(SETTING));
|
super(handler, resolver, Settings.Secure.getUriFor(SETTING));
|
||||||
@@ -43,6 +45,10 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
|
|||||||
return mIsNonIncrementalOnly;
|
return mIsNonIncrementalOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isDeviceTransfer() {
|
||||||
|
return mIsDeviceTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
public String getSettingValue(ContentResolver resolver) {
|
public String getSettingValue(ContentResolver resolver) {
|
||||||
return Settings.Secure.getString(resolver, SETTING);
|
return Settings.Secure.getString(resolver, SETTING);
|
||||||
}
|
}
|
||||||
@@ -50,5 +56,6 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
|
|||||||
public void update(KeyValueListParser parser) {
|
public void update(KeyValueListParser parser) {
|
||||||
mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
|
mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
|
||||||
mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
|
mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
|
||||||
|
mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user