1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package vogar.android;
18 
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.util.HashSet;
22 import java.util.Set;
23 import vogar.FileCache;
24 import vogar.Log;
25 import vogar.commands.Command;
26 
27 public class DeviceFileCache implements FileCache {
28     private final Log log;
29     private final File cacheRoot;
30     private DeviceFilesystem deviceFilesystem;
31 
32     /** filled lazily */
33     private Set<File> cachedFiles;
34 
DeviceFileCache(Log log, File deviceDir, DeviceFilesystem deviceFilesystem)35     public DeviceFileCache(Log log, File deviceDir, DeviceFilesystem deviceFilesystem) {
36         this.log = log;
37         this.cacheRoot = new File(deviceDir, "md5-cache");
38         this.deviceFilesystem = deviceFilesystem;
39     }
40 
41     @Override
existsInCache(String key)42     public boolean existsInCache(String key) {
43         if (cachedFiles == null) {
44             try {
45                 cachedFiles = new HashSet<File>();
46                 cachedFiles.addAll(deviceFilesystem.ls(cacheRoot));
47                 log.verbose("indexed on-device cache: " + cachedFiles.size() + " entries.");
48             } catch (FileNotFoundException e) {
49                 // cacheRoot probably just hasn't been created yet.
50                 cachedFiles = new HashSet<File>();
51             }
52         }
53         File cachedFile = new File(cacheRoot, key);
54         return cachedFiles.contains(cachedFile);
55     }
56 
57     @Override
copyFromCache(String key, File destination)58     public void copyFromCache(String key, File destination) {
59         File cachedFile = new File(cacheRoot, key);
60         cp(cachedFile, destination);
61     }
62 
63     @Override
copyToCache(File source, String key)64     public void copyToCache(File source, String key) {
65         File cachedFile = new File(cacheRoot, key);
66         deviceFilesystem.mkdirs(cacheRoot);
67         // Copy it onto the same file system first, then atomically move it into place.
68         // That way, if we fail, we don't leave anything dangerous lying around.
69         File temporary = new File(cachedFile + ".tmp");
70         cp(source, temporary);
71         mv(cachedFile, temporary);
72     }
73 
mv(File cachedFile, File temporary)74     private void mv(File cachedFile, File temporary) {
75         new Command(log, "adb", "shell", "mv", temporary.getPath(), cachedFile.getPath()).execute();
76     }
77 
cp(File source, File temporary)78     private void cp(File source, File temporary) {
79         // adb doesn't support "cp" command directly
80         new Command(log, "adb", "shell", "cat", source.getPath(), ">", temporary.getPath())
81                 .execute();
82     }
83 }
84