Merge "Fix FreeMemListener and TotalPssListener"
diff --git a/build/tasks/tests/instrumentation_test_list.mk b/build/tasks/tests/instrumentation_test_list.mk
index d3f2e68..84790cb 100644
--- a/build/tasks/tests/instrumentation_test_list.mk
+++ b/build/tasks/tests/instrumentation_test_list.mk
@@ -69,16 +69,6 @@
SettingsUITests \
ExtServicesUnitTests
-# Android Things specific tests
-ifeq ($(PRODUCT_IOT),true)
-
-instrumentation_tests += \
- AndroidThingsTests \
- ThingsIntegrationTests \
- WifiSetupUnitTests
-
-endif # PRODUCT_IOT == true
-
# Storage Manager may not exist on device
ifneq ($(filter StorageManager, $(PRODUCT_PACKAGES)),)
diff --git a/build/tasks/tests/native_test_list.mk b/build/tasks/tests/native_test_list.mk
index c3b9159..e1abfd9 100644
--- a/build/tasks/tests/native_test_list.mk
+++ b/build/tasks/tests/native_test_list.mk
@@ -58,7 +58,6 @@
libbpf_android_test \
libcutils_test \
libcutils_test_static \
- libdemangle_test \
libgui_test \
libhidl_test \
libinput_tests \
@@ -130,18 +129,3 @@
NeuralNetworksTest_static \
SurfaceFlinger_test \
lmkd_unit_test
-
-# Android Things specific tests
-ifeq ($(PRODUCT_IOT),true)
-
-native_tests += \
- crash_reporter_tests \
- libandroidthings_pio_tests \
- libbrillo_test \
- libchrome_test \
- libusersensors_binder_test \
- peripheralman_unittests \
- sensors_userdriver_test \
- userinputdriver_test
-
-endif # PRODUCT_IOT == true
diff --git a/libraries/annotations/src/android/platform/test/annotations/SystemUserOnly.java b/libraries/annotations/src/android/platform/test/annotations/SystemUserOnly.java
new file mode 100644
index 0000000..fc318fe
--- /dev/null
+++ b/libraries/annotations/src/android/platform/test/annotations/SystemUserOnly.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Marks that the test is valid only when running against system user. */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SystemUserOnly {
+ /** The reason why the test has to be run against system user. */
+ String reason() default "";
+}
diff --git a/libraries/app-helpers/handheld/Android.bp b/libraries/app-helpers/handheld/Android.bp
new file mode 100644
index 0000000..5815fa2
--- /dev/null
+++ b/libraries/app-helpers/handheld/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2019 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: "handheld-app-helpers",
+ sdk_version: "test_current",
+ static_libs: [
+ "app-helpers-handheld-interfaces",
+ "business-card-app-helper",
+ "performance-launch-app-helper"
+ ],
+ srcs: ["src/**/*.java"],
+}
diff --git a/libraries/app-helpers/handheld/business-card-app-helper/Android.bp b/libraries/app-helpers/handheld/business-card-app-helper/Android.bp
new file mode 100644
index 0000000..91cf865
--- /dev/null
+++ b/libraries/app-helpers/handheld/business-card-app-helper/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 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: "business-card-app-helper",
+ libs: [
+ "app-helpers-handheld-interfaces",
+ ],
+ srcs: ["src/**/*.java"],
+ sdk_version: "test_current",
+}
diff --git a/libraries/app-helpers/handheld/business-card-app-helper/src/android/platform/helpers/BusinessCardHelperImpl.java b/libraries/app-helpers/handheld/business-card-app-helper/src/android/platform/helpers/BusinessCardHelperImpl.java
new file mode 100644
index 0000000..1d8ae1d
--- /dev/null
+++ b/libraries/app-helpers/handheld/business-card-app-helper/src/android/platform/helpers/BusinessCardHelperImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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.helpers;
+
+import android.app.Instrumentation;
+
+public class BusinessCardHelperImpl extends AbstractStandardAppHelper
+ implements IBusinessCardHelper {
+ private static final String UI_PACKAGE_NAME = "com.example.android.businesscard";
+
+ public BusinessCardHelperImpl(Instrumentation instrumentation) {
+ super(instrumentation);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getPackage() {
+ return UI_PACKAGE_NAME;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getLauncherName() {
+ return "Business Card";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void dismissInitialDialogs() {
+ // There are no initial dialogs to dismiss for Business Card.
+ }
+}
diff --git a/libraries/app-helpers/handheld/performance-launch-app-helper/Android.bp b/libraries/app-helpers/handheld/performance-launch-app-helper/Android.bp
new file mode 100644
index 0000000..1d339a1
--- /dev/null
+++ b/libraries/app-helpers/handheld/performance-launch-app-helper/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 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: "performance-launch-app-helper",
+ libs: [
+ "app-helpers-handheld-interfaces",
+ ],
+ srcs: ["src/**/*.java"],
+ sdk_version: "test_current",
+}
diff --git a/libraries/app-helpers/handheld/performance-launch-app-helper/src/android/platform/helpers/PerformanceLaunchHelperImpl.java b/libraries/app-helpers/handheld/performance-launch-app-helper/src/android/platform/helpers/PerformanceLaunchHelperImpl.java
new file mode 100644
index 0000000..8385dc8
--- /dev/null
+++ b/libraries/app-helpers/handheld/performance-launch-app-helper/src/android/platform/helpers/PerformanceLaunchHelperImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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.helpers;
+
+import android.app.Instrumentation;
+
+public class PerformanceLaunchHelperImpl extends AbstractStandardAppHelper
+ implements IPerformanceLaunchHelper {
+ private static final String UI_PACKAGE_NAME = "com.android.performanceLaunch";
+
+ public PerformanceLaunchHelperImpl(Instrumentation instrumentation) {
+ super(instrumentation);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getPackage() {
+ return UI_PACKAGE_NAME;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getLauncherName() {
+ return "PerformanceLaunch";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void dismissInitialDialogs() {
+ // There are no initial dialogs to dismiss for Business Card.
+ }
+}
diff --git a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IBusinessCardHelper.java b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IBusinessCardHelper.java
new file mode 100644
index 0000000..bf08f08
--- /dev/null
+++ b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IBusinessCardHelper.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 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.helpers;
+
+/** An App Helper interface for Business Card. */
+public interface IBusinessCardHelper extends IAppHelper {}
diff --git a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPerformanceLaunchHelper.java b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPerformanceLaunchHelper.java
new file mode 100644
index 0000000..6a0eb5f
--- /dev/null
+++ b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPerformanceLaunchHelper.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 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.helpers;
+
+/** An App Helper interface for Performance Launch. */
+public interface IPerformanceLaunchHelper extends IAppHelper {}
diff --git a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IYTMusicHelper.java b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IYTMusicHelper.java
index 1908529..cd83af6 100644
--- a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IYTMusicHelper.java
+++ b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IYTMusicHelper.java
@@ -34,6 +34,15 @@
public void openAlbums();
/**
+ * Setup expectations: YT Music is open and the Library tab is visible.
+ *
+ * <p>This method will select the songs. This method blocks until the process is complete.
+ */
+ public default void openSongs() {
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ /**
* Setup expectations: YT Music is open and the Albums page is visible.
*
* <p>This method will browse the device files. The method will block until the process is
@@ -42,6 +51,15 @@
public void browseDeviceFiles();
/**
+ * Setup expectations: YT Music is open and the song list is visible.
+ *
+ * <p>This method will select the song. The method will block until the song is playing.
+ */
+ public default void selectSong(String song) {
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ /**
* Setup expectations: YT Music is open and the album list is visible.
*
* <p>This method will select the album and select the song. The method will block until the
diff --git a/libraries/collectors-helper/memory/src/com/android/helpers/FreeMemHelper.java b/libraries/collectors-helper/memory/src/com/android/helpers/FreeMemHelper.java
index 1a5fd7b..da0ff2c 100644
--- a/libraries/collectors-helper/memory/src/com/android/helpers/FreeMemHelper.java
+++ b/libraries/collectors-helper/memory/src/com/android/helpers/FreeMemHelper.java
@@ -43,7 +43,7 @@
* freeMemHelper.getMetrics();
* freeMemHelper.stopCollecting();
*/
-public final class FreeMemHelper implements ICollectorHelper<Long> {
+public class FreeMemHelper implements ICollectorHelper<Long> {
private static final String TAG = FreeMemHelper.class.getSimpleName();
private static final String SEPARATOR = "\\s+";
private static final String DUMPSYS_MEMIFNO = "dumpsys meminfo";
diff --git a/libraries/collectors-helper/power/Android.bp b/libraries/collectors-helper/power/Android.bp
new file mode 100644
index 0000000..8d68a83
--- /dev/null
+++ b/libraries/collectors-helper/power/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2019 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 perfetto traces.
+java_library {
+ name: "power-helper",
+ defaults: ["tradefed_errorprone_defaults"],
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "collector-helper-utilities",
+ "androidx.test.runner",
+ "guava",
+ "ub-uiautomator",
+ ],
+
+ sdk_version: "current",
+}
+
diff --git a/libraries/collectors-helper/power/src/com/android/helpers/PwrStatsUtilHelper.java b/libraries/collectors-helper/power/src/com/android/helpers/PwrStatsUtilHelper.java
new file mode 100644
index 0000000..7782857
--- /dev/null
+++ b/libraries/collectors-helper/power/src/com/android/helpers/PwrStatsUtilHelper.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 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.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.test.InstrumentationRegistry;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * PwrStatsUtilHelper runs and collects power stats HAL metrics from the Pixel-specific
+ * pwrstats_util tool that is already included on the device in userdebug builds.
+ */
+public class PwrStatsUtilHelper implements ICollectorHelper<Long> {
+ private static final String LOG_TAG = PwrStatsUtilHelper.class.getSimpleName();
+
+ private UiDevice mDevice = null;
+
+ @VisibleForTesting protected int mUtilPid = 0;
+ @VisibleForTesting protected File mLogFile;
+
+ @Override
+ public boolean startCollecting() {
+ Log.i(LOG_TAG, "Starting pwrstats_util collection...");
+ // Create temp log file for pwrstats_util
+ try {
+ mLogFile = File.createTempFile("pwrstats_output", ".txt");
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.toString());
+ return false;
+ }
+ mLogFile.delete();
+
+ // Kick off pwrstats_util and get its PID
+ final String pid_regex = "^pid = (\\d+)$";
+ final Pattern pid_pattern = Pattern.compile(pid_regex);
+ String output;
+ try {
+ output = executeShellCommand("pwrstats_util -d " + mLogFile.getAbsolutePath());
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.toString());
+ return false;
+ }
+ Matcher m = pid_pattern.matcher(output);
+ if (m.find()) {
+ mUtilPid = Integer.parseInt(m.group(1));
+ }
+ return true;
+ }
+
+ @Override
+ public boolean stopCollecting() {
+ Log.i(LOG_TAG, "Ending pwrstats_util collection...");
+ try {
+ executeShellCommand("kill -INT " + mUtilPid);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.toString());
+ return false;
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, e.toString());
+ }
+ return true;
+ }
+
+ @Override
+ public Map<String, Long> getMetrics() {
+ stopCollecting();
+
+ Log.i(LOG_TAG, "Getting metrics...");
+ return processMetricsFromLogFile();
+ }
+
+ @VisibleForTesting
+ /* Execute a shell command and return its output. */
+ protected String executeShellCommand(String command) throws IOException {
+ if (mDevice == null) {
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
+ Log.i(LOG_TAG, "Running '" + command + "'");
+ return mDevice.executeShellCommand(command);
+ }
+
+ /* Parse each of the metrics into a key value pair and delete the log file. */
+ private Map<String, Long> processMetricsFromLogFile() {
+ final String PATTERN = "^(.*)=(\\d+)$";
+ final Pattern r = Pattern.compile(PATTERN);
+ Map<String, Long> metrics = new HashMap<>();
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(mLogFile));
+ // First line is elapsed time
+ String line = br.readLine();
+ Matcher m;
+ while ((line = br.readLine()) != null) {
+ m = r.matcher(line);
+ if (m.find()) {
+ Log.i(LOG_TAG, m.group(1) + "=" + m.group(2));
+ metrics.put(m.group(1), Long.parseLong(m.group(2)));
+ }
+ }
+ mLogFile.delete();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.toString());
+ }
+
+ try {
+ if (br != null) br.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.toString());
+ }
+ return metrics;
+ }
+}
diff --git a/libraries/collectors-helper/power/test/Android.bp b/libraries/collectors-helper/power/test/Android.bp
new file mode 100644
index 0000000..fa1d4c8
--- /dev/null
+++ b/libraries/collectors-helper/power/test/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2019 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: "power-helper-test",
+ defaults: ["tradefed_errorprone_defaults"],
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "mockito-target",
+ "power-helper",
+ ],
+
+ sdk_version: "current",
+}
diff --git a/libraries/collectors-helper/power/test/src/com/android/helpers/PwrStatsUtilHelperTest.java b/libraries/collectors-helper/power/test/src/com/android/helpers/PwrStatsUtilHelperTest.java
new file mode 100644
index 0000000..f4052f7
--- /dev/null
+++ b/libraries/collectors-helper/power/test/src/com/android/helpers/PwrStatsUtilHelperTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 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.support.test.uiautomator.UiDevice;
+
+
+import java.io.IOException;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.Mockito.doReturn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public final class PwrStatsUtilHelperTest {
+ private @Spy PwrStatsUtilHelper mHelper;
+ private @Mock UiDevice mUiDevice;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void successfulRun() {
+ final String pid_output = "pid = 11386\n";
+ final String metric_output =
+ "elapsed time: 14.8746s\n"
+ + "SLPI__Sleep=14505\n"
+ + "SLPI_ISLAND__uImage=14498\n"
+ + "SoC__CXSD=0\n"
+ + "SoC__AOSD=0\n";
+ try {
+ doReturn(metric_output).when(mHelper).executeShellCommand(matches("kill -INT \\d+"));
+ doReturn(pid_output).when(mHelper).executeShellCommand(matches("pwrstats_util -d .*"));
+ } catch (IOException e) {
+ assertTrue(e.toString(), false);
+ }
+
+ // Validate startCollecting()
+ assertTrue(mHelper.startCollecting());
+ assertNotNull(mHelper.mLogFile);
+ assertTrue(
+ "Expecting PID " + mHelper.mUtilPid + " to be greater than 0",
+ (mHelper.mUtilPid > 0));
+
+ // Validate getMetrics()
+ Map<String, Long> metrics = mHelper.getMetrics();
+ assertEquals(metrics.size(), 4);
+
+ // Validate that stopCollecting() works when run after getMetrics()
+ assertTrue(mHelper.stopCollecting());
+ }
+}
diff --git a/libraries/collectors-helper/system/Android.bp b/libraries/collectors-helper/system/Android.bp
new file mode 100644
index 0000000..9baeeed
--- /dev/null
+++ b/libraries/collectors-helper/system/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2019 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 the any of the metrics from the system.
+java_library {
+ name: "system-metric-helper",
+ defaults: ["tradefed_errorprone_defaults"],
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "androidx.test.runner",
+ "collector-helper-utilities",
+ "guava",
+ "ub-uiautomator",
+ ],
+
+ sdk_version: "current",
+}
+
diff --git a/libraries/collectors-helper/system/src/com/android/helpers/ProcLoadHelper.java b/libraries/collectors-helper/system/src/com/android/helpers/ProcLoadHelper.java
new file mode 100644
index 0000000..025d53e
--- /dev/null
+++ b/libraries/collectors-helper/system/src/com/android/helpers/ProcLoadHelper.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 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.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** An {@link ProcLoadHelper} to check for cpu load in last minute is lesser or equal
+ * to given threshold for a given timeout and collect the cpu load as metric.
+ */
+public class ProcLoadHelper implements ICollectorHelper<Double> {
+
+ private static final String LOG_TAG = ProcLoadHelper.class.getSimpleName();
+ private static final String LOAD_CMD = "cat /proc/loadavg";
+ public static final String LAST_MINUTE_LOAD_METRIC_KEY = "proc_loadavg_last_minute";
+
+ private static final Pattern LOAD_OUTPUT_PATTERN = Pattern.compile(
+ "(?<LASTMINUTELOAD>.*)\\s.*\\s.*\\s.*\\s.*");
+
+ private double mProcLoadThreshold = 0;
+ private long mProcLoadWaitTimeInMs = 0;
+ // Default to 500 msecs timeout.
+ private long mProcLoadIntervalInMs = 500;
+ private double mRecentLoad = 0;
+ private UiDevice mDevice;
+
+ /** Wait untill the proc/load reaches below the threshold or timeout expires */
+ @Override
+ public boolean startCollecting() {
+ mRecentLoad = 0;
+ long remainingWaitTime = mProcLoadWaitTimeInMs;
+ while (true) {
+ mRecentLoad = getProcLoadInLastMinute();
+ Log.i(LOG_TAG, String.format("Average cpu load in last minute is : %s", mRecentLoad));
+ if (mRecentLoad <= mProcLoadThreshold) {
+ break;
+ } else {
+ if (remainingWaitTime <= 0) {
+ Log.i(LOG_TAG, "Timeout because proc/loadavg never went below the threshold.");
+ return false;
+ }
+ long currWaitTime = (mProcLoadIntervalInMs < remainingWaitTime)
+ ? mProcLoadIntervalInMs : remainingWaitTime;
+ Log.d(LOG_TAG, String.format("Waiting for %s msecs", currWaitTime));
+ SystemClock.sleep(currWaitTime);
+ remainingWaitTime = remainingWaitTime - mProcLoadIntervalInMs;
+ }
+ }
+ return true;
+ }
+
+ /** Collect the proc/load_avg last minute cpu load average metric. */
+ @Override
+ public Map<String, Double> getMetrics() {
+ // Adding the last recorded load in the metric that will be reported.
+ Map<String, Double> result = new HashMap<>();
+ Log.i(LOG_TAG, String.format("proc/loadavg in last minute before test is : %s",
+ mRecentLoad));
+ result.put(LAST_MINUTE_LOAD_METRIC_KEY, mRecentLoad);
+ return result;
+ }
+
+ /** Do nothing, because nothing is needed to disable cpuy load avg. */
+ @Override
+ public boolean stopCollecting() {
+ return true;
+ }
+
+ /**
+ * Parse the last minute cpu load from proc/loadavg
+ *
+ * @return cpu load in last minute. Returns -1 in case if it is failed to parse.
+ */
+ private double getProcLoadInLastMinute() {
+ try {
+ String output = getDevice().executeShellCommand(LOAD_CMD);
+ Log.i(LOG_TAG, String.format("Output of proc_loadavg is : %s", output));
+ // Output of the load command
+ // 1.39 1.10 1.21 2/2679 6380
+ // 1.39 is the proc load in the last minute.
+
+ Matcher match = null;
+ if ((match = matches(LOAD_OUTPUT_PATTERN, output.trim())) != null) {
+ Log.i(LOG_TAG, String.format("Current load is : %s",
+ match.group("LASTMINUTELOAD")));
+ return Double.parseDouble(match.group("LASTMINUTELOAD"));
+ } else {
+ Log.w(LOG_TAG, "Not able to parse the proc/loadavg");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to get proc/loadavg.", e);
+ }
+
+ return -1;
+ }
+
+ /** Returns the {@link UiDevice} under test. */
+ private UiDevice getDevice() {
+ if (mDevice == null) {
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+ return mDevice;
+ }
+
+ /**
+ * Checks whether {@code line} matches the given {@link Pattern}.
+ *
+ * @return The resulting {@link Matcher} obtained by matching the {@code line} against
+ * {@code pattern}, or null if the {@code line} does not match.
+ */
+ private static Matcher matches(Pattern pattern, String line) {
+ Matcher ret = pattern.matcher(line);
+ return ret.matches() ? ret : null;
+ }
+
+ /**
+ * Sets the threshold value which the device cpu load average should be lesser than or equal.
+ */
+ public void setProcLoadThreshold(double procLoadThreshold) {
+ mProcLoadThreshold = procLoadThreshold;
+ }
+
+ /**
+ * Sets the timeout in msecs checking for threshold before proceeding with the testing.
+ */
+ public void setProcLoadWaitTimeInMs(long procLoadWaitTimeInMs) {
+ mProcLoadWaitTimeInMs = procLoadWaitTimeInMs;
+ }
+
+ /**
+ * Sets the interval time in msecs to check continuosly untill the timeout expires.
+ */
+ public void setProcLoadIntervalInMs(long procLoadIntervalInMs) {
+ mProcLoadIntervalInMs = procLoadIntervalInMs;
+ }
+}
diff --git a/libraries/collectors-helper/system/test/Android.bp b/libraries/collectors-helper/system/test/Android.bp
new file mode 100644
index 0000000..4d94e5a
--- /dev/null
+++ b/libraries/collectors-helper/system/test/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 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: "system-helper-test",
+ defaults: ["tradefed_errorprone_defaults"],
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.test.runner",
+ "system-metric-helper",
+ "junit",
+ "mockito-target",
+ "truth-prebuilt",
+ ],
+
+ sdk_version: "current",
+}
diff --git a/libraries/collectors-helper/system/test/src/com/android/helpers/tests/ProcLoadHelperTest.java b/libraries/collectors-helper/system/test/src/com/android/helpers/tests/ProcLoadHelperTest.java
new file mode 100644
index 0000000..a66d8bc
--- /dev/null
+++ b/libraries/collectors-helper/system/test/src/com/android/helpers/tests/ProcLoadHelperTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.helpers.ProcLoadHelper;
+import static com.android.helpers.ProcLoadHelper.LAST_MINUTE_LOAD_METRIC_KEY;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+/**
+ * Android Unit tests for {@link ProcLoadHelperTest}.
+ *
+ * To run:
+ * atest CollectorsHelperTest:com.android.helpers.tests.ProcLoadHelperTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class ProcLoadHelperTest {
+
+ private ProcLoadHelper mLoadHelper;
+
+ @Before
+ public void setUp() {
+ mLoadHelper = new ProcLoadHelper();
+ }
+
+ /** Test to verify succesfull threshold flow. **/
+ @Test
+ public void testThresholdSuccess() {
+ // By setting the threshold higher(i.e 100) the current load should be always
+ // lesser than the the 100 which should proceed with add the current
+ // load avg during the last minute in the metrics.
+ mLoadHelper.setProcLoadThreshold(100);
+ mLoadHelper.setProcLoadWaitTimeInMs(1100L);
+ mLoadHelper.setProcLoadIntervalInMs(100L);
+ assertTrue(mLoadHelper.startCollecting());
+ Map<String, Double> procLoadMetric = mLoadHelper.getMetrics();
+ assertTrue(procLoadMetric.containsKey(LAST_MINUTE_LOAD_METRIC_KEY));
+ assertTrue(procLoadMetric.get(LAST_MINUTE_LOAD_METRIC_KEY) > 0);
+ }
+
+ /** Test to verify threshold not met workflow. */
+ @Test
+ public void testMetricAfterTimeout() {
+ // By setting the threshold lower(i.e 0) the cpu utilization will never be met
+ // which should result in timeout.
+ mLoadHelper.setProcLoadThreshold(0);
+ mLoadHelper.setProcLoadWaitTimeInMs(4000L);
+ mLoadHelper.setProcLoadIntervalInMs(200L);
+ assertFalse(mLoadHelper.startCollecting());
+ Map<String, Double> procLoadMetric = mLoadHelper.getMetrics();
+ assertTrue(procLoadMetric.get(LAST_MINUTE_LOAD_METRIC_KEY) > 0);
+ }
+
+ /** Test to verify the timeout if the threshold did not meet. */
+ @Test
+ public void testWaitForTimeout() {
+ // By setting the threshold lower(i.e 0) the cpu utilization will never be met
+ // which should result in timeout.
+ mLoadHelper.setProcLoadThreshold(0);
+ mLoadHelper.setProcLoadWaitTimeInMs(4000L);
+ mLoadHelper.setProcLoadIntervalInMs(200L);
+ long startTime = System.currentTimeMillis();
+ assertFalse(mLoadHelper.startCollecting());
+ long waitTime = System.currentTimeMillis() - startTime;
+ assertTrue((waitTime > 4000L && waitTime < 6000L));
+ Map<String, Double> procLoadMetric = mLoadHelper.getMetrics();
+ assertTrue(procLoadMetric.get(LAST_MINUTE_LOAD_METRIC_KEY) > 0);
+ }
+
+ /** Test to verify metric exist and exits with the default threshold, timeout and interval */
+ @Test
+ public void testDefaults() {
+ long startTime = System.currentTimeMillis();
+ assertFalse(mLoadHelper.startCollecting());
+ Map<String, Double> procLoadMetric = mLoadHelper.getMetrics();
+ assertTrue(procLoadMetric.containsKey(LAST_MINUTE_LOAD_METRIC_KEY));
+ assertTrue(procLoadMetric.get(LAST_MINUTE_LOAD_METRIC_KEY) > 0);
+ }
+}
diff --git a/libraries/device-collectors/src/main/Android.bp b/libraries/device-collectors/src/main/Android.bp
index 9e144ed..9ae62aa 100644
--- a/libraries/device-collectors/src/main/Android.bp
+++ b/libraries/device-collectors/src/main/Android.bp
@@ -24,7 +24,9 @@
"junit",
"memory-helper",
"perfetto-helper",
+ "power-helper",
"ub-uiautomator",
+ "system-metric-helper",
],
sdk_version: "current",
diff --git a/libraries/device-collectors/src/main/java/android/device/collectors/FreeMemListener.java b/libraries/device-collectors/src/main/java/android/device/collectors/FreeMemListener.java
new file mode 100644
index 0000000..4b4bc51
--- /dev/null
+++ b/libraries/device-collectors/src/main/java/android/device/collectors/FreeMemListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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 androidx.annotation.VisibleForTesting;
+
+import com.android.helpers.FreeMemHelper;
+
+/**
+ * A {@link FreeMemListener} that captures and records free memory available
+ * in the device.
+ */
+@OptionClass(alias = "freemem-listener")
+public class FreeMemListener extends BaseCollectionListener<Long> {
+
+ public FreeMemListener() {
+ createHelperInstance(new FreeMemHelper());
+ }
+
+ @VisibleForTesting
+ public FreeMemListener(Bundle args, FreeMemHelper helper) {
+ super(args, helper);
+ }
+}
diff --git a/libraries/device-collectors/src/main/java/android/device/collectors/ProcLoadListener.java b/libraries/device-collectors/src/main/java/android/device/collectors/ProcLoadListener.java
new file mode 100644
index 0000000..adc4c7b
--- /dev/null
+++ b/libraries/device-collectors/src/main/java/android/device/collectors/ProcLoadListener.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 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 androidx.annotation.VisibleForTesting;
+
+import com.android.helpers.ProcLoadHelper;
+
+/**
+ * A {@link ProcLoadListener} that waits until the proc/load threshold is met
+ * or timeout expires.
+ *
+ * Options:
+ * <p>-e proc-loadavg-threshold 1 : The threshold the system cpu load has
+ * to be less than or equal in last minute.
+ *
+ * <p>-e proc-loadavg-timeout 1000 :
+ * Timeout to wait before the threshold is met.
+ *
+ * <p>-e proc-loadavg-interval 100 :
+ * Interval frequency to check if the threshold is met or not.
+ *
+ */
+@OptionClass(alias = "procload-collector")
+public class ProcLoadListener extends BaseCollectionListener<Double> {
+
+ private static final String TAG = ProcLoadListener.class.getSimpleName();
+ @VisibleForTesting
+ static final String PROC_LOAD_THRESHOLD = "proc-loadavg-threshold";
+ @VisibleForTesting
+ static final String PROC_THRESHOLD_TIMEOUT = "proc-loadavg-timeout";
+ @VisibleForTesting
+ static final String PROC_LOAD_INTERVAL = "proc-loadavg-interval";
+
+ private ProcLoadHelper mProcLoadHelper = new ProcLoadHelper();
+
+ public ProcLoadListener() {
+ createHelperInstance(mProcLoadHelper);
+ }
+
+ /**
+ * Constructor to simulate receiving the instrumentation arguments. Should not be used except
+ * for testing.
+ */
+ @VisibleForTesting
+ public ProcLoadListener(Bundle args, ProcLoadHelper helper) {
+ super(args, helper);
+ mProcLoadHelper = helper;
+ createHelperInstance(mProcLoadHelper);
+ }
+
+ /**
+ * Adds the options for total pss collector.
+ */
+ @Override
+ public void setupAdditionalArgs() {
+ Bundle args = getArgsBundle();
+
+ if (args.getString(PROC_LOAD_THRESHOLD) != null) {
+ mProcLoadHelper.setProcLoadThreshold(Double.parseDouble(args
+ .getString(PROC_LOAD_THRESHOLD)));
+ }
+
+ if (args.getString(PROC_THRESHOLD_TIMEOUT) != null) {
+ mProcLoadHelper.setProcLoadWaitTimeInMs(Long.parseLong(args
+ .getString(PROC_THRESHOLD_TIMEOUT)));
+ }
+
+ if (args.getString(PROC_LOAD_INTERVAL) != null) {
+ mProcLoadHelper.setProcLoadIntervalInMs(Long.parseLong(args
+ .getString(PROC_LOAD_INTERVAL)));
+ }
+
+ }
+}
diff --git a/libraries/device-collectors/src/main/java/android/device/collectors/PwrStatsUtilListener.java b/libraries/device-collectors/src/main/java/android/device/collectors/PwrStatsUtilListener.java
new file mode 100644
index 0000000..d797b66
--- /dev/null
+++ b/libraries/device-collectors/src/main/java/android/device/collectors/PwrStatsUtilListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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 com.android.helpers.PwrStatsUtilHelper;
+
+/**
+ * A {@link PwrStatsUtilListener} that captures power stats during the test method.
+ *
+ * <p>Do NOT throw exception anywhere in this class. We don't want to halt the test when metrics
+ * collection fails.
+ */
+@OptionClass(alias = "pwrstats-util-collector")
+public class PwrStatsUtilListener extends BaseCollectionListener<Long> {
+ public PwrStatsUtilListener() {
+ createHelperInstance(new PwrStatsUtilHelper());
+ }
+}
diff --git a/libraries/device-collectors/src/test/java/android/device/collectors/FreeMemListenerTest.java b/libraries/device-collectors/src/test/java/android/device/collectors/FreeMemListenerTest.java
new file mode 100644
index 0000000..c399125
--- /dev/null
+++ b/libraries/device-collectors/src/test/java/android/device/collectors/FreeMemListenerTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.app.Instrumentation;
+import android.os.Bundle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.helpers.FreeMemHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Android Unit tests for {@link FreeMemListener}.
+ *
+ * To run:
+ * atest CollectorDeviceLibTest:android.device.collectors.FreeMemListenerTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class FreeMemListenerTest {
+
+ @Mock
+ private Instrumentation mInstrumentation;
+ @Mock
+ private FreeMemHelper mFreeMemHelper;
+
+ private FreeMemListener mListener;
+ private Description mRunDesc;
+ private Description mTest1Desc;
+ private DataRecord mDataRecord;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mRunDesc = Description.createSuiteDescription("run");
+ mTest1Desc = Description.createTestDescription("run", "test1");
+ }
+
+ private FreeMemListener initListener() {
+ FreeMemListener listener = new FreeMemListener(new Bundle(), mFreeMemHelper);
+ listener.setInstrumentation(mInstrumentation);
+ mDataRecord = listener.createDataRecord();
+ return listener;
+ }
+
+ @Test
+ public void testFreeMemHelperCalls() throws Exception {
+ mListener = initListener();
+ mListener.testRunStarted(mRunDesc);
+
+ // Test test start behavior
+ mListener.testStarted(mTest1Desc);
+ verify(mFreeMemHelper, times(1)).startCollecting();
+ mListener.onTestEnd(mDataRecord, mTest1Desc);
+ verify(mFreeMemHelper, times(1)).stopCollecting();
+ }
+}
diff --git a/libraries/device-collectors/src/test/java/android/device/collectors/ProcLoadListenerTest.java b/libraries/device-collectors/src/test/java/android/device/collectors/ProcLoadListenerTest.java
new file mode 100644
index 0000000..f90470e
--- /dev/null
+++ b/libraries/device-collectors/src/test/java/android/device/collectors/ProcLoadListenerTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 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 android.device.collectors.ProcLoadListener.PROC_LOAD_THRESHOLD;
+import static android.device.collectors.ProcLoadListener.PROC_THRESHOLD_TIMEOUT;
+import static android.device.collectors.ProcLoadListener.PROC_LOAD_INTERVAL;
+
+
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.helpers.ProcLoadHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Android Unit tests for {@link ProcLoadListener}.
+ *
+ * To run:
+ * atest CollectorDeviceLibTest:android.device.collectors.ProcLoadListenerTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class ProcLoadListenerTest {
+
+ @Mock
+ private Instrumentation mInstrumentation;
+ @Mock
+ private ProcLoadHelper mProcLoadHelper;
+
+ private ProcLoadListener mListener;
+ private Description mRunDesc;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mRunDesc = Description.createSuiteDescription("run");
+ }
+
+ private ProcLoadListener initListener(Bundle b) {
+ ProcLoadListener listener = new ProcLoadListener(b, mProcLoadHelper);
+ listener.setInstrumentation(mInstrumentation);
+ return listener;
+ }
+
+ @Test
+ public void testLoadProcAdditionalOptions() throws Exception {
+ Bundle b = new Bundle();
+ b.putString(PROC_LOAD_THRESHOLD, "1");
+ b.putString(PROC_THRESHOLD_TIMEOUT, "3");
+ b.putString(PROC_LOAD_INTERVAL, "2");
+ mListener = initListener(b);
+ mListener.testRunStarted(mRunDesc);
+
+ verify(mProcLoadHelper).setProcLoadThreshold(1);
+ verify(mProcLoadHelper).setProcLoadWaitTimeInMs(3L);
+ verify(mProcLoadHelper).setProcLoadIntervalInMs(2L);
+ }
+}
diff --git a/libraries/health/runners/longevity/platform/Android.bp b/libraries/health/runners/longevity/platform/Android.bp
index b183da4..8cc34e0 100644
--- a/libraries/health/runners/longevity/platform/Android.bp
+++ b/libraries/health/runners/longevity/platform/Android.bp
@@ -37,5 +37,5 @@
"guava",
"platform-test-composers",
],
- sdk_version: "26",
+ min_sdk_version: "26",
}
diff --git a/libraries/health/runners/longevity/platform/samples/Android.bp b/libraries/health/runners/longevity/platform/samples/Android.bp
index 3cea772..9c59016 100644
--- a/libraries/health/runners/longevity/platform/samples/Android.bp
+++ b/libraries/health/runners/longevity/platform/samples/Android.bp
@@ -43,7 +43,7 @@
android_test {
name: "LongevityPlatformLibSamples",
- sdk_version: "24",
+ min_sdk_version: "24",
static_libs: [
"androidx.test.runner",
"common-platform-scenarios",
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 34382b2..a94e27c 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
@@ -46,11 +46,13 @@
*/
public class LongevityClassRunner extends BlockJUnit4ClassRunner {
@VisibleForTesting static final String FILTER_OPTION = "exclude-class";
- @VisibleForTesting static final String ITERATION_SEP = "@";
+ @VisibleForTesting static final String ITERATION_SEP_OPTION = "iteration-separator";
+ @VisibleForTesting static final String ITERATION_SEP_DEFAULT = "@";
// A constant to indicate that the iteration number is not set.
@VisibleForTesting static final int ITERATION_NOT_SET = -1;
private String[] mExcludedClasses;
+ private String mIterationSep = ITERATION_SEP_DEFAULT;
private boolean mTestFailed = true;
private boolean mTestAttempted = false;
@@ -68,6 +70,10 @@
args.containsKey(FILTER_OPTION)
? args.getString(FILTER_OPTION).split(",")
: new String[] {};
+ mIterationSep =
+ args.containsKey(ITERATION_SEP_OPTION)
+ ? args.getString(ITERATION_SEP_OPTION)
+ : mIterationSep;
}
/** Set the iteration of the test that this runner is running. */
@@ -268,7 +274,7 @@
return original;
}
return Description.createTestDescription(
- String.join(ITERATION_SEP, original.getClassName(), String.valueOf(mIteration)),
+ String.join(mIterationSep, original.getClassName(), String.valueOf(mIteration)),
original.getMethodName());
}
}
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 850a830..74a22ab 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
@@ -30,11 +30,13 @@
import androidx.annotation.VisibleForTesting;
import androidx.test.InstrumentationRegistry;
+import java.lang.reflect.Field;
import java.util.function.BiFunction;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.junit.internal.runners.ErrorReportingRunner;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
@@ -138,6 +140,11 @@
} catch (Throwable t) {
throw new InitializationError(t);
}
+ // If a scenario is an ErrorReportingRunner, an InitializationError has occurred when
+ // initializing the runner. Throw out a new error with the causes.
+ if (runner instanceof ErrorReportingRunner) {
+ throw new InitializationError(getCauses((ErrorReportingRunner) runner));
+ }
// All scenarios must extend BlockJUnit4ClassRunner.
if (!(runner instanceof BlockJUnit4ClassRunner)) {
throw new InitializationError(
@@ -232,4 +239,30 @@
mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
}
+
+ /** Gets the first cause out of a {@link ErrorReportingRunner}. Also logs the rest. */
+ private static List<Throwable> getCauses(ErrorReportingRunner runner) {
+ // Reflection is used for this operation as the runner itself does not allow the errors
+ // to be read directly, and masks everything as an InitializationError in its description,
+ // which is not very useful.
+ // It is ok to throw RuntimeException here as we have already entered a failure state. It is
+ // helpful to know that a ErrorReportingRunner has occurred even if we can't decipher it.
+ try {
+ Field causesField = runner.getClass().getDeclaredField("causes");
+ causesField.setAccessible(true);
+ return (List<Throwable>) causesField.get(runner);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(
+ String.format(
+ "Unable to find a \"causes\" field in the ErrorReportingRunner %s.",
+ runner.getDescription()),
+ e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ String.format(
+ "Unable to access the \"causes\" field in the ErrorReportingRunner %s.",
+ runner.getDescription()),
+ e);
+ }
+ }
}
diff --git a/libraries/health/runners/longevity/platform/tests/Android.bp b/libraries/health/runners/longevity/platform/tests/Android.bp
index 33d8587..a9e6a03 100644
--- a/libraries/health/runners/longevity/platform/tests/Android.bp
+++ b/libraries/health/runners/longevity/platform/tests/Android.bp
@@ -44,7 +44,7 @@
android_test {
name: "LongevityPlatformLibTests",
- sdk_version: "26",
+ min_sdk_version: "26",
static_libs: [
"androidx.test.runner",
"common-platform-scenarios",
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java
index 70669b4..4e8d76c 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevityClassRunnerTest.java
@@ -383,12 +383,15 @@
captor.getValue()
.getClassName()
.matches(
- String.join(LongevityClassRunner.ITERATION_SEP, "^.*", "[0-9]+$")));
+ String.join(
+ LongevityClassRunner.ITERATION_SEP_DEFAULT,
+ "^.*",
+ "[0-9]+$")));
}
- /** Test that the runner reports iteration when set. */
+ /** Test that the runner reports iteration when set and the default separator was used. */
@Test
- public void testReportIteration_withIteration() throws Throwable {
+ public void testReportIteration_withIteration_withDefaultSeparator() throws Throwable {
ArgumentCaptor<Description> captor = ArgumentCaptor.forClass(Description.class);
RunNotifier notifier = mock(RunNotifier.class);
mRunner = spy(new LongevityClassRunner(NoOpTest.class));
@@ -399,7 +402,27 @@
"Description class name should contain the iteration number.",
captor.getValue()
.getClassName()
- .matches(String.join(LongevityClassRunner.ITERATION_SEP, "^.*", "7$")));
+ .matches(
+ String.join(
+ LongevityClassRunner.ITERATION_SEP_DEFAULT, "^.*", "7$")));
+ }
+
+ /** Test that the runner reports iteration when set and a custom separator was supplied. */
+ @Test
+ public void testReportIteration_withIteration_withCustomSeparator() throws Throwable {
+ String sep = "--";
+ Bundle args = new Bundle();
+ args.putString(LongevityClassRunner.ITERATION_SEP_OPTION, sep);
+
+ ArgumentCaptor<Description> captor = ArgumentCaptor.forClass(Description.class);
+ RunNotifier notifier = mock(RunNotifier.class);
+ mRunner = spy(new LongevityClassRunner(NoOpTest.class, args));
+ mRunner.setIteration(7);
+ mRunner.run(notifier);
+ verify(notifier).fireTestStarted(captor.capture());
+ Assert.assertTrue(
+ "Description class name should contain the iteration number.",
+ captor.getValue().getClassName().matches(String.join(sep, "^.*", "7$")));
}
private List<FrameworkMethod> getMethodNameMatcher(String methodName) {
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevitySuiteTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevitySuiteTest.java
index d50d536..4a53202 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevitySuiteTest.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/LongevitySuiteTest.java
@@ -17,6 +17,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -31,15 +32,19 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.internal.runners.ErrorReportingRunner;
import org.junit.runner.Runner;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.JUnit4;
import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
import org.junit.runners.Suite.SuiteClasses;
import org.mockito.Mockito;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -168,6 +173,37 @@
Assert.assertEquals(runners.get(2).getIteration(), 2);
}
+ /**
+ * Test that when a builder ends up being a {@link ErrorReportingRunner}, the underlying error
+ * is reported as an InitializationError.
+ */
+ @Test
+ public void testThrowingErrorReportingRunnerCauses() throws Throwable {
+ RunnerBuilder builder = mock(RunnerBuilder.class);
+ InitializationError expected =
+ new InitializationError(
+ Arrays.asList(
+ new RuntimeException("Cause 1"), new RuntimeException("Cause 2")));
+ when(builder.runnerForClass(IterationSuite.TestOne.class))
+ .thenReturn(new BlockJUnit4ClassRunner(IterationSuite.TestOne.class));
+ when(builder.runnerForClass(IterationSuite.TestTwo.class))
+ .thenReturn(new ErrorReportingRunner(IterationSuite.TestTwo.class, expected));
+ try {
+ mSuite =
+ new LongevitySuite(
+ IterationSuite.class,
+ builder,
+ mInstrumentation,
+ mContext,
+ new Bundle());
+ Assert.fail("An InitializationError should have been thrown");
+ } catch (InitializationError e) {
+ Assert.assertEquals(e.getCauses().size(), 2);
+ Assert.assertEquals(e.getCauses().get(0).getMessage(), "Cause 1");
+ Assert.assertEquals(e.getCauses().get(1).getMessage(), "Cause 2");
+ }
+ }
+
/** Sample device-side test cases. */
@RunWith(LongevitySuite.class)
@SuiteClasses({
diff --git a/libraries/launcher-helper/src/android/support/test/launcherhelper/NexusLauncherStrategy.java b/libraries/launcher-helper/src/android/support/test/launcherhelper/NexusLauncherStrategy.java
index ce58081..472d7dd 100644
--- a/libraries/launcher-helper/src/android/support/test/launcherhelper/NexusLauncherStrategy.java
+++ b/libraries/launcher-helper/src/android/support/test/launcherhelper/NexusLauncherStrategy.java
@@ -57,7 +57,7 @@
*/
@Override
public BySelector getAllAppsSelector() {
- return By.res(getSupportedLauncherPackage(), "apps_view");
+ return By.res(getSupportedLauncherPackage(), "apps_list_view");
}
/**
diff --git a/tests/health/scenarios/Android.bp b/tests/health/scenarios/Android.bp
index 3afce78..56e87e4 100644
--- a/tests/health/scenarios/Android.bp
+++ b/tests/health/scenarios/Android.bp
@@ -14,12 +14,15 @@
java_library_static {
name: "common-platform-scenarios",
- sdk_version: "24",
+ min_sdk_version: "24",
srcs: [ "src/**/*.java" ],
libs: [
"androidx.test.runner",
"junit",
"platform-test-options",
"ub-uiautomator",
+ "app-helpers-handheld-interfaces",
+ "platform-test-rules",
+ "handheld-app-helpers"
],
}
diff --git a/tests/health/scenarios/src/android/platform/test/scenario/businesscard/DismissDialogs.java b/tests/health/scenarios/src/android/platform/test/scenario/businesscard/DismissDialogs.java
new file mode 100644
index 0000000..b48dc36
--- /dev/null
+++ b/tests/health/scenarios/src/android/platform/test/scenario/businesscard/DismissDialogs.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 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.scenario.businesscard;
+
+import android.platform.helpers.HelperAccessor;
+import android.platform.helpers.IBusinessCardHelper;
+import android.platform.test.rule.NaturalOrientationRule;
+import android.platform.test.scenario.annotation.AppSetup;
+import android.platform.test.scenario.annotation.Scenario;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Dismisses initial dialogs. */
+@AppSetup
+@Scenario
+@RunWith(JUnit4.class)
+public class DismissDialogs {
+ // Class-level rules
+ @ClassRule public static NaturalOrientationRule orientationRule = new NaturalOrientationRule();
+
+ private static HelperAccessor<IBusinessCardHelper> sHelper =
+ new HelperAccessor<>(IBusinessCardHelper.class);
+
+ @BeforeClass
+ public static void openApp() {
+ sHelper.get().open();
+ }
+
+ @Test
+ public void testDismissDialogs() {
+ sHelper.get().dismissInitialDialogs();
+ }
+
+ @AfterClass
+ public static void closeApp() {
+ sHelper.get().exit();
+ }
+}
diff --git a/tests/health/scenarios/src/android/platform/test/scenario/businesscard/OpenApp.java b/tests/health/scenarios/src/android/platform/test/scenario/businesscard/OpenApp.java
new file mode 100644
index 0000000..a9b8473
--- /dev/null
+++ b/tests/health/scenarios/src/android/platform/test/scenario/businesscard/OpenApp.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.scenario.businesscard;
+
+import android.platform.helpers.HelperAccessor;
+import android.platform.helpers.IBusinessCardHelper;
+import android.platform.test.rule.NaturalOrientationRule;
+import android.platform.test.scenario.annotation.Scenario;
+
+import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Opens the Business Card application and exits after. */
+@Scenario
+@RunWith(JUnit4.class)
+public class OpenApp {
+ // Class-level rules
+ @ClassRule public static NaturalOrientationRule orientationRule = new NaturalOrientationRule();
+
+ private static HelperAccessor<IBusinessCardHelper> sHelper =
+ new HelperAccessor<>(IBusinessCardHelper.class);
+
+ @Test
+ public void testOpen() {
+ sHelper.get().open();
+ }
+
+ @AfterClass
+ public static void closeApp() {
+ sHelper.get().exit();
+ }
+}
diff --git a/tests/health/scenarios/src/android/platform/test/scenario/performancelaunch/DismissDialogs.java b/tests/health/scenarios/src/android/platform/test/scenario/performancelaunch/DismissDialogs.java
new file mode 100644
index 0000000..59d3f4d
--- /dev/null
+++ b/tests/health/scenarios/src/android/platform/test/scenario/performancelaunch/DismissDialogs.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 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.scenario.performancelaunch;
+
+import android.platform.helpers.HelperAccessor;
+import android.platform.helpers.IPerformanceLaunchHelper;
+import android.platform.test.rule.NaturalOrientationRule;
+import android.platform.test.scenario.annotation.AppSetup;
+import android.platform.test.scenario.annotation.Scenario;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Dismisses initial dialogs. */
+@AppSetup
+@Scenario
+@RunWith(JUnit4.class)
+public class DismissDialogs {
+ // Class-level rules
+ @ClassRule public static NaturalOrientationRule orientationRule = new NaturalOrientationRule();
+
+ private static HelperAccessor<IPerformanceLaunchHelper> sHelper =
+ new HelperAccessor<>(IPerformanceLaunchHelper.class);
+
+ @BeforeClass
+ public static void openApp() {
+ sHelper.get().open();
+ }
+
+ @Test
+ public void testDismissDialogs() {
+ sHelper.get().dismissInitialDialogs();
+ }
+
+ @AfterClass
+ public static void closeApp() {
+ sHelper.get().exit();
+ }
+}
diff --git a/tests/health/scenarios/src/android/platform/test/scenario/performancelaunch/OpenApp.java b/tests/health/scenarios/src/android/platform/test/scenario/performancelaunch/OpenApp.java
new file mode 100644
index 0000000..ca4b835
--- /dev/null
+++ b/tests/health/scenarios/src/android/platform/test/scenario/performancelaunch/OpenApp.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.scenario.performancelaunch;
+
+import android.platform.helpers.HelperAccessor;
+import android.platform.helpers.IPerformanceLaunchHelper;
+import android.platform.test.rule.NaturalOrientationRule;
+import android.platform.test.scenario.annotation.Scenario;
+
+import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Opens the Performance Launch application and exits after. */
+@Scenario
+@RunWith(JUnit4.class)
+public class OpenApp {
+ // Class-level rules
+ @ClassRule public static NaturalOrientationRule orientationRule = new NaturalOrientationRule();
+
+ private static HelperAccessor<IPerformanceLaunchHelper> sHelper =
+ new HelperAccessor<>(IPerformanceLaunchHelper.class);
+
+ @Test
+ public void testOpen() {
+ sHelper.get().open();
+ }
+
+ @AfterClass
+ public static void closeApp() {
+ sHelper.get().exit();
+ }
+}
diff --git a/tests/health/scenarios/tests/Android.bp b/tests/health/scenarios/tests/Android.bp
index a108c82..af33979 100644
--- a/tests/health/scenarios/tests/Android.bp
+++ b/tests/health/scenarios/tests/Android.bp
@@ -53,6 +53,8 @@
"platform-test-composers",
"platform-test-options",
"platform-test-rules",
+ "handheld-app-helpers",
+ "launcher-helper-lib",
],
srcs: ["src/**/*.java"],
test_suites: ["device-tests"],