1 /* 2 * Copyright (C) 2020 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.perftests.utils; 18 19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 20 21 import android.app.KeyguardManager; 22 import android.app.UiAutomation; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.os.ParcelFileDescriptor; 26 import android.os.PowerManager; 27 import android.os.SystemClock; 28 29 import androidx.test.rule.ActivityTestRule; 30 31 import org.junit.After; 32 import org.junit.BeforeClass; 33 34 import java.io.ByteArrayOutputStream; 35 import java.io.File; 36 import java.io.FileInputStream; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.util.Objects; 40 import java.util.concurrent.TimeUnit; 41 import java.util.function.Consumer; 42 43 /** The base class for window related performance tests. */ 44 public class WindowPerfTestBase { 45 public static final long NANOS_PER_S = 1000L * 1000 * 1000; 46 public static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; 47 48 static boolean sIsProfilingMethod; 49 50 @BeforeClass setUpOnce()51 public static void setUpOnce() { 52 final Context context = getInstrumentation().getContext(); 53 54 if (!context.getSystemService(PowerManager.class).isInteractive() 55 || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) { 56 executeShellCommand("input keyevent KEYCODE_WAKEUP"); 57 executeShellCommand("wm dismiss-keyguard"); 58 } 59 context.startActivity(new Intent(Intent.ACTION_MAIN) 60 .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 61 } 62 63 @After tearDown()64 public void tearDown() { 65 // Make sure that profiling is stopped if test fails. 66 if (sIsProfilingMethod) { 67 stopProfiling(); 68 } 69 } 70 getUiAutomation()71 public static UiAutomation getUiAutomation() { 72 return getInstrumentation().getUiAutomation(); 73 } 74 startAsyncAtrace(String tags)75 public static void startAsyncAtrace(String tags) { 76 getUiAutomation().executeShellCommand("atrace -b 32768 --async_start " + tags); 77 // Avoid atrace isn't ready immediately. 78 SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); 79 } 80 stopAsyncAtraceWithStream()81 public static InputStream stopAsyncAtraceWithStream() { 82 return new ParcelFileDescriptor.AutoCloseInputStream( 83 getUiAutomation().executeShellCommand("atrace --async_stop")); 84 } 85 86 /** Starts method tracing on system server. */ startProfiling(File basePath, String outFileName)87 public static void startProfiling(File basePath, String outFileName) { 88 if (!basePath.exists()) { 89 executeShellCommand("mkdir -p " + basePath); 90 } 91 final String samplingArg = WindowPerfRunPreconditionBase.sSamplingIntervalUs > 0 92 ? ("--sampling " + WindowPerfRunPreconditionBase.sSamplingIntervalUs) 93 : ""; 94 executeShellCommand("am profile start " + samplingArg + " system " 95 + new File(basePath, outFileName)); 96 sIsProfilingMethod = true; 97 } 98 99 /** Stops method tracing of system server. */ stopProfiling()100 public static void stopProfiling() { 101 executeShellCommand("am profile stop system"); 102 sIsProfilingMethod = false; 103 } 104 sIsProfilingMethod()105 public static boolean sIsProfilingMethod() { 106 return sIsProfilingMethod; 107 } 108 109 /** Returns how many iterations should run with method tracing. */ getProfilingIterations()110 public static int getProfilingIterations() { 111 return WindowPerfRunPreconditionBase.sProfilingIterations; 112 } 113 114 /** 115 * Executes shell command with reading the output. It may also used to block until the current 116 * command is completed. 117 */ executeShellCommand(String command)118 public static ByteArrayOutputStream executeShellCommand(String command) { 119 final ParcelFileDescriptor pfd = getUiAutomation().executeShellCommand(command); 120 final byte[] buf = new byte[512]; 121 final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 122 int bytesRead; 123 try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { 124 while ((bytesRead = fis.read(buf)) != -1) { 125 bytes.write(buf, 0, bytesRead); 126 } 127 } catch (IOException e) { 128 throw new RuntimeException(e); 129 } 130 return bytes; 131 } 132 runWithShellPermissionIdentity(Runnable runnable)133 public static void runWithShellPermissionIdentity(Runnable runnable) { 134 getUiAutomation().adoptShellPermissionIdentity(); 135 try { 136 runnable.run(); 137 } finally { 138 getUiAutomation().dropShellPermissionIdentity(); 139 } 140 } 141 142 public static class SettingsSession<T> implements AutoCloseable { 143 private final Consumer<T> mSetter; 144 private final T mOriginalValue; 145 private boolean mChanged; 146 SettingsSession(T originalValue, Consumer<T> setter)147 public SettingsSession(T originalValue, Consumer<T> setter) { 148 mOriginalValue = originalValue; 149 mSetter = setter; 150 } 151 set(T value)152 public void set(T value) { 153 if (Objects.equals(value, mOriginalValue)) { 154 mChanged = false; 155 return; 156 } 157 mSetter.accept(value); 158 mChanged = true; 159 } 160 161 @Override close()162 public void close() { 163 if (mChanged) { 164 mSetter.accept(mOriginalValue); 165 } 166 } 167 } 168 169 /** 170 * Provides the {@link PerfTestActivity} with an associated customizable intent. 171 */ 172 public static class PerfTestActivityRuleBase extends ActivityTestRule<PerfTestActivity> { 173 protected final Intent mStartIntent = 174 new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class); 175 PerfTestActivityRuleBase()176 public PerfTestActivityRuleBase() { 177 this(false /* launchActivity */); 178 } 179 PerfTestActivityRuleBase(boolean launchActivity)180 public PerfTestActivityRuleBase(boolean launchActivity) { 181 super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity); 182 } 183 184 @Override getActivityIntent()185 public Intent getActivityIntent() { 186 return mStartIntent; 187 } 188 launchActivity()189 public PerfTestActivity launchActivity() { 190 return launchActivity(mStartIntent); 191 } 192 } 193 } 194