1 package com.android.launcher3.util.rule; 2 3 import static androidx.test.InstrumentationRegistry.getInstrumentation; 4 5 import android.os.FileUtils; 6 import android.os.ParcelFileDescriptor.AutoCloseInputStream; 7 import android.util.Log; 8 9 import androidx.test.uiautomator.UiDevice; 10 11 import com.android.launcher3.tapl.LauncherInstrumentation; 12 import com.android.launcher3.ui.AbstractLauncherUiTest; 13 14 import org.junit.rules.TestWatcher; 15 import org.junit.runner.Description; 16 17 import java.io.File; 18 import java.io.FileOutputStream; 19 import java.io.IOException; 20 import java.io.OutputStream; 21 import java.util.zip.ZipEntry; 22 import java.util.zip.ZipOutputStream; 23 24 public class FailureWatcher extends TestWatcher { 25 private static final String TAG = "FailureWatcher"; 26 final private UiDevice mDevice; 27 private final LauncherInstrumentation mLauncher; 28 FailureWatcher(UiDevice device, LauncherInstrumentation launcher)29 public FailureWatcher(UiDevice device, LauncherInstrumentation launcher) { 30 mDevice = device; 31 mLauncher = launcher; 32 } 33 34 @Override succeeded(Description description)35 protected void succeeded(Description description) { 36 super.succeeded(description); 37 AbstractLauncherUiTest.checkDetectedLeaks(mLauncher); 38 } 39 40 @Override failed(Throwable e, Description description)41 protected void failed(Throwable e, Description description) { 42 onError(mDevice, description, e); 43 } 44 onError(UiDevice device, Description description, Throwable e)45 public static void onError(UiDevice device, Description description, Throwable e) { 46 if (device == null) return; 47 final File parentFile = getInstrumentation().getTargetContext().getFilesDir(); 48 final File sceenshot = new File(parentFile, 49 "TestScreenshot-" + description.getMethodName() + ".png"); 50 final File hierarchy = new File(parentFile, 51 "Hierarchy-" + description.getMethodName() + ".zip"); 52 53 // Dump window hierarchy 54 try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(hierarchy))) { 55 out.putNextEntry(new ZipEntry("bugreport.txt")); 56 dumpStringCommand("dumpsys window windows", out); 57 dumpStringCommand("dumpsys package", out); 58 dumpStringCommand("dumpsys activity service TouchInteractionService", out); 59 out.closeEntry(); 60 61 out.putNextEntry(new ZipEntry("visible_windows.zip")); 62 dumpCommand("cmd window dump-visible-window-views", out); 63 out.closeEntry(); 64 } catch (IOException ex) { } 65 66 Log.e(TAG, "Failed test " + description.getMethodName() 67 + ",\nscreenshot will be saved to " + sceenshot 68 + ",\nUI dump at: " + hierarchy 69 + " (use go/web-hv to open the dump file)", e); 70 device.takeScreenshot(sceenshot); 71 } 72 dumpStringCommand(String cmd, OutputStream out)73 private static void dumpStringCommand(String cmd, OutputStream out) throws IOException { 74 out.write(("\n\n" + cmd + "\n").getBytes()); 75 dumpCommand(cmd, out); 76 } 77 dumpCommand(String cmd, OutputStream out)78 private static void dumpCommand(String cmd, OutputStream out) throws IOException { 79 try (AutoCloseInputStream in = new AutoCloseInputStream(getInstrumentation() 80 .getUiAutomation().executeShellCommand(cmd))) { 81 FileUtils.copy(in, out); 82 } 83 } 84 } 85