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 t = getCacheDirFromInstrumentationRegistry("android.support.test.InstrumentationRegistry"); 27 } 28 if (t == null) { 29 t = getCacheDirFromInstrumentationRegistry("androidx.test.InstrumentationRegistry"); 30 } 31 if (t == null) { 32 try { 33 Class<?> clazz = Class.forName("dalvik.system.PathClassLoader"); 34 Field pathField = clazz.getDeclaredField("path"); 35 pathField.setAccessible(true); 36 String pathFromThisClassLoader = (String) pathField.get(AndroidTempFileLocator.class.getClassLoader()); 37 File[] results = guessPath(pathFromThisClassLoader); 38 if (results.length > 0) { 39 t = results[0]; 40 } 41 } catch (Throwable ignored) { 42 } 43 } 44 target = t; 45 } 46 getCacheDirFromInstrumentationRegistry(String className)47 private static File getCacheDirFromInstrumentationRegistry(String className) { 48 try { 49 Class<?> clazz = Class.forName(className); 50 Object context = clazz.getDeclaredMethod("getTargetContext").invoke(clazz); 51 return (File) context.getClass().getMethod("getCacheDir").invoke(context); 52 } catch (Throwable ignored) { 53 } 54 return null; 55 } 56 guessPath(String input)57 private static File[] guessPath(String input) { 58 List<File> results = new ArrayList<File>(); 59 for (String potential : splitPathList(input)) { 60 if (!potential.startsWith("/data/app/")) { 61 continue; 62 } 63 int start = "/data/app/".length(); 64 int end = potential.lastIndexOf(".apk"); 65 if (end != potential.length() - 4) { 66 continue; 67 } 68 int dash = potential.indexOf("-"); 69 if (dash != -1) { 70 end = dash; 71 } 72 String packageName = potential.substring(start, end); 73 File dataDir = new File("/data/data/" + packageName); 74 if (isWritableDirectory(dataDir)) { 75 File cacheDir = new File(dataDir, "cache"); 76 if (fileOrDirExists(cacheDir) || cacheDir.mkdir()) { 77 if (isWritableDirectory(cacheDir)) { 78 results.add(cacheDir); 79 } 80 } 81 } 82 } 83 return results.toArray(new File[results.size()]); 84 } 85 splitPathList(String input)86 private static String[] splitPathList(String input) { 87 String trimmed = input; 88 if (input.startsWith("dexPath=")) { 89 int start = "dexPath=".length(); 90 int end = input.indexOf(','); 91 92 trimmed = (end == -1) ? input.substring(start) : input.substring(start, end); 93 } 94 95 return trimmed.split(":"); 96 } 97 fileOrDirExists(File file)98 private static boolean fileOrDirExists(File file) { 99 return file.exists(); 100 } 101 isWritableDirectory(File file)102 private static boolean isWritableDirectory(File file) { 103 return file.isDirectory() && file.canWrite(); 104 } 105 } 106