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

Commit ecae5d80 authored by Eric Lin's avatar Eric Lin Committed by Android (Google) Code Review
Browse files

Merge "Extract WindowManagerService test support logic." into main

parents e2be8cf7 32e1982d
Loading
Loading
Loading
Loading
+31 −17
Original line number Diff line number Diff line
@@ -331,6 +331,7 @@ import android.window.WindowContextInfo;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -600,6 +601,7 @@ public class WindowManagerService extends IWindowManager.Stub
    final boolean mLimitedAlphaCompositing;
    final int mMaxUiWidth;

    @NonNull
    @VisibleForTesting
    WindowManagerPolicy mPolicy;

@@ -1054,13 +1056,16 @@ public class WindowManagerService extends IWindowManager.Stub
    private boolean mAnimationsDisabled = false;
    boolean mPointerLocationEnabled = false;

    @NonNull
    final AppCompatConfiguration mAppCompatConfiguration;

    private boolean mIsIgnoreOrientationRequestDisabled;

    @NonNull
    final InputManagerService mInputManager;
    final DisplayManagerInternal mDisplayManagerInternal;
    final DisplayManager mDisplayManager;
    @NonNull
    final ActivityTaskManagerService mAtmService;

    /** Indicates whether this device supports wide color gamut / HDR rendering */
@@ -1116,7 +1121,9 @@ public class WindowManagerService extends IWindowManager.Stub
    static WindowManagerThreadPriorityBooster sThreadPriorityBooster =
            new WindowManagerThreadPriorityBooster();

    @NonNull
    Supplier<SurfaceControl.Builder> mSurfaceControlFactory;
    @NonNull
    Supplier<SurfaceControl.Transaction> mTransactionFactory;

    private final SurfaceControl.Transaction mTransaction;
@@ -1188,9 +1195,11 @@ public class WindowManagerService extends IWindowManager.Stub

    private volatile boolean mDisableSecureWindows = false;

    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, WindowManagerPolicy policy,
            ActivityTaskManagerService atm) {
    /** Creates an instance of the WindowManagerService for the system server. */
    public static WindowManagerService main(@NonNull final Context context,
            @NonNull final InputManagerService im, final boolean showBootMsgs,
            @NonNull final WindowManagerPolicy policy,
            @NonNull final ActivityTaskManagerService atm) {
        // Using SysUI context to have access to Material colors extracted from Wallpaper.
        final AppCompatConfiguration appCompat = new AppCompatConfiguration(
                ActivityThread.currentActivityThread().getSystemUiContext());
@@ -1204,15 +1213,19 @@ public class WindowManagerService extends IWindowManager.Stub

    /**
     * Creates and returns an instance of the WindowManagerService. This call allows the caller
     * to override factories that can be used to stub native calls during test.
     * to override factories that can be used to stub native calls during test. Tests should use
     * {@link WindowManagerServiceTestSupport} instead of calling this directly to ensure
     * proper initialization and cleanup of dependencies.
     */
    @VisibleForTesting
    public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
            DisplayWindowSettingsProvider displayWindowSettingsProvider,
            Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<SurfaceControl.Builder> surfaceControlFactory,
            AppCompatConfiguration appCompat) {
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    static WindowManagerService main(@NonNull final Context context,
            @NonNull final InputManagerService im, boolean showBootMsgs,
            @NonNull final WindowManagerPolicy policy,
            @NonNull final ActivityTaskManagerService atm,
            @NonNull final DisplayWindowSettingsProvider displayWindowSettingsProvider,
            @NonNull final Supplier<SurfaceControl.Transaction> transactionFactory,
            @NonNull final Supplier<SurfaceControl.Builder> surfaceControlFactory,
            @NonNull final AppCompatConfiguration appCompat) {

        final WindowManagerService[] wms = new WindowManagerService[1];
        DisplayThread.getHandler().runWithScissors(() ->
@@ -1238,12 +1251,13 @@ public class WindowManagerService extends IWindowManager.Stub
        new WindowManagerShellCommand(this).exec(this, in, out, err, args, callback, result);
    }

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
            DisplayWindowSettingsProvider displayWindowSettingsProvider,
            Supplier<SurfaceControl.Transaction> transactionFactory,
            Supplier<SurfaceControl.Builder> surfaceControlFactory,
            AppCompatConfiguration appCompat) {
    private WindowManagerService(@NonNull Context context,
            @NonNull InputManagerService inputManager, boolean showBootMsgs,
            @NonNull WindowManagerPolicy policy, @NonNull ActivityTaskManagerService atm,
            @NonNull DisplayWindowSettingsProvider displayWindowSettingsProvider,
            @NonNull Supplier<SurfaceControl.Transaction> transactionFactory,
            @NonNull Supplier<SurfaceControl.Builder> surfaceControlFactory,
            @NonNull AppCompatConfiguration appCompat) {
        installLock(this, INDEX_WINDOW);
        mGlobalLock = atm.getGlobalLock();
        mAtmService = atm;
+47 −19
Original line number Diff line number Diff line
@@ -11,19 +11,46 @@ package {
    default_applicable_licenses: ["frameworks_base_license"],
}

// Include all test java files.
filegroup {
    name: "wmtests-sources",
    name: "wmtests-support-sources",
    srcs: [
        "src/**/*.java",
        "src/com/android/server/wm/WindowManagerServiceTestSupport.kt",
    ],
    path: "src",
    visibility: ["//visibility:private"],
}

java_library {
    name: "wmtests-support",
    srcs: [":wmtests-support-sources"],
    static_libs: [
        "com.android.window.flags.window-aconfig-java",
        "kotlin-stdlib",
        "services.core",
    ],
    lint: {
        test: true,
    },
    visibility: [
        "//frameworks/base/services/tests/wmtests",
        "//frameworks/opt/car/services/updatableServices/tests",
    ],
}

// Include all test files, but exclude test support files.
filegroup {
    name: "wmtests-sources",
    srcs: ["src/**/*.java"],
    exclude_srcs: [":wmtests-support-sources"],
    path: "src",
    visibility: ["//visibility:private"],
}

java_genrule {
    name: "wmtests.protologsrc",
    srcs: [
        ":protolog-impl",
        ":protolog-groups",
        ":protolog-impl",
        ":wmtests-sources",
    ],
    tools: ["protologtool"],
@@ -52,33 +79,34 @@ android_test {
    ],

    static_libs: [
        "frameworks-base-testutils",
        "services.core",
        "service-permission.stubs.system_server",
        "androidx.test.runner",
        "CtsSurfaceValidatorLib",
        "android.view.inputmethod.flags-aconfig-java",
        "androidx.test.rules",
        "androidx.test.runner",
        "com.android.window.flags.window-aconfig-java",
        "flag-junit",
        "flickerlib",
        "frameworks-base-testutils",
        "hamcrest-library",
        "junit-params",
        "mockito-kotlin2",
        "mockito-target-extended-minus-junit4",
        "platform-compat-test-rules",
        "platform-test-annotations",
        "service-permission.stubs.system_server",
        "service-sdksandbox.impl",
        "services.core",
        "servicestests-utils",
        "testables",
        "testng",
        "truth",
        "testables",
        "hamcrest-library",
        "flag-junit",
        "platform-compat-test-rules",
        "CtsSurfaceValidatorLib",
        "service-sdksandbox.impl",
        "com.android.window.flags.window-aconfig-java",
        "android.view.inputmethod.flags-aconfig-java",
        "flag-junit",
        "wmtests-support",
    ],

    libs: [
        "android.hardware.power-V1-java",
        "android.test.mock.stubs.system",
        "android.test.base.stubs.system",
        "android.test.mock.stubs.system",
        "android.test.runner.stubs.system",
    ],

@@ -94,8 +122,8 @@ android_test {

    platform_apis: true,
    test_suites: [
        "device-tests",
        "automotive-tests",
        "device-tests",
    ],

    certificate: "platform",
+14 −26
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;

import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppOpsManager;
@@ -67,7 +68,6 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.StrictMode;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -75,7 +75,6 @@ import android.util.Log;
import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.SurfaceControl;
import android.window.ConfigurationChangeSetting;

import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.os.BackgroundThread;
@@ -96,11 +95,9 @@ import com.android.server.input.InputManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.window.flags.Flags;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -144,13 +141,15 @@ public class SystemServicesTestRule implements TestRule {
    private ActivityTaskManagerService mAtmService;
    private WindowManagerService mWmService;
    private InputManagerService mImService;
    private Runnable mOnBeforeServicesCreated;
    @Nullable
    private final Runnable mOnBeforeServicesCreated;

    /**
     * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
     */
    SurfaceControl.Transaction mTransaction;

    public SystemServicesTestRule(Runnable onBeforeServicesCreated) {
    public SystemServicesTestRule(@Nullable Runnable onBeforeServicesCreated) {
        mOnBeforeServicesCreated = onBeforeServicesCreated;
    }

@@ -398,15 +397,13 @@ public class SystemServicesTestRule implements TestRule {
    }

    private void setUpWindowManagerService() {
        TestWindowManagerPolicy wmPolicy = new TestWindowManagerPolicy();
        TestDisplayWindowSettingsProvider testDisplayWindowSettingsProvider =
                new TestDisplayWindowSettingsProvider();
        // Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
        DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
        mWmService = WindowManagerService.main(
                mContext, mImService, false, wmPolicy, mAtmService,
                testDisplayWindowSettingsProvider, StubTransaction::new,
                MockSurfaceControlBuilder::new, mAppCompat);
        // Use a spied Transaction class to prevent native code calls and verify interactions.
        mTransaction = spy(StubTransaction.class);

        mWmService = WindowManagerServiceTestSupport.setUpService(mContext, mImService,
                new TestWindowManagerPolicy(), mAtmService, new TestDisplayWindowSettingsProvider(),
                mTransaction, new MockSurfaceControlBuilder(), mAppCompat);

        spyOn(mWmService);
        spyOn(mWmService.mRoot);
        // Invoked during {@link ActivityStack} creation.
@@ -418,10 +415,6 @@ public class SystemServicesTestRule implements TestRule {
        spyOn(mWmService.mDisplayWindowSettings);
        spyOn(mWmService.mDisplayWindowSettingsProvider);

        // Setup factory classes to prevent calls to native code.
        mTransaction = spy(StubTransaction.class);
        // Return a spied Transaction class than can be used to verify calls.
        mWmService.mTransactionFactory = () -> mTransaction;
        mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner(
                null, null, mTransaction, mWmService.mPowerManagerInternal);

@@ -488,12 +481,12 @@ public class SystemServicesTestRule implements TestRule {
    }

    private static void tearDownLocalServices() {
        WindowManagerServiceTestSupport.tearDownService();

        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
        LocalServices.removeServiceForTest(PowerManagerInternal.class);
        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
        LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
        LocalServices.removeServiceForTest(WindowManagerInternal.class);
        LocalServices.removeServiceForTest(WindowManagerPolicy.class);
        LocalServices.removeServiceForTest(PackageManagerInternal.class);
        LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
        LocalServices.removeServiceForTest(PermissionPolicyInternal.class);
@@ -501,12 +494,7 @@ public class SystemServicesTestRule implements TestRule {
        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
        LocalServices.removeServiceForTest(UserManagerInternal.class);
        LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy.class);
        LocalServices.removeServiceForTest(GrammaticalInflectionManagerInternal.class);
        if (Flags.condenseConfigurationChangeForSimpleMode()) {
            LocalServices.removeServiceForTest(
                    ConfigurationChangeSetting.ConfigurationChangeSettingInternal.class);
        }
    }

    Description getDescription() {
+112 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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 com.android.server.wm

import android.content.Context
import android.os.StrictMode
import android.view.SurfaceControl
import android.window.ConfigurationChangeSetting
import com.android.server.DisplayThread
import com.android.server.LocalServices
import com.android.server.input.InputManagerService
import com.android.server.policy.WindowManagerPolicy
import com.android.window.flags.Flags

/**
 * Provides support for tests that require a [WindowManagerService].
 *
 * It provides functionalities for setting up and tearing down the service with proper dependencies,
 * which can be used across different test modules.
 */
object WindowManagerServiceTestSupport {

    /**
     * Sets up and initializes a [WindowManagerService] instance with the provided dependencies.
     *
     * This method constructs a [WindowManagerService] using the provided dependencies for testing.
     * It's marked as `internal` due to the package-private classes [DisplayWindowSettingsProvider]
     * and [AppCompatConfiguration]. The `@JvmName` annotation is used to bypass name mangling and
     * allow access from Java via `WindowManagerServiceTestSupport.setUpService`.
     *
     * **Important:** Before calling this method, ensure that any previous [WindowManagerService]
     * instance and its related services are properly torn down. In your test's setup, it is
     * recommended to call [tearDownService] before calling [setUpService] to handle cases where a
     * previous test might have crashed and left services in an inconsistent state. This is crucial
     * for test reliability.
     *
     * Example usage in a test's `setUp()` method:
     * ```
     * @Before
     * fun setUp() {
     *     WindowManagerServiceTestSupport.tearDownService() // Clean up before setup.
     *     mWindowManagerService = WindowManagerServiceTestSupport.setUpService(...)
     *     // ... rest of your setup logic ...
     * }
     * ```
     *
     * @param context the [Context]] for the service.
     * @param im the [InputManagerService] to use.
     * @param policy the [WindowManagerPolicy] to use.
     * @param atm the [ActivityTaskManagerService] to use.
     * @param displayWindowSettingsProvider the [DisplayWindowSettingsProvider] to use.
     * @param surfaceControlTransaction the [SurfaceControl.Transaction] instance to use.
     * @param surfaceControlBuilder the [SurfaceControl.Builder] instance to use.
     * @param appCompat the [AppCompatConfiguration] to use.
     * @return the created [WindowManagerService] instance.
     */
    @JvmStatic
    @JvmName("setUpService")
    internal fun setUpService(
        context: Context,
        im: InputManagerService,
        policy: WindowManagerPolicy,
        atm: ActivityTaskManagerService,
        displayWindowSettingsProvider: DisplayWindowSettingsProvider,
        surfaceControlTransaction: SurfaceControl.Transaction,
        surfaceControlBuilder: SurfaceControl.Builder,
        appCompat: AppCompatConfiguration,
    ): WindowManagerService {
        // Suppress StrictMode violation (DisplayWindowSettings) to avoid log flood.
        DisplayThread.getHandler().post { StrictMode.allowThreadDiskWritesMask() }

        return WindowManagerService.main(
            context,
            im,
            false, /* showBootMsgs */
            policy,
            atm,
            displayWindowSettingsProvider,
            { surfaceControlTransaction },
            { surfaceControlBuilder },
            appCompat,
        )
    }

    /** Tears down the [WindowManagerService] and removes related local services. */
    @JvmStatic
    fun tearDownService() {
        LocalServices.removeServiceForTest(WindowManagerPolicy::class.java)
        LocalServices.removeServiceForTest(WindowManagerInternal::class.java)
        LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy::class.java)

        if (Flags.condenseConfigurationChangeForSimpleMode()) {
            LocalServices.removeServiceForTest(
                ConfigurationChangeSetting.ConfigurationChangeSettingInternal::class.java,
            )
        }
    }
}