• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.server.wm;
18 
19 import static android.server.wm.ComponentNameUtils.getActivityName;
20 import static android.server.wm.ShellCommandHelper.executeShellCommand;
21 import static android.server.wm.ShellCommandHelper.executeShellCommandAndGetStdout;
22 import static android.server.wm.profileable.Components.PROFILEABLE_APP_ACTIVITY;
23 import static android.server.wm.profileable.Components.ProfileableAppActivity.COMMAND_WAIT_FOR_PROFILE_OUTPUT;
24 import static android.server.wm.profileable.Components.ProfileableAppActivity.OUTPUT_DIR;
25 import static android.server.wm.profileable.Components.ProfileableAppActivity.OUTPUT_FILE_PATH;
26 
27 import static org.hamcrest.MatcherAssert.assertThat;
28 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
29 import static org.junit.Assert.assertEquals;
30 
31 import android.content.ComponentName;
32 import android.content.Intent;
33 import android.platform.test.annotations.Presubmit;
34 import android.server.wm.CommandSession.ActivitySession;
35 import android.server.wm.CommandSession.DefaultLaunchProxy;
36 
37 import org.junit.AfterClass;
38 import org.junit.BeforeClass;
39 import org.junit.Test;
40 
41 /**
42  * Build/Install/Run:
43  *     atest CtsWindowManagerDeviceTestCases:AmProfileTests
44  *
45  * Please talk to Android Studio team first if you want to modify or delete these tests.
46  */
47 @Presubmit
48 public class AmProfileTests extends ActivityManagerTestBase {
49 
50     private static final String FIRST_WORD_NO_STREAMING = "*version\n";
51     private static final String FIRST_WORD_STREAMING = "SLOW";  // Magic word set by runtime.
52 
53     @BeforeClass
setUpClass()54     public static void setUpClass() {
55         // Allow ProfileableAppActivity to monitor the path.
56         executeShellCommand("mkdir -m 777 -p " + OUTPUT_DIR);
57     }
58 
59     @AfterClass
tearDownClass()60     public static void tearDownClass() {
61         executeShellCommand("rm -rf " + OUTPUT_DIR);
62     }
63 
64     /**
65      * Test am profile functionality with the following 3 configurable options:
66      *    starting the activity before start profiling? yes;
67      *    sampling-based profiling? no;
68      *    using streaming output mode? no.
69      */
70     @Test
testAmProfileStartNoSamplingNoStreaming()71     public void testAmProfileStartNoSamplingNoStreaming() throws Exception {
72         // am profile start ... , and the same to the following 3 test methods.
73         testProfile(true, false, false);
74     }
75 
76     /**
77      * The following tests are similar to testAmProfileStartNoSamplingNoStreaming(),
78      * only different in the three configuration options.
79      */
80     @Test
testAmProfileStartNoSamplingStreaming()81     public void testAmProfileStartNoSamplingStreaming() throws Exception {
82         testProfile(true, false, true);
83     }
84 
85     @Test
testAmProfileStartSamplingNoStreaming()86     public void testAmProfileStartSamplingNoStreaming() throws Exception {
87         testProfile(true, true, false);
88     }
89 
90     @Test
testAmProfileStartSamplingStreaming()91     public void testAmProfileStartSamplingStreaming() throws Exception {
92         testProfile(true, true, true);
93     }
94 
95     @Test
testAmStartStartProfilerNoSamplingNoStreaming()96     public void testAmStartStartProfilerNoSamplingNoStreaming() throws Exception {
97         // am start --start-profiler ..., and the same to the following 3 test methods.
98         testProfile(false, false, false);
99     }
100 
101     @Test
testAmStartStartProfilerNoSamplingStreaming()102     public void testAmStartStartProfilerNoSamplingStreaming() throws Exception {
103         testProfile(false, false, true);
104     }
105 
106     @Test
testAmStartStartProfilerSamplingNoStreaming()107     public void testAmStartStartProfilerSamplingNoStreaming() throws Exception {
108         testProfile(false, true, false);
109     }
110 
111     @Test
testAmStartStartProfilerSamplingStreaming()112     public void testAmStartStartProfilerSamplingStreaming() throws Exception {
113         testProfile(false, true, true);
114     }
115 
testProfile(final boolean startActivityFirst, final boolean sampling, final boolean streaming)116     private void testProfile(final boolean startActivityFirst, final boolean sampling,
117             final boolean streaming) throws Exception {
118         final ActivitySession activitySession;
119         if (startActivityFirst) {
120             activitySession = createManagedActivityClientSession().startActivity(
121                     new Intent().setComponent(PROFILEABLE_APP_ACTIVITY));
122             startProfiling(PROFILEABLE_APP_ACTIVITY.getPackageName(), sampling, streaming);
123         } else {
124             activitySession = startActivityProfiling(PROFILEABLE_APP_ACTIVITY, sampling, streaming);
125         }
126 
127         // Go to home screen and then warm start the activity to generate some interesting trace.
128         launchHomeActivity();
129         launchActivity(PROFILEABLE_APP_ACTIVITY);
130 
131         executeShellCommand(getStopProfileCmd(PROFILEABLE_APP_ACTIVITY));
132 
133         activitySession.sendCommandAndWaitReply(COMMAND_WAIT_FOR_PROFILE_OUTPUT);
134         verifyOutputFileFormat(streaming);
135     }
136 
137     /** Starts profiler on a started process. */
startProfiling(String processName, boolean sampling, boolean streaming)138     private static void startProfiling(String processName, boolean sampling, boolean streaming) {
139         final StringBuilder builder = new StringBuilder("am profile start");
140         appendProfileParameters(builder, sampling, streaming);
141         builder.append(String.format(" %s %s", processName, OUTPUT_FILE_PATH));
142         executeShellCommand(builder.toString());
143     }
144 
145     /** Starts the activity with profiler. */
startActivityProfiling(ComponentName activityName, boolean sampling, boolean streaming)146     private ActivitySession startActivityProfiling(ComponentName activityName, boolean sampling,
147             boolean streaming) {
148         return createManagedActivityClientSession().startActivity(new DefaultLaunchProxy() {
149 
150             @Override
151             public boolean shouldWaitForLaunched() {
152                 // The shell command included "-W".
153                 return false;
154             }
155 
156             @Override
157             public void execute() {
158                 final StringBuilder builder = new StringBuilder();
159                 builder.append(String.format("am start -n %s -W -S --start-profiler %s",
160                         getActivityName(activityName), OUTPUT_FILE_PATH));
161                 appendProfileParameters(builder, sampling, streaming);
162                 mLaunchInjector.setupShellCommand(builder);
163                 executeShellCommand(builder.toString());
164             }
165         });
166     }
167 
168     private static void appendProfileParameters(StringBuilder builder, boolean sampling,
169             boolean streaming) {
170         if (sampling) {
171             builder.append(" --sampling 1000");
172         }
173         if (streaming) {
174             builder.append(" --streaming");
175         }
176     }
177 
178     private static String getStopProfileCmd(final ComponentName activityName) {
179         return "am profile stop " + activityName.getPackageName();
180     }
181 
182     private void verifyOutputFileFormat(final boolean streaming) throws Exception {
183         // This is a hack. The am service has to write to /data/local/tmp because it doesn't have
184         // access to the sdcard. The test cannot read from /data/local/tmp. This allows us to
185         // scan the content to validate what is needed for this test.
186         final String firstLine = executeShellCommandAndGetStdout("head -1 " + OUTPUT_FILE_PATH);
187 
188         final String expectedFirstWord = streaming ? FIRST_WORD_STREAMING : FIRST_WORD_NO_STREAMING;
189         assertThat(
190                 "data size", firstLine.length(), greaterThanOrEqualTo(expectedFirstWord.length()));
191         final String actualFirstWord = firstLine.substring(0, expectedFirstWord.length());
192         assertEquals("Unexpected first word", expectedFirstWord, actualFirstWord);
193 
194         // Clean up.
195         executeShellCommand("rm -f " + OUTPUT_FILE_PATH);
196     }
197 }
198