diff options
| -rw-r--r-- | core/java/android/app/backup/BackupAgent.java | 33 | ||||
| -rw-r--r-- | core/java/android/app/backup/BackupUtils.java | 58 | ||||
| -rw-r--r-- | services/robotests/src/android/app/backup/BackupUtilsTest.java | 195 |
3 files changed, 256 insertions, 30 deletions
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 965792271f81..ec2cf0cf0dae 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -43,7 +43,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.util.Collection; import java.util.LinkedList; import java.util.Map; import java.util.Set; @@ -833,7 +832,7 @@ public abstract class BackupAgent extends ContextWrapper { } if (excludes != null && - isFileSpecifiedInPathList(destination, excludes)) { + BackupUtils.isFileSpecifiedInPathList(destination, excludes)) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { Log.v(FullBackup.TAG_XML_PARSER, "onRestoreFile: \"" + destinationCanonicalPath + "\": listed in" @@ -847,7 +846,8 @@ public abstract class BackupAgent extends ContextWrapper { // it's a small list), we'll go through and look for it. boolean explicitlyIncluded = false; for (Set<PathWithRequiredFlags> domainIncludes : includes.values()) { - explicitlyIncluded |= isFileSpecifiedInPathList(destination, domainIncludes); + explicitlyIncluded |= + BackupUtils.isFileSpecifiedInPathList(destination, domainIncludes); if (explicitlyIncluded) { break; } @@ -866,33 +866,6 @@ public abstract class BackupAgent extends ContextWrapper { } /** - * @return True if the provided file is either directly in the provided list, or the provided - * file is within a directory in the list. - */ - private boolean isFileSpecifiedInPathList(File file, - Collection<PathWithRequiredFlags> canonicalPathList) throws IOException { - for (PathWithRequiredFlags canonical : canonicalPathList) { - String canonicalPath = canonical.getPath(); - File fileFromList = new File(canonicalPath); - if (fileFromList.isDirectory()) { - if (file.isDirectory()) { - // If they are both directories check exact equals. - return file.equals(fileFromList); - } else { - // O/w we have to check if the file is within the directory from the list. - return file.getCanonicalPath().startsWith(canonicalPath); - } - } else { - if (file.equals(fileFromList)) { - // Need to check the explicit "equals" so we don't end up with substrings. - return true; - } - } - } - return false; - } - - /** * Only specialized platform agents should overload this entry point to support * restores to crazy non-app locations. * @hide diff --git a/core/java/android/app/backup/BackupUtils.java b/core/java/android/app/backup/BackupUtils.java new file mode 100644 index 000000000000..8cf8a84f0181 --- /dev/null +++ b/core/java/android/app/backup/BackupUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 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 android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; + +/** @hide */ +public class BackupUtils { + + private BackupUtils() {} + + /** + * Returns {@code true} if {@code file} is either directly in {@code canonicalPathList} or is a + * file contained in a directory in the list. + */ + public static boolean isFileSpecifiedInPathList( + File file, Collection<PathWithRequiredFlags> canonicalPathList) throws IOException { + for (PathWithRequiredFlags canonical : canonicalPathList) { + String canonicalPath = canonical.getPath(); + File fileFromList = new File(canonicalPath); + if (fileFromList.isDirectory()) { + if (file.isDirectory()) { + // If they are both directories check exact equals. + if (file.equals(fileFromList)) { + return true; + } + } else { + // O/w we have to check if the file is within the directory from the list. + if (file.toPath().startsWith(canonicalPath)) { + return true; + } + } + } else if (file.equals(fileFromList)) { + // Need to check the explicit "equals" so we don't end up with substrings. + return true; + } + } + return false; + } +} diff --git a/services/robotests/src/android/app/backup/BackupUtilsTest.java b/services/robotests/src/android/app/backup/BackupUtilsTest.java new file mode 100644 index 000000000000..04a2a14b50e9 --- /dev/null +++ b/services/robotests/src/android/app/backup/BackupUtilsTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2018 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 android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; +import android.content.Context; +import android.platform.test.annotations.Presubmit; + +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.internal.DoNotInstrument; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"android.app.backup"}) +@Presubmit +@DoNotInstrument +public class BackupUtilsTest { + private Context mContext; + + @Before + public void setUp() throws Exception { + mContext = RuntimeEnvironment.application; + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListHasIt() throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(file("a/b.txt"), paths(file("a/b.txt"))); + + assertThat(isSpecified).isTrue(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListHasItsDirectory() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(file("a/b.txt"), paths(directory("a"))); + + assertThat(isSpecified).isTrue(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListHasOtherFile() throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(file("a/b.txt"), paths(file("a/c.txt"))); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListEmpty() throws Exception { + boolean isSpecified = BackupUtils.isFileSpecifiedInPathList(file("a/b.txt"), paths()); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenDirectoryAndPathListHasIt() throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(directory("a"), paths(directory("a"))); + + assertThat(isSpecified).isTrue(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenDirectoryAndPathListEmpty() throws Exception { + boolean isSpecified = BackupUtils.isFileSpecifiedInPathList(directory("a"), paths()); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenDirectoryAndPathListHasParent() throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(directory("a/b"), paths(directory("a"))); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListDoesntContainDirectory() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(file("a/b.txt"), paths(directory("c"))); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListHasDirectoryWhoseNameIsPrefix() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList(file("a/b.txt"), paths(directory("a/b"))); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void testIsFileSpecifiedInPathList_whenFileAndPathListHasDirectoryWhoseNameIsPrefix2() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList( + file("name/subname.txt"), paths(directory("nam"))); + + assertThat(isSpecified).isFalse(); + } + + @Test + public void + testIsFileSpecifiedInPathList_whenFileAndPathListContainsFirstNotRelatedAndSecondContainingDirectory() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList( + file("a/b.txt"), paths(directory("b"), directory("a"))); + + assertThat(isSpecified).isTrue(); + } + + @Test + public void + testIsFileSpecifiedInPathList_whenDirectoryAndPathListContainsFirstNotRelatedAndSecondSameDirectory() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList( + directory("a/b"), paths(directory("b"), directory("a/b"))); + + assertThat(isSpecified).isTrue(); + } + + @Test + public void + testIsFileSpecifiedInPathList_whenFileAndPathListContainsFirstNotRelatedFileAndSecondSameFile() + throws Exception { + boolean isSpecified = + BackupUtils.isFileSpecifiedInPathList( + file("a/b.txt"), paths(directory("b"), file("a/b.txt"))); + + assertThat(isSpecified).isTrue(); + } + + private File file(String path) throws IOException { + File file = new File(mContext.getDataDir(), path); + File parent = file.getParentFile(); + parent.mkdirs(); + file.createNewFile(); + if (!file.isFile()) { + throw new IOException("Couldn't create file"); + } + return file; + } + + private File directory(String path) throws IOException { + File directory = new File(mContext.getDataDir(), path); + directory.mkdirs(); + if (!directory.isDirectory()) { + throw new IOException("Couldn't create directory"); + } + return directory; + } + + private Collection<PathWithRequiredFlags> paths(File... files) { + return Stream.of(files) + .map(file -> new PathWithRequiredFlags(file.getPath(), 0)) + .collect(Collectors.toList()); + } +} |