Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b873d05d authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Add some preconditions for WmPerfTests"

parents f2da154d 36a901b6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -21,9 +21,17 @@
        <option name="test-file-name" value="WmPerfTests.apk" />
    </target_preparer>

    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
        <option name="force-skip-system-props" value="true" />
        <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
        <option name="run-command" value="cmd window dismiss-keyguard" />
        <option name="run-command" value="cmd package compile -m speed com.android.perftests.wm" />
    </target_preparer>

    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.perftests.wm" />
        <option name="hidden-api-checks" value="false"/>
        <option name="device-listeners" value="android.wm.WmPerfRunListener" />
    </test>

    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+27 −0
Original line number Diff line number Diff line
## Window manager performance tests

### Precondition
To reduce the variance of the test, if `perf-setup.sh` (platform_testing/scripts/perf-setup)
is available, it is better to use the following instructions to lock CPU and GPU frequencies.
```
m perf-setup.sh
PERF_SETUP_PATH=/data/local/tmp/perf-setup.sh
adb push $OUT/$PERF_SETUP_PATH $PERF_SETUP_PATH
adb shell chmod +x $PERF_SETUP_PATH
adb shell $PERF_SETUP_PATH
```

### Example to run
Use `atest`
```
atest WmPerfTests:RelayoutPerfTest -- \
      --module-arg WmPerfTests:instrumentation-arg:kill-bg:=true
```
Use `am instrument`
```
adb shell am instrument -w -r -e class android.wm.RelayoutPerfTest \
          -e listener android.wm.WmPerfRunListener \
          -e kill-bg true \
          com.android.perftests.wm/androidx.test.runner.AndroidJUnitRunner
```
* `kill-bg` is optional.
+39 −26
Original line number Diff line number Diff line
@@ -23,18 +23,15 @@ import android.app.KeyguardManager;
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
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;
@@ -43,7 +40,9 @@ 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();
@@ -56,21 +55,11 @@ public class WindowManagerPerfTestBase {
     * 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;
    static final File BASE_OUT_PATH = new File("/data/local/WmPerfTests");

    @BeforeClass
    public static void setUpOnce() {
        final Context context = getInstrumentation().getContext();
        final int stayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
        sOriginalStayOnWhilePluggedIn = -1;
        if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) {
            sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn;
            // Keep the device awake during testing.
            setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY);
        }

        if (!BASE_OUT_PATH.exists()) {
            executeShellCommand("mkdir -p " + BASE_OUT_PATH);
@@ -84,18 +73,6 @@ public class WindowManagerPerfTestBase {
                .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
    }

    @AfterClass
    public static void tearDownOnce() {
        if (sOriginalStayOnWhilePluggedIn != -1) {
            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.
@@ -124,6 +101,42 @@ public class WindowManagerPerfTestBase {
        executeShellCommand("am profile stop system");
    }

    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.
     */
+130 −0
Original line number Diff line number Diff line
/*
 * 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.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.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;

/** Prepare the preconditions before running performance test. */
public class WmPerfRunListener extends RunListener {

    private static final String OPTION_KILL_BACKGROUND = "kill-bg";
    private static final long KILL_BACKGROUND_WAIT_MS = 3000;

    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();

        // 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.removeStacksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD,
                    ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED });
        });
        PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests");

        if (Boolean.parseBoolean(arguments.getString(OPTION_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();
    }
}