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

Commit 706c5691 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Don't use mockito for UiAutomation

Bug: 417503571
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh -s
Flag: EXEMPT host test change only
Change-Id: I29ea00ad7c80e789fe34c11eacbbb853b90ffe14
parent 8392a9a2
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -117,6 +117,8 @@ import java.util.concurrent.TimeoutException;
 * interacting with another application whose behavior depends on that setting.
 * </p>
 */
@android.ravenwood.annotation.RavenwoodKeepPartialClass
@android.ravenwood.annotation.RavenwoodRedirectionClass("UiAutomation_ravenwood")
public final class UiAutomation {

    private static final String LOG_TAG = UiAutomation.class.getSimpleName();
@@ -284,6 +286,7 @@ public final class UiAutomation {
     *
     * @hide
     */
    @android.ravenwood.annotation.RavenwoodKeep
    public UiAutomation(Context context, IUiAutomationConnection connection) {
        this(getDisplayId(context), context.getMainLooper(), connection);
    }
@@ -307,6 +310,7 @@ public final class UiAutomation {
        Log.w(LOG_TAG, "Created with deprecatead constructor, assumes DEFAULT_DISPLAY");
    }

    @android.ravenwood.annotation.RavenwoodKeep
    private UiAutomation(int displayId, Looper looper, IUiAutomationConnection connection) {
        Preconditions.checkArgument(looper != null, "Looper cannot be null!");
        Preconditions.checkArgument(connection != null, "Connection cannot be null!");
@@ -586,6 +590,7 @@ public final class UiAutomation {
     * @see #adoptShellPermissionIdentity(String...)
     * @see #dropShellPermissionIdentity()
     */
    @android.ravenwood.annotation.RavenwoodRedirect
    public void adoptShellPermissionIdentity() {
        try {
            // Calling out without a lock held.
@@ -611,6 +616,7 @@ public final class UiAutomation {
     * @see #adoptShellPermissionIdentity()
     * @see #dropShellPermissionIdentity()
     */
    @android.ravenwood.annotation.RavenwoodRedirect
    public void adoptShellPermissionIdentity(@Nullable String... permissions) {
        try {
            // Calling out without a lock held.
@@ -627,6 +633,7 @@ public final class UiAutomation {
     *
     * @see #adoptShellPermissionIdentity()
     */
    @android.ravenwood.annotation.RavenwoodRedirect
    public void dropShellPermissionIdentity() {
        try {
            // Calling out without a lock held.
@@ -645,6 +652,7 @@ public final class UiAutomation {
     */
    @TestApi
    @NonNull
    @android.ravenwood.annotation.RavenwoodRedirect
    public Set<String> getAdoptedShellPermissions() {
        try {
            final List<String> permissions = mUiAutomationConnection.getAdoptedShellPermissions();
@@ -1884,6 +1892,7 @@ public final class UiAutomation {
     * <p><b>NOTE: </b> must be a static method because it's called from a constructor to call
     * another one.
     */
    @android.ravenwood.annotation.RavenwoodReplace(reason = "Always use DEFAULT_DISPLAY")
    private static int getDisplayId(Context context) {
        Preconditions.checkArgument(context != null, "Context cannot be null!");

@@ -1917,6 +1926,10 @@ public final class UiAutomation {
        return userDisplayId;
    }

    private static int getDisplayId$ravenwood(Context context) {
        return DEFAULT_DISPLAY;
    }

    private static int getMainDisplayIdAssignedToUser(Context context, UserManager userManager) {
        if (!userManager.isUserVisible()) {
            // Should also not happen, but ...
+50 −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 android.app;

import android.annotation.Nullable;

import java.util.Collections;
import java.util.Set;

public class UiAutomation_ravenwood {
    private static Set<String> sAdoptedPermissions = Collections.emptySet();

    public static void reset() {
        sAdoptedPermissions = Collections.emptySet();
    }

    public static void adoptShellPermissionIdentity(UiAutomation self) {
        sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
    }

    public static void adoptShellPermissionIdentity(UiAutomation self,
            @Nullable String... permissions) {
        if (permissions == null) {
            sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
        } else {
            sAdoptedPermissions = Set.of(permissions);
        }
    }

    public static void dropShellPermissionIdentity(UiAutomation self) {
        sAdoptedPermissions = Collections.emptySet();
    }

    public static Set<String> getAdoptedShellPermissions(UiAutomation self) {
        return sAdoptedPermissions;
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -186,7 +186,6 @@ java_library {
        "ravenwood-helper-framework-runtime",
        "ravenwood-helper-libcore-runtime",
        "hoststubgen-helper-runtime.ravenwood",
        "mockito-ravenwood-prebuilt",
    ],
    visibility: [":__subpackages__"],
    jarjar_rules: ":ravenwood-services-jarjar-rules",
+6 −43
Original line number Diff line number Diff line
@@ -30,17 +30,16 @@ import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;

import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread_ravenwood;
import android.app.AppCompatCallbacks;
import android.app.IUiAutomationConnection;
import android.app.Instrumentation;
import android.app.ResourcesManager;
import android.app.UiAutomation;
import android.app.UiAutomation_ravenwood;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
@@ -83,14 +82,12 @@ import org.junit.runner.Description;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -196,7 +193,6 @@ public class RavenwoodRuntimeEnvironmentController {

    /** Map from path -> resources. */
    private static final HashMap<File, Resources> sCachedResources = new HashMap<>();
    private static Set<String> sAdoptedPermissions = Collections.emptySet();

    private static final Object sInitializationLock = new Object();

@@ -414,6 +410,8 @@ public class RavenwoodRuntimeEnvironmentController {
        var systemServerContext =
                new RavenwoodContext(ANDROID_PACKAGE_NAME, main, systemResourcesLoader);

        var uiAutomation = new UiAutomation(sInstContext, new IUiAutomationConnection.Default());

        var instArgs = Bundle.EMPTY;
        RavenwoodUtils.runOnMainThreadSync(() -> {
            var instClassName = withDefault(sInstrumentationClass, DEFAULT_INSTRUMENTATION_CLASS);
@@ -430,7 +428,7 @@ public class RavenwoodRuntimeEnvironmentController {
                }
            }

            initInstrumentation();
            sInstrumentation.basicInit(sInstContext, sTargetContext, uiAutomation);
            sInstrumentation.onCreate(instArgs);
        });
        InstrumentationRegistry.registerInstance(sInstrumentation, instArgs);
@@ -471,19 +469,12 @@ public class RavenwoodRuntimeEnvironmentController {
        }
    }

    private static void initInstrumentation() {
        // We need to recreate the mocks for each test class, because sometimes tests
        // will call Mockito.framework().clearInlineMocks() after execution.
        sInstrumentation.basicInit(sInstContext, sTargetContext, createMockUiAutomation());
    }

    /**
     * Partially reset and initialize before each test class invocation
     */
    public static void initForRunner() {
        initInstrumentation();

        // Reset some global state
        UiAutomation_ravenwood.reset();
        Process_ravenwood.reset();
        DeviceConfig_host.reset();
        Binder.restoreCallingIdentity(sCallingIdentity);
@@ -724,34 +715,6 @@ public class RavenwoodRuntimeEnvironmentController {
                () -> Class.forName("org.mockito.Matchers"));
    }

    static <T> T makeDefaultThrowMock(Class<T> clazz) {
        return mock(clazz, inv -> { throw new RavenwoodUnsupportedApiException(); });
    }

    // TODO: use the real UiAutomation class instead of a mock
    private static UiAutomation createMockUiAutomation() {
        sAdoptedPermissions = Collections.emptySet();
        var mock = makeDefaultThrowMock(UiAutomation.class);
        doAnswer(inv -> {
            sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
            return null;
        }).when(mock).adoptShellPermissionIdentity();
        doAnswer(inv -> {
            if (inv.getArgument(0) == null) {
                sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
            } else {
                sAdoptedPermissions = (Set) Set.of(inv.getArguments());
            }
            return null;
        }).when(mock).adoptShellPermissionIdentity(any());
        doAnswer(inv -> {
            sAdoptedPermissions = Collections.emptySet();
            return null;
        }).when(mock).dropShellPermissionIdentity();
        doAnswer(inv -> sAdoptedPermissions).when(mock).getAdoptedShellPermissions();
        return mock;
    }

    private static void dumpCommandLineArgs() {
        Log.i(TAG, "JVM arguments:");

+1 −0
Original line number Diff line number Diff line
@@ -303,6 +303,7 @@ android.app.ComponentOptions
android.app.Instrumentation
android.app.LocaleConfig
android.app.ResourcesManager
android.app.UiAutomation
android.app.WindowConfiguration

android.metrics.LogMaker