Merge "Enable screen recording in legacy app launch test." am: ca4379a866

Change-Id: I61d3105211127d9a99d4b8dab6f541f27a2753d6
This commit is contained in:
Treehugger Robot
2020-04-17 22:00:26 +00:00
committed by Automerger Merge Worker
2 changed files with 153 additions and 2 deletions

View File

@@ -8,6 +8,8 @@ android_test {
"android.test.base", "android.test.base",
"android.test.runner", "android.test.runner",
], ],
static_libs: ["androidx.test.rules"], static_libs: [
"androidx.test.rules",
"ub-uiautomator"],
test_suites: ["device-tests"], test_suites: ["device-tests"],
} }

View File

@@ -15,6 +15,8 @@
*/ */
package com.android.tests.applaunch; package com.android.tests.applaunch;
import static org.junit.Assert.assertNotNull;
import android.accounts.Account; import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.ActivityManager; import android.app.ActivityManager;
@@ -29,7 +31,9 @@ import android.content.pm.ResolveInfo;
import android.os.Bundle; import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.support.test.uiautomator.UiDevice;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import android.test.InstrumentationTestRunner; import android.test.InstrumentationTestRunner;
import android.util.Log; import android.util.Log;
@@ -46,6 +50,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.nio.file.Paths;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
@@ -67,6 +72,7 @@ import java.util.Set;
* in the following format: * in the following format:
* -e apps <app name>^<result key>|<app name>^<result key> * -e apps <app name>^<result key>|<app name>^<result key>
*/ */
@Deprecated
public class AppLaunch extends InstrumentationTestCase { public class AppLaunch extends InstrumentationTestCase {
private static final int JOIN_TIMEOUT = 10000; private static final int JOIN_TIMEOUT = 10000;
@@ -94,6 +100,9 @@ public class AppLaunch extends InstrumentationTestCase {
private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval"; private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
private static final String KEY_COMPILER_FILTERS = "compiler_filters"; private static final String KEY_COMPILER_FILTERS = "compiler_filters";
private static final String KEY_FORCE_STOP_APP = "force_stop_app"; private static final String KEY_FORCE_STOP_APP = "force_stop_app";
private static final String ENABLE_SCREEN_RECORDING = "enable_screen_recording";
private static final int MAX_RECORDING_PARTS = 5;
private static final long VIDEO_TAIL_BUFFER = 500;
private static final String SIMPLEPERF_APP_CMD = private static final String SIMPLEPERF_APP_CMD =
"simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s"; "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
@@ -144,14 +153,17 @@ public class AppLaunch extends InstrumentationTestCase {
private Map<String, Intent> mNameToIntent; private Map<String, Intent> mNameToIntent;
private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>(); private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
private RecordingThread mCurrentThread;
private Map<String, String> mNameToResultKey; private Map<String, String> mNameToResultKey;
private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime; private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
private IActivityManager mAm; private IActivityManager mAm;
private File launchSubDir = null;
private String mSimplePerfCmd = null; private String mSimplePerfCmd = null;
private String mLaunchOrder = null; private String mLaunchOrder = null;
private boolean mDropCache = false; private boolean mDropCache = false;
private int mLaunchIterations = 10; private int mLaunchIterations = 10;
private boolean mForceStopApp = true; private boolean mForceStopApp = true;
private boolean mEnableRecording = false;
private int mTraceLaunchCount = 0; private int mTraceLaunchCount = 0;
private String mTraceDirectoryStr = null; private String mTraceDirectoryStr = null;
private Bundle mResult = new Bundle(); private Bundle mResult = new Bundle();
@@ -166,6 +178,7 @@ public class AppLaunch extends InstrumentationTestCase {
private boolean mCycleCleanUp = false; private boolean mCycleCleanUp = false;
private boolean mTraceAll = false; private boolean mTraceAll = false;
private boolean mIterationCycle = false; private boolean mIterationCycle = false;
private UiDevice mDevice;
enum IorapStatus { enum IorapStatus {
UNDEFINED, UNDEFINED,
@@ -222,7 +235,7 @@ public class AppLaunch extends InstrumentationTestCase {
} }
try { try {
File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY); launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
if (!launchSubDir.exists() && !launchSubDir.mkdirs()) { if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
throw new IOException("Unable to create the lauch file sub directory " throw new IOException("Unable to create the lauch file sub directory "
@@ -921,9 +934,16 @@ public class AppLaunch extends InstrumentationTestCase {
mLaunchIterations = Integer.parseInt(launchIterations); mLaunchIterations = Integer.parseInt(launchIterations);
} }
String forceStopApp = args.getString(KEY_FORCE_STOP_APP); String forceStopApp = args.getString(KEY_FORCE_STOP_APP);
if (forceStopApp != null) { if (forceStopApp != null) {
mForceStopApp = Boolean.parseBoolean(forceStopApp); mForceStopApp = Boolean.parseBoolean(forceStopApp);
} }
String enableRecording = args.getString(ENABLE_SCREEN_RECORDING);
if (enableRecording != null) {
mEnableRecording = Boolean.parseBoolean(enableRecording);
}
String appList = args.getString(KEY_APPS); String appList = args.getString(KEY_APPS);
if (appList == null) if (appList == null)
return; return;
@@ -1036,6 +1056,9 @@ public class AppLaunch extends InstrumentationTestCase {
private AppLaunchResult startApp(String appName, String launchReason) private AppLaunchResult startApp(String appName, String launchReason)
throws NameNotFoundException, RemoteException { throws NameNotFoundException, RemoteException {
Log.i(TAG, "Starting " + appName); Log.i(TAG, "Starting " + appName);
if(mEnableRecording) {
startRecording(appName, launchReason);
}
Intent startIntent = mNameToIntent.get(appName); Intent startIntent = mNameToIntent.get(appName);
if (startIntent == null) { if (startIntent == null) {
@@ -1051,6 +1074,10 @@ public class AppLaunch extends InstrumentationTestCase {
} catch (InterruptedException e) { } catch (InterruptedException e) {
// ignore // ignore
} }
if(mEnableRecording) {
stopRecording();
}
return runnable.getResult(); return runnable.getResult();
} }
@@ -1358,4 +1385,126 @@ public class AppLaunch extends InstrumentationTestCase {
} }
} }
/**
* Start the screen recording while launching the app.
*
* @param appName
* @param launchReason
*/
private void startRecording(String appName, String launchReason) {
Log.v(TAG, "Started Recording");
mCurrentThread = new RecordingThread("test-screen-record",
String.format("%s_%s", appName, launchReason));
mCurrentThread.start();
}
/**
* Stop already started screen recording.
*/
private void stopRecording() {
// Skip if not directory.
if (launchSubDir == null) {
return;
}
// Add some extra time to the video end.
SystemClock.sleep(VIDEO_TAIL_BUFFER);
// Ctrl + C all screen record processes.
mCurrentThread.cancel();
// Wait for the thread to completely die.
try {
mCurrentThread.join();
} catch (InterruptedException ex) {
Log.e(TAG, "Interrupted when joining the recording thread.", ex);
}
Log.v(TAG, "Stopped Recording");
}
/** Returns the recording's name for part {@code part} of launch description. */
private File getOutputFile(String description, int part) {
// Omit the iteration number for the first iteration.
final String fileName =
String.format(
"%s-video%s.mp4", description, part == 1 ? "" : part);
return Paths.get(launchSubDir.getAbsolutePath(), description).toFile();
}
/**
* Encapsulates the start and stop screen recording logic.
* Copied from ScreenRecordCollector.
*/
private class RecordingThread extends Thread {
private final String mDescription;
private final List<File> mRecordings;
private boolean mContinue;
public RecordingThread(String name, String description) {
super(name);
mContinue = true;
mRecordings = new ArrayList<>();
assertNotNull("No test description provided for recording.", description);
mDescription = description;
}
@Override
public void run() {
try {
// Start at i = 1 to encode parts as X.mp4, X2.mp4, X3.mp4, etc.
for (int i = 1; i <= MAX_RECORDING_PARTS && mContinue; i++) {
File output = getOutputFile(mDescription, i);
Log.d(
TAG,
String.format("Recording screen to %s", output.getAbsolutePath()));
mRecordings.add(output);
// Make sure not to block on this background command in the main thread so
// that the test continues to run, but block in this thread so it does not
// trigger a new screen recording session before the prior one completes.
getDevice().executeShellCommand(
String.format("screenrecord %s", output.getAbsolutePath()));
}
} catch (IOException e) {
throw new RuntimeException("Caught exception while screen recording.");
}
}
public void cancel() {
mContinue = false;
// Identify the screenrecord PIDs and send SIGINT 2 (Ctrl + C) to each.
try {
String[] pids = getDevice().executeShellCommand(
"pidof screenrecord").split(" ");
for (String pid : pids) {
// Avoid empty process ids, because of weird splitting behavior.
if (pid.isEmpty()) {
continue;
}
getDevice().executeShellCommand(
String.format("kill -2 %s", pid));
Log.d(
TAG,
String.format("Sent SIGINT 2 to screenrecord process (%s)", pid));
}
} catch (IOException e) {
throw new RuntimeException("Failed to kill screen recording process.");
}
}
public List<File> getRecordings() {
return mRecordings;
}
}
public UiDevice getDevice() {
if (mDevice == null) {
mDevice = UiDevice.getInstance(getInstrumentation());
}
return mDevice;
}
} }