Merge "Track MemFree from cat proc/meminfo"
diff --git a/build/tasks/tests/instrumentation_test_list.mk b/build/tasks/tests/instrumentation_test_list.mk
index f6761d9..5ef9952 100644
--- a/build/tasks/tests/instrumentation_test_list.mk
+++ b/build/tasks/tests/instrumentation_test_list.mk
@@ -70,9 +70,6 @@
FrameworksPrivacyLibraryTests \
SettingsUITests \
ExtServicesUnitTests\
- NexusLauncherOutOfProcTests\
- NexusLauncherDebug\
- NexusLauncherTests\
FrameworksNetSmokeTests\
diff --git a/build/tasks/tests/native_test_list.mk b/build/tasks/tests/native_test_list.mk
index 9e7ffcd..0d7693a 100644
--- a/build/tasks/tests/native_test_list.mk
+++ b/build/tasks/tests/native_test_list.mk
@@ -111,6 +111,7 @@
prioritydumper_test \
puffin_unittest \
recovery_unit_test \
+ resolv_gold_test \
resolv_integration_test \
resolv_unit_test \
scrape_mmap_addr \
@@ -129,7 +130,6 @@
NeuralNetworksTest_mt_static \
NeuralNetworksTest_operations \
NeuralNetworksTest_static \
- NeuralNetworksTest_static_asan \
SurfaceFlinger_test \
lmkd_unit_test \
vrflinger_test
diff --git a/build/tasks/tests/platform_test_list.mk b/build/tasks/tests/platform_test_list.mk
index ba96337..b6a4a16 100644
--- a/build/tasks/tests/platform_test_list.mk
+++ b/build/tasks/tests/platform_test_list.mk
@@ -59,6 +59,7 @@
InternalLocTestApp \
JankMicroBenchmarkTests \
libbluetooth_gd \
+ long_trace_config.textproto \
libgrpc++_unsecure \
MemoryUsage \
MultiDexLegacyTestApp \
@@ -79,14 +80,13 @@
NotificationFunctionalTests \
NotificationStressTests \
OverviewFunctionalTests \
+ perfetto_trace_processor_shell \
PerformanceAppTest \
PerformanceLaunch \
PermissionFunctionalTests \
PermissionTestAppMV1 \
PermissionUtils \
- PlatformScenarioTests \
PowerPerfTest \
- root-canal \
SettingsUITests \
SimpleTestApp \
skia_dm \
@@ -96,6 +96,7 @@
SmokeTestApp \
SysAppJankTestsWear \
TouchLatencyJankTestWear \
+ trace_config_detailed.textproto \
UbSystemUiJankTests \
UbWebViewJankTests \
UiBench \
@@ -117,8 +118,12 @@
platform_tests += perf-setup.sh
endif
-ifneq ($(filter vsoc_x86 vsoc_x86_64, $(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter vsoc_arm vsoc_arm64 vsoc_x86 vsoc_x86_64, $(TARGET_BOARD_PLATFORM)),)
platform_tests += \
CuttlefishRilTests \
CuttlefishWifiTests
endif
+
+ifeq ($(HOST_OS),linux)
+platform_tests += root-canal
+endif
diff --git a/libraries/app-helpers/interfaces/common/src/android/platform/helpers/IContactsHelper.java b/libraries/app-helpers/interfaces/common/src/android/platform/helpers/IContactsHelper.java
index 0c07aa6..7ef499c 100644
--- a/libraries/app-helpers/interfaces/common/src/android/platform/helpers/IContactsHelper.java
+++ b/libraries/app-helpers/interfaces/common/src/android/platform/helpers/IContactsHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -38,6 +38,19 @@
}
/**
+ * Setup expectation: Contacts is open
+ *
+ * <p>Clicks search field and inputs contact to search. Provide alternative ways to input
+ * contact.
+ *
+ * @param contact The contact to search.
+ * @param useKeyboard Use KeyEvent to input contact if true, use UiObject2 setText otherwise.
+ */
+ public default void searchForContact(String contact, boolean useKeyboard) {
+ throw new UnsupportedOperationException("Not yet implemented.");
+ }
+
+ /**
* Setup expectations: The search results of contact showed.
* <p>
* Selects the contact by the specific index.
diff --git a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPhotosHelper.java b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPhotosHelper.java
index 85b243d..15684fd 100644
--- a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPhotosHelper.java
+++ b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IPhotosHelper.java
@@ -112,22 +112,22 @@
public void openPicture(int index);
/**
- * Setup expectations: Photos is open and a picture album is open.
+ * Setup expectations: Photos is open and a picture is open.
*
- * This method will scroll the picture album in the specified direction.
+ * <p>This method will scroll to next or previous picture in the specified direction.
*
* @param direction The direction to scroll, must be LEFT or RIGHT.
- * @return Returns whether album can be still scrolled in the given direction
+ * @return Returns whether picture can be still scrolled in the given direction
*/
- public boolean scrollAlbum(Direction direction);
+ public boolean scrollPicture(Direction direction);
/**
- * Setup expectations: Photos is open and a picture folder is open.
+ * Setup expectations: Photos is open and a page contains pictures or albums is open.
*
- * This method will scroll the Photos grid view in the specified direction.
+ * <p>This method will scroll the page in the specified direction.
*
* @param direction The direction of the scroll, must be UP or DOWN.
* @return Returns whether the object can still scroll in the given direction
*/
- public boolean scrollGridView(Direction direction);
+ public boolean scrollPage(Direction direction);
}
diff --git a/libraries/collectors-helper/jank/src/com/android/helpers/SfStatsCollectionHelper.java b/libraries/collectors-helper/jank/src/com/android/helpers/SfStatsCollectionHelper.java
index aaa5d2d..b2c0948 100644
--- a/libraries/collectors-helper/jank/src/com/android/helpers/SfStatsCollectionHelper.java
+++ b/libraries/collectors-helper/jank/src/com/android/helpers/SfStatsCollectionHelper.java
@@ -37,7 +37,8 @@
private static final String LOG_TAG = SfStatsCollectionHelper.class.getSimpleName();
- private static final Pattern KEY_VALUE_PATTERN = Pattern.compile("^(\\w+)\\s+=\\s+(\\S+)");
+ private static final Pattern KEY_VALUE_PATTERN =
+ Pattern.compile("^(\\w+)\\s+=\\s+(\\d+\\.?\\d*|.*).*");
private static final Pattern HISTOGRAM_PATTERN =
Pattern.compile("([^\\n]+)\\n((\\d+ms=\\d+\\s+)+)");
diff --git a/libraries/collectors-helper/jank/test/src/com/android/helpers/SfStatsCollectionHelperTest.java b/libraries/collectors-helper/jank/test/src/com/android/helpers/SfStatsCollectionHelperTest.java
index 3d851ea..c986a67 100644
--- a/libraries/collectors-helper/jank/test/src/com/android/helpers/SfStatsCollectionHelperTest.java
+++ b/libraries/collectors-helper/jank/test/src/com/android/helpers/SfStatsCollectionHelperTest.java
@@ -85,7 +85,25 @@
+ "post2present histogram is as below:\n"
+ "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=264 9ms=0\n"
+ "post2acquire histogram is as below:\n"
- + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=264 9ms=0";
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=264 9ms=0\n"
+ + "\n"
+ + "layerName = SurfaceView - com.mxtech.videoplayer.ad/com.mxtech.videoplayer.ad.ActivityScreen#0\n"
+ + "packageName = \n"
+ + "totalFrames = 2352\n"
+ + "droppedFrames = 0\n"
+ + "averageFPS = 59.999\n"
+ + "present2present histogram is as below:\n"
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=2352 9ms=0\n"
+ + "latch2present histogram is as below:\n"
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=2352 9ms=0\n"
+ + "desired2present histogram is as below:\n"
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=2352 9ms=0\n"
+ + "acquire2present histogram is as below:\n"
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=2352 9ms=0\n"
+ + "post2present histogram is as below:\n"
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=2352 9ms=0\n"
+ + "post2acquire histogram is as below:\n"
+ + "0ms=0 1ms=0 2ms=0 3ms=0 4ms=0 5ms=0 6ms=0 7ms=0 8ms=2352 9ms=0";
private static final String LOG_TAG = SfStatsCollectionHelperTest.class.getSimpleName();
@@ -140,6 +158,27 @@
constructKey(
SFSTATS_METRICS_PREFIX,
"GLOBAL",
+ "clientCompositionFrames".toUpperCase())))
+ .isEqualTo(Double.valueOf(0));
+ assertThat(
+ metrics.get(
+ constructKey(
+ SFSTATS_METRICS_PREFIX,
+ "GLOBAL",
+ "displayOnTime".toUpperCase())))
+ .isEqualTo(Double.valueOf(2485421));
+ assertThat(
+ metrics.get(
+ constructKey(
+ SFSTATS_METRICS_PREFIX,
+ "GLOBAL",
+ "totalP2PTime".toUpperCase())))
+ .isEqualTo(Double.valueOf(2674034));
+ assertThat(
+ metrics.get(
+ constructKey(
+ SFSTATS_METRICS_PREFIX,
+ "GLOBAL",
"FRAME_CPU_DURATION_AVG")))
.isEqualTo(Double.valueOf(5.5));
assertThat(
@@ -191,6 +230,27 @@
"com.google.android.nexuslauncher.NexusLauncherActivity#0",
"AVERAGE_FPS")))
.isEqualTo(84.318);
+ assertThat(
+ metrics.get(
+ constructKey(
+ SFSTATS_METRICS_PREFIX,
+ "SurfaceView - com.mxtech.videoplayer.ad/com.mxtech.videoplayer.ad.ActivityScreen#0",
+ "TOTAL_FRAMES")))
+ .isEqualTo(Double.valueOf(2352));
+ assertThat(
+ metrics.get(
+ constructKey(
+ SFSTATS_METRICS_PREFIX,
+ "SurfaceView - com.mxtech.videoplayer.ad/com.mxtech.videoplayer.ad.ActivityScreen#0",
+ "DROPPED_FRAMES")))
+ .isEqualTo(Double.valueOf(0));
+ assertThat(
+ metrics.get(
+ constructKey(
+ SFSTATS_METRICS_PREFIX,
+ "SurfaceView - com.mxtech.videoplayer.ad/com.mxtech.videoplayer.ad.ActivityScreen#0",
+ "AVERAGE_FPS")))
+ .isEqualTo(59.999);
mHelper.stopCollecting();
}
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 8217182..b2f1f8c 100644
--- a/libraries/collectors-helper/memory/src/com/android/helpers/FreeMemHelper.java
+++ b/libraries/collectors-helper/memory/src/com/android/helpers/FreeMemHelper.java
@@ -117,7 +117,7 @@
for (String process : cachedProcList) {
Log.i(TAG, "Cached Process" + process);
Matcher match;
- if (((match = matches(PID_PATTERN, process))) != null) {
+ if ((match = matches(PID_PATTERN, process)) != null) {
String processId = match.group(PROCESS_ID);
String processDumpSysMemInfo = String.format(DUMPSYS_PROCESS, processId);
String processInfoStr;
@@ -183,7 +183,7 @@
Log.i(TAG, currLine);
Matcher match;
if (!isCacheProcSection
- && ((match = matches(CACHE_PROC_START_PATTERN, currLine))) == null) {
+ && (match = matches(CACHE_PROC_START_PATTERN, currLine)) == null) {
// Continue untill the start of cache proc section.
continue;
} else {
diff --git a/libraries/device-collectors/src/test/java/android/device/preparers/GarbageCollectionPreparerTest.java b/libraries/device-collectors/src/test/java/android/device/preparers/GarbageCollectionPreparerTest.java
index 81bad3a..2449264 100644
--- a/libraries/device-collectors/src/test/java/android/device/preparers/GarbageCollectionPreparerTest.java
+++ b/libraries/device-collectors/src/test/java/android/device/preparers/GarbageCollectionPreparerTest.java
@@ -20,13 +20,11 @@
import static android.device.preparers.GarbageCollectionPreparer.PROCESS_NAMES_KEY;
import static android.device.preparers.GarbageCollectionPreparer.PROCESS_SEPARATOR;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.app.Instrumentation;
-import android.device.collectors.DataRecord;
import android.os.Bundle;
import com.android.helpers.GarbageCollectionHelper;
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/Assertions.java b/libraries/flicker/src/com/android/server/wm/flicker/Assertions.java
index ff2de41..82b92bd 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/Assertions.java
+++ b/libraries/flicker/src/com/android/server/wm/flicker/Assertions.java
@@ -114,9 +114,13 @@
private String prettyTimestamp(long timestamp_ns) {
StringBuilder prettyTimestamp = new StringBuilder();
TimeUnit[] timeUnits = {
- TimeUnit.HOURS, TimeUnit.MINUTES, TimeUnit.SECONDS, TimeUnit.MILLISECONDS
+ TimeUnit.DAYS,
+ TimeUnit.HOURS,
+ TimeUnit.MINUTES,
+ TimeUnit.SECONDS,
+ TimeUnit.MILLISECONDS
};
- String[] unitSuffixes = {"h", "m", "s", "ms"};
+ String[] unitSuffixes = {"d", "h", "m", "s", "ms"};
for (int i = 0; i < timeUnits.length; i++) {
long convertedTime = timeUnits[i].convert(timestamp_ns, TimeUnit.NANOSECONDS);
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/LayersTrace.java b/libraries/flicker/src/com/android/server/wm/flicker/LayersTrace.java
index 74faca7..b273e6b 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/LayersTrace.java
+++ b/libraries/flicker/src/com/android/server/wm/flicker/LayersTrace.java
@@ -126,6 +126,33 @@
this.mRootLayers = rootLayers;
}
+ /**
+ * Determines the id of the root element.
+ *
+ * <p>On some files, such as the ones used in the FlickerLib testdata, the root nodes are
+ * those that have parent=0, on newer traces, the root nodes are those that have parent=-1
+ *
+ * <p>This function keeps compatibility with both new and older traces by searching for a
+ * known root layer (Display Root) and considering its parent Id as overall root.
+ */
+ private static Layer getRootLayer(SparseArray<Layer> layerMap) {
+ Layer knownRoot = null;
+ int numKeys = layerMap.size();
+ for (int i = 0; i < numKeys; ++i) {
+ Layer currentLayer = layerMap.valueAt(i);
+ if (currentLayer.isRootLayer()) {
+ knownRoot = currentLayer;
+ break;
+ }
+ }
+
+ if (knownRoot == null) {
+ throw new IllegalStateException("Display root layer not found.");
+ }
+
+ return layerMap.get(knownRoot.getParentId());
+ }
+
/** Constructs the layer hierarchy from a flattened list of layers. */
public static Entry fromFlattenedLayers(long timestamp, LayerProto[] protos,
Consumer<Layer> orphanLayerCallback) {
@@ -156,13 +183,14 @@
newLayer.addParent(layerMap.get(parentId));
}
- // Remove root node (id = 0)
- orphans.remove(layerMap.get(-1));
+ // Remove root node
+ Layer rootLayer = getRootLayer(layerMap);
+ orphans.remove(rootLayer);
// Fail if we find orphan layers.
orphans.forEach(
orphan -> {
if (orphanLayerCallback != null) {
- // Workaround for b/141326137, ignore the existance of an orphan layer
+ // Workaround for b/141326137, ignore the existence of an orphan layer
orphanLayerCallback.accept(orphan);
return;
}
@@ -171,7 +199,7 @@
.stream()
.map(node -> Integer.toString(node.getId()))
.collect(Collectors.joining(", "));
- int orphanId = orphan.mChildren.get(0).mProto.parent;
+ int orphanId = orphan.mChildren.get(0).getParentId();
throw new RuntimeException(
"Failed to parse layers trace. Found orphan layers with parent "
+ "layer id:"
@@ -180,7 +208,7 @@
+ childNodes);
});
- return new Entry(timestamp, layerMap.get(-1).mChildren);
+ return new Entry(timestamp, rootLayer.mChildren);
}
/** Extracts {@link Rect} from {@link RectProto}. */
@@ -363,6 +391,18 @@
return mProto.id;
}
+ public int getParentId() {
+ return mProto.parent;
+ }
+
+ public String getName() {
+ if (mProto != null) {
+ return mProto.name;
+ }
+
+ return "";
+ }
+
public boolean isActiveBufferEmpty() {
return this.mProto.activeBuffer == null
|| this.mProto.activeBuffer.height == 0
@@ -394,7 +434,7 @@
}
public boolean isRootLayer() {
- return mParent == null || mParent.mProto == null;
+ return mParent != null && mParent.mProto == null;
}
public boolean isInvisible() {
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java b/libraries/flicker/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java
index 8b138aa..feedee7 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java
+++ b/libraries/flicker/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java
@@ -22,8 +22,6 @@
import android.util.Log;
-import androidx.annotation.VisibleForTesting;
-
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -31,38 +29,36 @@
/** Captures screen contents and saves it as a mp4 video file. */
public class ScreenRecorder implements ITransitionMonitor {
- @VisibleForTesting
- public static final Path DEFAULT_OUTPUT_PATH = OUTPUT_DIR.resolve("transition.mp4");
-
private static final String TAG = "FLICKER";
private int mWidth;
private int mHeight;
+ private Path mOutputPath;
private Thread mRecorderThread;
public ScreenRecorder() {
- this(720, 1280);
+ this(720, 1280, OUTPUT_DIR.resolve("transition.mp4"));
}
- public ScreenRecorder(int width, int height) {
+ public ScreenRecorder(int width, int height, Path outputPath) {
mWidth = width;
mHeight = height;
+ mOutputPath = outputPath;
}
- @VisibleForTesting
- public static Path getPath(String testTag) {
- return OUTPUT_DIR.resolve(testTag + ".mp4");
+ public Path getPath() {
+ return mOutputPath;
}
@Override
public void start() {
- OUTPUT_DIR.toFile().mkdirs();
+ mOutputPath.getParent().toFile().mkdirs();
String command =
String.format(
Locale.getDefault(),
"screenrecord --size %dx%d %s",
mWidth,
mHeight,
- DEFAULT_OUTPUT_PATH);
+ mOutputPath);
mRecorderThread =
new Thread(
() -> {
@@ -87,13 +83,14 @@
@Override
public Path save(String testTag) {
- if (!Files.exists(DEFAULT_OUTPUT_PATH)) {
- Log.w(TAG, "No video file found on " + DEFAULT_OUTPUT_PATH);
+ if (!Files.exists(mOutputPath)) {
+ Log.w(TAG, "No video file found on " + mOutputPath);
return null;
}
try {
- Path targetPath = Files.move(DEFAULT_OUTPUT_PATH, getPath(testTag), REPLACE_EXISTING);
+ Path targetPath =
+ Files.move(mOutputPath, OUTPUT_DIR.resolve(testTag + ".mp4"), REPLACE_EXISTING);
Log.i(TAG, "Video saved to " + targetPath.toString());
return targetPath;
} catch (IOException e) {
diff --git a/libraries/flicker/test/assets/testdata/layers_trace_root.pb b/libraries/flicker/test/assets/testdata/layers_trace_root.pb
new file mode 100644
index 0000000..d961714
--- /dev/null
+++ b/libraries/flicker/test/assets/testdata/layers_trace_root.pb
Binary files differ
diff --git a/libraries/flicker/test/assets/testdata/layers_trace_root_aosp.pb b/libraries/flicker/test/assets/testdata/layers_trace_root_aosp.pb
new file mode 100644
index 0000000..666b328
--- /dev/null
+++ b/libraries/flicker/test/assets/testdata/layers_trace_root_aosp.pb
Binary files differ
diff --git a/libraries/flicker/test/src/com/android/server/wm/flicker/LayersTraceSubjectTest.java b/libraries/flicker/test/src/com/android/server/wm/flicker/LayersTraceSubjectTest.java
index 0415f81..2ccae42 100644
--- a/libraries/flicker/test/src/com/android/server/wm/flicker/LayersTraceSubjectTest.java
+++ b/libraries/flicker/test/src/com/android/server/wm/flicker/LayersTraceSubjectTest.java
@@ -33,6 +33,8 @@
import org.junit.runners.MethodSorters;
import java.nio.file.Paths;
+import java.util.List;
+import java.util.stream.Collectors;
/**
* Contains {@link LayersTraceSubject} tests. To run this test: {@code atest
@@ -89,7 +91,9 @@
assertWithMessage("Contains path to trace")
.that(e.getMessage())
.contains("layers_trace_invalid_layer_visibility.pb");
- assertWithMessage("Contains timestamp").that(e.getMessage()).contains("70h13m14s303ms");
+ assertWithMessage("Contains timestamp")
+ .that(e.getMessage())
+ .contains("2d22h13m14s303ms");
assertWithMessage("Contains assertion function")
.that(e.getMessage())
.contains("!isVisible");
@@ -100,4 +104,37 @@
+ ".SimpleActivity#0 is visible");
}
}
+
+ private void detectRootLayer(String fileName) {
+ LayersTrace layersTrace = readLayerTraceFromFile(fileName);
+
+ for (LayersTrace.Entry entry : layersTrace.getEntries()) {
+ List<LayersTrace.Layer> flattened = entry.asFlattenedLayers();
+ List<LayersTrace.Layer> rootLayers =
+ flattened
+ .stream()
+ .filter(LayersTrace.Layer::isRootLayer)
+ .collect(Collectors.toList());
+
+ assertWithMessage("Does not have any root layer")
+ .that(rootLayers.size())
+ .isGreaterThan(0);
+
+ int firstParentId = rootLayers.get(0).getParentId();
+
+ assertWithMessage("Has multiple root layers")
+ .that(rootLayers.stream().allMatch(p -> p.getParentId() == firstParentId))
+ .isTrue();
+ }
+ }
+
+ @Test
+ public void testCanDetectRootLayer() {
+ detectRootLayer("layers_trace_root.pb");
+ }
+
+ @Test
+ public void testCanDetectRootLayerAOSP() {
+ detectRootLayer("layers_trace_root_aosp.pb");
+ }
}
diff --git a/libraries/flicker/test/src/com/android/server/wm/flicker/TransitionRunnerTest.java b/libraries/flicker/test/src/com/android/server/wm/flicker/TransitionRunnerTest.java
index d75c58a..92c1d8c 100644
--- a/libraries/flicker/test/src/com/android/server/wm/flicker/TransitionRunnerTest.java
+++ b/libraries/flicker/test/src/com/android/server/wm/flicker/TransitionRunnerTest.java
@@ -58,7 +58,7 @@
@Mock private WindowManagerTraceMonitor mWindowManagerTraceMonitorMock;
@Mock private LayersTraceMonitor mLayersTraceMonitorMock;
@Mock private WindowAnimationFrameStatsMonitor mWindowAnimationFrameStatsMonitor;
- @InjectMocks private TransitionBuilder mTransitionBuilder;
+ @InjectMocks private TransitionBuilder mTransitionBuilder = TransitionRunner.newBuilder();
@Before
public void init() {
diff --git a/libraries/flicker/test/src/com/android/server/wm/flicker/monitor/ScreenRecorderTest.java b/libraries/flicker/test/src/com/android/server/wm/flicker/monitor/ScreenRecorderTest.java
index 967f565..01aa3c9 100644
--- a/libraries/flicker/test/src/com/android/server/wm/flicker/monitor/ScreenRecorderTest.java
+++ b/libraries/flicker/test/src/com/android/server/wm/flicker/monitor/ScreenRecorderTest.java
@@ -18,9 +18,6 @@
import static android.os.SystemClock.sleep;
-import static com.android.server.wm.flicker.monitor.ScreenRecorder.DEFAULT_OUTPUT_PATH;
-import static com.android.server.wm.flicker.monitor.ScreenRecorder.getPath;
-
import static com.google.common.truth.Truth.assertThat;
import androidx.test.runner.AndroidJUnit4;
@@ -33,6 +30,7 @@
import org.junit.runners.MethodSorters;
import java.io.File;
+import java.nio.file.Path;
/**
* Contains {@link ScreenRecorder} tests. To run this test: {@code atest
@@ -43,6 +41,7 @@
public class ScreenRecorderTest {
private static final String TEST_VIDEO_FILENAME = "test.mp4";
private ScreenRecorder mScreenRecorder;
+ private Path mSavedVideoPath = null;
@Before
public void setup() {
@@ -51,8 +50,10 @@
@After
public void teardown() {
- DEFAULT_OUTPUT_PATH.toFile().delete();
- getPath(TEST_VIDEO_FILENAME).toFile().delete();
+ mScreenRecorder.getPath().toFile().delete();
+ if (mSavedVideoPath != null) {
+ mSavedVideoPath.toFile().delete();
+ }
}
@Test
@@ -60,7 +61,7 @@
mScreenRecorder.start();
sleep(100);
mScreenRecorder.stop();
- File file = DEFAULT_OUTPUT_PATH.toFile();
+ File file = mScreenRecorder.getPath().toFile();
assertThat(file.exists()).isTrue();
}
@@ -69,8 +70,7 @@
mScreenRecorder.start();
sleep(100);
mScreenRecorder.stop();
- mScreenRecorder.save(TEST_VIDEO_FILENAME);
- File file = getPath(TEST_VIDEO_FILENAME).toFile();
+ File file = mScreenRecorder.save(TEST_VIDEO_FILENAME).toFile();
assertThat(file.exists()).isTrue();
}
}
diff --git a/libraries/health/rules/tests/src/android/platform/test/rule/TracePointRuleTest.java b/libraries/health/rules/tests/src/android/platform/test/rule/TracePointRuleTest.java
index cdae78a..c3f8f14 100644
--- a/libraries/health/rules/tests/src/android/platform/test/rule/TracePointRuleTest.java
+++ b/libraries/health/rules/tests/src/android/platform/test/rule/TracePointRuleTest.java
@@ -16,13 +16,11 @@
package android.platform.test.rule;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import java.util.ArrayList;
diff --git a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java
index 01e5ef6..794b576 100644
--- a/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java
+++ b/libraries/health/runners/longevity/platform/src/android/platform/test/longevity/ScheduledScenarioRunner.java
@@ -18,14 +18,23 @@
import static java.lang.Math.max;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
-import android.os.SystemClock;
+import android.os.Process;
import android.platform.test.longevity.proto.Configuration.Scenario;
import android.platform.test.longevity.proto.Configuration.Scenario.ExtraArg;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.test.InstrumentationRegistry;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
@@ -48,6 +57,8 @@
// rule and also outside of it.
@VisibleForTesting static final long TEARDOWN_LEEWAY_MS = 3000;
+ private static final String LOG_TAG = ScheduledScenarioRunner.class.getSimpleName();
+
private final Scenario mScenario;
private final long mTotalTimeoutMs;
// Timeout after the teardown leeway is taken into account.
@@ -162,20 +173,83 @@
@VisibleForTesting
protected void performIdleBeforeTeardown(long durationMs) {
- idleWithSystemClockSleep(durationMs);
+ suspensionAwareSleep(durationMs);
}
@VisibleForTesting
protected void performIdleBeforeNextScenario(long durationMs) {
// TODO (b/119386011): Change this idle method to using a sleep test; for now, using the
// same idling logic as {@link performIdleBeforeTeardown}.
- idleWithSystemClockSleep(durationMs);
+ suspensionAwareSleep(durationMs);
}
- private void idleWithSystemClockSleep(long durationMs) {
- if (durationMs <= 0) {
- return;
+ /**
+ * Idle with a sleep that will be accurate despite the device entering power-saving modes (e.g.
+ * suspend, Doze).
+ */
+ @VisibleForTesting
+ static void suspensionAwareSleep(long durationMs) {
+ // Call the testable version of this method with arguments for the intended sleep behavior.
+ suspensionAwareSleep(durationMs, durationMs);
+ }
+
+ /**
+ * A testable version of suspension-aware sleep.
+ *
+ * <p>This method sets up a {@link CountDownLatch} that waits for a wake-up event, which is
+ * triggered by an {@link AlarmManager} alarm set to fire after the sleep duration. When the
+ * device enters suspend mode, the {@link CountDownLatch} await no longer works as intended and
+ * in effect waits for much longer than expected, in which case the alarm fires and ends the
+ * sleep behavior, ensuring that the device still sleeps for the expected amount of time. If the
+ * device does not enter suspend mode, this method only waits for the {@link CountDownLatch} and
+ * functions similarly to {@code Thread.sleep()}.
+ *
+ * <p>This testable method enables tests to set a longer await timeout on the {@link
+ * CountDownLatch}, enabling that the alarm fires before the {@code CountDownLatch.await()}
+ * timeout is reached, thus simulating the case where the device goes into suspend mode.
+ */
+ @VisibleForTesting
+ static void suspensionAwareSleep(long durationMs, long countDownLatchTimeoutMs) {
+ Log.i(LOG_TAG, String.format("Starting suspension-aware sleep for %d ms", durationMs));
+
+ Context context = InstrumentationRegistry.getContext();
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+ String wakeUpAction =
+ String.format(
+ "%s.%d.%d.ScheduledScenarioRunnerSleepWakeUp"
+ .format(
+ context.getPackageName(),
+ Process.myPid(),
+ Thread.currentThread().getId()));
+
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ IntentFilter wakeUpActionFilter = new IntentFilter(wakeUpAction);
+ BroadcastReceiver receiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(
+ LOG_TAG,
+ "Suspension-aware sleep ended by receiving the wake-up intent.");
+ countDownLatch.countDown();
+ }
+ };
+ context.registerReceiver(receiver, wakeUpActionFilter);
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(
+ context, 0, new Intent(wakeUpAction), PendingIntent.FLAG_UPDATE_CURRENT);
+
+ alarmManager.setExactAndAllowWhileIdle(
+ AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + durationMs, pendingIntent);
+
+ try {
+ countDownLatch.await(countDownLatchTimeoutMs, TimeUnit.MILLISECONDS);
+ Log.i(LOG_TAG, "Suspension-aware sleep ended.");
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ context.unregisterReceiver(receiver);
}
- SystemClock.sleep(durationMs);
}
}
diff --git a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java
index 7afec46..a65fce0 100644
--- a/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java
+++ b/libraries/health/runners/longevity/platform/tests/src/android/platform/test/longevity/ScheduledScenarioRunnerTest.java
@@ -81,8 +81,8 @@
}
}
- // Threshold above which missing a schedule is considered a failure.
- private static final long TIMEOUT_ERROR_MARGIN_MS = 500;
+ // Threshold above which missing the expected timing is considered a failure.
+ private static final long TIMING_LEEWAY_MS = 500;
// Holds the state of the instrumentation args before each test for restoring after, as one test
// might affect the state of another otherwise.
@@ -144,7 +144,7 @@
long expectedTimeout =
timeoutMs - ScheduledScenarioRunner.TEARDOWN_LEEWAY_MS;
return abs(exceptionTimeout - expectedTimeout)
- <= TIMEOUT_ERROR_MARGIN_MS;
+ <= TIMING_LEEWAY_MS;
});
Assert.assertTrue(correctTestTimedOutExceptionFired);
}
@@ -197,8 +197,7 @@
verify(runner, times(1))
.performIdleBeforeNextScenario(
getWithinMarginMatcher(
- ScheduledScenarioRunner.TEARDOWN_LEEWAY_MS,
- TIMEOUT_ERROR_MARGIN_MS));
+ ScheduledScenarioRunner.TEARDOWN_LEEWAY_MS, TIMING_LEEWAY_MS));
}
/** Test that a test set to stay in the app after the test idles after its @Test method. */
@@ -228,7 +227,7 @@
.performIdleBeforeTeardown(
getWithinMarginMatcher(
timeoutMs - 2 * ScheduledScenarioRunner.TEARDOWN_LEEWAY_MS,
- TIMEOUT_ERROR_MARGIN_MS));
+ TIMING_LEEWAY_MS));
// Test should have passed.
verify(mRunNotifier, never()).fireTestFailure(any(Failure.class));
}
@@ -257,8 +256,7 @@
verify(runner, never()).performIdleBeforeTeardown(anyLong());
// Idles before the next scenario; duration should be roughly equal to the timeout.
verify(runner, times(1))
- .performIdleBeforeNextScenario(
- getWithinMarginMatcher(timeoutMs, TIMEOUT_ERROR_MARGIN_MS));
+ .performIdleBeforeNextScenario(getWithinMarginMatcher(timeoutMs, TIMING_LEEWAY_MS));
// Test should have passed.
verify(mRunNotifier, never()).fireTestFailure(any(Failure.class));
}
@@ -295,8 +293,7 @@
verify(listener, times(1)).testIgnored(any());
// Idles before the next scenario; duration should be roughly equal to the timeout.
verify(runner, times(1))
- .performIdleBeforeNextScenario(
- getWithinMarginMatcher(timeoutMs, TIMEOUT_ERROR_MARGIN_MS));
+ .performIdleBeforeNextScenario(getWithinMarginMatcher(timeoutMs, TIMING_LEEWAY_MS));
}
/** Test that the last test does not have idle after it, regardless of its AfterTest policy. */
@@ -370,6 +367,28 @@
Assert.assertTrue(bundlesContainSameStringKeyValuePairs(argsBeforeTest, argsAfterTest));
}
+ /** Test that suspension-aware sleep will sleep for the expected duration. */
+ @Test
+ public void testSuspensionAwareSleep_sleepsForExpectedDuration() {
+ long expectedSleepMillis = TimeUnit.SECONDS.toMillis(5);
+ long timestampBeforeSleep = System.currentTimeMillis();
+ ScheduledScenarioRunner.suspensionAwareSleep(expectedSleepMillis);
+ long actualSleepDuration = System.currentTimeMillis() - timestampBeforeSleep;
+ Assert.assertTrue(abs(actualSleepDuration - expectedSleepMillis) <= TIMING_LEEWAY_MS);
+ }
+
+ /** Test that suspension-aware sleep will end due to alarm going off. */
+ @Test
+ public void testSuspensionAwareSleep_isWokenUpByAlarm() {
+ long expectedSleepMillis = TimeUnit.SECONDS.toMillis(5);
+ long timestampBeforeSleep = System.currentTimeMillis();
+ // Supply a longer CountDownLatch timeout so that the alarm will fire before the timeout is
+ // reached.
+ ScheduledScenarioRunner.suspensionAwareSleep(expectedSleepMillis, expectedSleepMillis * 2);
+ long actualSleepDuration = System.currentTimeMillis() - timestampBeforeSleep;
+ Assert.assertTrue(abs(actualSleepDuration - expectedSleepMillis) <= TIMING_LEEWAY_MS);
+ }
+
/**
* Helper method to get an argument matcher that checks whether the input value is equal to
* expected value within a margin.
diff --git a/libraries/telephony-utility/src/android/telephony/utility/SimCardUtil.java b/libraries/telephony-utility/src/android/telephony/utility/SimCardUtil.java
index 5c2d2cd..bdce1e2 100644
--- a/libraries/telephony-utility/src/android/telephony/utility/SimCardUtil.java
+++ b/libraries/telephony-utility/src/android/telephony/utility/SimCardUtil.java
@@ -19,11 +19,9 @@
import android.content.Context;
import android.device.collectors.util.SendToInstrumentation;
import android.os.Bundle;
-import android.se.omapi.Channel;
import android.se.omapi.Reader;
import android.se.omapi.SEService;
import android.se.omapi.SEService.OnConnectedListener;
-import android.se.omapi.Session;
import android.telephony.TelephonyManager;
import java.util.Timer;
@@ -52,7 +50,7 @@
private static final String SECURED_ELEMENT = "has_secured_element";
private static final String SE_SERVICE = "has_se_service";
- private final long SERVICE_CONNECTION_TIME_OUT = 3000;
+ private static final long SERVICE_CONNECTION_TIME_OUT = 3000;
private SEService mSeService;
private Object mServiceMutex = new Object();
@@ -136,6 +134,7 @@
}
private class SynchronousExecutor implements Executor {
+ @Override
public void execute(Runnable r) {
r.run();
}
diff --git a/scripts/perfetto-setup/Android.mk b/scripts/perfetto-setup/Android.mk
new file mode 100644
index 0000000..180ddb2
--- /dev/null
+++ b/scripts/perfetto-setup/Android.mk
@@ -0,0 +1,42 @@
+#
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := trace_config_detailed.textproto
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PREBUILT_MODULE_FILE := prebuilts/tools/linux-x86_64/perfetto/configs/trace_config_detailed.textproto
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := long_trace_config.textproto
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PREBUILT_MODULE_FILE := prebuilts/tools/linux-x86_64/perfetto/configs/long_trace_config.textproto
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := perfetto_trace_processor_shell
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_CHECK_ELF_FILES := false
+LOCAL_PREBUILT_MODULE_FILE := prebuilts/tools/linux-x86_64/perfetto/trace_processor_shell
+include $(BUILD_PREBUILT)
+
+
diff --git a/tests/health/scenarios/src/android/platform/test/scenario/sleep/Idle.java b/tests/health/scenarios/src/android/platform/test/scenario/sleep/Idle.java
index 882523c..4efbd07 100644
--- a/tests/health/scenarios/src/android/platform/test/scenario/sleep/Idle.java
+++ b/tests/health/scenarios/src/android/platform/test/scenario/sleep/Idle.java
@@ -18,8 +18,10 @@
import android.os.SystemClock;
import android.platform.test.option.LongOption;
+import android.platform.test.rule.NaturalOrientationRule;
import android.platform.test.scenario.annotation.Scenario;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,6 +33,9 @@
@Scenario
@RunWith(JUnit4.class)
public class Idle {
+ // Class-level rules
+ @ClassRule public static NaturalOrientationRule orientationRule = new NaturalOrientationRule();
+
@Rule public final LongOption mDurationMs = new LongOption("durationMs").setDefault(1000L);
@Test
diff --git a/tests/health/scenarios/src/android/platform/test/scenario/system/ScreenOff.java b/tests/health/scenarios/src/android/platform/test/scenario/system/ScreenOff.java
index d3dc780..a2e1290 100644
--- a/tests/health/scenarios/src/android/platform/test/scenario/system/ScreenOff.java
+++ b/tests/health/scenarios/src/android/platform/test/scenario/system/ScreenOff.java
@@ -18,44 +18,52 @@
import android.os.RemoteException;
import android.os.SystemClock;
+import android.platform.test.option.BooleanOption;
+import android.platform.test.option.LongOption;
import android.platform.test.scenario.annotation.Scenario;
import android.support.test.uiautomator.UiDevice;
import androidx.test.InstrumentationRegistry;
+import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-/**
- * Shuts the screen off and waits for a specified amount of time.
- */
+/** Shuts the screen off and waits for a specified amount of time. */
@Scenario
@RunWith(JUnit4.class)
public class ScreenOff {
- private static final String DURATION_OPTION = "screenOffDurationMs";
- private static final String DURATION_DEFAULT = "1000";
+ @Rule public LongOption mDurationMs = new LongOption("screenOffDurationMs").setDefault(1000L);
- private long mDurationMs = 0L;
+ @Rule
+ public BooleanOption mTurnScreenBackOn =
+ new BooleanOption("screenOffTurnScreenBackOnAfterTest").setDefault(false);
+
private UiDevice mDevice;
@Before
public void setUp() {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- String durationMsString =
- InstrumentationRegistry.getArguments().getString(DURATION_OPTION, DURATION_DEFAULT);
- try {
- mDurationMs = Long.parseLong(durationMsString);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format(
- "Failed to parse option %s: %s", DURATION_OPTION, durationMsString));
- }
}
@Test
public void testScreenOff() throws RemoteException {
mDevice.sleep();
- SystemClock.sleep(mDurationMs);
+ SystemClock.sleep(mDurationMs.get());
+ }
+
+ @After
+ public void tearDown() throws RemoteException {
+ if (mTurnScreenBackOn.get()) {
+ // Wake up the display. wakeUp() is not used here as when the duration is short, the
+ // device might register a double power button press and launch camera.
+ mDevice.pressMenu();
+ mDevice.waitForIdle();
+ // Unlock the screen.
+ mDevice.pressMenu();
+ mDevice.waitForIdle();
+ }
}
}