[CTS] Add tests for profiler functionality in 'am' command line tool
Verify the profiling funcitonality is avaialbe using both
'am start --start-profiler' and 'am profile start' commands.
Also briefly verify the output file regardless of whether
'--sampling N' and '--streaming' options are given.
Bug: 33300765
Test: android.server.cts.ActivityManagerAmProfileTests
#testAmProfileStartNoSamplingNoStreaming
#testAmProfileStartNoSamplingStreaming
#testAmProfileStartSamplingNoStreaming
#testAmProfileStartSamplingStreaming
#testAmStartStartProfilerNoSamplingNoStreaming
#testAmStartStartProfilerNoSamplingStreaming
#testAmStartStartProfilerSamplingNoStreaming
#testAmStartStartProfilerSamplingStreaming
Change-Id: I4d3c58e5dec6b5fe88d27694ac6410475a39e1a8
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/AndroidTest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/AndroidTest.xml
index 6b2a9c2..883cc5b 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/AndroidTest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/AndroidTest.xml
@@ -19,11 +19,12 @@
<option name="test-file-name" value="CtsDeviceServicesTestApp.apk" />
<option name="test-file-name" value="CtsDeviceServicesTestSecondApp.apk" />
<option name="test-file-name" value="CtsDeviceServicesTestThirdApp.apk" />
+ <option name="test-file-name" value="CtsDeviceDebuggableApp.apk" />
<option name="test-file-name" value="CtsDeviceDisplaySizeApp.apk" />
<option name="test-file-name" value="CtsDeviceTranslucentTestApp.apk" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsServicesHostTestCases.jar" />
- <option name="runtime-hint" value="4m7s" />
+ <option name="runtime-hint" value="4m44s" />
</test>
</configuration>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk
new file mode 100644
index 0000000..fa381fb
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := test_current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
+
+LOCAL_PACKAGE_NAME := CtsDeviceDebuggableApp
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/AndroidManifest.xml
new file mode 100644
index 0000000..0ab25aa
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.server.cts">
+
+ <!--
+ * Security policy requires that only debuggable processes can be profiled
+ * which is tested by ActivityManagerAmProfileTests.
+ -->
+ <application android:debuggable="true">
+ <activity android:name=".DebuggableAppActivity"
+ android:resizeableActivity="true"
+ android:exported="true" />
+ </application>
+
+</manifest>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/src/android/server/cts/DebuggableAppActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/src/android/server/cts/DebuggableAppActivity.java
new file mode 100644
index 0000000..e844ef7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/appDebuggable/src/android/server/cts/DebuggableAppActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.cts;
+
+import android.app.Activity;
+
+public class DebuggableAppActivity extends Activity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmProfileTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmProfileTests.java
new file mode 100644
index 0000000..87e62f1d
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmProfileTests.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.cts;
+
+import com.google.common.io.Files;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.lang.StringBuilder;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.ActivityManagerAmProfileTests
+ *
+ * Please talk to Android Studio team first if you want to modify or delete these tests.
+ */
+public class ActivityManagerAmProfileTests extends ActivityManagerTestBase {
+
+ private static final String TEST_ACTIVITY_NAME = "DebuggableAppActivity";
+ private static final String OUTPUT_FILE_PATH = "/data/local/tmp/profile.trace";
+ private static final String FIRST_WORD_NO_STREAMING = "*version\n";
+ private static final String FIRST_WORD_STREAMING = "SLOW"; // Magic word set by runtime.
+
+ private ITestDevice mDevice;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDevice = getDevice();
+ }
+
+ /**
+ * Test am profile functionality with the following 3 configurable options:
+ * starting the activity before start profiling? yes;
+ * sampling-based profiling? no;
+ * using streaming output mode? no.
+ */
+ public void testAmProfileStartNoSamplingNoStreaming() throws Exception {
+ // am profile start ... , and the same to the following 3 test methods.
+ testProfile(true, false, false);
+ }
+
+ /**
+ * The following tests are similar to testAmProfileStartNoSamplingNoStreaming(),
+ * only different in the three configuration options.
+ */
+ public void testAmProfileStartNoSamplingStreaming() throws Exception {
+ testProfile(true, false, true);
+ }
+ public void testAmProfileStartSamplingNoStreaming() throws Exception {
+ testProfile(true, true, false);
+ }
+ public void testAmProfileStartSamplingStreaming() throws Exception {
+ testProfile(true, true, true);
+ }
+ public void testAmStartStartProfilerNoSamplingNoStreaming() throws Exception {
+ // am start --start-profiler ..., and the same to the following 3 test methods.
+ testProfile(false, false, false);
+ }
+ public void testAmStartStartProfilerNoSamplingStreaming() throws Exception {
+ testProfile(false, false, true);
+ }
+ public void testAmStartStartProfilerSamplingNoStreaming() throws Exception {
+ testProfile(false, true, false);
+ }
+ public void testAmStartStartProfilerSamplingStreaming() throws Exception {
+ testProfile(false, true, true);
+ }
+
+ private void testProfile(boolean startActivityFirst,
+ boolean sampling, boolean streaming) throws Exception {
+ if (startActivityFirst) {
+ launchActivity(TEST_ACTIVITY_NAME);
+ }
+
+ String cmd = getStartCmd(TEST_ACTIVITY_NAME, startActivityFirst, sampling, streaming);
+ executeShellCommand(cmd);
+ // Go to home screen and then warm start the activity to generate some interesting trace.
+ pressHomeButton();
+ launchActivity(TEST_ACTIVITY_NAME);
+
+ cmd = "am profile stop " + componentName;
+ executeShellCommand(cmd);
+ // Sleep for 0.1 second (100 milliseconds) so the generation of the profiling
+ // file is complete.
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ //ignored
+ }
+ verifyOutputFileFormat(streaming);
+ }
+
+ private String getStartCmd(String activityName, boolean activityAlreadyStarted,
+ boolean sampling, boolean streaming) {
+ StringBuilder builder = new StringBuilder("am");
+ if (activityAlreadyStarted) {
+ builder.append(" profile start");
+ } else {
+ builder.append(String.format(" start -n %s/.%s -W --start-profiler %s",
+ componentName, activityName, OUTPUT_FILE_PATH));
+ }
+ if (sampling) {
+ builder.append(" --sampling 1000");
+ }
+ if (streaming) {
+ builder.append(" --streaming");
+ }
+ if (activityAlreadyStarted) {
+ builder.append(String.format(" %s %s", componentName, OUTPUT_FILE_PATH));
+ } else {
+
+ }
+ return builder.toString();
+ }
+
+ private void verifyOutputFileFormat(boolean streaming) throws Exception {
+ String expectedFirstWord = streaming ? FIRST_WORD_STREAMING : FIRST_WORD_NO_STREAMING;
+ byte[] data = readFileOnClient(OUTPUT_FILE_PATH);
+ assertTrue("data size=" + data.length, data.length >= expectedFirstWord.length());
+ String actualFirstWord = new String(data, 0, expectedFirstWord.length());
+ assertTrue("Unexpected first word: '" + actualFirstWord + "'",
+ actualFirstWord.equals(expectedFirstWord));
+ // Clean up.
+ executeShellCommand("rm -f " + OUTPUT_FILE_PATH);
+ }
+
+ private byte[] readFileOnClient(String clientPath) throws Exception {
+ assertTrue("File not found on client: " + clientPath,
+ mDevice.doesFileExist(clientPath));
+ File copyOnHost = File.createTempFile("host", "copy");
+ try {
+ executeAdbCommand("pull", clientPath, copyOnHost.getPath());
+ return Files.toByteArray(copyOnHost);
+ } finally {
+ FileUtil.deleteFile(copyOnHost);
+ }
+ }
+
+ private String[] executeAdbCommand(String... command) throws DeviceNotAvailableException {
+ String output = mDevice.executeAdbCommand(command);
+ // "".split() returns { "" }, but we want an empty array
+ String[] lines = output.equals("") ? new String[0] : output.split("\n");
+ return lines;
+ }
+
+}