diff options
author | Riddle Hsu <riddlehsu@google.com> | 2020-11-26 18:01:46 +0800 |
---|---|---|
committer | Riddle Hsu <riddlehsu@google.com> | 2020-12-07 19:26:40 +0800 |
commit | 700bdd58fdb3daec08199e8cd6b1055980b88b5d (patch) | |
tree | e511c91b2c0870438fca147bfeb11f8bfbd13d18 | |
parent | 386bec73e4184820b421f03ce56929a3322cd8fc (diff) |
Extract window related perf test base classes
Add WindowPerfTestBase and WindowPerfRunPreconditionBase
into apct-perftests-utils. So window manager and input
method manager can share the same functions.
Bug: 174292015
Test: WmPerfTests ImePerfTests
Change-Id: Ie2818536d6611d1ba5f4b6cd725cd2d4a95e1cac
10 files changed, 373 insertions, 532 deletions
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java index fc48fd5271a8..4bfcadebc2d9 100644 --- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java +++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java @@ -16,134 +16,8 @@ package android.inputmethod; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.inputmethod.ImePerfTestBase.executeShellCommand; -import static android.inputmethod.ImePerfTestBase.runWithShellPermissionIdentity; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.ActivityTaskManager; -import android.content.Context; -import android.inputmethod.ImePerfTestBase.SettingsSession; -import android.os.BatteryManager; -import android.os.Bundle; -import android.os.SystemClock; -import android.provider.Settings; -import android.util.Log; -import android.view.WindowManagerPolicyConstants; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.internal.policy.PhoneWindow; - -import org.junit.runner.Description; -import org.junit.runner.Result; -import org.junit.runner.notification.RunListener; - -import java.util.List; +import android.perftests.utils.WindowPerfRunPreconditionBase; /** Prepare the preconditions before running performance test. */ -public class ImePerfRunPrecondition extends RunListener { - private static final String TAG = ImePerfRunPrecondition.class.getSimpleName(); - - private static final String ARGUMENT_LOG_ONLY = "log"; - private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg"; - private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations"; - private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling"; - private static final String DEFAULT_PROFILING_ITERATIONS = "10"; - private static final String DEFAULT_PROFILING_SAMPLING_US = "10"; - private static final long KILL_BACKGROUND_WAIT_MS = 3000; - - /** The requested iterations to run with method profiling. */ - static int sProfilingIterations; - - /** The interval of sample profiling in microseconds. */ - static int sSamplingIntervalUs; - - private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); - private long mWaitPreconditionDoneMs = 500; - - private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>( - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0), - value -> executeShellCommand(String.format("settings put global %s %d", - Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value))); - - private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>( - mContext.getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode), - value -> { - final String navOverlay; - switch (value) { - case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL: - default: - navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; - break; - } - executeShellCommand("cmd overlay enable-exclusive " + navOverlay); - }); - - /** It only executes once before all tests. */ - @Override - public void testRunStarted(Description description) { - final Bundle arguments = InstrumentationRegistry.getArguments(); - // If true, it only logs the method names without running. - final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false")); - Log.i(TAG, "arguments=" + arguments); - if (skip) { - return; - } - sProfilingIterations = Integer.parseInt( - arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS)); - sSamplingIntervalUs = Integer.parseInt( - arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US)); - - // Use same navigation mode (gesture navigation) across all devices and tests - // for consistency. - mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL); - // Keep the device awake during testing. - mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY); - - runWithShellPermissionIdentity(() -> { - final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class); - atm.removeAllVisibleRecentTasks(); - atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD, - ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED }); - }); - PhoneWindow.sendCloseSystemWindows(mContext, "ImePerfTests"); - - if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) { - runWithShellPermissionIdentity(this::killBackgroundProcesses); - mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS; - } - // Wait a while for the precondition setup to complete. - SystemClock.sleep(mWaitPreconditionDoneMs); - } - - private void killBackgroundProcesses() { - Log.i(TAG, "Killing background processes..."); - final ActivityManager am = mContext.getSystemService(ActivityManager.class); - final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses(); - if (processes == null) { - return; - } - for (RunningAppProcessInfo processInfo : processes) { - if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN - && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) { - for (String pkg : processInfo.pkgList) { - am.forceStopPackage(pkg); - } - } - } - } - - /** It only executes once after all tests. */ - @Override - public void testRunFinished(Result result) { - mNavigationModeSetting.close(); - mStayOnWhilePluggedInSetting.close(); - } +public class ImePerfRunPrecondition extends WindowPerfRunPreconditionBase { } diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java index 2b7af2f0a11e..689fb3645daf 100644 --- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java +++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java @@ -29,7 +29,6 @@ import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.inputmethodservice.InputMethodService; -import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemClock; import android.perftests.utils.ManualBenchmarkState; @@ -420,23 +419,20 @@ public class ImePerfTest extends ImePerfTestBase }); } - private void startAsyncAtrace() throws IOException { + private void startAsyncAtrace() { mIsTraceStarted = true; // IMF uses 'wm' component for trace in InputMethodService, InputMethodManagerService, // WindowManagerService and 'view' for client window (InsetsController). // TODO(b/167947940): Consider a separate input_method atrace - UI_AUTOMATION.executeShellCommand("atrace -b 32768 --async_start wm view"); - // Avoid atrace isn't ready immediately. - SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); + startAsyncAtrace("wm view"); } private void stopAsyncAtrace() { if (!mIsTraceStarted) { return; } - final ParcelFileDescriptor pfd = UI_AUTOMATION.executeShellCommand("atrace --async_stop"); mIsTraceStarted = false; - final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + final InputStream inputStream = stopAsyncAtraceWithStream(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; while ((line = reader.readLine()) != null) { diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java index 1a861d7ba87b..f70d79cf9153 100644 --- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java +++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java @@ -18,135 +18,21 @@ package android.inputmethod; import static android.perftests.utils.PerfTestActivity.INTENT_EXTRA_ADD_EDIT_TEXT; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import android.app.KeyguardManager; -import android.app.UiAutomation; -import android.content.Context; import android.content.Intent; -import android.os.ParcelFileDescriptor; -import android.os.PowerManager; import android.perftests.utils.PerfTestActivity; +import android.perftests.utils.WindowPerfTestBase; - -import androidx.test.rule.ActivityTestRule; - -import org.junit.BeforeClass; - -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Objects; -import java.util.function.Consumer; - -public class ImePerfTestBase { - static final UiAutomation UI_AUTOMATION = getInstrumentation().getUiAutomation(); - static final long NANOS_PER_S = 1000L * 1000 * 1000; - static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; +public class ImePerfTestBase extends WindowPerfTestBase { static final long TIMEOUT_1_S_IN_MS = 1 * 1000L; - @BeforeClass - public static void setUpOnce() { - final Context context = getInstrumentation().getContext(); - - if (!context.getSystemService(PowerManager.class).isInteractive() - || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) { - 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)); - } - - /** - * 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 = UI_AUTOMATION.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; - } - - /** Returns how many iterations should run with method tracing. */ - static int getProfilingIterations() { - return ImePerfRunPrecondition.sProfilingIterations; - } - - static void runWithShellPermissionIdentity(Runnable runnable) { - UI_AUTOMATION.adoptShellPermissionIdentity(); - try { - runnable.run(); - } finally { - UI_AUTOMATION.dropShellPermissionIdentity(); - } - } - - static class SettingsSession<T> implements AutoCloseable { - private final Consumer<T> mSetter; - private final T mOriginalValue; - private boolean mChanged; - - SettingsSession(T originalValue, Consumer<T> setter) { - mOriginalValue = originalValue; - mSetter = setter; - } - - void set(T value) { - if (Objects.equals(value, mOriginalValue)) { - mChanged = false; - return; - } - mSetter.accept(value); - mChanged = true; - } - - @Override - public void close() { - if (mChanged) { - mSetter.accept(mOriginalValue); - } - } - } - - /** - * 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); - - PerfTestActivityRule() { - this(false /* launchActivity */); - } - - PerfTestActivityRule(boolean launchActivity) { - super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity); - } - - @Override - protected Intent getActivityIntent() { - return mStartIntent; - } + /** Provides an activity that contains an edit text view.*/ + static class PerfTestActivityRule extends PerfTestActivityRuleBase { @Override public PerfTestActivity launchActivity(Intent intent) { intent.putExtra(INTENT_EXTRA_ADD_EDIT_TEXT, true); return super.launchActivity(intent); } - - PerfTestActivity launchActivity() { - return launchActivity(mStartIntent); - } } static String[] buildArray(String[]... arrays) { diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java new file mode 100644 index 000000000000..8d2ac0276592 --- /dev/null +++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2020 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.perftests.utils; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.perftests.utils.WindowPerfTestBase.executeShellCommand; +import static android.perftests.utils.WindowPerfTestBase.runWithShellPermissionIdentity; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.ActivityTaskManager; +import android.content.Context; +import android.os.BatteryManager; +import android.os.Bundle; +import android.os.SystemClock; +import android.perftests.utils.WindowPerfTestBase.SettingsSession; +import android.provider.Settings; +import android.util.Log; +import android.view.WindowManagerPolicyConstants; + +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.policy.PhoneWindow; + +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.RunListener; + +import java.util.List; + +/** Prepare the preconditions before running performance test. */ +public class WindowPerfRunPreconditionBase extends RunListener { + protected final String mTag = getClass().getSimpleName(); + + private static final String ARGUMENT_LOG_ONLY = "log"; + private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg"; + private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations"; + private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling"; + private static final String DEFAULT_PROFILING_ITERATIONS = "0"; + private static final String DEFAULT_PROFILING_SAMPLING_US = "10"; + private static final long KILL_BACKGROUND_WAIT_MS = 3000; + + /** The requested iterations to run with method profiling. */ + static int sProfilingIterations; + + /** The interval of sample profiling in microseconds. */ + static int sSamplingIntervalUs; + + private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); + private long mWaitPreconditionDoneMs = 500; + + private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>( + Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0), + value -> executeShellCommand(String.format("settings put global %s %d", + Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value))); + + private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>( + mContext.getResources().getInteger( + com.android.internal.R.integer.config_navBarInteractionMode), + value -> { + final String navOverlay; + switch (value) { + case WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON: + navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY; + break; + case WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON: + navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; + break; + case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL: + default: + navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; + break; + } + executeShellCommand("cmd overlay enable-exclusive " + navOverlay); + }); + + /** It only executes once before all tests. */ + @Override + public void testRunStarted(Description description) { + final Bundle arguments = InstrumentationRegistry.getArguments(); + // If true, it only logs the method names without running. + final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false")); + Log.i(mTag, "arguments=" + arguments); + if (skip) { + return; + } + sProfilingIterations = Integer.parseInt( + arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS)); + sSamplingIntervalUs = Integer.parseInt( + arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US)); + + // Use same navigation mode (gesture navigation) across all devices and tests + // for consistency. + mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL); + // Keep the device awake during testing. + mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY); + + runWithShellPermissionIdentity(() -> { + final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class); + atm.removeAllVisibleRecentTasks(); + atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD, + ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED }); + }); + PhoneWindow.sendCloseSystemWindows(mContext, mTag); + + if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) { + runWithShellPermissionIdentity(this::killBackgroundProcesses); + mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS; + } + // Wait a while for the precondition setup to complete. + SystemClock.sleep(mWaitPreconditionDoneMs); + } + + private void killBackgroundProcesses() { + Log.i(mTag, "Killing background processes..."); + final ActivityManager am = mContext.getSystemService(ActivityManager.class); + final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses(); + if (processes == null) { + return; + } + for (RunningAppProcessInfo processInfo : processes) { + if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN + && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) { + for (String pkg : processInfo.pkgList) { + am.forceStopPackage(pkg); + } + } + } + } + + /** It only executes once after all tests. */ + @Override + public void testRunFinished(Result result) { + mNavigationModeSetting.close(); + mStayOnWhilePluggedInSetting.close(); + } +} diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java new file mode 100644 index 000000000000..ca5913701d3b --- /dev/null +++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020 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.perftests.utils; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import android.app.KeyguardManager; +import android.app.UiAutomation; +import android.content.Context; +import android.content.Intent; +import android.os.ParcelFileDescriptor; +import android.os.PowerManager; +import android.os.SystemClock; + +import androidx.test.rule.ActivityTestRule; + +import org.junit.After; +import org.junit.BeforeClass; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** The base class for window related performance tests. */ +public class WindowPerfTestBase { + public static final long NANOS_PER_S = 1000L * 1000 * 1000; + public static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; + + static boolean sIsProfilingMethod; + + @BeforeClass + public static void setUpOnce() { + final Context context = getInstrumentation().getContext(); + + if (!context.getSystemService(PowerManager.class).isInteractive() + || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) { + 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)); + } + + @After + public void tearDown() { + // Make sure that profiling is stopped if test fails. + if (sIsProfilingMethod) { + stopProfiling(); + } + } + + public static UiAutomation getUiAutomation() { + return getInstrumentation().getUiAutomation(); + } + + public static void startAsyncAtrace(String tags) { + getUiAutomation().executeShellCommand("atrace -b 32768 --async_start " + tags); + // Avoid atrace isn't ready immediately. + SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); + } + + public static InputStream stopAsyncAtraceWithStream() { + return new ParcelFileDescriptor.AutoCloseInputStream( + getUiAutomation().executeShellCommand("atrace --async_stop")); + } + + /** Starts method tracing on system server. */ + public static void startProfiling(File basePath, String outFileName) { + if (!basePath.exists()) { + executeShellCommand("mkdir -p " + basePath); + } + final String samplingArg = WindowPerfRunPreconditionBase.sSamplingIntervalUs > 0 + ? ("--sampling " + WindowPerfRunPreconditionBase.sSamplingIntervalUs) + : ""; + executeShellCommand("am profile start " + samplingArg + " system " + + new File(basePath, outFileName)); + sIsProfilingMethod = true; + } + + /** Stops method tracing of system server. */ + public static void stopProfiling() { + executeShellCommand("am profile stop system"); + sIsProfilingMethod = false; + } + + public static boolean sIsProfilingMethod() { + return sIsProfilingMethod; + } + + /** Returns how many iterations should run with method tracing. */ + public static int getProfilingIterations() { + return WindowPerfRunPreconditionBase.sProfilingIterations; + } + + /** + * Executes shell command with reading the output. It may also used to block until the current + * command is completed. + */ + public static ByteArrayOutputStream executeShellCommand(String command) { + final ParcelFileDescriptor pfd = getUiAutomation().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; + } + + public static void runWithShellPermissionIdentity(Runnable runnable) { + getUiAutomation().adoptShellPermissionIdentity(); + try { + runnable.run(); + } finally { + getUiAutomation().dropShellPermissionIdentity(); + } + } + + public static class SettingsSession<T> implements AutoCloseable { + private final Consumer<T> mSetter; + private final T mOriginalValue; + private boolean mChanged; + + public SettingsSession(T originalValue, Consumer<T> setter) { + mOriginalValue = originalValue; + mSetter = setter; + } + + public void set(T value) { + if (Objects.equals(value, mOriginalValue)) { + mChanged = false; + return; + } + mSetter.accept(value); + mChanged = true; + } + + @Override + public void close() { + if (mChanged) { + mSetter.accept(mOriginalValue); + } + } + } + + /** + * Provides the {@link PerfTestActivity} with an associated customizable intent. + */ + public static class PerfTestActivityRuleBase extends ActivityTestRule<PerfTestActivity> { + protected final Intent mStartIntent = + new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class); + + public PerfTestActivityRuleBase() { + this(false /* launchActivity */); + } + + public PerfTestActivityRuleBase(boolean launchActivity) { + super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity); + } + + @Override + public Intent getActivityIntent() { + return mStartIntent; + } + + public PerfTestActivity launchActivity() { + return launchActivity(mStartIntent); + } + } +} diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java index 5c09ec2e760f..bccef533be32 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java @@ -18,7 +18,6 @@ package android.wm; import static android.perftests.utils.ManualBenchmarkState.StatsReport; -import android.os.ParcelFileDescriptor; import android.os.SystemClock; import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest; @@ -37,7 +36,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.concurrent.TimeUnit; /** Measure the performance of internal methods in window manager service by trace tag. */ @LargeTest @@ -85,7 +83,7 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase while (state.keepRunning(measuredTimeNs)) { if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) { - startAsyncAtrace(); + startAsyncAtrace("wm"); mIsTraceStarted = true; } final long startTime = SystemClock.elapsedRealtimeNanos(); @@ -108,15 +106,8 @@ public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase Log.i(TAG, String.valueOf(mTraceMarkParser)); } - private void startAsyncAtrace() throws IOException { - sUiAutomation.executeShellCommand("atrace -b 32768 --async_start wm"); - // Avoid atrace isn't ready immediately. - SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); - } - private void stopAsyncAtrace() { - final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("atrace --async_stop"); - final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + final InputStream inputStream = stopAsyncAtraceWithStream(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; while ((line = reader.readLine()) != null) { diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java index 833cc0ff37a0..2aea61f4e540 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java @@ -96,7 +96,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase @BeforeClass public static void setUpClass() { // Get the permission to invoke startRecentsActivity. - sUiAutomation.adoptShellPermissionIdentity(); + getUiAutomation().adoptShellPermissionIdentity(); final Context context = getInstrumentation().getContext(); final PackageManager pm = context.getPackageManager(); @@ -129,7 +129,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase ActivityManager.resumeAppSwitches(); } catch (RemoteException ignored) { } - sUiAutomation.dropShellPermissionIdentity(); + getUiAutomation().dropShellPermissionIdentity(); } @Before @@ -233,7 +233,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase // Ensure the animation callback is done. Assume.assumeTrue(recentsSemaphore.tryAcquire( - sIsProfilingMethod ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS, + sIsProfilingMethod() ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS, TimeUnit.NANOSECONDS)); } } diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java index 29606030a041..9403e8b72348 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java @@ -54,12 +54,12 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase @BeforeClass public static void setUpClass() { // Get the permission to use most window types. - sUiAutomation.adoptShellPermissionIdentity(); + getUiAutomation().adoptShellPermissionIdentity(); } @AfterClass public static void tearDownClass() { - sUiAutomation.dropShellPermissionIdentity(); + getUiAutomation().dropShellPermissionIdentity(); } /** The last customized iterations will provide the information of method profiling. */ diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java index b51a9a8fb0dd..4b1982f60092 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java @@ -19,36 +19,21 @@ package android.wm; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import android.app.Activity; -import android.app.KeyguardManager; -import android.app.UiAutomation; -import android.content.Context; import android.content.Intent; -import android.os.ParcelFileDescriptor; -import android.os.PowerManager; import android.perftests.utils.PerfTestActivity; +import android.perftests.utils.WindowPerfTestBase; -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.After; -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.Objects; import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -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; +public class WindowManagerPerfTestBase extends WindowPerfTestBase { static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S; /** @@ -58,121 +43,21 @@ public class WindowManagerPerfTestBase { */ static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests"); - static boolean sIsProfilingMethod; - - @BeforeClass - public static void setUpOnce() { - final Context context = getInstrumentation().getContext(); - - if (!context.getSystemService(PowerManager.class).isInteractive() - || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) { - 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)); - } - - @After - public void tearDown() { - // Make sure that profiling is stopped if test fails. - if (sIsProfilingMethod) { - stopProfiling(); - } + static void startProfiling(String outFileName) { + startProfiling(BASE_OUT_PATH, outFileName); } /** - * Executes shell command with reading the output. It may also used to block until the current - * command is completed. + * Provides an activity that is able to wait for a stable lifecycle stage. */ - 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. */ - static void startProfiling(String subPath) { - if (!BASE_OUT_PATH.exists()) { - executeShellCommand("mkdir -p " + BASE_OUT_PATH); - } - final String samplingArg = WmPerfRunListener.sSamplingIntervalUs > 0 - ? ("--sampling " + WmPerfRunListener.sSamplingIntervalUs) - : ""; - executeShellCommand("am profile start " + samplingArg + " system " - + new File(BASE_OUT_PATH, subPath)); - sIsProfilingMethod = true; - } - - static void stopProfiling() { - executeShellCommand("am profile stop system"); - sIsProfilingMethod = false; - } - - /** Returns how many iterations should run with method tracing. */ - static int getProfilingIterations() { - return WmPerfRunListener.sProfilingIterations; - } - - static void runWithShellPermissionIdentity(Runnable runnable) { - sUiAutomation.adoptShellPermissionIdentity(); - try { - runnable.run(); - } finally { - sUiAutomation.dropShellPermissionIdentity(); - } - } - - static class SettingsSession<T> implements AutoCloseable { - private final Consumer<T> mSetter; - private final T mOriginalValue; - private boolean mChanged; - - SettingsSession(T originalValue, Consumer<T> setter) { - mOriginalValue = originalValue; - mSetter = setter; - } - - void set(T value) { - if (Objects.equals(value, mOriginalValue)) { - mChanged = false; - return; - } - mSetter.accept(value); - mChanged = true; - } - - @Override - public void close() { - if (mChanged) { - mSetter.accept(mOriginalValue); - } - } - } - - /** - * 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); + static class PerfTestActivityRule extends PerfTestActivityRuleBase { private final LifecycleListener mLifecycleListener = new LifecycleListener(); PerfTestActivityRule() { - this(false /* launchActivity */); } PerfTestActivityRule(boolean launchActivity) { - super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity); + super(launchActivity); } @Override @@ -191,21 +76,12 @@ public class WindowManagerPerfTestBase { } @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); } diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java index a9d57167f6d2..2b0801af12cb 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java @@ -16,138 +16,8 @@ package android.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.wm.WindowManagerPerfTestBase.executeShellCommand; -import static android.wm.WindowManagerPerfTestBase.runWithShellPermissionIdentity; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.ActivityTaskManager; -import android.content.Context; -import android.os.BatteryManager; -import android.os.Bundle; -import android.os.SystemClock; -import android.provider.Settings; -import android.util.Log; -import android.view.WindowManagerPolicyConstants; -import android.wm.WindowManagerPerfTestBase.SettingsSession; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.internal.policy.PhoneWindow; - -import org.junit.runner.Description; -import org.junit.runner.Result; -import org.junit.runner.notification.RunListener; - -import java.util.List; +import android.perftests.utils.WindowPerfRunPreconditionBase; /** Prepare the preconditions before running performance test. */ -public class WmPerfRunListener extends RunListener { - private static final String TAG = WmPerfRunListener.class.getSimpleName(); - - private static final String ARGUMENT_LOG_ONLY = "log"; - private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg"; - private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations"; - private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling"; - private static final String DEFAULT_PROFILING_ITERATIONS = "0"; - private static final String DEFAULT_PROFILING_SAMPLING_US = "10"; - private static final long KILL_BACKGROUND_WAIT_MS = 3000; - - /** The requested iterations to run with method profiling. */ - static int sProfilingIterations; - - /** The interval of sample profiling in microseconds. */ - static int sSamplingIntervalUs; - - private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); - private long mWaitPreconditionDoneMs = 500; - - private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>( - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0), - value -> executeShellCommand(String.format("settings put global %s %d", - Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value))); - - private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>( - mContext.getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode), - value -> { - final String navOverlay; - switch (value) { - case WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON: - navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY; - break; - case WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON: - navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; - break; - case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL: - default: - navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; - break; - } - executeShellCommand("cmd overlay enable-exclusive " + navOverlay); - }); - - /** It only executes once before all tests. */ - @Override - public void testRunStarted(Description description) { - final Bundle arguments = InstrumentationRegistry.getArguments(); - // If true, it only logs the method names without running. - final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false")); - Log.i(TAG, "arguments=" + arguments); - if (skip) { - return; - } - sProfilingIterations = Integer.parseInt( - arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS)); - sSamplingIntervalUs = Integer.parseInt( - arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US)); - - // Use gesture navigation for consistency. - mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL); - // Keep the device awake during testing. - mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY); - - runWithShellPermissionIdentity(() -> { - final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class); - atm.removeAllVisibleRecentTasks(); - atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD, - ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED }); - }); - PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests"); - - if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) { - runWithShellPermissionIdentity(this::killBackgroundProcesses); - mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS; - } - // Wait a while for the precondition setup to complete. - SystemClock.sleep(mWaitPreconditionDoneMs); - } - - private void killBackgroundProcesses() { - final ActivityManager am = mContext.getSystemService(ActivityManager.class); - final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses(); - if (processes == null) { - return; - } - for (RunningAppProcessInfo processInfo : processes) { - if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN - && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) { - for (String pkg : processInfo.pkgList) { - am.forceStopPackage(pkg); - } - } - } - } - - /** It only executes once after all tests. */ - @Override - public void testRunFinished(Result result) { - mNavigationModeSetting.close(); - mStayOnWhilePluggedInSetting.close(); - } +public class WmPerfRunListener extends WindowPerfRunPreconditionBase { } |