1 /* 2 * Copyright (C) 2017 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 com.android.cts.storageapp; 18 19 import android.content.Context; 20 import android.system.Os; 21 import android.system.OsConstants; 22 import android.system.StructUtsname; 23 import android.util.Log; 24 25 import junit.framework.AssertionFailedError; 26 27 import java.io.BufferedReader; 28 import java.io.ByteArrayOutputStream; 29 import java.io.File; 30 import java.io.FileDescriptor; 31 import java.io.FileOutputStream; 32 import java.io.FileReader; 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.io.OutputStream; 36 import java.util.Arrays; 37 import java.util.regex.Matcher; 38 import java.util.regex.Pattern; 39 40 public class Utils { 41 public static final String TAG = "StorageApp"; 42 43 public static final String PKG_A = "com.android.cts.storageapp_a"; 44 public static final String PKG_B = "com.android.cts.storageapp_b"; 45 46 // You will pry my kibibytes from my cold dead hands! But to make test 47 // results easier to debug, we'll use kilobytes... 48 public static final long KB_IN_BYTES = 1000; 49 public static final long MB_IN_BYTES = KB_IN_BYTES * 1000; 50 public static final long GB_IN_BYTES = MB_IN_BYTES * 1000; 51 52 public static final long DATA_INT = (2 + 3 + 5 + 13 + 17 + 19 + 23) * MB_IN_BYTES; 53 public static final long DATA_EXT = (7 + 11) * MB_IN_BYTES; 54 public static final long DATA_ALL = DATA_INT + DATA_EXT; // 100MB 55 56 public static final long CACHE_INT = (3 + 5 + 17 + 19 + 23) * MB_IN_BYTES; 57 public static final long CACHE_EXT = (11) * MB_IN_BYTES; 58 public static final long CACHE_ALL = CACHE_INT + CACHE_EXT; // 78MB 59 60 public static final long CODE_ALL = 29 * MB_IN_BYTES; 61 useSpace(Context c)62 public static void useSpace(Context c) throws Exception { 63 // We use prime numbers for all values so that we can easily identify 64 // which file(s) are missing from broken test results. 65 useWrite(makeUniqueFile(c.getFilesDir()), 2 * MB_IN_BYTES); 66 useWrite(makeUniqueFile(c.getCodeCacheDir()), 3 * MB_IN_BYTES); 67 useWrite(makeUniqueFile(c.getCacheDir()), 5 * MB_IN_BYTES); 68 useWrite(makeUniqueFile(c.getExternalFilesDir("meow")), 7 * MB_IN_BYTES); 69 useWrite(makeUniqueFile(c.getExternalCacheDir()), 11 * MB_IN_BYTES); 70 71 useFallocate(makeUniqueFile(c.getFilesDir()), 13 * MB_IN_BYTES); 72 useFallocate(makeUniqueFile(c.getCodeCacheDir()), 17 * MB_IN_BYTES); 73 useFallocate(makeUniqueFile(c.getCacheDir()), 19 * MB_IN_BYTES); 74 final File subdir = makeUniqueFile(c.getCacheDir()); 75 Os.mkdir(subdir.getAbsolutePath(), 0700); 76 useFallocate(makeUniqueFile(subdir), 23 * MB_IN_BYTES); 77 78 useWrite(makeUniqueFile(c.getObbDir()), 29 * MB_IN_BYTES); 79 } 80 assertAtLeast(long expected, long actual)81 public static void assertAtLeast(long expected, long actual) { 82 if (actual < expected) { 83 throw new AssertionFailedError("Expected at least " + expected + " but was " + actual 84 + " [" + android.os.Process.myUserHandle() + "]"); 85 } 86 } 87 assertMostlyEquals(long expected, long actual)88 public static void assertMostlyEquals(long expected, long actual) { 89 assertMostlyEquals(expected, actual, 500 * KB_IN_BYTES); 90 } 91 assertMostlyEquals(long expected, long actual, long delta)92 public static void assertMostlyEquals(long expected, long actual, long delta) { 93 if (Math.abs(expected - actual) > delta) { 94 throw new AssertionFailedError("Expected roughly " + expected + " but was " + actual 95 + " [" + android.os.Process.myUserHandle() + "]"); 96 } 97 } 98 makeUniqueFile(File dir)99 public static File makeUniqueFile(File dir) { 100 return new File(dir, Long.toString(System.nanoTime())); 101 } 102 useWrite(File file, long size)103 public static File useWrite(File file, long size) throws Exception { 104 try (FileOutputStream os = new FileOutputStream(file)) { 105 final byte[] buf = new byte[1024]; 106 while (size > 0) { 107 os.write(buf, 0, (int) Math.min(buf.length, size)); 108 size -= buf.length; 109 } 110 } 111 return file; 112 } 113 useFallocate(File file, long length, long time)114 public static File useFallocate(File file, long length, long time) throws Exception { 115 final File res = useFallocate(file, length); 116 file.setLastModified(time); 117 return res; 118 } 119 useFallocate(File file, long length)120 public static File useFallocate(File file, long length) throws Exception { 121 final FileDescriptor fd = Os.open(file.getAbsolutePath(), 122 OsConstants.O_CREAT | OsConstants.O_RDWR | OsConstants.O_TRUNC, 0700); 123 try { 124 Os.posix_fallocate(fd, 0, length); 125 } finally { 126 Os.close(fd); 127 } 128 return file; 129 } 130 getSizeManual(File dir)131 public static long getSizeManual(File dir) throws Exception { 132 return getSizeManual(dir, false); 133 } 134 getSizeManual(File dir, boolean excludeObb)135 public static long getSizeManual(File dir, boolean excludeObb) throws Exception { 136 long size = getAllocatedSize(dir); 137 File[] files = dir.listFiles(); 138 139 if (files == null) { 140 // This can happen on devices with scoped storage, where we're not allowed 141 // to iterate Android/ anymore. 142 return size; 143 } 144 145 for (File f : files) { 146 if (f.isDirectory()) { 147 if (excludeObb && f.getName().equalsIgnoreCase("obb") 148 && f.getParentFile().getName().equalsIgnoreCase("Android")) { 149 Log.d(TAG, "Ignoring OBB directory " + f); 150 } else { 151 size += getSizeManual(f, excludeObb); 152 } 153 } else { 154 size += getAllocatedSize(f); 155 } 156 } 157 return size; 158 } 159 getAllocatedSize(File f)160 private static long getAllocatedSize(File f) throws Exception { 161 return Os.lstat(f.getAbsolutePath()).st_blocks * 512 / 162 Os.lstat(f.getAbsolutePath()).st_blksize * 163 Os.lstat(f.getAbsolutePath()).st_blksize ; 164 } 165 deleteContents(File dir)166 public static boolean deleteContents(File dir) { 167 File[] files = dir.listFiles(); 168 boolean success = true; 169 if (files != null) { 170 for (File file : files) { 171 if (file.isDirectory()) { 172 success &= deleteContents(file); 173 } 174 if (!file.delete()) { 175 success = false; 176 } 177 } 178 } 179 return success; 180 } 181 logCommand(String... cmd)182 public static void logCommand(String... cmd) throws Exception { 183 final Process proc = new ProcessBuilder(cmd).redirectErrorStream(true).start(); 184 185 final ByteArrayOutputStream buf = new ByteArrayOutputStream(); 186 copy(proc.getInputStream(), buf); 187 final int res = proc.waitFor(); 188 189 Log.d(TAG, Arrays.toString(cmd) + " result " + res + ":"); 190 Log.d(TAG, buf.toString()); 191 } 192 193 /** Shamelessly lifted from libcore.io.Streams */ copy(InputStream in, OutputStream out)194 public static int copy(InputStream in, OutputStream out) throws IOException { 195 int total = 0; 196 byte[] buffer = new byte[8192]; 197 int c; 198 while ((c = in.read(buffer)) != -1) { 199 total += c; 200 out.write(buffer, 0, c); 201 } 202 return total; 203 } 204 } 205