Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4853f5ae authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Enable screen recording in legacy app launch test." into rvc-dev am: 0e82ef5b

Change-Id: I0c8723c71a0070953127320a3208cdc547655c42
parents cad3d2a7 0e82ef5b
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -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"],
}
}
+150 −1
Original line number Original line Diff line number Diff line
@@ -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 "
@@ -923,9 +936,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;
@@ -1038,6 +1058,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) {
@@ -1053,6 +1076,10 @@ public class AppLaunch extends InstrumentationTestCase {
        } catch (InterruptedException e) {
        } catch (InterruptedException e) {
            // ignore
            // ignore
        }
        }

        if(mEnableRecording) {
            stopRecording();
        }
        return runnable.getResult();
        return runnable.getResult();
    }
    }


@@ -1360,4 +1387,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;
    }
}
}