• 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.activity;
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.ActivityManagerTestBase;
35 import android.server.wm.CommandSession.ActivitySession;
36 import android.server.wm.CommandSession.DefaultLaunchProxy;
37 
38 import org.junit.After;
39 import org.junit.AfterClass;
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 
43 /**
44  * Build/Install/Run:
45  *     atest CtsWindowManagerDeviceActivity:AmProfileTests
46  *
47  * Please talk to Android Studio team first if you want to modify or delete these tests.
48  */
49 @Presubmit
50 public class AmProfileTests extends ActivityManagerTestBase {
51     private static final String TEST_PACKAGE = PROFILEABLE_APP_ACTIVITY.getPackageName();
52     private static final String FIRST_WORD_NO_STREAMING = "*version\n";
53     private static final String FIRST_WORD_STREAMING = "SLOW";  // Magic word set by runtime.
54 
55     @BeforeClass
setUpClass()56     public static void setUpClass() {
57         // Allow ProfileableAppActivity to monitor the path.
58         executeShellCommand("mkdir -m 777 -p " + OUTPUT_DIR);
59     }
60 
61     @AfterClass
tearDownClass()62     public static void tearDownClass() {
63         executeShellCommand("rm -rf " + OUTPUT_DIR);
64     }
65 
66     @After
tearDown()67     public void tearDown() {
68         stopTestPackage(TEST_PACKAGE);
69     }
70 
71     /**
72      * Test am profile functionality with the following 3 configurable options:
73      *    starting the activity before start profiling? yes;
74      *    sampling-based profiling? no;
75      *    using streaming output mode? no.
76      */
77     @Test
testAmProfileStartNoSamplingNoStreaming()78     public void testAmProfileStartNoSamplingNoStreaming() throws Exception {
79         // am profile start ... , and the same to the following 3 test methods.
80         testProfile(true, false, false);
81     }
82 
83     /**
84      * The following tests are similar to testAmProfileStartNoSamplingNoStreaming(),
85      * only different in the three configuration options.
86      */
87     @Test
testAmProfileStartNoSamplingStreaming()88     public void testAmProfileStartNoSamplingStreaming() throws Exception {
89         testProfile(true, false, true);
90     }
91 
92     @Test
testAmProfileStartSamplingNoStreaming()93     public void testAmProfileStartSamplingNoStreaming() throws Exception {
94         testProfile(true, true, false);
95     }
96 
97     @Test
testAmProfileStartSamplingStreaming()98     public void testAmProfileStartSamplingStreaming() throws Exception {
99         testProfile(true, true, true);
100     }
101 
102     @Test
testAmStartStartProfilerNoSamplingNoStreaming()103     public void testAmStartStartProfilerNoSamplingNoStreaming() throws Exception {
104         // am start --start-profiler ..., and the same to the following 3 test methods.
105         testProfile(false, false, false);
106     }
107 
108     @Test
testAmStartStartProfilerNoSamplingStreaming()109     public void testAmStartStartProfilerNoSamplingStreaming() throws Exception {
110         testProfile(false, false, true);
111     }
112 
113     @Test
testAmStartStartProfilerSamplingNoStreaming()114     public void testAmStartStartProfilerSamplingNoStreaming() throws Exception {
115         testProfile(false, true, false);
116     }
117 
118     @Test
testAmStartStartProfilerSamplingStreaming()119     public void testAmStartStartProfilerSamplingStreaming() throws Exception {
120         testProfile(false, true, true);
121     }
122 
testProfile(final boolean startActivityFirst, final boolean sampling, final boolean streaming)123     private void testProfile(final boolean startActivityFirst, final boolean sampling,
124             final boolean streaming) throws Exception {
125         final ActivitySession activitySession;
126         if (startActivityFirst) {
127             activitySession = createManagedActivityClientSession().startActivity(
128                     new Intent().setComponent(PROFILEABLE_APP_ACTIVITY));
129             startProfiling(PROFILEABLE_APP_ACTIVITY.getPackageName(), sampling, streaming);
130         } else {
131             activitySession = startActivityProfiling(PROFILEABLE_APP_ACTIVITY, sampling, streaming);
132         }
133 
134         // Go to home screen and then warm start the activity to generate some interesting trace.
135         launchHomeActivity();
136         launchActivity(PROFILEABLE_APP_ACTIVITY);
137 
138         executeShellCommand(getStopProfileCmd(PROFILEABLE_APP_ACTIVITY));
139 
140         activitySession.sendCommandAndWaitReply(COMMAND_WAIT_FOR_PROFILE_OUTPUT);
141         verifyOutputFileFormat(streaming);
142     }
143 
144     /** Starts profiler on a started process. */
startProfiling(String processName, boolean sampling, boolean streaming)145     private static void startProfiling(String processName, boolean sampling, boolean streaming) {
146         final StringBuilder builder = new StringBuilder("am profile start");
147         appendProfileParameters(builder, sampling, streaming);
148         builder.append(String.format(" %s %s", processName, OUTPUT_FILE_PATH));
149         executeShellCommand(builder.toString());
150     }
151 
152     /** Starts the activity with profiler. */
startActivityProfiling(ComponentName activityName, boolean sampling, boolean streaming)153     private ActivitySession startActivityProfiling(ComponentName activityName, boolean sampling,
154             boolean streaming) {
155         return createManagedActivityClientSession().startActivity(new DefaultLaunchProxy() {
156 
157             @Override
158             public boolean shouldWaitForLaunched() {
159                 // The shell command included "-W".
160                 return false;
161             }
162 
163             @Override
164             public void execute() {
165                 final StringBuilder builder = new StringBuilder();
166                 builder.append(String.format("am start -n %s -W -S --start-profiler %s",
167                         getActivityName(activityName), OUTPUT_FILE_PATH) + " --user "
168                         + android.os.Process.myUserHandle().getIdentifier());
169                 appendProfileParameters(builder, sampling, streaming);
170                 mLaunchInjector.setupShellCommand(builder);
171                 executeShellCommand(builder.toString());
172             }
173         });
174     }
175 
176     private static void appendProfileParameters(StringBuilder builder, boolean sampling,
177             boolean streaming) {
178         if (sampling) {
179             builder.append(" --sampling 1000");
180         }
181         if (streaming) {
182             builder.append(" --streaming");
183         }
184     }
185 
186     private static String getStopProfileCmd(final ComponentName activityName) {
187         return "am profile stop " + activityName.getPackageName();
188     }
189 
190     private void verifyOutputFileFormat(final boolean streaming) throws Exception {
191         // This is a hack. The am service has to write to /data/local/tmp because it doesn't have
192         // access to the sdcard. The test cannot read from /data/local/tmp. This allows us to
193         // scan the content to validate what is needed for this test.
194         final String firstLine = executeShellCommandAndGetStdout("head -1 " + OUTPUT_FILE_PATH);
195 
196         final String expectedFirstWord = streaming ? FIRST_WORD_STREAMING : FIRST_WORD_NO_STREAMING;
197         assertThat(
198                 "data size", firstLine.length(), greaterThanOrEqualTo(expectedFirstWord.length()));
199         final String actualFirstWord = firstLine.substring(0, expectedFirstWord.length());
200         assertEquals("Unexpected first word", expectedFirstWord, actualFirstWord);
201 
202         // Clean up.
203         executeShellCommand("rm -f " + OUTPUT_FILE_PATH);
204     }
205 }
206