1 /* 2 * Copyright (C) 2019 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.wm; 18 19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 20 21 import android.app.Activity; 22 import android.content.Intent; 23 import android.perftests.utils.PerfTestActivity; 24 import android.perftests.utils.WindowPerfTestBase; 25 26 import androidx.test.runner.lifecycle.ActivityLifecycleCallback; 27 import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; 28 import androidx.test.runner.lifecycle.Stage; 29 30 import org.junit.runner.Description; 31 import org.junit.runners.model.Statement; 32 33 import java.io.File; 34 import java.util.concurrent.TimeUnit; 35 36 public class WindowManagerPerfTestBase extends WindowPerfTestBase { 37 static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S; 38 39 /** 40 * The out directory matching the directory-keys of collector in AndroidTest.xml. The directory 41 * is in /data because while enabling method profiling of system server, it cannot write the 42 * trace to external storage. 43 */ 44 static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests"); 45 startProfiling(String outFileName)46 static void startProfiling(String outFileName) { 47 startProfiling(BASE_OUT_PATH, outFileName); 48 } 49 50 /** 51 * Provides an activity that is able to wait for a stable lifecycle stage. 52 */ 53 static class PerfTestActivityRule extends PerfTestActivityRuleBase { 54 private final LifecycleListener mLifecycleListener = new LifecycleListener(); 55 PerfTestActivityRule()56 PerfTestActivityRule() { 57 } 58 PerfTestActivityRule(boolean launchActivity)59 PerfTestActivityRule(boolean launchActivity) { 60 super(launchActivity); 61 } 62 63 @Override apply(Statement base, Description description)64 public Statement apply(Statement base, Description description) { 65 final Statement wrappedStatement = new Statement() { 66 @Override 67 public void evaluate() throws Throwable { 68 ActivityLifecycleMonitorRegistry.getInstance() 69 .addLifecycleCallback(mLifecycleListener); 70 base.evaluate(); 71 ActivityLifecycleMonitorRegistry.getInstance() 72 .removeLifecycleCallback(mLifecycleListener); 73 } 74 }; 75 return super.apply(wrappedStatement, description); 76 } 77 78 @Override launchActivity(Intent intent)79 public PerfTestActivity launchActivity(Intent intent) { 80 final PerfTestActivity activity = super.launchActivity(intent); 81 mLifecycleListener.setTargetActivity(activity); 82 return activity; 83 } 84 waitForIdleSync(Stage state)85 void waitForIdleSync(Stage state) { 86 mLifecycleListener.waitForIdleSync(state); 87 } 88 } 89 90 static class LifecycleListener implements ActivityLifecycleCallback { 91 private Activity mTargetActivity; 92 private Stage mWaitingStage; 93 private Stage mReceivedStage; 94 setTargetActivity(Activity activity)95 void setTargetActivity(Activity activity) { 96 mTargetActivity = activity; 97 mReceivedStage = mWaitingStage = null; 98 } 99 waitForIdleSync(Stage stage)100 void waitForIdleSync(Stage stage) { 101 synchronized (this) { 102 if (stage != mReceivedStage) { 103 mWaitingStage = stage; 104 try { 105 wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS)); 106 } catch (InterruptedException impossible) { } 107 } 108 mWaitingStage = mReceivedStage = null; 109 } 110 getInstrumentation().waitForIdleSync(); 111 } 112 113 @Override onActivityLifecycleChanged(Activity activity, Stage stage)114 public void onActivityLifecycleChanged(Activity activity, Stage stage) { 115 if (mTargetActivity != activity) { 116 return; 117 } 118 119 synchronized (this) { 120 mReceivedStage = stage; 121 if (mWaitingStage == mReceivedStage) { 122 notifyAll(); 123 } 124 } 125 } 126 } 127 } 128