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