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 17package android.server.am; 18 19import static android.server.am.ComponentNameUtils.getActivityName; 20import static android.server.am.UiDeviceUtils.pressHomeButton; 21import static android.server.am.debuggable.Components.DEBUGGABLE_APP_ACTIVITY; 22 23import static org.hamcrest.MatcherAssert.assertThat; 24import static org.hamcrest.Matchers.greaterThanOrEqualTo; 25import static org.junit.Assert.assertEquals; 26import static org.junit.Assert.assertTrue; 27 28import android.content.ComponentName; 29import android.support.test.InstrumentationRegistry; 30 31import org.junit.Before; 32import org.junit.Test; 33 34import java.io.File; 35import java.io.FileInputStream; 36 37/** 38 * Build/Install/Run: 39 * atest CtsActivityManagerDeviceTestCases:ActivityManagerAmProfileTests 40 * 41 * Please talk to Android Studio team first if you want to modify or delete these tests. 42 */ 43public class ActivityManagerAmProfileTests extends ActivityManagerTestBase { 44 45 private static final String OUTPUT_FILE_PATH = "/data/local/tmp/profile.trace"; 46 private static final String FIRST_WORD_NO_STREAMING = "*version\n"; 47 private static final String FIRST_WORD_STREAMING = "SLOW"; // Magic word set by runtime. 48 49 private String mReadableFilePath = null; 50 51 @Before 52 @Override 53 public void setUp() throws Exception { 54 super.setUp(); 55 mReadableFilePath = InstrumentationRegistry.getContext() 56 .getExternalFilesDir(null) 57 .getPath() + "/profile.trace"; 58 } 59 60 /** 61 * Test am profile functionality with the following 3 configurable options: 62 * starting the activity before start profiling? yes; 63 * sampling-based profiling? no; 64 * using streaming output mode? no. 65 */ 66 @Test 67 public void testAmProfileStartNoSamplingNoStreaming() throws Exception { 68 // am profile start ... , and the same to the following 3 test methods. 69 testProfile(true, false, false); 70 } 71 72 /** 73 * The following tests are similar to testAmProfileStartNoSamplingNoStreaming(), 74 * only different in the three configuration options. 75 */ 76 @Test 77 public void testAmProfileStartNoSamplingStreaming() throws Exception { 78 testProfile(true, false, true); 79 } 80 81 @Test 82 public void testAmProfileStartSamplingNoStreaming() throws Exception { 83 testProfile(true, true, false); 84 } 85 86 @Test 87 public void testAmProfileStartSamplingStreaming() throws Exception { 88 testProfile(true, true, true); 89 } 90 91 @Test 92 public void testAmStartStartProfilerNoSamplingNoStreaming() throws Exception { 93 // am start --start-profiler ..., and the same to the following 3 test methods. 94 testProfile(false, false, false); 95 } 96 97 @Test 98 public void testAmStartStartProfilerNoSamplingStreaming() throws Exception { 99 testProfile(false, false, true); 100 } 101 102 @Test 103 public void testAmStartStartProfilerSamplingNoStreaming() throws Exception { 104 testProfile(false, true, false); 105 } 106 107 @Test 108 public void testAmStartStartProfilerSamplingStreaming() throws Exception { 109 testProfile(false, true, true); 110 } 111 112 private void testProfile(final boolean startActivityFirst, final boolean sampling, 113 final boolean streaming) throws Exception { 114 if (startActivityFirst) { 115 launchActivity(DEBUGGABLE_APP_ACTIVITY); 116 } 117 118 executeShellCommand( 119 getStartCmd(DEBUGGABLE_APP_ACTIVITY, startActivityFirst, sampling, streaming)); 120 // Go to home screen and then warm start the activity to generate some interesting trace. 121 pressHomeButton(); 122 launchActivity(DEBUGGABLE_APP_ACTIVITY); 123 124 executeShellCommand(getStopProfileCmd(DEBUGGABLE_APP_ACTIVITY)); 125 // Sleep for 0.1 second (100 milliseconds) so the generation of the profiling 126 // file is complete. 127 try { 128 Thread.sleep(100); 129 } catch (InterruptedException e) { 130 //ignored 131 } 132 verifyOutputFileFormat(streaming); 133 } 134 135 private static String getStartCmd(final ComponentName activityName, 136 final boolean activityAlreadyStarted, final boolean sampling, final boolean streaming) { 137 final StringBuilder builder = new StringBuilder("am"); 138 if (activityAlreadyStarted) { 139 builder.append(" profile start"); 140 } else { 141 builder.append(String.format(" start -n %s -W -S --start-profiler %s", 142 getActivityName(activityName), OUTPUT_FILE_PATH)); 143 } 144 if (sampling) { 145 builder.append(" --sampling 1000"); 146 } 147 if (streaming) { 148 builder.append(" --streaming"); 149 } 150 if (activityAlreadyStarted) { 151 builder.append(String.format( 152 " %s %s", activityName.getPackageName(), OUTPUT_FILE_PATH)); 153 } 154 return builder.toString(); 155 } 156 157 private static String getStopProfileCmd(final ComponentName activityName) { 158 return "am profile stop " + activityName.getPackageName(); 159 } 160 161 private void verifyOutputFileFormat(final boolean streaming) throws Exception { 162 // This is a hack. The am service has to write to /data/local/tmp because it doesn't have 163 // access to the sdcard but the test app can't read there 164 executeShellCommand("mv " + OUTPUT_FILE_PATH + " " + mReadableFilePath); 165 166 final String expectedFirstWord = streaming ? FIRST_WORD_STREAMING : FIRST_WORD_NO_STREAMING; 167 final byte[] data = readFile(mReadableFilePath); 168 assertThat("data size", data.length, greaterThanOrEqualTo(expectedFirstWord.length())); 169 final String actualFirstWord = new String(data, 0, expectedFirstWord.length()); 170 assertEquals("Unexpected first word", expectedFirstWord, actualFirstWord); 171 172 // Clean up. 173 executeShellCommand("rm -f " + OUTPUT_FILE_PATH + " " + mReadableFilePath); 174 } 175 176 private static byte[] readFile(String clientPath) throws Exception { 177 final File file = new File(clientPath); 178 assertTrue("File not found on client: " + clientPath, file.isFile()); 179 final int size = (int) file.length(); 180 final byte[] bytes = new byte[size]; 181 try (final FileInputStream fis = new FileInputStream(file)) { 182 final int readSize = fis.read(bytes, 0, bytes.length); 183 assertEquals("Read all data", bytes.length, readSize); 184 return bytes; 185 } 186 } 187} 188