1 /* 2 * Copyright (C) 2016 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 android.support.test.aupt; 18 19 import android.app.ActivityManager; 20 import android.app.Instrumentation; 21 import android.os.Environment; 22 import android.os.ParcelFileDescriptor; 23 import android.os.RemoteException; 24 import android.util.Log; 25 26 import java.io.ByteArrayOutputStream; 27 import java.io.File; 28 import java.io.FileNotFoundException; 29 import java.io.FileOutputStream; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 import java.text.SimpleDateFormat; 34 import java.util.Date; 35 import java.util.Locale; 36 37 public class FilesystemUtil { 38 private static final String TAG = FilesystemUtil.class.getSimpleName(); 39 40 /** Save the output of a process to a file */ saveProcessOutput(Instrumentation instr, String command, File file)41 public static void saveProcessOutput(Instrumentation instr, String command, File file) 42 throws IOException { 43 Log.d(TAG, String.format("Saving command \"%s\" output into file %s", 44 command, file.getAbsolutePath())); 45 46 OutputStream out = new FileOutputStream(file); 47 saveProcessOutput(instr, command, out); 48 out.close(); 49 } 50 51 /** Send the output of a process to an OutputStream. */ saveProcessOutput(Instrumentation instr, String command, OutputStream out)52 public static void saveProcessOutput(Instrumentation instr, String command, OutputStream out) 53 throws IOException { 54 try { 55 // First, try to execute via our UiAutomation 56 ParcelFileDescriptor pfd = instr.getUiAutomation().executeShellCommand(command); 57 pipe(new ParcelFileDescriptor.AutoCloseInputStream(pfd), out); 58 } catch (IllegalStateException ise) { 59 // If we don't have a UiAutomation, we'll get an IllegalStatException; 60 // so try to do it via an exec() 61 Process process = Runtime.getRuntime().exec(command); 62 pipe(process.getInputStream(), out); 63 64 // Wait for our process to finish 65 try { 66 process.waitFor(); 67 } catch (InterruptedException ie) { 68 throw new IOException("Thread interrupted waiting for command: " + command); 69 } 70 71 // Make sure it succeeded. 72 if (process.exitValue() != 0) { 73 throw new IOException("Failed to save output of command: " + command); 74 } 75 } 76 } 77 78 /** Save a bugreport to the given file */ saveBugreport(Instrumentation instr, String filename)79 public static void saveBugreport(Instrumentation instr, String filename) 80 throws IOException, InterruptedException { 81 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 82 String cmdline = String.format("/system/bin/sh -c /system/bin/bugreport>%s", 83 templateToFilename(filename)); 84 saveProcessOutput(instr, cmdline, baos); 85 baos.close(); 86 } 87 88 /** Save a bugreport to the given file */ saveBugreportz(Instrumentation instr)89 public static void saveBugreportz(Instrumentation instr) throws IOException { 90 try { 91 ActivityManager.getService().requestBugReport(ActivityManager.BUGREPORT_OPTION_FULL); 92 } catch (RemoteException e) { 93 throw new IOException("Could not capture bugreportz", e); 94 } 95 } 96 97 /** Save annotated Meminfo to our default logging directory */ dumpMeminfo(Instrumentation instr, String notes)98 public static void dumpMeminfo(Instrumentation instr, String notes) { 99 long epochSeconds = System.currentTimeMillis() / 1000; 100 File outputDir = new File(Environment.getExternalStorageDirectory(), "meminfo"); 101 Log.i(TAG, outputDir.toString()); 102 if (!outputDir.exists()) { 103 boolean yes = outputDir.mkdirs(); 104 Log.i(TAG, yes ? "created" : "not created"); 105 } 106 File outputFile = new File(outputDir, String.format("%d.txt", epochSeconds)); 107 Log.i(TAG, outputFile.toString()); 108 FileOutputStream fos = null; 109 110 try { 111 fos = new FileOutputStream(outputFile); 112 fos.write(String.format("notes: %s\n\n", notes).getBytes()); 113 114 saveProcessOutput(instr, "dumpsys meminfo -c", fos); 115 fos.close(); 116 } catch (FileNotFoundException e) { 117 Log.e(TAG, "exception while dumping meminfo", e); 118 } catch (IOException e) { 119 Log.e(TAG, "exception while dumping meminfo", e); 120 } 121 } 122 123 /** Splice the date into the "%s" in a file name */ templateToFilename(String filenameTemplate)124 public static String templateToFilename(String filenameTemplate) { 125 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); 126 return String.format(filenameTemplate, sdf.format(new Date())); 127 } 128 129 /** Pipe an inputstream to an outputstream. This matches Apache's IOUtils::copy */ pipe(InputStream in, OutputStream out)130 private static void pipe(InputStream in, OutputStream out) throws IOException { 131 byte[] buffer = new byte[4096]; 132 int bytesRead = 0; 133 134 try { 135 while (bytesRead >= 0) { 136 out.write(buffer, 0, bytesRead); 137 bytesRead = in.read(buffer); 138 } 139 } finally { 140 in.close(); 141 out.flush(); 142 } 143 } 144 } 145