Loading core/java/android/app/backup/FullBackup.java +100 −18 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -468,32 +484,96 @@ 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 Loading @@ -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); } Loading Loading @@ -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); Loading packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java +7 −0 Original line number Diff line number Diff line Loading @@ -27,9 +27,11 @@ public class LocalTransportParameters extends KeyValueSettingObserver { 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_NON_INCREMENTAL_ONLY = "non_incremental_only"; private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer"; private boolean mFakeEncryptionFlag; private boolean mIsNonIncrementalOnly; private boolean mIsDeviceTransfer; public LocalTransportParameters(Handler handler, ContentResolver resolver) { super(handler, resolver, Settings.Secure.getUriFor(SETTING)); Loading @@ -43,6 +45,10 @@ public class LocalTransportParameters extends KeyValueSettingObserver { return mIsNonIncrementalOnly; } boolean isDeviceTransfer() { return mIsDeviceTransfer; } public String getSettingValue(ContentResolver resolver) { return Settings.Secure.getString(resolver, SETTING); } Loading @@ -50,5 +56,6 @@ public class LocalTransportParameters extends KeyValueSettingObserver { public void update(KeyValueListParser parser) { mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false); mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false); } } Loading
core/java/android/app/backup/FullBackup.java +100 −18 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -468,32 +484,96 @@ 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 Loading @@ -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); } Loading Loading @@ -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); Loading
packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java +7 −0 Original line number Diff line number Diff line Loading @@ -27,9 +27,11 @@ public class LocalTransportParameters extends KeyValueSettingObserver { 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_NON_INCREMENTAL_ONLY = "non_incremental_only"; private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer"; private boolean mFakeEncryptionFlag; private boolean mIsNonIncrementalOnly; private boolean mIsDeviceTransfer; public LocalTransportParameters(Handler handler, ContentResolver resolver) { super(handler, resolver, Settings.Secure.getUriFor(SETTING)); Loading @@ -43,6 +45,10 @@ public class LocalTransportParameters extends KeyValueSettingObserver { return mIsNonIncrementalOnly; } boolean isDeviceTransfer() { return mIsDeviceTransfer; } public String getSettingValue(ContentResolver resolver) { return Settings.Secure.getString(resolver, SETTING); } Loading @@ -50,5 +56,6 @@ public class LocalTransportParameters extends KeyValueSettingObserver { public void update(KeyValueListParser parser) { mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false); mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false); } }