1 /*
2  * Copyright (c) 2017 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.android.internal.creation;
6 
7 import java.io.File;
8 import java.lang.reflect.Field;
9 import java.util.ArrayList;
10 import java.util.List;
11 
12 class AndroidTempFileLocator {
13 
14     final static File target;
15 
16     static {
17         File t = null;
18         try {
19             String user = System.getProperty("org.mockito.android.target");
20             if (user != null) {
21                 t = new File(user);
22             }
23         } catch (Throwable ignored) {
24         }
25         if (t == null) {
26             try {
27                 Class<?> clazz = Class.forName("android.support.test.InstrumentationRegistry");
28                 Object context = clazz.getDeclaredMethod("getTargetContext").invoke(clazz);
29                 t = (File) context.getClass().getMethod("getCacheDir").invoke(context);
30             } catch (Throwable ignored) {
31             }
32         }
33         if (t == null) {
34             try {
35                 Class<?> clazz = Class.forName("dalvik.system.PathClassLoader");
36                 Field pathField = clazz.getDeclaredField("path");
37                 pathField.setAccessible(true);
38                 String pathFromThisClassLoader = (String) pathField.get(AndroidTempFileLocator.class.getClassLoader());
39                 File[] results = guessPath(pathFromThisClassLoader);
40                 if (results.length > 0) {
41                     t = results[0];
42                 }
43             } catch (Throwable ignored) {
44             }
45         }
46         target = t;
47     }
48 
guessPath(String input)49     private static File[] guessPath(String input) {
50         List<File> results = new ArrayList<File>();
51         for (String potential : splitPathList(input)) {
52             if (!potential.startsWith("/data/app/")) {
53                 continue;
54             }
55             int start = "/data/app/".length();
56             int end = potential.lastIndexOf(".apk");
57             if (end != potential.length() - 4) {
58                 continue;
59             }
60             int dash = potential.indexOf("-");
61             if (dash != -1) {
62                 end = dash;
63             }
64             String packageName = potential.substring(start, end);
65             File dataDir = new File("/data/data/" + packageName);
66             if (isWriteableDirectory(dataDir)) {
67                 File cacheDir = new File(dataDir, "cache");
68                 if (fileOrDirExists(cacheDir) || cacheDir.mkdir()) {
69                     if (isWriteableDirectory(cacheDir)) {
70                         results.add(cacheDir);
71                     }
72                 }
73             }
74         }
75         return results.toArray(new File[results.size()]);
76     }
77 
splitPathList(String input)78     private static String[] splitPathList(String input) {
79         String trimmed = input;
80         if (input.startsWith("dexPath=")) {
81             int start = "dexPath=".length();
82             int end = input.indexOf(',');
83 
84             trimmed = (end == -1) ? input.substring(start) : input.substring(start, end);
85         }
86 
87         return trimmed.split(":");
88     }
89 
fileOrDirExists(File file)90     private static boolean fileOrDirExists(File file) {
91         return file.exists();
92     }
93 
isWriteableDirectory(File file)94     private static boolean isWriteableDirectory(File file) {
95         return file.isDirectory() && file.canWrite();
96     }
97 }
98