diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-11-03 18:09:46 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-11-03 18:09:46 +0000 |
commit | 3850efb9a2ff1e1ede404df5c9ba0d92d753ab32 (patch) | |
tree | ba5820cf3e320c4b66f946fdfb72763dad10ce49 | |
parent | bd51d8dc0e22a17d2e07592fd99c5e9a9462c5ef (diff) | |
parent | 535eccd4cbf1e5c8309fd59c5bc67379efc5a9d3 (diff) | |
download | platform_testing-3850efb9a2ff1e1ede404df5c9ba0d92d753ab32.tar.gz |
Snap for 6948038 from 535eccd4cbf1e5c8309fd59c5bc67379efc5a9d3 to rvc-platform-releaseandroid-platform-11.0.0_r4android-platform-11.0.0_r3
Change-Id: Ie6b6c83b1474d522556f7c3a7b18eab3b11ade05
20 files changed, 1039 insertions, 198 deletions
diff --git a/libraries/app-helpers/core/src/android/platform/helpers/AbstractStandardAppHelper.java b/libraries/app-helpers/core/src/android/platform/helpers/AbstractStandardAppHelper.java index 331091541..fe710b0b0 100644 --- a/libraries/app-helpers/core/src/android/platform/helpers/AbstractStandardAppHelper.java +++ b/libraries/app-helpers/core/src/android/platform/helpers/AbstractStandardAppHelper.java @@ -198,7 +198,7 @@ public abstract class AbstractStandardAppHelper implements IAppHelper { } } if (!mDevice.wait( - Until.hasObject(mLauncherStrategy.getWorkspaceSelector()), EXIT_WAIT_TIMEOUT)) { + Until.hasObject(getLauncherStrategy().getWorkspaceSelector()), EXIT_WAIT_TIMEOUT)) { throw new IllegalStateException("Failed to exit the app to launcher."); } } diff --git a/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoSettingHelper.java b/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoSettingHelper.java index 403b50e6c..7ad708441 100644 --- a/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoSettingHelper.java +++ b/libraries/app-helpers/interfaces/auto/src/android/platform/helpers/IAutoSettingHelper.java @@ -191,4 +191,32 @@ public interface IAutoSettingHelper extends IAppHelper, Scrollable { * <p>get day/night mode status. */ DayNightMode getDayNightModeStatus(); + + /** + * Setup expectations: full settings facet is open. + * + * <p>search in settings app and select the first search result. + * + * @param item to be searched. + */ + void searchAndSelect(String item); + + /** + * Setup expectations: full settings facet is open. + * + * <p>search in settings app. + * + * @param item to be searched. + * @param selectedIndex determines which search result to select. + */ + void searchAndSelect(String item, int selectedIndex); + + /** + * Setup expectations: search result is open. + * + * <p>verify page title contains the searched item. + * + * @param item to be verified. + */ + boolean isValidPageTitle(String item); } diff --git a/libraries/collectors-helper/simpleperf/Android.bp b/libraries/collectors-helper/simpleperf/Android.bp new file mode 100644 index 000000000..98d66b039 --- /dev/null +++ b/libraries/collectors-helper/simpleperf/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Used for collecting simpleperf samples. +java_library { + name: "simpleperf-helper", + defaults: ["tradefed_errorprone_defaults"], + + srcs: ["src/**/*.java"], + + static_libs: [ + "androidx.test.runner", + "ub-uiautomator", + ], + + sdk_version: "current", +} + diff --git a/libraries/collectors-helper/simpleperf/src/com/android/helpers/SimpleperfHelper.java b/libraries/collectors-helper/simpleperf/src/com/android/helpers/SimpleperfHelper.java new file mode 100644 index 000000000..2e08f65b7 --- /dev/null +++ b/libraries/collectors-helper/simpleperf/src/com/android/helpers/SimpleperfHelper.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.helpers; + +import android.os.SystemClock; +import android.support.test.uiautomator.UiDevice; +import android.util.Log; +import androidx.test.InstrumentationRegistry; + +import java.io.IOException; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * SimpleperfHelper is used to start and stop simpleperf sample collection and move the output + * sample file to the destination folder. + */ +public class SimpleperfHelper { + + private static final String LOG_TAG = SimpleperfHelper.class.getSimpleName(); + private static final String SIMPLEPERF_TMP_FILE_PATH = "/data/local/tmp/perf.data"; + + private static final String SIMPLEPERF_START_CMD = + "simpleperf record -o %s -g --post-unwind=yes -f 500 -a --exclude-perf"; + private static final String SIMPLEPERF_STOP_CMD = "pkill -INT simpleperf"; + private static final String SIMPLEPERF_PROC_ID_CMD = "pidof simpleperf"; + private static final String REMOVE_CMD = "rm %s"; + private static final String MOVE_CMD = "mv %s %s"; + + private static final int SIMPLEPERF_STOP_WAIT_COUNT = 12; + private static final long SIMPLEPERF_STOP_WAIT_TIME = 5000; + + private UiDevice mUiDevice; + + public boolean startCollecting() { + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + try { + // Cleanup any running simpleperf sessions. + Log.i(LOG_TAG, "Cleanup simpleperf before starting."); + if (isSimpleperfRunning()) { + Log.i(LOG_TAG, "Simpleperf is already running. Stopping simpleperf."); + if (!stopSimpleperf()) { + return false; + } + } + + Log.i(LOG_TAG, String.format("Starting simpleperf")); + new Thread() { + @Override + public void run() { + UiDevice uiDevice = + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + try { + uiDevice.executeShellCommand( + String.format(SIMPLEPERF_START_CMD, SIMPLEPERF_TMP_FILE_PATH)); + } catch (IOException e) { + Log.e(LOG_TAG, "Failed to start simpleperf."); + } + } + }.start(); + + if (!isSimpleperfRunning()) { + Log.e(LOG_TAG, "Simpleperf sampling failed to start."); + return false; + } + } catch (IOException e) { + Log.e(LOG_TAG, "Unable to start simpleperf sampling due to :" + e.getMessage()); + return false; + } + Log.i(LOG_TAG, "Simpleperf sampling started successfully."); + return true; + } + + /** + * Stop the simpleperf sample collection under /data/local/tmp/perf.data and copy the output to + * the destination file. + * + * @param destinationFile file to copy the simpleperf sample file to. + * @return true if the trace collection is successful otherwise false. + */ + public boolean stopCollecting(String destinationFile) { + Log.i(LOG_TAG, "Stopping simpleperf."); + try { + if (stopSimpleperf()) { + if (!copyFileOutput(destinationFile)) { + return false; + } + } else { + Log.e(LOG_TAG, "Simpleperf failed to stop"); + return false; + } + } catch (IOException e) { + Log.e(LOG_TAG, "Unable to stop the simpleperf samping due to " + e.getMessage()); + return false; + } + return true; + } + + /** + * Utility method for sending the signal to stop simpleperf. + * + * @return true if simpleperf is successfully stopped. + */ + public boolean stopSimpleperf() throws IOException { + if (!isSimpleperfRunning()) { + Log.e(LOG_TAG, "Simpleperf stop called, but simpleperf is not running."); + return false; + } + + String stopOutput = mUiDevice.executeShellCommand(SIMPLEPERF_STOP_CMD); + Log.i(LOG_TAG, String.format("Simpleperf stop command ran")); + int waitCount = 0; + while (isSimpleperfRunning()) { + if (waitCount < SIMPLEPERF_STOP_WAIT_COUNT) { + SystemClock.sleep(SIMPLEPERF_STOP_WAIT_TIME); + waitCount++; + continue; + } + return false; + } + Log.e(LOG_TAG, "Simpleperf stopped successfully."); + return true; + } + + /** + * Check if there is a simpleperf instance running. + * + * @return true if there is a running simpleperf instance, otherwise false. + */ + private boolean isSimpleperfRunning() { + try { + String simpleperfProcId = mUiDevice.executeShellCommand(SIMPLEPERF_PROC_ID_CMD); + Log.i(LOG_TAG, String.format("Simpleperf process id - %s", simpleperfProcId)); + if (simpleperfProcId.isEmpty()) { + return false; + } + } catch (IOException e) { + Log.e(LOG_TAG, "Unable to check simpleperf status: " + e.getMessage()); + return false; + } + return true; + } + + /** + * Copy the temporary simpleperf output file to the given destinationFile. + * + * @param destinationFile file to copy simpleperf output into. + * @return true if the simpleperf file copied successfully, otherwise false. + */ + private boolean copyFileOutput(String destinationFile) { + Path path = Paths.get(destinationFile); + String destDirectory = path.getParent().toString(); + // Check if directory already exists + File directory = new File(destDirectory); + if (!directory.exists()) { + boolean success = directory.mkdirs(); + if (!success) { + Log.e( + LOG_TAG, + String.format( + "Result output directory %s not created successfully.", + destDirectory)); + return false; + } + } + + // Copy the collected trace from /data/local/tmp to the destinationFile. + try { + String moveResult = + mUiDevice.executeShellCommand( + String.format(MOVE_CMD, SIMPLEPERF_TMP_FILE_PATH, destinationFile)); + if (!moveResult.isEmpty()) { + Log.e( + LOG_TAG, + String.format( + "Unable to move simpleperf output file from %s to %s due to %s", + SIMPLEPERF_TMP_FILE_PATH, destinationFile, moveResult)); + return false; + } + } catch (IOException e) { + Log.e( + LOG_TAG, + "Unable to move the simpleperf sample file to destination file." + + e.getMessage()); + return false; + } + return true; + } +} diff --git a/libraries/collectors-helper/simpleperf/test/Android.bp b/libraries/collectors-helper/simpleperf/test/Android.bp new file mode 100644 index 000000000..860dbac95 --- /dev/null +++ b/libraries/collectors-helper/simpleperf/test/Android.bp @@ -0,0 +1,30 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +java_library { + name: "simpleperf-helper-test", + defaults: ["tradefed_errorprone_defaults"], + + srcs: ["src/**/*.java"], + + static_libs: [ + "androidx.test.runner", + "android-support-test", + "simpleperf-helper", + "junit", + + ], + + sdk_version: "current", +} diff --git a/libraries/collectors-helper/simpleperf/test/src/com/android/helpers/tests/SimpleperfHelperTest.java b/libraries/collectors-helper/simpleperf/test/src/com/android/helpers/tests/SimpleperfHelperTest.java new file mode 100644 index 000000000..7c2fdd7a5 --- /dev/null +++ b/libraries/collectors-helper/simpleperf/test/src/com/android/helpers/tests/SimpleperfHelperTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.helpers.tests; + +import android.support.test.uiautomator.UiDevice; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.helpers.SimpleperfHelper; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Android Unit tests for {@link SimpleperfHelper}. + * + * <p>atest CollectorsHelperTest:com.android.helpers.tests.SimpleperfHelperTest + */ +@RunWith(AndroidJUnit4.class) +public class SimpleperfHelperTest { + + private static final String REMOVE_CMD = "rm %s"; + private static final String FILE_SIZE_IN_BYTES = "wc -c %s"; + + private SimpleperfHelper simpleperfHelper; + + @Before + public void setUp() { + simpleperfHelper = new SimpleperfHelper(); + } + + @After + public void teardown() throws IOException { + simpleperfHelper.stopCollecting("data/local/tmp/perf.data"); + UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + uiDevice.executeShellCommand(String.format(REMOVE_CMD, "/data/local/tmp/perf.data")); + } + + /** Test simpleperf collection starts collecting properly. */ + @Test + public void testSimpleperfStartSuccess() throws Exception { + assertTrue(simpleperfHelper.startCollecting()); + } + + /** Test if the path name is prefixed with /. */ + @Test + public void testSimpleperfValidOutputPath() throws Exception { + assertTrue(simpleperfHelper.startCollecting()); + assertTrue(simpleperfHelper.stopCollecting("data/local/tmp/perf.data")); + } + + /** Test the invalid output path. */ + @Test + public void testSimpleperfInvalidOutputPath() throws Exception { + assertTrue(simpleperfHelper.startCollecting()); + // Don't have permission to create new folder under /data + assertFalse(simpleperfHelper.stopCollecting("/data/dummy/xyz/perf.data")); + } + + /** Test simpleperf collection returns true and output file size greater than zero */ + @Test + public void testSimpleperfSuccess() throws Exception { + assertTrue(simpleperfHelper.startCollecting()); + Thread.sleep(1000); + assertTrue(simpleperfHelper.stopCollecting("/data/local/tmp/perf.data")); + Thread.sleep(1000); + UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + String[] fileStats = + uiDevice.executeShellCommand( + String.format(FILE_SIZE_IN_BYTES, "/data/local/tmp/perf.data")) + .split(" "); + int fileSize = Integer.parseInt(fileStats[0].trim()); + assertTrue(fileSize > 0); + } +} diff --git a/libraries/device-collectors/src/main/Android.bp b/libraries/device-collectors/src/main/Android.bp index 9ae62aaac..5da043a01 100644 --- a/libraries/device-collectors/src/main/Android.bp +++ b/libraries/device-collectors/src/main/Android.bp @@ -25,6 +25,7 @@ java_library { "memory-helper", "perfetto-helper", "power-helper", + "simpleperf-helper", "ub-uiautomator", "system-metric-helper", ], diff --git a/libraries/device-collectors/src/main/java/android/device/collectors/SimpleperfListener.java b/libraries/device-collectors/src/main/java/android/device/collectors/SimpleperfListener.java new file mode 100644 index 000000000..61fc87a5b --- /dev/null +++ b/libraries/device-collectors/src/main/java/android/device/collectors/SimpleperfListener.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.device.collectors; + +import android.device.collectors.annotations.OptionClass; +import android.os.Bundle; +import android.util.Log; +import androidx.annotation.VisibleForTesting; +import com.android.helpers.SimpleperfHelper; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; + +/** + * A {@link SimpleperfListener} that captures simpleperf samples for a test run or per test method + * run and saves the results under + * <root_folder>/<test_display_name>/SimpleperfListener/<test_display_name>-<invocation_count>.perf + */ +@OptionClass(alias = "simpleperf-collector") +public class SimpleperfListener extends BaseMetricListener { + + // Default output folder to store the simpleperf sample files. + private static final String DEFAULT_OUTPUT_ROOT = "/sdcard/test_results"; + // Destination directory to save the trace results. + private static final String TEST_OUTPUT_ROOT = "test_output_root"; + // Simpleperf file path key. + private static final String SIMPLEPERF_FILE_PATH = "simpleperf_file_path"; + // Argument determining whether we collect for the entire run, or per test. + public static final String COLLECT_PER_RUN = "per_run"; + public static final String SIMPLEPERF_PREFIX = "simpleperf_"; + // Skip failure metrics collection if set to true. + public static final String SKIP_TEST_FAILURE_METRICS = "skip_test_failure_metrics"; + + // Simpleperf samples collected during the test will be saved under this root folder. + private String mTestOutputRoot; + // Store the method name and invocation count to create a unique filename for each trace. + private Map<String, Integer> mTestIdInvocationCount = new HashMap<>(); + private boolean mSimpleperfStartSuccess = false; + private boolean mIsCollectPerRun; + private boolean mIsTestFailed = false; + private boolean mSkipTestFailureMetrics; + + private SimpleperfHelper mSimpleperfHelper = new SimpleperfHelper(); + + public SimpleperfListener() { + super(); + } + + /** + * Constructor to simulate receiving the instrumentation arguments. Shoud not be used except for + * testing. + */ + @VisibleForTesting + SimpleperfListener(Bundle args, SimpleperfHelper helper, Map invocationMap) { + super(args); + mSimpleperfHelper = helper; + mTestIdInvocationCount = invocationMap; + } + + @Override + public void onTestRunStart(DataRecord runData, Description description) { + Bundle args = getArgsBundle(); + + // Whether to collect for the entire run, or per test. + mIsCollectPerRun = Boolean.parseBoolean(args.getString(COLLECT_PER_RUN)); + + // Destination folder in the device to save all simpleperf sample files. + // Defaulted to /sdcard/test_results if test_output_root is not passed. + mTestOutputRoot = args.getString(TEST_OUTPUT_ROOT, DEFAULT_OUTPUT_ROOT); + + // By default this flag is set to false to collect metrics on test failure. + mSkipTestFailureMetrics = "true".equals(args.getString(SKIP_TEST_FAILURE_METRICS)); + + if (!mIsCollectPerRun) { + return; + } + + Log.i(getTag(), "Starting simpleperf before test run started."); + startSimpleperf(); + } + + @Override + public void onTestStart(DataRecord testData, Description description) { + mIsTestFailed = false; + if (mIsCollectPerRun) { + return; + } + + mTestIdInvocationCount.compute( + getTestFileName(description), (key, value) -> (value == null) ? 1 : value + 1); + Log.i(getTag(), "Starting simpleperf before test started."); + startSimpleperf(); + } + + @Override + public void onTestFail(DataRecord testData, Description description, Failure failure) { + mIsTestFailed = true; + } + + @Override + public void onTestEnd(DataRecord testData, Description description) { + if (mIsCollectPerRun) { + return; + } + + if (!mSimpleperfStartSuccess) { + Log.i( + getTag(), + "Skipping simpleperf stop attempt onTestEnd because simpleperf did not start" + + "successfully"); + return; + } + + if (mSkipTestFailureMetrics && mIsTestFailed) { + Log.i(getTag(), "Skipping metric collection due to test failure"); + // Stop the existing simpleperf session. + try { + if (!mSimpleperfHelper.stopSimpleperf()) { + Log.e(getTag(), "Failed to stop the simpleperf process."); + } + } catch (IOException e) { + Log.e(getTag(), "Failed to stop simpleperf", e); + } + } else { + Log.i(getTag(), "Stopping simpleperf after test ended."); + // Construct test output directory in the below format + // <root_folder>/<test_name>/SimpleperfListener/<test_name>-<count>.data + Path path = + Paths.get( + mTestOutputRoot, + getTestFileName(description), + this.getClass().getSimpleName(), + String.format( + "%s%s-%d.data", + SIMPLEPERF_PREFIX, + getTestFileName(description), + mTestIdInvocationCount.get(getTestFileName(description)))); + stopSimpleperf(path, testData); + } + } + + @Override + public void onTestRunEnd(DataRecord runData, Result result) { + if (!mIsCollectPerRun) { + return; + } + + if (!mSimpleperfStartSuccess) { + Log.i(getTag(), "Skipping simpleperf stop attempt as simpleperf failed to start."); + return; + } + + Log.i(getTag(), "Stopping simpleperf after test run ended"); + Path path = + Paths.get( + mTestOutputRoot, + this.getClass().getSimpleName(), + String.format( + "%s%d.data", SIMPLEPERF_PREFIX, UUID.randomUUID().hashCode())); + stopSimpleperf(path, runData); + } + + /** Start simpleperf sampling. */ + public void startSimpleperf() { + mSimpleperfStartSuccess = mSimpleperfHelper.startCollecting(); + if (!mSimpleperfStartSuccess) { + Log.e(getTag(), "Simpleperf did not start successfully."); + } + } + + /** Stop simpleperf sampling and dump the collected file into the given path. */ + private void stopSimpleperf(Path path, DataRecord record) { + if (!mSimpleperfHelper.stopCollecting(path.toString())) { + Log.e(getTag(), "Failed to collect the simpleperf output."); + } else { + record.addStringMetric(SIMPLEPERF_FILE_PATH, path.toString()); + } + } + + /** + * Returns the packagename.classname_methodname which has no special characters and is used to + * create file names. + */ + public static String getTestFileName(Description description) { + return String.format("%s_%s", description.getClassName(), description.getMethodName()); + } +} diff --git a/libraries/device-collectors/src/test/java/android/device/collectors/SimpleperfListenerTest.java b/libraries/device-collectors/src/test/java/android/device/collectors/SimpleperfListenerTest.java new file mode 100644 index 000000000..7473f71a6 --- /dev/null +++ b/libraries/device-collectors/src/test/java/android/device/collectors/SimpleperfListenerTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.device.collectors; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.Instrumentation; +import android.os.Bundle; +import androidx.test.runner.AndroidJUnit4; +import com.android.helpers.SimpleperfHelper; +import java.util.HashMap; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.Result; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +/** + * Android Unit tests for {@link SimpleperfListener}. + * + * <p>To run: atest CollectorDeviceLibTest:android.device.collectors.SimpleperfListenerTest + */ +@RunWith(AndroidJUnit4.class) +public class SimpleperfListenerTest { + + // A {@code Description} to pass when faking a test run start call. + private static final Description FAKE_DESCRIPTION = Description.createSuiteDescription("run"); + + private static final Description FAKE_TEST_DESCRIPTION = + Description.createTestDescription("class", "method"); + + private Description mRunDesc; + private Description mTest1Desc; + private Description mTest2Desc; + private SimpleperfListener mListener; + @Mock private Instrumentation mInstrumentation; + private Map<String, Integer> mInvocationCount; + private DataRecord mDataRecord; + + @Spy private SimpleperfHelper mSimpleperfHelper; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mRunDesc = Description.createSuiteDescription("run"); + mTest1Desc = Description.createTestDescription("run", "test1"); + mTest2Desc = Description.createTestDescription("run", "test2"); + } + + private SimpleperfListener initListener(Bundle b) { + mInvocationCount = new HashMap<>(); + + SimpleperfListener listener = + spy(new SimpleperfListener(b, mSimpleperfHelper, mInvocationCount)); + + mDataRecord = listener.createDataRecord(); + listener.setInstrumentation(mInstrumentation); + return listener; + } + + /* + * Verify simpleperf start and stop collection methods called exactly once for single test. + */ + @Test + public void testSimpleperfPerTestSuccessFlow() throws Exception { + Bundle b = new Bundle(); + mListener = initListener(b); + doReturn(true).when(mSimpleperfHelper).startCollecting(); + doReturn(true).when(mSimpleperfHelper).stopCollecting(anyString()); + // Test run start behavior + mListener.testRunStarted(mRunDesc); + + // Test test start behavior + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(1)).startCollecting(); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(1)).stopCollecting(anyString()); + } + + /* + * Verify stop collecting called exactly once when the test failed and the + * skip test failure mmetrics is enabled. + */ + @Test + public void testSimpleperfPerTestFailureFlowDefault() throws Exception { + Bundle b = new Bundle(); + b.putString(SimpleperfListener.SKIP_TEST_FAILURE_METRICS, "false"); + mListener = initListener(b); + + doReturn(true).when(mSimpleperfHelper).startCollecting(); + doReturn(true).when(mSimpleperfHelper).stopCollecting(anyString()); + // Test run start behavior + mListener.testRunStarted(mRunDesc); + + // Test test start behavior + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(1)).startCollecting(); + + // Test fail behaviour + Failure failureDesc = new Failure(FAKE_TEST_DESCRIPTION, new Exception()); + mListener.onTestFail(mDataRecord, mTest1Desc, failureDesc); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(1)).stopCollecting(anyString()); + } + + /* + * Verify stop simpleperf called exactly once when the test failed and the + * skip test failure metrics is enabled. + */ + @Test + public void testSimpleperfPerTestFailureFlowWithSkipMmetrics() throws Exception { + Bundle b = new Bundle(); + b.putString(SimpleperfListener.SKIP_TEST_FAILURE_METRICS, "true"); + mListener = initListener(b); + + doReturn(true).when(mSimpleperfHelper).startCollecting(); + doReturn(true).when(mSimpleperfHelper).stopSimpleperf(); + // Test run start behavior + mListener.testRunStarted(mRunDesc); + + // Test test start behavior + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(1)).startCollecting(); + + // Test fail behaviour + Failure failureDesc = new Failure(FAKE_TEST_DESCRIPTION, new Exception()); + mListener.onTestFail(mDataRecord, mTest1Desc, failureDesc); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(1)).stopSimpleperf(); + } + + /* + * Verify simpleperf start and stop collection methods called exactly once for test run. + * and not during each test method. + */ + @Test + public void testSimpleperfPerRunSuccessFlow() throws Exception { + Bundle b = new Bundle(); + b.putString(SimpleperfListener.COLLECT_PER_RUN, "true"); + mListener = initListener(b); + doReturn(true).when(mSimpleperfHelper).startCollecting(); + doReturn(true).when(mSimpleperfHelper).stopCollecting(anyString()); + + // Test run start behavior + mListener.onTestRunStart(mListener.createDataRecord(), FAKE_DESCRIPTION); + verify(mSimpleperfHelper, times(1)).startCollecting(); + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(1)).startCollecting(); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(0)).stopCollecting(anyString()); + mListener.onTestRunEnd(mListener.createDataRecord(), new Result()); + verify(mSimpleperfHelper, times(1)).stopCollecting(anyString()); + } + + /* + * Verify stop is not called if Simpleperf start did not succeed. + */ + @Test + public void testSimpleperfPerRunFailureFlow() throws Exception { + Bundle b = new Bundle(); + b.putString(SimpleperfListener.COLLECT_PER_RUN, "true"); + mListener = initListener(b); + doReturn(false).when(mSimpleperfHelper).startCollecting(); + + // Test run start behavior + mListener.onTestRunStart(mListener.createDataRecord(), FAKE_DESCRIPTION); + verify(mSimpleperfHelper, times(1)).startCollecting(); + mListener.onTestRunEnd(mListener.createDataRecord(), new Result()); + verify(mSimpleperfHelper, times(0)).stopCollecting(anyString()); + } + + /* + * Verify simpleperf stop is not invoked if start did not succeed. + */ + @Test + public void testSimpleperfStartFailureFlow() throws Exception { + Bundle b = new Bundle(); + mListener = initListener(b); + doReturn(false).when(mSimpleperfHelper).startCollecting(); + + // Test run start behavior + mListener.testRunStarted(mRunDesc); + + // Test test start behavior + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(1)).startCollecting(); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(0)).stopCollecting(anyString()); + } + + /* + * Verify test method invocation count is updated successfully based on the number of times the + * test method is invoked. + */ + @Test + public void testSimpleperfInvocationCount() throws Exception { + Bundle b = new Bundle(); + mListener = initListener(b); + doReturn(true).when(mSimpleperfHelper).startCollecting(); + doReturn(true).when(mSimpleperfHelper).stopCollecting(anyString()); + + // Test run start behavior + mListener.testRunStarted(mRunDesc); + + // Test1 invocation 1 start behavior + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(1)).startCollecting(); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(1)).stopCollecting(anyString()); + + // Test1 invocation 2 start behaviour + mListener.testStarted(mTest1Desc); + verify(mSimpleperfHelper, times(2)).startCollecting(); + mListener.onTestEnd(mDataRecord, mTest1Desc); + verify(mSimpleperfHelper, times(2)).stopCollecting(anyString()); + + // Test2 invocation 1 start behaviour + mListener.testStarted(mTest2Desc); + verify(mSimpleperfHelper, times(3)).startCollecting(); + mDataRecord = mListener.createDataRecord(); + mListener.onTestEnd(mDataRecord, mTest2Desc); + verify(mSimpleperfHelper, times(3)).stopCollecting(anyString()); + + // Check if the test count is incremented properly. + assertEquals(2, (int) mInvocationCount.get(mListener.getTestFileName(mTest1Desc))); + assertEquals(1, (int) mInvocationCount.get(mListener.getTestFileName(mTest2Desc))); + } +} diff --git a/libraries/health/rules/src/android/platform/test/rule/DisableAutofillRule.java b/libraries/health/rules/src/android/platform/test/rule/DisableAutofillRule.java new file mode 100644 index 000000000..ec936d0f8 --- /dev/null +++ b/libraries/health/rules/src/android/platform/test/rule/DisableAutofillRule.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.platform.test.rule; + +import android.support.test.uiautomator.UiDevice; +import android.text.TextUtils; + +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.runner.Description; + +import java.io.IOException; + +/** + * This rule sets the Android Autofill provider to none, and prevents autofill dialogs from popping + * up during the test. . + */ +public class DisableAutofillRule extends TestWatcher { + private String originalAutoFillService = "null"; + + @Override + protected void starting(Description description) { + try { + UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + String result = uiDevice.executeShellCommand("settings get secure autofill_service"); + if (!TextUtils.isEmpty(result) && !result.equals(originalAutoFillService)) { + originalAutoFillService = result; + } + uiDevice.executeShellCommand("settings put secure autofill_service null"); + } catch (IOException e) { + throw new RuntimeException("Failed to set autofill service to none"); + } + } + + @Override + protected void finished(Description description) { + try { + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + .executeShellCommand( + "settings put secure autofill_service " + originalAutoFillService); + } catch (IOException e) { + throw new RuntimeException("Failed to set autofill service back to original"); + } + } +} diff --git a/libraries/health/runners/longevity/host/src/android/host/test/longevity/listener/TimeoutTerminator.java b/libraries/health/runners/longevity/host/src/android/host/test/longevity/listener/TimeoutTerminator.java index 5204e44ef..65e6a0d20 100644 --- a/libraries/health/runners/longevity/host/src/android/host/test/longevity/listener/TimeoutTerminator.java +++ b/libraries/health/runners/longevity/host/src/android/host/test/longevity/listener/TimeoutTerminator.java @@ -44,7 +44,7 @@ public class TimeoutTerminator extends RunTerminator { * <p>Note: this initializes the countdown timer if unset. */ @Override - public void testRunStarted(Description description) { + public void testStarted(Description description) { if (mStartTimestamp == UNSET_TIMESTAMP) { mStartTimestamp = getCurrentTimestamp(); } diff --git a/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/LongevitySuiteTest.java b/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/LongevitySuiteTest.java index 261a87d80..d21a61f29 100644 --- a/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/LongevitySuiteTest.java +++ b/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/LongevitySuiteTest.java @@ -18,6 +18,8 @@ package android.host.test.longevity; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import android.host.test.longevity.listener.TimeoutTerminator; + import java.util.HashMap; import java.util.Map; @@ -81,7 +83,7 @@ public class LongevitySuiteTest { FailingTestSuite.class, new AllDefaultPossibilitiesBuilder(true), args); try { suite.run(new RunNotifier()); - fail("This run should be invalidated by test failures."); + fail("This run should be invalidated by test failure."); } catch (StoppedByUserException e) { // Expect this failure for an invalid, erroring test run. } @@ -91,9 +93,7 @@ public class LongevitySuiteTest { @SuiteClasses({ FailingTestSuite.FailingTest.class, }) - /** - * Sample device-side test cases. - */ + /** Sample device-side test case that fails. */ public static class FailingTestSuite { public static class FailingTest { @Test @@ -103,6 +103,38 @@ public class LongevitySuiteTest { } } + /** Tests that test runs are timing out if the tests run over the allotted suite time. */ + @Test + public void testTimeoutTestRuns() throws InitializationError { + Map<String, String> args = new HashMap(); + args.put(LongevitySuite.INVALIDATE_OPTION, "true"); + args.put(TimeoutTerminator.OPTION, "25"); + args.put(ITERATIONS_OPTION_NAME, String.valueOf(10)); + LongevitySuite suite = + new LongevitySuite( + TimeoutTestSuite.class, new AllDefaultPossibilitiesBuilder(true), args); + try { + suite.run(new RunNotifier()); + fail("This run should be ended by a timeout failure."); + } catch (StoppedByUserException e) { + // Expect this failure for an invalid, erroring test run. + } + } + + @RunWith(LongevitySuite.class) + @SuiteClasses({ + TimeoutTestSuite.TimedTest.class, + }) + /** Sample device-side test case that takes time. */ + public static class TimeoutTestSuite { + public static class TimedTest { + @Test + public void testSleep() throws InterruptedException { + Thread.sleep(10); + } + } + } + /** * Tests that the {@link LongevitySuite} properly accounts for the number of tests in children. */ diff --git a/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/listener/TimeoutTerminatorTest.java b/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/listener/TimeoutTerminatorTest.java index 1862e11b8..c439721f5 100644 --- a/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/listener/TimeoutTerminatorTest.java +++ b/libraries/health/runners/longevity/host/tests/src/android/host/test/longevity/listener/TimeoutTerminatorTest.java @@ -50,7 +50,7 @@ public class TimeoutTerminatorTest { */ @Test public void testTimeoutTerminator_pass() throws Exception { - mListener.testRunStarted(Description.EMPTY); + mListener.testStarted(Description.EMPTY); Thread.sleep(10L); mListener.testFinished(Description.EMPTY); verify(mNotifier, never()).pleaseStop(); @@ -61,7 +61,7 @@ public class TimeoutTerminatorTest { */ @Test public void testTimeoutTerminator_timeout() throws Exception { - mListener.testRunStarted(Description.EMPTY); + mListener.testStarted(Description.EMPTY); Thread.sleep(60L); mListener.testFinished(Description.EMPTY); verify(mNotifier).pleaseStop(); diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java index e565427e1..f1cc67d2b 100644 --- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java +++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevityClassRunner.java @@ -38,6 +38,7 @@ import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.MultipleFailureException; import org.junit.runners.model.Statement; +import org.junit.runner.notification.StoppedByUserException; /** * A {@link BlockJUnit4ClassRunner} that runs the test class's {@link BeforeClass} methods as {@link @@ -229,12 +230,16 @@ public class LongevityClassRunner extends BlockJUnit4ClassRunner { @Override public void evaluate() throws Throwable { List<Throwable> errors = new ArrayList<>(); + boolean stoppedByUser = false; try { mStatement.evaluate(); } catch (Throwable e) { + if (e instanceof StoppedByUserException) { + stoppedByUser = true; + } errors.add(e); } finally { - if (LongevityClassRunner.this.hasTestFailed()) { + if (!stoppedByUser && LongevityClassRunner.this.hasTestFailed()) { errors.addAll(invokeAndCollectErrors(mAfterClassMethods, mTarget)); } } diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java index ced687480..2e0df1c53 100644 --- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java +++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/LongevitySuite.java @@ -201,9 +201,7 @@ public class LongevitySuite extends android.host.test.longevity.LongevitySuite { super.runChild(suiteRunner, notifier); } - /** - * Returns the platform-specific {@link TimeoutTerminator} for Android devices. - */ + /** Returns the platform-specific {@link ErrorTerminator} for an Android device. */ @Override public android.host.test.longevity.listener.ErrorTerminator getErrorTerminator( final RunNotifier notifier) { @@ -211,7 +209,7 @@ public class LongevitySuite extends android.host.test.longevity.LongevitySuite { } /** - * Returns the platform-specific {@link TimeoutTerminator} for Android devices. + * Returns the platform-specific {@link TimeoutTerminator} for an Android device. * * <p>This method will always return the same {@link TimeoutTerminator} instance. */ diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/listener/TimeoutTerminatorTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/listener/TimeoutTerminatorTest.java index 76749ffb3..a6dfb79e9 100644 --- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/listener/TimeoutTerminatorTest.java +++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/listener/TimeoutTerminatorTest.java @@ -53,7 +53,7 @@ public class TimeoutTerminatorTest { */ @Test public void testTimeoutTerminator_pass() throws Exception { - mListener.testRunStarted(Description.EMPTY); + mListener.testStarted(Description.EMPTY); SystemClock.sleep(10L); verify(mNotifier, never()).pleaseStop(); } @@ -63,7 +63,7 @@ public class TimeoutTerminatorTest { */ @Test public void testTimeoutTerminator_timeout() throws Exception { - mListener.testRunStarted(Description.EMPTY); + mListener.testStarted(Description.EMPTY); SystemClock.sleep(60L); mListener.testFinished(Description.EMPTY); verify(mNotifier).pleaseStop(); diff --git a/libraries/launcher-helper/src/android/support/test/launcherhelper/LauncherStrategyFactory.java b/libraries/launcher-helper/src/android/support/test/launcherhelper/LauncherStrategyFactory.java index 8a3db419d..f812b991f 100644 --- a/libraries/launcher-helper/src/android/support/test/launcherhelper/LauncherStrategyFactory.java +++ b/libraries/launcher-helper/src/android/support/test/launcherhelper/LauncherStrategyFactory.java @@ -42,7 +42,6 @@ public class LauncherStrategyFactory { mKnownLauncherStrategies = new HashSet<>(); registerLauncherStrategy(AospLauncherStrategy.class); registerLauncherStrategy(AutoLauncherStrategy.class); - registerLauncherStrategy(VolvoLauncherStrategy.class); registerLauncherStrategy(GoogleExperienceLauncherStrategy.class); registerLauncherStrategy(Launcher3Strategy.class); registerLauncherStrategy(NexusLauncherStrategy.class); diff --git a/libraries/launcher-helper/src/android/support/test/launcherhelper/VolvoLauncherStrategy.java b/libraries/launcher-helper/src/android/support/test/launcherhelper/VolvoLauncherStrategy.java deleted file mode 100644 index d0cac6148..000000000 --- a/libraries/launcher-helper/src/android/support/test/launcherhelper/VolvoLauncherStrategy.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.support.test.launcherhelper; - -import android.app.Instrumentation; -import android.os.SystemClock; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.BySelector; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.Until; -import android.system.helpers.CommandsHelper; - -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** Implementation of {@link ILauncherStrategy} to support Volvo launcher */ -public class VolvoLauncherStrategy extends AutoLauncherStrategy { - private static final String VOLVO_LAUNCHER_PACKAGE = "com.volvocars.launcher"; - private static final String SYSTEM_UI_PACKAGE = "com.android.systemui"; - - private static final Map<String, BySelector> FACET_MAP = - Stream.of( - new Object[][] { - { - "App Grid", - By.res(SYSTEM_UI_PACKAGE, "nav_bar_apps").clickable(true) - }, - }) - .collect( - Collectors.toMap( - data -> (String) data[0], data -> (BySelector) data[1])); - - private static final Map<String, BySelector> APP_OPEN_VERIFIERS = - Stream.of( - new Object[][] { - {"App Grid", By.res(VOLVO_LAUNCHER_PACKAGE, "apps_pane")}, - }) - .collect( - Collectors.toMap( - data -> (String) data[0], data -> (BySelector) data[1])); - - private static final long APP_LAUNCH_TIMEOUT_MS = 10000; - private static final long UI_WAIT_TIMEOUT_MS = 5000; - private static final long POLL_INTERVAL = 100; - - protected UiDevice mDevice; - private Instrumentation mInstrumentation; - private CommandsHelper mCommandsHelper; - - @Override - public String getSupportedLauncherPackage() { - return VOLVO_LAUNCHER_PACKAGE; - } - - @Override - public void setUiDevice(UiDevice uiDevice) { - mDevice = uiDevice; - } - - @Override - public void setInstrumentation(Instrumentation instrumentation) { - super.setInstrumentation(instrumentation); - mInstrumentation = instrumentation; - mCommandsHelper = CommandsHelper.getInstance(mInstrumentation); - } - - @Override - public void openApp(String appName) { - if (checkApplicationExists(appName)) { - UiObject2 app = mDevice.findObject(By.clickable(true).hasDescendant(By.text(appName))); - app.clickAndWait(Until.newWindow(), APP_LAUNCH_TIMEOUT_MS); - mDevice.waitForIdle(); - } else { - throw new RuntimeException(String.format("Application %s not found", appName)); - } - } - - @Override - public void openBluetoothAudioApp() { - String appName = "Bluetooth Media Player"; - if (checkApplicationExists(appName)) { - UiObject2 app = mDevice.findObject(By.clickable(true).hasDescendant(By.text(appName))); - app.clickAndWait(Until.newWindow(), APP_LAUNCH_TIMEOUT_MS); - mDevice.waitForIdle(); - } else { - throw new RuntimeException(String.format("Application %s not found", appName)); - } - } - - @Override - public void openGooglePlayStore() { - mDevice.pressHome(); - mDevice.waitForIdle(); - mCommandsHelper.executeShellCommand( - "am start -a android.intent.action.MAIN " - + "-c android.intent.category.LAUNCHER " - + "-n com.android.vending/" - + "com.google.android.finsky.carmainactivity.MainActivity"); - } - - @Override - public boolean checkApplicationExists(String appName) { - openAppGridFacet(); - UiObject2 app = findApplication(appName); - return app != null; - } - - @Override - public void openAppGridFacet() { - openFacet("App Grid"); - } - - @Override - public void openMapsFacet() { - // Volvo does not have Facet for Maps, so open Maps from App Grid - openApp("Maps"); - } - - private void openFacet(String facetName) { - BySelector facetSelector = FACET_MAP.get(facetName); - UiObject2 facet = mDevice.findObject(facetSelector); - if (facet != null) { - facet.click(); - waitUntilAppOpen(facetName, APP_LAUNCH_TIMEOUT_MS); - } else { - throw new RuntimeException(String.format("Failed to find %s facet.", facetName)); - } - } - - private void waitUntilAppOpen(String appName, long timeout) { - SystemClock.sleep(timeout); - long startTime = SystemClock.uptimeMillis(); - boolean isOpen = false; - do { - isOpen = mDevice.hasObject(APP_OPEN_VERIFIERS.get(appName)); - if (isOpen) { - break; - } - SystemClock.sleep(POLL_INTERVAL); - } while ((SystemClock.uptimeMillis() - startTime) < timeout); - if (!isOpen) { - throw new IllegalStateException( - String.format( - "Did not find any app of %s in foreground after %d ms.", - appName, timeout)); - } - } - - private UiObject2 findApplication(String appName) { - BySelector appSelector = By.clickable(true).hasDescendant(By.text(appName)); - return mDevice.findObject(appSelector); - } - - /** {@inheritDoc} */ - @Override - public void openNotifications() { - String cmd = "cmd statusbar expand-notifications"; - mCommandsHelper.executeShellCommand(cmd); - } - - /** {@inheritDoc} */ - @Override - public void pressHome() { - String cmd = "input keyevent KEYCODE_HOME"; - mCommandsHelper.executeShellCommand(cmd); - } -} diff --git a/scripts/perf-setup/b5r3-setup.sh b/scripts/perf-setup/b5r3-setup.sh new file mode 100755 index 000000000..d02ee0771 --- /dev/null +++ b/scripts/perf-setup/b5r3-setup.sh @@ -0,0 +1,84 @@ +#!/system/bin/sh +# +# Copyright (C) 2020 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# performance test setup for 2020 devices +function disable_thermal() +{ + thermal_path='/sys/devices/virtual/thermal/' + + nz=$(ls -al $thermal_path | grep thermal_zone | wc -l) + i=0 + while [ $i -lt $nz ]; do + tz_path=$thermal_path'thermal_zone'$i'/' + mode_path=$tz_path'mode' + + if [ -f $mode_path ]; then + echo disabled > $tz_path'mode' + fi + i=$(($i + 1)); + done +} + +disable_thermal +setprop vendor.powerhal.init 0 +setprop ctl.restart vendor.power-hal-aidl + +cpubase=/sys/devices/system/cpu +gov=cpufreq/scaling_governor + +cpu=6 +top=8 +#Big Core 652800 940800 1152000 1478400 1728000 1900800 2092800 2208000 +#Big Plus 806400 1094400 1401600 1766400 1996800 2188800 2304000 2400000 +cpufreq=2092800 +# Set the bigcores around 2G +while [ $((cpu < $top)) -eq 1 ]; do + echo 1 > $cpubase/cpu${cpu}/online + echo userspace > $cpubase/cpu${cpu}/$gov + echo $cpufreq > /sys/devices/system/cpu/cpu$cpu/cpufreq/scaling_max_freq + echo $cpufreq > /sys/devices/system/cpu/cpu$cpu/cpufreq/scaling_setspeed + S=`cat $cpubase/cpu${cpu}/cpufreq/scaling_cur_freq` + echo "set cpu $cpu to $S kHz" + cpu=$(($cpu + 1)) +done + +cpu=0 +top=6 +# Disable the silver cores. +while [ $((cpu < $top)) -eq 1 ]; do + echo "disable cpu $cpu" + echo 0 > $cpubase/cpu${cpu}/online + cpu=$(($cpu + 1)) +done + +echo "disable GPU bus split" +echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split +echo "enable GPU force clock on" +echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on +echo "set GPU idle timer to 10000" +echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer + +# 0 381 572 762 1144 1571 2086 2597 2929 3879 4943 5931 6881 +echo performance > /sys/class/devfreq/soc:qcom,gpubw/governor +echo -n "set GPU bus frequency to max at " +cat /sys/class/devfreq/soc:qcom,gpubw/cur_freq + +#625 500 400 275 mhz +echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor +echo 0 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel +echo 0 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel +echo -n "set GPU frequency to max at " +cat /sys/class/kgsl/kgsl-3d0/devfreq/cur_freq diff --git a/tests/functional/devicehealthchecks/assets/bug_map b/tests/functional/devicehealthchecks/assets/bug_map index b6173492b..1448d8db5 100644 --- a/tests/functional/devicehealthchecks/assets/bug_map +++ b/tests/functional/devicehealthchecks/assets/bug_map @@ -13,6 +13,7 @@ system_app_crash com.google.android.inputmethod.latin 157051520 system_app_crash com.android.vending/com.google.android.finsky.verifier.impl.PackageVerificationService 156670156 system_app_crash com.google.android.apps.youtube.music.mediabrowser.MusicBrowserService.a 157917208 system_app_crash android.database.sqlite.SQLiteCloseable.acquireReference 159658068 +system_app_crash com.google.android.gms.backup.component.D2dTransportService 31428310 system_app_native_crash com.google.android.apps.safetyhub 154358781 system_app_native_crash com.google.android.providers.media.module 154416156 system_server_crash void.com.android.server.location.gnss.GnssBatchingProvider.enable 159504970 |