Loading core/java/android/app/ActivityThread.java +25 −8 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.annotation.Nullable; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; import android.app.backup.BackupManager; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; import android.app.servertransaction.ActivityRelaunchItem; Loading Loading @@ -289,6 +290,8 @@ public final class ActivityThread extends ClientTransactionHandler { private final Object mNetworkPolicyLock = new Object(); private static final String DEFAULT_FULL_BACKUP_AGENT = "android.app.backup.FullBackupAgent"; /** * Denotes the sequence number of the process state change for which the main thread needs * to block until the network rules are updated for it. Loading Loading @@ -737,6 +740,7 @@ public final class ActivityThread extends ClientTransactionHandler { CompatibilityInfo compatInfo; int backupMode; int userId; int operationType; public String toString() { return "CreateBackupAgentData{appInfo=" + appInfo + " backupAgent=" + appInfo.backupAgentName Loading Loading @@ -957,12 +961,13 @@ public final class ActivityThread extends ClientTransactionHandler { } public final void scheduleCreateBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo, int backupMode, int userId) { CompatibilityInfo compatInfo, int backupMode, int userId, int operationType) { CreateBackupAgentData d = new CreateBackupAgentData(); d.appInfo = app; d.compatInfo = compatInfo; d.backupMode = backupMode; d.userId = userId; d.operationType = operationType; sendMessage(H.CREATE_BACKUP_AGENT, d); } Loading Loading @@ -4075,12 +4080,7 @@ public final class ActivityThread extends ClientTransactionHandler { return; } String classname = data.appInfo.backupAgentName; // full backup operation but no app-supplied agent? use the default implementation if (classname == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) { classname = "android.app.backup.FullBackupAgent"; } String classname = getBackupAgentName(data); try { IBinder binder = null; Loading @@ -4104,7 +4104,7 @@ public final class ActivityThread extends ClientTransactionHandler { context.setOuterContext(agent); agent.attach(context); agent.onCreate(UserHandle.of(data.userId)); agent.onCreate(UserHandle.of(data.userId), data.operationType); binder = agent.onBind(); backupAgents.put(packageName, agent); } catch (Exception e) { Loading Loading @@ -4132,6 +4132,23 @@ public final class ActivityThread extends ClientTransactionHandler { } } private String getBackupAgentName(CreateBackupAgentData data) { String agentName = data.appInfo.backupAgentName; if (!UserHandle.isCore(data.appInfo.uid) && data.operationType == BackupManager.OperationType.MIGRATION) { // If this is a migration, use the default backup agent regardless of the app's // preferences. agentName = DEFAULT_FULL_BACKUP_AGENT; } else { // full backup operation but no app-supplied agent? use the default implementation if (agentName == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) { agentName = DEFAULT_FULL_BACKUP_AGENT; } } return agentName; } // Tear down a BackupAgent private void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); Loading core/java/android/app/IActivityManager.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -288,7 +288,8 @@ interface IActivityManager { void stopAppSwitches(); @UnsupportedAppUsage void resumeAppSwitches(); boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId); boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId, int operationType); void backupAgentCreated(in String packageName, in IBinder agent, int userId); void unbindBackupAgent(in ApplicationInfo appInfo); int getUidForIntentSender(in IIntentSender sender); Loading core/java/android/app/IApplicationThread.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -95,7 +95,7 @@ oneway interface IApplicationThread { void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType); void setSchedulingGroup(int group); void scheduleCreateBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, int backupMode, int userId); int backupMode, int userId, int operationType); void scheduleDestroyBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, int userId); void scheduleOnNewActivityOptions(IBinder token, in Bundle options); Loading core/java/android/app/backup/BackupAgent.java +93 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.app.backup; import android.annotation.Nullable; import android.app.IBackupAgent; import android.app.QueuedWork; import android.app.backup.BackupManager.OperationType; import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; import android.content.Context; import android.content.ContextWrapper; Loading @@ -38,6 +39,8 @@ import android.system.StructStat; import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParserException; Loading @@ -50,6 +53,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; Loading Loading @@ -129,6 +133,7 @@ import java.util.concurrent.CountDownLatch; public abstract class BackupAgent extends ContextWrapper { private static final String TAG = "BackupAgent"; private static final boolean DEBUG = false; private static final int DEFAULT_OPERATION_TYPE = OperationType.BACKUP; /** @hide */ public static final int RESULT_SUCCESS = 0; Loading Loading @@ -186,6 +191,9 @@ public abstract class BackupAgent extends ContextWrapper { Handler mHandler = null; @Nullable private UserHandle mUser; // This field is written from the main thread (in onCreate), and read in a Binder thread (in // onFullBackup that is called from system_server via Binder). @OperationType private volatile int mOperationType = DEFAULT_OPERATION_TYPE; Handler getHandler() { if (mHandler == null) { Loading Loading @@ -228,6 +236,13 @@ public abstract class BackupAgent extends ContextWrapper { public void onCreate() { } /** * @hide */ public void onCreate(UserHandle user) { onCreate(user, DEFAULT_OPERATION_TYPE); } /** * Provided as a convenience for agent implementations that need an opportunity * to do one-time initialization before the actual backup or restore operation Loading @@ -236,10 +251,11 @@ public abstract class BackupAgent extends ContextWrapper { * * @hide */ public void onCreate(UserHandle user) { public void onCreate(UserHandle user, @OperationType int operationType) { onCreate(); mUser = user; mOperationType = operationType; } /** Loading Loading @@ -390,12 +406,9 @@ public abstract class BackupAgent extends ContextWrapper { return; } Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap; ArraySet<PathWithRequiredFlags> manifestExcludeSet; IncludeExcludeRules includeExcludeRules; try { manifestIncludeMap = backupScheme.maybeParseAndGetCanonicalIncludePaths(); manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths(); includeExcludeRules = getIncludeExcludeRules(backupScheme); } catch (IOException | XmlPullParserException e) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { Log.v(FullBackup.TAG_XML_PARSER, Loading @@ -404,6 +417,10 @@ public abstract class BackupAgent extends ContextWrapper { } return; } Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap = includeExcludeRules.getIncludeMap(); Set<PathWithRequiredFlags> manifestExcludeSet = includeExcludeRules.getExcludeSet(); final String packageName = getPackageName(); final ApplicationInfo appInfo = getApplicationInfo(); Loading Loading @@ -528,6 +545,24 @@ public abstract class BackupAgent extends ContextWrapper { } } /** @hide */ @VisibleForTesting public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme) throws IOException, XmlPullParserException { if (mOperationType == OperationType.MIGRATION) { return IncludeExcludeRules.emptyRules(); } Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap; ArraySet<PathWithRequiredFlags> manifestExcludeSet; manifestIncludeMap = backupScheme.maybeParseAndGetCanonicalIncludePaths(); manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths(); return new IncludeExcludeRules(manifestIncludeMap, manifestExcludeSet); } /** * Notification that the application's current backup operation causes it to exceed * the maximum size permitted by the transport. The ongoing backup operation is Loading Loading @@ -570,7 +605,7 @@ public abstract class BackupAgent extends ContextWrapper { */ private void applyXmlFiltersAndDoFullBackupForDomain(String packageName, String domainToken, Map<String, Set<PathWithRequiredFlags>> includeMap, ArraySet<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet, Set<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet, FullBackupDataOutput data) throws IOException { if (includeMap == null || includeMap.size() == 0) { // Do entire sub-tree for the provided token. Loading Loading @@ -742,7 +777,7 @@ public abstract class BackupAgent extends ContextWrapper { * @hide */ protected final void fullBackupFileTree(String packageName, String domain, String startingPath, ArraySet<PathWithRequiredFlags> manifestExcludes, Set<PathWithRequiredFlags> manifestExcludes, ArraySet<String> systemExcludes, FullBackupDataOutput output) { // Pull out the domain and set it aside to use when making the tarball. Loading Loading @@ -811,7 +846,7 @@ public abstract class BackupAgent extends ContextWrapper { } private boolean manifestExcludesContainFilePath( ArraySet<PathWithRequiredFlags> manifestExcludes, String filePath) { Set<PathWithRequiredFlags> manifestExcludes, String filePath) { for (PathWithRequiredFlags exclude : manifestExcludes) { String excludePath = exclude.getPath(); if (excludePath != null && excludePath.equals(filePath)) { Loading Loading @@ -1265,4 +1300,53 @@ public abstract class BackupAgent extends ContextWrapper { throw new IllegalStateException(mMessage); } } /** @hide */ @VisibleForTesting public static class IncludeExcludeRules { private final Map<String, Set<PathWithRequiredFlags>> mManifestIncludeMap; private final Set<PathWithRequiredFlags> mManifestExcludeSet; /** @hide */ public IncludeExcludeRules( Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap, Set<PathWithRequiredFlags> manifestExcludeSet) { mManifestIncludeMap = manifestIncludeMap; mManifestExcludeSet = manifestExcludeSet; } /** @hide */ @VisibleForTesting public static IncludeExcludeRules emptyRules() { return new IncludeExcludeRules(Collections.emptyMap(), new ArraySet<>()); } private Map<String, Set<PathWithRequiredFlags>> getIncludeMap() { return mManifestIncludeMap; } private Set<PathWithRequiredFlags> getExcludeSet() { return mManifestExcludeSet; } /** @hide */ @Override public int hashCode() { return Objects.hash(mManifestIncludeMap, mManifestExcludeSet); } /** @hide */ @Override public boolean equals(Object object) { if (this == object) { return true; } if (object == null || getClass() != object.getClass()) { return false; } IncludeExcludeRules that = (IncludeExcludeRules) object; return Objects.equals(mManifestIncludeMap, that.mManifestIncludeMap) && Objects.equals(mManifestExcludeSet, that.mManifestExcludeSet); } } } core/tests/coretests/src/android/app/backup/BackupAgentTest.java 0 → 100644 +104 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.backup; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; import android.app.backup.BackupAgent.IncludeExcludeRules; import android.app.backup.BackupManager.OperationType; import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.Set; @Presubmit @RunWith(AndroidJUnit4.class) public class BackupAgentTest { // An arbitrary user. private static final UserHandle USER_HANDLE = new UserHandle(15); @Mock FullBackup.BackupScheme mBackupScheme; private BackupAgent mBackupAgent; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testGetIncludeExcludeRules_isMigration_returnsEmptyRules() throws Exception { mBackupAgent = getAgentForOperationType(OperationType.MIGRATION); IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme); assertThat(rules).isEqualTo(IncludeExcludeRules.emptyRules()); } @Test public void testGetIncludeExcludeRules_isNotMigration_returnsRules() throws Exception { PathWithRequiredFlags path = new PathWithRequiredFlags("path", /* requiredFlags */ 0); Map<String, Set<PathWithRequiredFlags>> includePaths = Collections.singletonMap("test", Collections.singleton(path)); ArraySet<PathWithRequiredFlags> excludePaths = new ArraySet<>(); excludePaths.add(path); IncludeExcludeRules expectedRules = new IncludeExcludeRules(includePaths, excludePaths); mBackupAgent = getAgentForOperationType(OperationType.BACKUP); when(mBackupScheme.maybeParseAndGetCanonicalExcludePaths()).thenReturn(excludePaths); when(mBackupScheme.maybeParseAndGetCanonicalIncludePaths()).thenReturn(includePaths); IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme); assertThat(rules).isEqualTo(expectedRules); } private BackupAgent getAgentForOperationType(@OperationType int operationType) { BackupAgent agent = new TestFullBackupAgent(); agent.onCreate(USER_HANDLE, operationType); return agent; } private static class TestFullBackupAgent extends BackupAgent { @Override public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException { // Left empty as this is a full backup agent. } @Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { // Left empty as this is a full backup agent. } } } Loading
core/java/android/app/ActivityThread.java +25 −8 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.annotation.Nullable; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; import android.app.backup.BackupManager; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; import android.app.servertransaction.ActivityRelaunchItem; Loading Loading @@ -289,6 +290,8 @@ public final class ActivityThread extends ClientTransactionHandler { private final Object mNetworkPolicyLock = new Object(); private static final String DEFAULT_FULL_BACKUP_AGENT = "android.app.backup.FullBackupAgent"; /** * Denotes the sequence number of the process state change for which the main thread needs * to block until the network rules are updated for it. Loading Loading @@ -737,6 +740,7 @@ public final class ActivityThread extends ClientTransactionHandler { CompatibilityInfo compatInfo; int backupMode; int userId; int operationType; public String toString() { return "CreateBackupAgentData{appInfo=" + appInfo + " backupAgent=" + appInfo.backupAgentName Loading Loading @@ -957,12 +961,13 @@ public final class ActivityThread extends ClientTransactionHandler { } public final void scheduleCreateBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo, int backupMode, int userId) { CompatibilityInfo compatInfo, int backupMode, int userId, int operationType) { CreateBackupAgentData d = new CreateBackupAgentData(); d.appInfo = app; d.compatInfo = compatInfo; d.backupMode = backupMode; d.userId = userId; d.operationType = operationType; sendMessage(H.CREATE_BACKUP_AGENT, d); } Loading Loading @@ -4075,12 +4080,7 @@ public final class ActivityThread extends ClientTransactionHandler { return; } String classname = data.appInfo.backupAgentName; // full backup operation but no app-supplied agent? use the default implementation if (classname == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) { classname = "android.app.backup.FullBackupAgent"; } String classname = getBackupAgentName(data); try { IBinder binder = null; Loading @@ -4104,7 +4104,7 @@ public final class ActivityThread extends ClientTransactionHandler { context.setOuterContext(agent); agent.attach(context); agent.onCreate(UserHandle.of(data.userId)); agent.onCreate(UserHandle.of(data.userId), data.operationType); binder = agent.onBind(); backupAgents.put(packageName, agent); } catch (Exception e) { Loading Loading @@ -4132,6 +4132,23 @@ public final class ActivityThread extends ClientTransactionHandler { } } private String getBackupAgentName(CreateBackupAgentData data) { String agentName = data.appInfo.backupAgentName; if (!UserHandle.isCore(data.appInfo.uid) && data.operationType == BackupManager.OperationType.MIGRATION) { // If this is a migration, use the default backup agent regardless of the app's // preferences. agentName = DEFAULT_FULL_BACKUP_AGENT; } else { // full backup operation but no app-supplied agent? use the default implementation if (agentName == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) { agentName = DEFAULT_FULL_BACKUP_AGENT; } } return agentName; } // Tear down a BackupAgent private void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); Loading
core/java/android/app/IActivityManager.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -288,7 +288,8 @@ interface IActivityManager { void stopAppSwitches(); @UnsupportedAppUsage void resumeAppSwitches(); boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId); boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId, int operationType); void backupAgentCreated(in String packageName, in IBinder agent, int userId); void unbindBackupAgent(in ApplicationInfo appInfo); int getUidForIntentSender(in IIntentSender sender); Loading
core/java/android/app/IApplicationThread.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -95,7 +95,7 @@ oneway interface IApplicationThread { void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType); void setSchedulingGroup(int group); void scheduleCreateBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, int backupMode, int userId); int backupMode, int userId, int operationType); void scheduleDestroyBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, int userId); void scheduleOnNewActivityOptions(IBinder token, in Bundle options); Loading
core/java/android/app/backup/BackupAgent.java +93 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.app.backup; import android.annotation.Nullable; import android.app.IBackupAgent; import android.app.QueuedWork; import android.app.backup.BackupManager.OperationType; import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; import android.content.Context; import android.content.ContextWrapper; Loading @@ -38,6 +39,8 @@ import android.system.StructStat; import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParserException; Loading @@ -50,6 +53,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; Loading Loading @@ -129,6 +133,7 @@ import java.util.concurrent.CountDownLatch; public abstract class BackupAgent extends ContextWrapper { private static final String TAG = "BackupAgent"; private static final boolean DEBUG = false; private static final int DEFAULT_OPERATION_TYPE = OperationType.BACKUP; /** @hide */ public static final int RESULT_SUCCESS = 0; Loading Loading @@ -186,6 +191,9 @@ public abstract class BackupAgent extends ContextWrapper { Handler mHandler = null; @Nullable private UserHandle mUser; // This field is written from the main thread (in onCreate), and read in a Binder thread (in // onFullBackup that is called from system_server via Binder). @OperationType private volatile int mOperationType = DEFAULT_OPERATION_TYPE; Handler getHandler() { if (mHandler == null) { Loading Loading @@ -228,6 +236,13 @@ public abstract class BackupAgent extends ContextWrapper { public void onCreate() { } /** * @hide */ public void onCreate(UserHandle user) { onCreate(user, DEFAULT_OPERATION_TYPE); } /** * Provided as a convenience for agent implementations that need an opportunity * to do one-time initialization before the actual backup or restore operation Loading @@ -236,10 +251,11 @@ public abstract class BackupAgent extends ContextWrapper { * * @hide */ public void onCreate(UserHandle user) { public void onCreate(UserHandle user, @OperationType int operationType) { onCreate(); mUser = user; mOperationType = operationType; } /** Loading Loading @@ -390,12 +406,9 @@ public abstract class BackupAgent extends ContextWrapper { return; } Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap; ArraySet<PathWithRequiredFlags> manifestExcludeSet; IncludeExcludeRules includeExcludeRules; try { manifestIncludeMap = backupScheme.maybeParseAndGetCanonicalIncludePaths(); manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths(); includeExcludeRules = getIncludeExcludeRules(backupScheme); } catch (IOException | XmlPullParserException e) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { Log.v(FullBackup.TAG_XML_PARSER, Loading @@ -404,6 +417,10 @@ public abstract class BackupAgent extends ContextWrapper { } return; } Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap = includeExcludeRules.getIncludeMap(); Set<PathWithRequiredFlags> manifestExcludeSet = includeExcludeRules.getExcludeSet(); final String packageName = getPackageName(); final ApplicationInfo appInfo = getApplicationInfo(); Loading Loading @@ -528,6 +545,24 @@ public abstract class BackupAgent extends ContextWrapper { } } /** @hide */ @VisibleForTesting public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme) throws IOException, XmlPullParserException { if (mOperationType == OperationType.MIGRATION) { return IncludeExcludeRules.emptyRules(); } Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap; ArraySet<PathWithRequiredFlags> manifestExcludeSet; manifestIncludeMap = backupScheme.maybeParseAndGetCanonicalIncludePaths(); manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths(); return new IncludeExcludeRules(manifestIncludeMap, manifestExcludeSet); } /** * Notification that the application's current backup operation causes it to exceed * the maximum size permitted by the transport. The ongoing backup operation is Loading Loading @@ -570,7 +605,7 @@ public abstract class BackupAgent extends ContextWrapper { */ private void applyXmlFiltersAndDoFullBackupForDomain(String packageName, String domainToken, Map<String, Set<PathWithRequiredFlags>> includeMap, ArraySet<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet, Set<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet, FullBackupDataOutput data) throws IOException { if (includeMap == null || includeMap.size() == 0) { // Do entire sub-tree for the provided token. Loading Loading @@ -742,7 +777,7 @@ public abstract class BackupAgent extends ContextWrapper { * @hide */ protected final void fullBackupFileTree(String packageName, String domain, String startingPath, ArraySet<PathWithRequiredFlags> manifestExcludes, Set<PathWithRequiredFlags> manifestExcludes, ArraySet<String> systemExcludes, FullBackupDataOutput output) { // Pull out the domain and set it aside to use when making the tarball. Loading Loading @@ -811,7 +846,7 @@ public abstract class BackupAgent extends ContextWrapper { } private boolean manifestExcludesContainFilePath( ArraySet<PathWithRequiredFlags> manifestExcludes, String filePath) { Set<PathWithRequiredFlags> manifestExcludes, String filePath) { for (PathWithRequiredFlags exclude : manifestExcludes) { String excludePath = exclude.getPath(); if (excludePath != null && excludePath.equals(filePath)) { Loading Loading @@ -1265,4 +1300,53 @@ public abstract class BackupAgent extends ContextWrapper { throw new IllegalStateException(mMessage); } } /** @hide */ @VisibleForTesting public static class IncludeExcludeRules { private final Map<String, Set<PathWithRequiredFlags>> mManifestIncludeMap; private final Set<PathWithRequiredFlags> mManifestExcludeSet; /** @hide */ public IncludeExcludeRules( Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap, Set<PathWithRequiredFlags> manifestExcludeSet) { mManifestIncludeMap = manifestIncludeMap; mManifestExcludeSet = manifestExcludeSet; } /** @hide */ @VisibleForTesting public static IncludeExcludeRules emptyRules() { return new IncludeExcludeRules(Collections.emptyMap(), new ArraySet<>()); } private Map<String, Set<PathWithRequiredFlags>> getIncludeMap() { return mManifestIncludeMap; } private Set<PathWithRequiredFlags> getExcludeSet() { return mManifestExcludeSet; } /** @hide */ @Override public int hashCode() { return Objects.hash(mManifestIncludeMap, mManifestExcludeSet); } /** @hide */ @Override public boolean equals(Object object) { if (this == object) { return true; } if (object == null || getClass() != object.getClass()) { return false; } IncludeExcludeRules that = (IncludeExcludeRules) object; return Objects.equals(mManifestIncludeMap, that.mManifestIncludeMap) && Objects.equals(mManifestExcludeSet, that.mManifestExcludeSet); } } }
core/tests/coretests/src/android/app/backup/BackupAgentTest.java 0 → 100644 +104 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.backup; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; import android.app.backup.BackupAgent.IncludeExcludeRules; import android.app.backup.BackupManager.OperationType; import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.Set; @Presubmit @RunWith(AndroidJUnit4.class) public class BackupAgentTest { // An arbitrary user. private static final UserHandle USER_HANDLE = new UserHandle(15); @Mock FullBackup.BackupScheme mBackupScheme; private BackupAgent mBackupAgent; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testGetIncludeExcludeRules_isMigration_returnsEmptyRules() throws Exception { mBackupAgent = getAgentForOperationType(OperationType.MIGRATION); IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme); assertThat(rules).isEqualTo(IncludeExcludeRules.emptyRules()); } @Test public void testGetIncludeExcludeRules_isNotMigration_returnsRules() throws Exception { PathWithRequiredFlags path = new PathWithRequiredFlags("path", /* requiredFlags */ 0); Map<String, Set<PathWithRequiredFlags>> includePaths = Collections.singletonMap("test", Collections.singleton(path)); ArraySet<PathWithRequiredFlags> excludePaths = new ArraySet<>(); excludePaths.add(path); IncludeExcludeRules expectedRules = new IncludeExcludeRules(includePaths, excludePaths); mBackupAgent = getAgentForOperationType(OperationType.BACKUP); when(mBackupScheme.maybeParseAndGetCanonicalExcludePaths()).thenReturn(excludePaths); when(mBackupScheme.maybeParseAndGetCanonicalIncludePaths()).thenReturn(includePaths); IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme); assertThat(rules).isEqualTo(expectedRules); } private BackupAgent getAgentForOperationType(@OperationType int operationType) { BackupAgent agent = new TestFullBackupAgent(); agent.onCreate(USER_HANDLE, operationType); return agent; } private static class TestFullBackupAgent extends BackupAgent { @Override public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException { // Left empty as this is a full backup agent. } @Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { // Left empty as this is a full backup agent. } } }