diff options
Diffstat (limited to 'apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java')
-rw-r--r-- | apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java new file mode 100644 index 000000000000..9e17e940a06b --- /dev/null +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.wm; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import android.app.Activity; +import android.app.UiAutomation; +import android.content.Context; +import android.content.Intent; +import android.os.BatteryManager; +import android.os.ParcelFileDescriptor; +import android.perftests.utils.PerfTestActivity; +import android.provider.Settings; + +import androidx.test.rule.ActivityTestRule; +import androidx.test.runner.lifecycle.ActivityLifecycleCallback; +import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; +import androidx.test.runner.lifecycle.Stage; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public class WindowManagerPerfTestBase { + static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation(); + static final long NANOS_PER_S = 1000L * 1000 * 1000; + static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; + static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S; + + /** + * The out directory matching the directory-keys of collector in AndroidTest.xml. The directory + * is in /data because while enabling method profling of system server, it cannot write the + * trace to external storage. + */ + static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests"); + + private static int sOriginalStayOnWhilePluggedIn; + + @BeforeClass + public static void setUpOnce() { + final Context context = getInstrumentation().getContext(); + sOriginalStayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); + // Keep the device awake during testing. + setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_USB); + + if (!BASE_OUT_PATH.exists()) { + executeShellCommand("mkdir -p " + BASE_OUT_PATH); + } + // In order to be closer to the real use case. + executeShellCommand("input keyevent KEYCODE_WAKEUP"); + executeShellCommand("wm dismiss-keyguard"); + context.startActivity(new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + @AfterClass + public static void tearDownOnce() { + setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn); + } + + private static void setStayOnWhilePluggedIn(int value) { + executeShellCommand(String.format("settings put global %s %d", + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value)); + } + + /** + * Executes shell command with reading the output. It may also used to block until the current + * command is completed. + */ + static ByteArrayOutputStream executeShellCommand(String command) { + final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand(command); + final byte[] buf = new byte[512]; + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + int bytesRead; + try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + while ((bytesRead = fis.read(buf)) != -1) { + bytes.write(buf, 0, bytesRead); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return bytes; + } + + /** Starts method tracing on system server. */ + void startProfiling(String subPath) { + executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath)); + } + + void stopProfiling() { + executeShellCommand("am profile stop system"); + } + + /** + * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage. + */ + static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> { + private final Intent mStartIntent = + new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class); + private final LifecycleListener mLifecycleListener = new LifecycleListener(); + + PerfTestActivityRule() { + this(false /* launchActivity */); + } + + PerfTestActivityRule(boolean launchActivity) { + super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity); + } + + @Override + public Statement apply(Statement base, Description description) { + final Statement wrappedStatement = new Statement() { + @Override + public void evaluate() throws Throwable { + ActivityLifecycleMonitorRegistry.getInstance() + .addLifecycleCallback(mLifecycleListener); + base.evaluate(); + ActivityLifecycleMonitorRegistry.getInstance() + .removeLifecycleCallback(mLifecycleListener); + } + }; + return super.apply(wrappedStatement, description); + } + + @Override + protected Intent getActivityIntent() { + return mStartIntent; + } + + @Override + public PerfTestActivity launchActivity(Intent intent) { + final PerfTestActivity activity = super.launchActivity(intent); + mLifecycleListener.setTargetActivity(activity); + return activity; + } + + PerfTestActivity launchActivity() { + return launchActivity(mStartIntent); + } + + void waitForIdleSync(Stage state) { + mLifecycleListener.waitForIdleSync(state); + } + } + + static class LifecycleListener implements ActivityLifecycleCallback { + private Activity mTargetActivity; + private Stage mWaitingStage; + private Stage mReceivedStage; + + void setTargetActivity(Activity activity) { + mTargetActivity = activity; + mReceivedStage = mWaitingStage = null; + } + + void waitForIdleSync(Stage stage) { + synchronized (this) { + if (stage != mReceivedStage) { + mWaitingStage = stage; + try { + wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS)); + } catch (InterruptedException impossible) { } + } + mWaitingStage = mReceivedStage = null; + } + getInstrumentation().waitForIdleSync(); + } + + @Override + public void onActivityLifecycleChanged(Activity activity, Stage stage) { + if (mTargetActivity != activity) { + return; + } + + synchronized (this) { + mReceivedStage = stage; + if (mWaitingStage == mReceivedStage) { + notifyAll(); + } + } + } + } +} |