• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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