• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.google.android.libraries.backup.shadow;
2 
3 import android.app.backup.FileBackupHelper;
4 import android.content.Context;
5 import android.util.Log;
6 import com.google.common.annotations.VisibleForTesting;
7 import com.google.common.base.Preconditions;
8 import com.google.common.collect.ImmutableMap;
9 import com.google.common.collect.ImmutableSet;
10 import com.google.common.io.Files;
11 import java.io.File;
12 import java.io.IOException;
13 import java.lang.reflect.Field;
14 import java.util.Arrays;
15 import java.util.Map;
16 import java.util.Set;
17 
18 /**
19  * Representation of {@link FileBackupHelper} configuration used for testing. This class simulates
20  * backing up and restoring files by storing their contents in memory.
21  *
22  * <p>{@see BackupAgentHelperShadow}
23  */
24 public class FileBackupHelperSimulator extends BackupHelperSimulator {
25   private static final String TAG = "FileBackupHelperSimulat";
26 
27   /** Filenames which should be backed up/restored. */
28   private final Set<String> fileNames;
29 
FileBackupHelperSimulator(String keyPrefix, Set<String> fileNames)30   private FileBackupHelperSimulator(String keyPrefix, Set<String> fileNames) {
31     super(keyPrefix);
32     this.fileNames = Preconditions.checkNotNull(fileNames);
33   }
34 
fromFileNames(String keyPrefix, Set<String> fileNames)35   public static FileBackupHelperSimulator fromFileNames(String keyPrefix, Set<String> fileNames) {
36     return new FileBackupHelperSimulator(keyPrefix, fileNames);
37   }
38 
fromHelper(String keyPrefix, FileBackupHelper helper)39   public static FileBackupHelperSimulator fromHelper(String keyPrefix, FileBackupHelper helper) {
40     return new FileBackupHelperSimulator(keyPrefix, extractFileNamesFromHelper(helper));
41   }
42 
43   @VisibleForTesting
extractFileNamesFromHelper(FileBackupHelper helper)44   static Set<String> extractFileNamesFromHelper(FileBackupHelper helper) {
45     try {
46       Field filesField = FileBackupHelper.class.getDeclaredField("mFiles");
47       filesField.setAccessible(true);
48       return ImmutableSet.copyOf((String[]) filesField.get(helper));
49     } catch (ReflectiveOperationException e) {
50       throw new IllegalStateException(e);
51     }
52   }
53 
54   /** Collection of backed up files. */
55   public static class FilesBackupData {
56     /** Map from file names to their backed up contents. */
57     private final Map<String, FileBackupContents> files;
58 
FilesBackupData(Map<String, FileBackupContents> files)59     public FilesBackupData(Map<String, FileBackupContents> files) {
60       this.files = Preconditions.checkNotNull(files);
61     }
62 
63     @Override
equals(Object obj)64     public boolean equals(Object obj) {
65       return obj instanceof FilesBackupData && files.equals(((FilesBackupData) obj).files);
66     }
67 
68     @Override
hashCode()69     public int hashCode() {
70       return files.hashCode();
71     }
72 
getFiles()73     public Map<String, FileBackupContents> getFiles() {
74       return files;
75     }
76   }
77 
78   /** Single backed up file. */
79   public static class FileBackupContents {
80     private final byte[] bytes;
81 
FileBackupContents(byte[] bytes)82     public FileBackupContents(byte[] bytes) {
83       this.bytes = Preconditions.checkNotNull(bytes);
84     }
85 
86     @Override
equals(Object obj)87     public boolean equals(Object obj) {
88       return obj instanceof FileBackupContents
89           && Arrays.equals(bytes, ((FileBackupContents) obj).bytes);
90     }
91 
92     @Override
hashCode()93     public int hashCode() {
94       return Arrays.hashCode(bytes);
95     }
96 
readFromFile(File file)97     public static FileBackupContents readFromFile(File file) {
98       return new FileBackupContents(readBytesFromFile(file));
99     }
100 
writeToFile(File file)101     public void writeToFile(File file) {
102       writeBytesToFile(file, bytes);
103     }
104 
readBytesFromFile(File file)105     public static byte[] readBytesFromFile(File file) {
106       try {
107         return Files.toByteArray(file);
108       } catch (IOException e) {
109         throw new IllegalStateException(e);
110       }
111     }
112 
writeBytesToFile(File file, byte[] bytes)113     public static void writeBytesToFile(File file, byte[] bytes) {
114       try {
115         Files.write(bytes, file);
116       } catch (IOException e) {
117         throw new IllegalStateException(e);
118       }
119     }
120   }
121 
122   @Override
backup(Context context)123   public Object backup(Context context) {
124     File base = context.getFilesDir();
125     ImmutableMap.Builder<String, FileBackupContents> dataToBackupBuilder = ImmutableMap.builder();
126     for (String fileName : fileNames) {
127       File file = new File(base, fileName);
128       if (!file.exists()) {
129         Log.w(TAG, "File \"" + fileName + "\" not found by helper \"" + keyPrefix + "\".");
130         continue;
131       }
132       dataToBackupBuilder.put(fileName, FileBackupContents.readFromFile(file));
133     }
134     return new FilesBackupData(dataToBackupBuilder.build());
135   }
136 
137   @Override
restore(Context context, Object data)138   public void restore(Context context, Object data) {
139     if (!(data instanceof FilesBackupData)) {
140       throw new IllegalArgumentException("Invalid type of files to restore in helper \""
141           + keyPrefix + "\": " + data.getClass());
142     }
143 
144     File base = context.getFilesDir();
145     Map<String, FileBackupContents> dataToRestore = ((FilesBackupData) data).getFiles();
146     for (Map.Entry<String, FileBackupContents> restoreEntry : dataToRestore.entrySet()) {
147       String fileName = restoreEntry.getKey();
148       if (!fileNames.contains(fileName)) {
149         Log.w(TAG, "File \"" + fileName + "\" ignored by helper \"" + keyPrefix + "\".");
150         continue;
151       }
152       FileBackupContents contents = restoreEntry.getValue();
153       File file = new File(base, fileName);
154       contents.writeToFile(file);
155     }
156   }
157 }
158