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

Commit 7c88e66c authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Support ANRs from windows that are not tracked by WM

Previously, ANRs for gesture monitors were reported using the pid of the
owner, and ANRs for all windows were reported using its input channel,
which was tracked by WM.

Now, there can be input windows that are not tracked by WM. We unify the
ANR reporting pipeline so that we first try to report an ANR using the
window's input channel. If the ANR reporting fails because the input
channel was not tracked by WM, we fall back on reporting ANR via the
pid of the window owner.

Bug: 210978621
Test: manual: Create a gesture monitor that sleeps while processing
input events, ensure there is an ANR.

Change-Id: If368ccf4a5cc676f64f3ed9de4f765b0abe63284
parent ec3e6791
Loading
Loading
Loading
Loading
+13 −55
Original line number Original line Diff line number Diff line
@@ -144,6 +144,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Locale;
import java.util.Map;
import java.util.Map;
import java.util.Objects;
import java.util.Objects;
import java.util.OptionalInt;


/*
/*
 * Wraps the C++ InputManager and provides its callbacks.
 * Wraps the C++ InputManager and provides its callbacks.
@@ -2915,48 +2916,17 @@ public class InputManagerService extends IInputManager.Stub


    // Native callback
    // Native callback
    @SuppressWarnings("unused")
    @SuppressWarnings("unused")
    private void notifyWindowUnresponsive(IBinder token, String reason) {
    private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
        int gestureMonitorPid = -1;
            String reason) {
        synchronized (mInputMonitors) {
        mWindowManagerCallbacks.notifyWindowUnresponsive(token,
            final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
                isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
            if (gestureMonitor != null) {
                gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
            }
        }
        if (gestureMonitorPid != -1) {
            mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(gestureMonitorPid, reason);
            return;
        }
        mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason);
    }

    // Native callback
    @SuppressWarnings("unused")
    private void notifyMonitorUnresponsive(int pid, String reason) {
        mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(pid, reason);
    }
    }


    // Native callback
    // Native callback
    @SuppressWarnings("unused")
    @SuppressWarnings("unused")
    private void notifyWindowResponsive(IBinder token) {
    private void notifyWindowResponsive(IBinder token, int pid, boolean isPidValid) {
        int gestureMonitorPid = -1;
        mWindowManagerCallbacks.notifyWindowResponsive(token,
        synchronized (mInputMonitors) {
                isPidValid ? OptionalInt.of(pid) : OptionalInt.empty());
            final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
            if (gestureMonitor != null) {
                gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
            }
        }
        if (gestureMonitorPid != -1) {
            mWindowManagerCallbacks.notifyGestureMonitorResponsive(gestureMonitorPid);
            return;
        }
        mWindowManagerCallbacks.notifyWindowResponsive(token);
    }

    // Native callback
    @SuppressWarnings("unused")
    private void notifyMonitorResponsive(int pid) {
        mWindowManagerCallbacks.notifyGestureMonitorResponsive(pid);
    }
    }


    // Native callback.
    // Native callback.
@@ -3328,35 +3298,23 @@ public class InputManagerService extends IInputManager.Stub
         */
         */
        void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle);
        void notifyNoFocusedWindowAnr(InputApplicationHandle applicationHandle);


        /**
         * Notify the window manager about a gesture monitor that is unresponsive.
         *
         * @param pid the pid of the gesture monitor process
         * @param reason the reason why this connection is unresponsive
         */
        void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason);

        /**
        /**
         * Notify the window manager about a window that is unresponsive.
         * Notify the window manager about a window that is unresponsive.
         *
         *
         * @param token the token that can be used to look up the window
         * @param token the token that can be used to look up the window
         * @param pid the pid of the window owner, if known
         * @param reason the reason why this connection is unresponsive
         * @param reason the reason why this connection is unresponsive
         */
         */
        void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull String reason);
        void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,

                @NonNull String reason);
        /**
         * Notify the window manager about a gesture monitor that has become responsive.
         *
         * @param pid the pid of the gesture monitor process
         */
        void notifyGestureMonitorResponsive(int pid);


        /**
        /**
         * Notify the window manager about a window that has become responsive.
         * Notify the window manager about a window that has become responsive.
         *
         *
         * @param token the token that can be used to look up the window
         * @param token the token that can be used to look up the window
         * @param pid the pid of the window owner, if known
         */
         */
        void notifyWindowResponsive(@NonNull IBinder token);
        void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid);


        /**
        /**
         * This callback is invoked when an event first arrives to InputDispatcher and before it is
         * This callback is invoked when an event first arrives to InputDispatcher and before it is
+76 −26
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.server.wm.ActivityRecord.INVALID_PID;
import static com.android.server.wm.ActivityRecord.INVALID_PID;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;


import android.annotation.NonNull;
import android.os.Build;
import android.os.Build;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Process;
import android.os.Process;
@@ -35,6 +36,7 @@ import com.android.server.criticalevents.CriticalEventLog;


import java.io.File;
import java.io.File;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.OptionalInt;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;


@@ -75,7 +77,33 @@ class AnrController {
        activity.inputDispatchingTimedOut(reason, INVALID_PID);
        activity.inputDispatchingTimedOut(reason, INVALID_PID);
    }
    }


    void notifyWindowUnresponsive(IBinder inputToken, String reason) {

    /**
     * Notify a window was unresponsive.
     *
     * @param token - the input token of the window
     * @param pid - the pid of the window, if known
     * @param reason - the reason for the window being unresponsive
     */
    void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
            @NonNull String reason) {
        if (notifyWindowUnresponsive(token, reason)) {
            return;
        }
        if (!pid.isPresent()) {
            Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was unresponsive.");
            return;
        }
        notifyWindowUnresponsive(pid.getAsInt(), reason);
    }

    /**
     * Notify a window identified by its input token was unresponsive.
     *
     * @return true if the window was identified by the given input token and the request was
     *         handled, false otherwise.
     */
    private boolean notifyWindowUnresponsive(@NonNull IBinder inputToken, String reason) {
        preDumpIfLockTooSlow();
        preDumpIfLockTooSlow();
        final int pid;
        final int pid;
        final boolean aboveSystem;
        final boolean aboveSystem;
@@ -83,10 +111,8 @@ class AnrController {
        synchronized (mService.mGlobalLock) {
        synchronized (mService.mGlobalLock) {
            InputTarget target = mService.getInputTargetFromToken(inputToken);
            InputTarget target = mService.getInputTargetFromToken(inputToken);
            if (target == null) {
            if (target == null) {
                Slog.e(TAG_WM, "Unknown token, dropping notifyConnectionUnresponsive request");
                return false;
                return;
            }
            }

            WindowState windowState = target.getWindowState();
            WindowState windowState = target.getWindowState();
            pid = target.getPid();
            pid = target.getPid();
            // Blame the activity if the input token belongs to the window. If the target is
            // Blame the activity if the input token belongs to the window. If the target is
@@ -102,34 +128,63 @@ class AnrController {
        } else {
        } else {
            mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, reason);
            mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, reason);
        }
        }
        return true;
    }

    /**
     * Notify a window owned by the provided pid was unresponsive.
     */
    private void notifyWindowUnresponsive(int pid, String reason) {
        Slog.i(TAG_WM, "ANR in input window owned by pid=" + pid + ". Reason: " + reason);
        dumpAnrStateLocked(null /* activity */, null /* windowState */, reason);

        // We cannot determine the z-order of the window, so place the anr dialog as high
        // as possible.
        mService.mAmInternal.inputDispatchingTimedOut(pid, true /*aboveSystem*/, reason);
    }

    /**
     * Notify a window was responsive after previously being unresponsive.
     *
     * @param token - the input token of the window
     * @param pid - the pid of the window, if known
     */
    void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid) {
        if (notifyWindowResponsive(token)) {
            return;
        }
        if (!pid.isPresent()) {
            Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was responsive.");
            return;
        }
        notifyWindowResponsive(pid.getAsInt());
    }
    }


    void notifyWindowResponsive(IBinder inputToken) {
    /**
     * Notify a window identified by its input token was responsive after previously being
     * unresponsive.
     *
     * @return true if the window was identified by the given input token and the request was
     *         handled, false otherwise.
     */
    private boolean notifyWindowResponsive(@NonNull IBinder inputToken) {
        final int pid;
        final int pid;
        synchronized (mService.mGlobalLock) {
        synchronized (mService.mGlobalLock) {
            InputTarget target = mService.getInputTargetFromToken(inputToken);
            InputTarget target = mService.getInputTargetFromToken(inputToken);
            if (target == null) {
            if (target == null) {
                Slog.e(TAG_WM, "Unknown token, dropping notifyWindowConnectionResponsive request");
                return false;
                return;
            }
            }
            pid = target.getPid();
            pid = target.getPid();
        }
        }
        mService.mAmInternal.inputDispatchingResumed(pid);
        mService.mAmInternal.inputDispatchingResumed(pid);
        return true;
    }
    }


    void notifyGestureMonitorUnresponsive(int gestureMonitorPid, String reason) {
    /**
        preDumpIfLockTooSlow();
     * Notify a window owned by the provided pid was responsive after previously being unresponsive.
        synchronized (mService.mGlobalLock) {
     */
            Slog.i(TAG_WM, "ANR in gesture monitor owned by pid:" + gestureMonitorPid
    private void notifyWindowResponsive(int pid) {
                    + ".  Reason: " + reason);
        mService.mAmInternal.inputDispatchingResumed(pid);
            dumpAnrStateLocked(null /* activity */, null /* windowState */, reason);
        }
        mService.mAmInternal.inputDispatchingTimedOut(gestureMonitorPid, /* aboveSystem */ true,
                reason);
    }

    void notifyGestureMonitorResponsive(int gestureMonitorPid) {
        mService.mAmInternal.inputDispatchingResumed(gestureMonitorPid);
    }
    }


    /**
    /**
@@ -228,12 +283,7 @@ class AnrController {
        mService.mAtmService.saveANRState(reason);
        mService.mAtmService.saveANRState(reason);
    }
    }


    private boolean isWindowAboveSystem(WindowState windowState) {
    private boolean isWindowAboveSystem(@NonNull WindowState windowState) {
        if (windowState == null) {
            // If the window state is not available we cannot easily determine its z order. Try to
            // place the anr dialog as high as possible.
            return true;
        }
        int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw(
        int systemAlertLayer = mService.mPolicy.getWindowLayerFromTypeLw(
                TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow);
                TYPE_APPLICATION_OVERLAY, windowState.mOwnerCanAddInternalSystemWindow);
        return windowState.mBaseLayer > systemAlertLayer;
        return windowState.mBaseLayer > systemAlertLayer;
+6 −14
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.input.InputManagerService;
import com.android.server.input.InputManagerService;


import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.OptionalInt;


final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM;
    private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM;
@@ -98,23 +99,14 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
    }
    }


    @Override
    @Override
    public void notifyGestureMonitorUnresponsive(int pid, @NonNull String reason) {
    public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
        mService.mAnrController.notifyGestureMonitorUnresponsive(pid, reason);
            @NonNull String reason) {
        mService.mAnrController.notifyWindowUnresponsive(token, pid, reason);
    }
    }


    @Override
    @Override
    public void notifyWindowUnresponsive(@NonNull IBinder token, String reason) {
    public void notifyWindowResponsive(@NonNull IBinder token, @NonNull OptionalInt pid) {
        mService.mAnrController.notifyWindowUnresponsive(token, reason);
        mService.mAnrController.notifyWindowResponsive(token, pid);
    }

    @Override
    public void notifyGestureMonitorResponsive(int pid) {
        mService.mAnrController.notifyGestureMonitorResponsive(pid);
    }

    @Override
    public void notifyWindowResponsive(@NonNull IBinder token) {
        mService.mAnrController.notifyWindowResponsive(token);
    }
    }


    /** Notifies that the input device configuration has changed. */
    /** Notifies that the input device configuration has changed. */
+11 −46
Original line number Original line Diff line number Diff line
@@ -96,8 +96,6 @@ static struct {
    jmethodID notifyNoFocusedWindowAnr;
    jmethodID notifyNoFocusedWindowAnr;
    jmethodID notifyWindowUnresponsive;
    jmethodID notifyWindowUnresponsive;
    jmethodID notifyWindowResponsive;
    jmethodID notifyWindowResponsive;
    jmethodID notifyMonitorUnresponsive;
    jmethodID notifyMonitorResponsive;
    jmethodID notifyFocusChanged;
    jmethodID notifyFocusChanged;
    jmethodID notifySensorEvent;
    jmethodID notifySensorEvent;
    jmethodID notifySensorAccuracy;
    jmethodID notifySensorAccuracy;
@@ -308,10 +306,9 @@ public:
    void notifyConfigurationChanged(nsecs_t when) override;
    void notifyConfigurationChanged(nsecs_t when) override;
    // ANR-related callbacks -- start
    // ANR-related callbacks -- start
    void notifyNoFocusedWindowAnr(const std::shared_ptr<InputApplicationHandle>& handle) override;
    void notifyNoFocusedWindowAnr(const std::shared_ptr<InputApplicationHandle>& handle) override;
    void notifyWindowUnresponsive(const sp<IBinder>& token, const std::string& reason) override;
    void notifyWindowUnresponsive(const sp<IBinder>& token, std::optional<int32_t> pid,
    void notifyWindowResponsive(const sp<IBinder>& token) override;
                                  const std::string& reason) override;
    void notifyMonitorUnresponsive(int32_t pid, const std::string& reason) override;
    void notifyWindowResponsive(const sp<IBinder>& token, std::optional<int32_t> pid) override;
    void notifyMonitorResponsive(int32_t pid) override;
    // ANR-related callbacks -- end
    // ANR-related callbacks -- end
    void notifyInputChannelBroken(const sp<IBinder>& token) override;
    void notifyInputChannelBroken(const sp<IBinder>& token) override;
    void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
    void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
@@ -838,6 +835,7 @@ void NativeInputManager::notifyNoFocusedWindowAnr(
}
}


void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
                                                  std::optional<int32_t> pid,
                                                  const std::string& reason) {
                                                  const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyWindowUnresponsive");
    ALOGD("notifyWindowUnresponsive");
@@ -851,11 +849,12 @@ void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
    ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
    ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));


    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
                        reasonObj.get());
                        pid.value_or(0), pid.has_value(), reasonObj.get());
    checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
    checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
}
}


void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token) {
void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token,
                                                std::optional<int32_t> pid) {
#if DEBUG_INPUT_DISPATCHER_POLICY
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyWindowResponsive");
    ALOGD("notifyWindowResponsive");
#endif
#endif
@@ -866,39 +865,11 @@ void NativeInputManager::notifyWindowResponsive(const sp<IBinder>& token) {


    jobject tokenObj = javaObjectForIBinder(env, token);
    jobject tokenObj = javaObjectForIBinder(env, token);


    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowResponsive, tokenObj);
    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowResponsive, tokenObj,
                        pid.value_or(0), pid.has_value());
    checkAndClearExceptionFromCallback(env, "notifyWindowResponsive");
    checkAndClearExceptionFromCallback(env, "notifyWindowResponsive");
}
}


void NativeInputManager::notifyMonitorUnresponsive(int32_t pid, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyMonitorUnresponsive");
#endif
    ATRACE_CALL();

    JNIEnv* env = jniEnv();
    ScopedLocalFrame localFrame(env);

    ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));

    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyMonitorUnresponsive, pid,
                        reasonObj.get());
    checkAndClearExceptionFromCallback(env, "notifyMonitorUnresponsive");
}

void NativeInputManager::notifyMonitorResponsive(int32_t pid) {
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyMonitorResponsive");
#endif
    ATRACE_CALL();

    JNIEnv* env = jniEnv();
    ScopedLocalFrame localFrame(env);

    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyMonitorResponsive, pid);
    checkAndClearExceptionFromCallback(env, "notifyMonitorResponsive");
}

void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) {
void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) {
#if DEBUG_INPUT_DISPATCHER_POLICY
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyInputChannelBroken");
    ALOGD("notifyInputChannelBroken");
@@ -2506,16 +2477,10 @@ int register_android_server_InputManager(JNIEnv* env) {
                  "(Landroid/view/InputApplicationHandle;)V");
                  "(Landroid/view/InputApplicationHandle;)V");


    GET_METHOD_ID(gServiceClassInfo.notifyWindowUnresponsive, clazz, "notifyWindowUnresponsive",
    GET_METHOD_ID(gServiceClassInfo.notifyWindowUnresponsive, clazz, "notifyWindowUnresponsive",
                  "(Landroid/os/IBinder;Ljava/lang/String;)V");
                  "(Landroid/os/IBinder;IZLjava/lang/String;)V");

    GET_METHOD_ID(gServiceClassInfo.notifyMonitorUnresponsive, clazz, "notifyMonitorUnresponsive",
                  "(ILjava/lang/String;)V");


    GET_METHOD_ID(gServiceClassInfo.notifyWindowResponsive, clazz, "notifyWindowResponsive",
    GET_METHOD_ID(gServiceClassInfo.notifyWindowResponsive, clazz, "notifyWindowResponsive",
                  "(Landroid/os/IBinder;)V");
                  "(Landroid/os/IBinder;IZ)V");

    GET_METHOD_ID(gServiceClassInfo.notifyMonitorResponsive, clazz, "notifyMonitorResponsive",
                  "(I)V");


    GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
    GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
            "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
            "filterInputEvent", "(Landroid/view/InputEvent;I)Z");