10aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang/*
20bebaf393a6e531e5c0b20306c4e8ebc9e4d64f2Xia Wang * Copyright (C) 2013 The Android Open Source Project
30aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang *
40aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * Licensed under the Apache License, Version 2.0 (the "License");
50aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * you may not use this file except in compliance with the License.
60aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * You may obtain a copy of the License at
70aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang *
80aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang *      http://www.apache.org/licenses/LICENSE-2.0
90aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang *
100aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * Unless required by applicable law or agreed to in writing, software
110aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * distributed under the License is distributed on an "AS IS" BASIS,
120aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * See the License for the specific language governing permissions and
140aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang * limitations under the License.
150aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang */
160aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
170bebaf393a6e531e5c0b20306c4e8ebc9e4d64f2Xia Wangpackage com.android.uiautomator.platform;
180aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
190aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport android.os.Bundle;
200aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport android.os.Environment;
210aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport android.util.Log;
220aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
230aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport com.android.uiautomator.core.UiDevice;
240aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport com.android.uiautomator.testrunner.UiAutomatorTestCase;
250aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
265967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.io.BufferedOutputStream;
275967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.io.BufferedReader;
280aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.io.BufferedWriter;
290aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.io.File;
300aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.io.FileInputStream;
310aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.io.FileNotFoundException;
325967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.io.FileOutputStream;
330aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.io.FileWriter;
340aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.io.IOException;
355967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.io.InputStream;
365967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.io.InputStreamReader;
375967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.util.ArrayList;
385967bd5f7085577474e1ea7905db714f046de862Xia Wangimport java.util.List;
390aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangimport java.util.Properties;
400aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
410aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang/**
425967bd5f7085577474e1ea7905db714f046de862Xia Wang * Base class for jank test.
435967bd5f7085577474e1ea7905db714f046de862Xia Wang * All jank test needs to extend JankTestBase
440aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang */
450aac99898b24c3633876b1cc6ab0612b2e893910Xia Wangpublic class JankTestBase extends UiAutomatorTestCase {
4644ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String TAG = JankTestBase.class.getSimpleName();
475967bd5f7085577474e1ea7905db714f046de862Xia Wang
480aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected UiDevice mDevice;
495967bd5f7085577474e1ea7905db714f046de862Xia Wang    protected TestWatchers mTestWatchers = null;
500aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected BufferedWriter mWriter = null;
510aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected BufferedWriter mStatusWriter = null;
5276c7edc9e8b5e9108c9006a73a9abb80775edc4fXia Wang    protected int mIteration = 20; // default iteration is set 20
535967bd5f7085577474e1ea7905db714f046de862Xia Wang    /* can be used to enable/disable systrace in the test */
545967bd5f7085577474e1ea7905db714f046de862Xia Wang    protected int mTraceTime = 0;
550aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected Bundle mParams;
560aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected String mTestCaseName;
570aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected int mSuccessTestRuns = 0;
585967bd5f7085577474e1ea7905db714f046de862Xia Wang    protected Thread mThread = null;
590aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
600aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    // holds all params for the derived tests
6144ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String PROPERTY_FILE_NAME = "UiJankinessTests.conf";
6244ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String PARAM_CONFIG = "conf";
6344ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String LOCAL_TMP_DIR = "/data/local/tmp/";
640aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    // File that hold the test results
650aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private static String OUTPUT_FILE_NAME = LOCAL_TMP_DIR + "UiJankinessTestsOutput.txt";
660aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    // File that hold test status, e.g successful test iterations
670aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private static String STATUS_FILE_NAME = LOCAL_TMP_DIR + "UiJankinessTestsStatus.txt";
6844ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String RAW_DATA_DIR = LOCAL_TMP_DIR + "UiJankinessRawData";
695967bd5f7085577474e1ea7905db714f046de862Xia Wang
700aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private static int SUCCESS_THRESHOLD = 80;
710aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private static boolean DEBUG = false;
720aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
735967bd5f7085577474e1ea7905db714f046de862Xia Wang    /* default animation time is set to 2 seconds */
7444ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    protected static final long DEFAULT_ANIMATION_TIME = 2 * 1000;
755967bd5f7085577474e1ea7905db714f046de862Xia Wang    /* default swipe steps for fling animation */
7644ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    protected static final int DEFAULT_FLING_STEPS = 8;
775967bd5f7085577474e1ea7905db714f046de862Xia Wang
780aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /* Array to record jankiness data in each test iteration */
790aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private int[] jankinessArray;
800aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /* Array to record frame rate in each test iteration */
810aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private double[] frameRateArray;
820aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /* Array to save max accumulated frame number in each test iteration */
830aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private int[] maxDeltaVsyncArray;
845967bd5f7085577474e1ea7905db714f046de862Xia Wang    /* Default file to store the systrace */
8544ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final File SYSTRACE_DIR = new File(LOCAL_TMP_DIR, "systrace");
865967bd5f7085577474e1ea7905db714f046de862Xia Wang    /* Default trace file name */
8744ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String TRACE_FILE_NAME = "trace.txt";
885967bd5f7085577474e1ea7905db714f046de862Xia Wang    /* Default tracing time is 5 seconds */
8944ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final int DEFAULT_TRACE_TIME = 5; // 5 seconds
905967bd5f7085577474e1ea7905db714f046de862Xia Wang    // Command to dump compressed trace data
9144ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    private static final String ATRACE_COMMAND = "atrace -z -t %d gfx input view sched freq";
925967bd5f7085577474e1ea7905db714f046de862Xia Wang
935967bd5f7085577474e1ea7905db714f046de862Xia Wang    /**
945967bd5f7085577474e1ea7905db714f046de862Xia Wang     * Thread to capture systrace log from the test
955967bd5f7085577474e1ea7905db714f046de862Xia Wang     */
965967bd5f7085577474e1ea7905db714f046de862Xia Wang    public class SystraceTracker implements Runnable {
975967bd5f7085577474e1ea7905db714f046de862Xia Wang        File mFile = new File(SYSTRACE_DIR, TRACE_FILE_NAME);
985967bd5f7085577474e1ea7905db714f046de862Xia Wang        int mTime = DEFAULT_TRACE_TIME;
995967bd5f7085577474e1ea7905db714f046de862Xia Wang
1005967bd5f7085577474e1ea7905db714f046de862Xia Wang        public SystraceTracker(int traceTime, String fileName) {
1015967bd5f7085577474e1ea7905db714f046de862Xia Wang            try {
1025967bd5f7085577474e1ea7905db714f046de862Xia Wang                if (!SYSTRACE_DIR.exists()) {
1035967bd5f7085577474e1ea7905db714f046de862Xia Wang                    if (!SYSTRACE_DIR.mkdir()) {
1045967bd5f7085577474e1ea7905db714f046de862Xia Wang                        log(String.format("create directory %s failed, you can manually create "
1055967bd5f7085577474e1ea7905db714f046de862Xia Wang                                + "it and start the test again", SYSTRACE_DIR.getAbsolutePath()));
1065967bd5f7085577474e1ea7905db714f046de862Xia Wang                        return;
1075967bd5f7085577474e1ea7905db714f046de862Xia Wang                    }
1085967bd5f7085577474e1ea7905db714f046de862Xia Wang                }
1095967bd5f7085577474e1ea7905db714f046de862Xia Wang            } catch (SecurityException e) {
1105967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.e(TAG, "creating directory failed?", e);
1115967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
1125967bd5f7085577474e1ea7905db714f046de862Xia Wang
1135967bd5f7085577474e1ea7905db714f046de862Xia Wang            if (traceTime > 0) {
1145967bd5f7085577474e1ea7905db714f046de862Xia Wang                mTime = traceTime;
1155967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
1165967bd5f7085577474e1ea7905db714f046de862Xia Wang            if (fileName != null) {
1175967bd5f7085577474e1ea7905db714f046de862Xia Wang                mFile = new File(SYSTRACE_DIR, fileName);
1185967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
1195967bd5f7085577474e1ea7905db714f046de862Xia Wang        }
1205967bd5f7085577474e1ea7905db714f046de862Xia Wang
1215967bd5f7085577474e1ea7905db714f046de862Xia Wang        @Override
1225967bd5f7085577474e1ea7905db714f046de862Xia Wang        public void run() {
1235967bd5f7085577474e1ea7905db714f046de862Xia Wang            String command = String.format(ATRACE_COMMAND, mTime);
1245967bd5f7085577474e1ea7905db714f046de862Xia Wang            Log.v(TAG, "command: " + command);
1255967bd5f7085577474e1ea7905db714f046de862Xia Wang            Process p = null;
1265967bd5f7085577474e1ea7905db714f046de862Xia Wang            InputStream in = null;
1275967bd5f7085577474e1ea7905db714f046de862Xia Wang            BufferedOutputStream out = null;
1285967bd5f7085577474e1ea7905db714f046de862Xia Wang            try {
1295967bd5f7085577474e1ea7905db714f046de862Xia Wang                p = Runtime.getRuntime().exec(command);
1305967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.v(TAG, "write systrace into file: " + mFile.getAbsolutePath());
1315967bd5f7085577474e1ea7905db714f046de862Xia Wang                // read bytes from the process output stream as the output is compressed
1325967bd5f7085577474e1ea7905db714f046de862Xia Wang                byte[] buffer = new byte[1024];
1335967bd5f7085577474e1ea7905db714f046de862Xia Wang                in = p.getInputStream();
1345967bd5f7085577474e1ea7905db714f046de862Xia Wang                out = new BufferedOutputStream(new FileOutputStream(mFile));
1355967bd5f7085577474e1ea7905db714f046de862Xia Wang                int n;
1365967bd5f7085577474e1ea7905db714f046de862Xia Wang                while ((n = in.read(buffer)) != -1) {
1375967bd5f7085577474e1ea7905db714f046de862Xia Wang                    out.write(buffer, 0, n);
1385967bd5f7085577474e1ea7905db714f046de862Xia Wang                    out.flush();
1395967bd5f7085577474e1ea7905db714f046de862Xia Wang                }
1405967bd5f7085577474e1ea7905db714f046de862Xia Wang                in.close();
1415967bd5f7085577474e1ea7905db714f046de862Xia Wang                out.close();
1425967bd5f7085577474e1ea7905db714f046de862Xia Wang                // read error message
1435967bd5f7085577474e1ea7905db714f046de862Xia Wang                BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
1445967bd5f7085577474e1ea7905db714f046de862Xia Wang                String line;
1455967bd5f7085577474e1ea7905db714f046de862Xia Wang                while ((line = br.readLine()) != null) {
1465967bd5f7085577474e1ea7905db714f046de862Xia Wang                    Log.e(TAG, "Command return errors: " + line);
1475967bd5f7085577474e1ea7905db714f046de862Xia Wang                }
1485967bd5f7085577474e1ea7905db714f046de862Xia Wang                br.close();
1495967bd5f7085577474e1ea7905db714f046de862Xia Wang
1505967bd5f7085577474e1ea7905db714f046de862Xia Wang                // Due to limited buffer size for standard input and output stream,
1515967bd5f7085577474e1ea7905db714f046de862Xia Wang                // promptly reading from the input stream or output stream to avoid block
1525967bd5f7085577474e1ea7905db714f046de862Xia Wang                int status = p.waitFor();
1535967bd5f7085577474e1ea7905db714f046de862Xia Wang                if (status != 0) {
1545967bd5f7085577474e1ea7905db714f046de862Xia Wang                    Log.e(TAG, String.format("Run shell command: %s, status: %s",
1555967bd5f7085577474e1ea7905db714f046de862Xia Wang                            command, status));
1565967bd5f7085577474e1ea7905db714f046de862Xia Wang                }
1575967bd5f7085577474e1ea7905db714f046de862Xia Wang            } catch (InterruptedException e) {
1585967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.e(TAG, "Exception from command " + command + ":");
1595967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.e(TAG, "Thread interrupted? ", e);
1605967bd5f7085577474e1ea7905db714f046de862Xia Wang            } catch (IOException e) {
1615967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.e(TAG, "Open file error: ", e);
1625967bd5f7085577474e1ea7905db714f046de862Xia Wang            } catch (IllegalThreadStateException e) {
1635967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.e(TAG, "the process has not exit yet ", e);
1645967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
1655967bd5f7085577474e1ea7905db714f046de862Xia Wang        }
1665967bd5f7085577474e1ea7905db714f046de862Xia Wang    }
1670aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
1680aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    @Override
1690aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected void setUp() throws Exception {
1700aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        super.setUp();
1710aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mDevice = UiDevice.getInstance();
1725967bd5f7085577474e1ea7905db714f046de862Xia Wang        mTestWatchers = new TestWatchers(); // extends the common class UiWatchers
1735967bd5f7085577474e1ea7905db714f046de862Xia Wang        mTestWatchers.registerAnrAndCrashWatchers();
1740aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
1750aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mWriter = new BufferedWriter(new FileWriter(new File(OUTPUT_FILE_NAME), true));
1760aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mStatusWriter = new BufferedWriter(new FileWriter(new File(STATUS_FILE_NAME), true));
1770aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
1780aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mParams = getParams();
1790aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (mParams != null && !mParams.isEmpty()) {
1800aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log("mParams is not empty, get properties.");
1815967bd5f7085577474e1ea7905db714f046de862Xia Wang            String mIterationStr = getPropertyString(mParams, "iteration");
1825967bd5f7085577474e1ea7905db714f046de862Xia Wang            if (mIterationStr != null) {
1830aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                mIteration = Integer.valueOf(mIterationStr);
1840aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            }
1855967bd5f7085577474e1ea7905db714f046de862Xia Wang            String mTraceTimeStr = getPropertyString(mParams, "tracetime");
1865967bd5f7085577474e1ea7905db714f046de862Xia Wang            if (mTraceTimeStr  != null) {
1875967bd5f7085577474e1ea7905db714f046de862Xia Wang                mTraceTime = Integer.valueOf(mTraceTimeStr);
1885967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
1890aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
1900aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        jankinessArray = new int[mIteration];
1910aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        frameRateArray = new double[mIteration];
1920aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        maxDeltaVsyncArray = new int[mIteration];
1930aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mTestCaseName = this.getName();
1940aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
1950aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mSuccessTestRuns = 0;
1960aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        mDevice.pressHome();
1970aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
1980aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
1990aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /**
2005967bd5f7085577474e1ea7905db714f046de862Xia Wang     * Create a new thread for systrace and start the thread
2015967bd5f7085577474e1ea7905db714f046de862Xia Wang     *
2025967bd5f7085577474e1ea7905db714f046de862Xia Wang     * @param testCaseName
2035967bd5f7085577474e1ea7905db714f046de862Xia Wang     * @param iteration
2045967bd5f7085577474e1ea7905db714f046de862Xia Wang     */
2055967bd5f7085577474e1ea7905db714f046de862Xia Wang    protected void startTrace(String testCaseName, int iteration) {
2065967bd5f7085577474e1ea7905db714f046de862Xia Wang        if (mTraceTime > 0) {
2075967bd5f7085577474e1ea7905db714f046de862Xia Wang            String outputFile = String.format("%s_%d_trace", mTestCaseName, iteration);
2085967bd5f7085577474e1ea7905db714f046de862Xia Wang            mThread = new Thread(new SystraceTracker(mTraceTime, outputFile));
2095967bd5f7085577474e1ea7905db714f046de862Xia Wang            mThread.start();
2105967bd5f7085577474e1ea7905db714f046de862Xia Wang        }
2115967bd5f7085577474e1ea7905db714f046de862Xia Wang    }
2125967bd5f7085577474e1ea7905db714f046de862Xia Wang
2135967bd5f7085577474e1ea7905db714f046de862Xia Wang    /**
2145967bd5f7085577474e1ea7905db714f046de862Xia Wang     * Wait for the tracing thread to exit
2155967bd5f7085577474e1ea7905db714f046de862Xia Wang     */
2165967bd5f7085577474e1ea7905db714f046de862Xia Wang    protected void endTrace() {
2175967bd5f7085577474e1ea7905db714f046de862Xia Wang        if (mThread != null) {
2185967bd5f7085577474e1ea7905db714f046de862Xia Wang            try {
2195967bd5f7085577474e1ea7905db714f046de862Xia Wang                mThread.join();
2205967bd5f7085577474e1ea7905db714f046de862Xia Wang            } catch (InterruptedException e) {
2215967bd5f7085577474e1ea7905db714f046de862Xia Wang                Log.e(TAG, "wait for the trace thread to exit exception:", e);
2225967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
2235967bd5f7085577474e1ea7905db714f046de862Xia Wang        }
2245967bd5f7085577474e1ea7905db714f046de862Xia Wang    }
2255967bd5f7085577474e1ea7905db714f046de862Xia Wang
2265967bd5f7085577474e1ea7905db714f046de862Xia Wang    /**
2270aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * Expects a file from the command line via conf param or default following format each on its
2280aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * own line. <code>
2290aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    key=Value
2300aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    Browser_URL1=cnn.com
2310aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    Browser_URL2=google.com
2320aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    Camera_ShutterDelay=1000
2330aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    etc...
2340aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * </code>
2350aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param Bundle params
2360aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param key
2370aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @return the value of the property else defaultValue
2380aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @throws FileNotFoundException
2390aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @throws IOException
2400aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     */
2410aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected String getPropertyString(Bundle params, String key)
2420aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            throws FileNotFoundException, IOException {
2430aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        Properties prop = new Properties();
2440aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        prop.load(new FileInputStream(new File(LOCAL_TMP_DIR,
2450aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                params.getString(PARAM_CONFIG, PROPERTY_FILE_NAME))));
2460aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        String value = prop.getProperty(key);
2470aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (value != null && !value.isEmpty())
2480aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            return value;
2490aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        return null;
2500aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
2510aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
2520aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /**
2530aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * Expects a file from the command line via conf param or default following format each on its
2540aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * own line. <code>
2550aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    key=Value
2560aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    Browser_URL1=cnn.com
2570aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    Browser_URL2=google.com
2580aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    Camera_ShutterDelay=1000
2590aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     *    etc...
2600aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * </code>
2610aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param Bundle params
2620aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param key
2630aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @return the value of the property else defaultValue
2640aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @throws FileNotFoundException
2650aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @throws IOException
2660aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     */
2670aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected long getPropertyLong(Bundle params, String key)
2680aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            throws FileNotFoundException, IOException {
2690aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        Properties prop = new Properties();
2700aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        prop.load(new FileInputStream(new File(LOCAL_TMP_DIR,
2710aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                params.getString(PARAM_CONFIG, PROPERTY_FILE_NAME))));
2720aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        String value = prop.getProperty(key);
2730aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (value != null && !value.trim().isEmpty())
2740aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            return Long.valueOf(value.trim());
2750aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        return 0;
2760aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
2770aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
2780aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /**
27944ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang     * Verify the test result by comparing data sample size with expected value
28044ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang     * @param expectedDataSize the expected data size
28144ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang     */
28244ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    protected boolean validateResults(int expectedDataSize) {
28344ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang        int receivedDataSize = SurfaceFlingerHelper.getDataSampleSize();
28444ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang        return ((expectedDataSize > 0) && (receivedDataSize >= expectedDataSize));
28544ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    }
28644ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang
28744ef31d58e8b998ac487ad6973fff3ac156f77e2Xia Wang    /**
2880aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * Process the raw data, calculate jankiness, frame rate and max accumulated frames number
2890aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param testCaseName
2900aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param iteration
2910aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     */
2920aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected void recordResults(String testCaseName, int iteration) {
2930aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        long refreshPeriod = SurfaceFlingerHelper.getRefreshPeriod();
2945967bd5f7085577474e1ea7905db714f046de862Xia Wang        // if the raw directory doesn't exit, create the directory
2955967bd5f7085577474e1ea7905db714f046de862Xia Wang        File rawDataDir = new File(RAW_DATA_DIR);
2965967bd5f7085577474e1ea7905db714f046de862Xia Wang        try {
2975967bd5f7085577474e1ea7905db714f046de862Xia Wang            if (!rawDataDir.exists()) {
2985967bd5f7085577474e1ea7905db714f046de862Xia Wang                if (!rawDataDir.mkdir()) {
2995967bd5f7085577474e1ea7905db714f046de862Xia Wang                    log(String.format("create directory %s failed, you can manually create " +
3005967bd5f7085577474e1ea7905db714f046de862Xia Wang                            "it and start the test again", rawDataDir));
3015967bd5f7085577474e1ea7905db714f046de862Xia Wang                }
3025967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
3035967bd5f7085577474e1ea7905db714f046de862Xia Wang        } catch (SecurityException e) {
3045967bd5f7085577474e1ea7905db714f046de862Xia Wang            Log.e(TAG, "create directory failed: ", e);
3055967bd5f7085577474e1ea7905db714f046de862Xia Wang        }
3065967bd5f7085577474e1ea7905db714f046de862Xia Wang        String rawFileName = String.format("%s/%s_%d.txt", RAW_DATA_DIR, testCaseName, iteration);
3075967bd5f7085577474e1ea7905db714f046de862Xia Wang        // write results into a file
3085967bd5f7085577474e1ea7905db714f046de862Xia Wang        BufferedWriter fw = null;
3095967bd5f7085577474e1ea7905db714f046de862Xia Wang        try {
3105967bd5f7085577474e1ea7905db714f046de862Xia Wang            fw = new BufferedWriter(new FileWriter(new File(rawFileName), false));
3115967bd5f7085577474e1ea7905db714f046de862Xia Wang            fw.write(SurfaceFlingerHelper.getFrameBufferData());
3125967bd5f7085577474e1ea7905db714f046de862Xia Wang        } catch (IOException e) {
3135967bd5f7085577474e1ea7905db714f046de862Xia Wang            Log.e(TAG, "failed to write to file", e);
3145967bd5f7085577474e1ea7905db714f046de862Xia Wang            return;
3155967bd5f7085577474e1ea7905db714f046de862Xia Wang        } finally {
3165967bd5f7085577474e1ea7905db714f046de862Xia Wang            try {
3175967bd5f7085577474e1ea7905db714f046de862Xia Wang                if (fw != null) {
3185967bd5f7085577474e1ea7905db714f046de862Xia Wang                    fw.close();
3195967bd5f7085577474e1ea7905db714f046de862Xia Wang                }
3205967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
3215967bd5f7085577474e1ea7905db714f046de862Xia Wang            catch (IOException e) {
3225967bd5f7085577474e1ea7905db714f046de862Xia Wang                    Log.e(TAG, "close file failed.", e);
3235967bd5f7085577474e1ea7905db714f046de862Xia Wang            }
3245967bd5f7085577474e1ea7905db714f046de862Xia Wang        }
3255967bd5f7085577474e1ea7905db714f046de862Xia Wang
3260aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        // get jankiness count
3270aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int jankinessCount = SurfaceFlingerHelper.getVsyncJankiness();
3280aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        // get frame rate
3290aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        double frameRate = SurfaceFlingerHelper.getFrameRate();
3300aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        // get max accumulated frames
3310aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int maxDeltaVsync = SurfaceFlingerHelper.getMaxDeltaVsync();
3320aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3330aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        // only record data when they are valid
3340aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (jankinessCount >=0 && frameRate > 0) {
3350aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            jankinessArray[iteration] = jankinessCount;
3360aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            frameRateArray[iteration] = frameRate;
3370aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            maxDeltaVsyncArray[iteration] = maxDeltaVsync;
3380aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            mSuccessTestRuns++;
3390aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
3400aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        String msg = String.format("%s, iteration %d\n" +
3410aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "refresh period: %d\n" +
3420aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "jankiness count: %d\n" +
3430aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "frame rate: %f\n" +
3440aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "max accumulated frames: %d\n",
3450aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                testCaseName, iteration, refreshPeriod,
3460aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                jankinessCount, frameRate, maxDeltaVsync);
3470aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        log(msg);
3480aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (DEBUG) {
3490aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            SurfaceFlingerHelper.printData(testCaseName, iteration);
3500aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
3510aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
3520aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3530aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    /**
3540aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * Process data from all test iterations, and save to disk
3550aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     * @param testCaseName
3560aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang     */
3570aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected void saveResults(String testCaseName) {
3580aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        // write test status into status file
3590aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        try {
3600aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            mStatusWriter.write(String.format("%s: %d success runs out of %d iterations\n",
3610aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                    testCaseName, mSuccessTestRuns, mIteration));
3620aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        } catch (IOException e) {
3630aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log("failed to write output for test case " + testCaseName);
3640aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
3650aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3660aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        // if successful test runs is less than the threshold, no results will be saved.
3670aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (mSuccessTestRuns * 100 / mIteration < SUCCESS_THRESHOLD) {
3680aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log(String.format("In %s, # of successful test runs out of %s iterations: %d ",
3690aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                    testCaseName, mIteration, mSuccessTestRuns));
3700aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log(String.format("threshold is %d%%", SUCCESS_THRESHOLD));
3710aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            return;
3720aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
3730aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3740aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (DEBUG) {
3750aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            print(jankinessArray, "jankiness array");
3760aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            print(frameRateArray, "frame rate array");
3770aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            print(maxDeltaVsyncArray, "max delta vsync array");
3780aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
3790aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        double avgJankinessCount = getAverage(jankinessArray);
3800aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int maxJankinessCount = getMaxValue(jankinessArray);
3810aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        double avgFrameRate = getAverage(frameRateArray);
3820aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        double avgMaxDeltaVsync = getAverage(maxDeltaVsyncArray);
3830aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3840aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        String avgMsg = String.format("%s\n" +
3850aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "average number of jankiness: %f\n" +
3860aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "max number of jankiness: %d\n" +
3870aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "average frame rate: %f\n" +
3880aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                "average of max accumulated frames: %f\n",
3890aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                testCaseName, avgJankinessCount, maxJankinessCount, avgFrameRate, avgMaxDeltaVsync);
3900aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        log(avgMsg);
3910aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3920aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        try {
3930aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            mWriter.write(avgMsg);
3940aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        } catch (IOException e) {
3950aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log("failed to write output for test case " + testCaseName);
3960aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
3970aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
3980aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
3990aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    // return the max value in an integer array
4000aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private int getMaxValue(int[] intArray) {
4010aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int index = 0;
4020aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int max = intArray[index];
4030aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        for (int i  = 1; i < intArray.length; i++) {
4040aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            if (max < intArray[i]) {
4050aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                max = intArray[i];
4060aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            }
4070aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4080aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        return max;
4090aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
4100aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4110aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private double getAverage(int[] intArray) {
4120aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int mean = 0;
4130aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int numberTests = 0;
4140aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        for (int i = 0; i < intArray.length; i++) {
4150aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            // in case in some iteration, test fails, no data points is collected
4160aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            if (intArray[i] >= 0) {
4170aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                mean += intArray[i];
4180aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                ++numberTests;
4190aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            }
4200aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4210aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        return (double)mean/numberTests;
4220aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
4230aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4240aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private double getAverage(double[] doubleArray) {
4250aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        double mean = 0;
4260aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        int numberTests = 0;
4270aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        for (int i = 0; i < doubleArray.length; i++) {
4280aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            // in case in some iteration, test fails, no data points is collected
4290aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            if (doubleArray[i] >= 0) {
4300aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                mean += doubleArray[i];
4310aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang                ++numberTests;
4320aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            }
4330aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4340aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        return mean/numberTests;
4350aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
4360aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4370aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private void print(int[] intArray, String arrayName) {
4380aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        log("start to print array for " + arrayName);
4390aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        for (int i = 0; i < intArray.length; i++) {
4400aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log(String.format("%d: %d", i, intArray[i]));
4410aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4420aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
4430aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4440aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    private void print(double[] doubleArray, String arrayName) {
4450aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        log("start to print array for " + arrayName);
4460aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        for (int i = 0; i < doubleArray.length; i++) {
4470aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            log(String.format("%d: %f", i, doubleArray[i]));
4480aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4490aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
4500aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4510aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    @Override
4520aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    protected void tearDown() throws Exception {
4530aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        super.tearDown();
4540aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (mWriter != null) {
4550aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            mWriter.close();
4560aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4570aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        if (mStatusWriter != null) {
4580aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang            mStatusWriter.close();
4590aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang        }
4600aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    }
4610aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4620aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   private void log(String message) {
4630aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang       Log.v(TAG, message);
4640aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   }
4650aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4660aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   /**
4670aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    * Set the total number of test iteration
4680aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    * @param iteration
4690aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    */
4700aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   protected void setIteration(int iteration){
4710aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang       mIteration = iteration;
4720aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   }
4730aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang
4740aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   /**
4750aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    * Get the total number of test iteration
4760aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    * @return iteration
4770aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang    */
4780aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   protected int getIteration(){
4790aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang       return mIteration;
4800aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang   }
4810aac99898b24c3633876b1cc6ab0612b2e893910Xia Wang}
482