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

Commit d576dacb authored by Orhan Uysal's avatar Orhan Uysal Committed by Android (Google) Code Review
Browse files

Merge "Add a crash handler to run on Init" into main

parents a1273fc2 1f1db489
Loading
Loading
Loading
Loading
+65 −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.wm.shell.common

import android.app.ActivityManager
import android.app.ActivityOptions
import android.app.PendingIntent
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.content.Context
import android.content.Intent
import android.os.UserHandle
import android.view.Display.DEFAULT_DISPLAY
import android.window.WindowContainerTransaction
import com.android.window.flags.Flags

/** Creates home intent **/
class HomeIntentProvider(
    private val context: Context,
) {
    fun addLaunchHomePendingIntent(
        wct: WindowContainerTransaction, displayId: Int, userId: Int? = null
    ) {
        val userHandle =
            if (userId != null) UserHandle.of(userId) else UserHandle.of(ActivityManager.getCurrentUser())

        val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply {
            if (displayId != DEFAULT_DISPLAY) {
                addCategory(Intent.CATEGORY_SECONDARY_HOME)
            } else {
                addCategory(Intent.CATEGORY_HOME)
            }
        }
        val options = ActivityOptions.makeBasic().apply {
            launchWindowingMode = WINDOWING_MODE_FULLSCREEN
            pendingIntentBackgroundActivityStartMode =
                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
            if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
                launchDisplayId = displayId
            }
        }
        val pendingIntent = PendingIntent.getActivityAsUser(
            context,
            /* requestCode= */ 0,
            launchHomeIntent,
            PendingIntent.FLAG_IMMUTABLE,
            /* options= */ null,
            userHandle,
        )
        wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle())
    }
}
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
# WM shell sub-module crash handling owners
uysalorhan@google.com
 No newline at end of file
+75 −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.wm.shell.crashhandling

import android.app.WindowConfiguration
import android.content.Context
import android.view.Display.DEFAULT_DISPLAY
import android.window.DesktopExperienceFlags
import android.window.WindowContainerTransaction
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.HomeIntentProvider
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.sysui.ShellInit

/** [ShellCrashHandler] for shell to use when it's being initialized. Currently it only restores
 *  the home task to top.
 **/
class ShellCrashHandler(
    private val context: Context,
    private val shellTaskOrganizer: ShellTaskOrganizer,
    private val homeIntentProvider: HomeIntentProvider,
    shellInit: ShellInit,
) {
    init {
        shellInit.addInitCallback(::onInit, this)
    }

    private fun onInit() {
        handleCrashIfNeeded()
    }

    private fun handleCrashIfNeeded() {
        // For now only handle crashes when desktop mode is enabled on the device.
        if (DesktopModeStatus.canEnterDesktopMode(context) &&
            !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            var freeformTaskExists = false
            // If there are running tasks at init, WMShell has crashed but WMCore is still alive.
            for (task in shellTaskOrganizer.getRunningTasks()) {
                if (task.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) {
                    freeformTaskExists = true
                }

                if (freeformTaskExists) {
                    shellTaskOrganizer.applyTransaction(
                        addLaunchHomePendingIntent(WindowContainerTransaction(), DEFAULT_DISPLAY)
                    )
                    break
                }
            }
        }
    }

    private fun addLaunchHomePendingIntent(
        wct: WindowContainerTransaction, displayId: Int
    ): WindowContainerTransaction {
        // TODO: b/400462917 - Check that crashes are also handled correctly on HSUM devices. We
        // might need to pass the [userId] here to launch the correct home.
        homeIntentProvider.addLaunchHomePendingIntent(wct, displayId)
        return wct
    }
}
 No newline at end of file
+24 −3
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.HomeIntentProvider;
import com.android.wm.shell.common.LaunchAdjacentController;
import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController;
import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface;
@@ -80,6 +81,7 @@ import com.android.wm.shell.common.UserProfileContexts;
import com.android.wm.shell.common.split.SplitState;
import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler;
import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver;
import com.android.wm.shell.crashhandling.ShellCrashHandler;
import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
import com.android.wm.shell.dagger.pip.PipModule;
import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler;
@@ -779,7 +781,8 @@ public abstract class WMShellModule {
            UserProfileContexts userProfileContexts,
            DesktopModeCompatPolicy desktopModeCompatPolicy,
            DragToDisplayTransitionHandler dragToDisplayTransitionHandler,
            DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler) {
            DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler,
            HomeIntentProvider homeIntentProvider) {
        return new DesktopTasksController(
                context,
                shellInit,
@@ -820,7 +823,8 @@ public abstract class WMShellModule {
                userProfileContexts,
                desktopModeCompatPolicy,
                dragToDisplayTransitionHandler,
                moveToDisplayTransitionHandler);
                moveToDisplayTransitionHandler,
                homeIntentProvider);
    }

    @WMSingleton
@@ -1544,7 +1548,8 @@ public abstract class WMShellModule {
            Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional,
            Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler,
            Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler,
            Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler) {
            Optional<SystemModalsTransitionHandler> systemModalsTransitionHandler,
            ShellCrashHandler shellCrashHandler) {
        return new Object();
    }

@@ -1564,4 +1569,20 @@ public abstract class WMShellModule {
        return new UserProfileContexts(context, shellController, shellInit);
    }

    @WMSingleton
    @Provides
    static ShellCrashHandler provideShellCrashHandler(
            Context context,
            ShellTaskOrganizer shellTaskOrganizer,
            HomeIntentProvider homeIntentProvider,
            ShellInit shellInit) {
        return new ShellCrashHandler(context, shellTaskOrganizer, homeIntentProvider, shellInit);
    }

    @WMSingleton
    @Provides
    static HomeIntentProvider provideHomeIntentProvider(Context context) {
        return new HomeIntentProvider(context);
    }

}
+3 −28
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ import com.android.wm.shell.bubbles.BubbleController
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.ExternalInterfaceBinder
import com.android.wm.shell.common.HomeIntentProvider
import com.android.wm.shell.common.MultiInstanceHelper
import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent
import com.android.wm.shell.common.RemoteCallable
@@ -211,6 +212,7 @@ class DesktopTasksController(
    private val desktopModeCompatPolicy: DesktopModeCompatPolicy,
    private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler,
    private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler,
    private val homeIntentProvider: HomeIntentProvider,
) :
    RemoteCallable<DesktopTasksController>,
    Transitions.TransitionHandler,
@@ -1718,34 +1720,7 @@ class DesktopTasksController(
    }

    private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) {
        val userHandle = UserHandle.of(userId)
        val launchHomeIntent =
            Intent(Intent.ACTION_MAIN).apply {
                if (displayId != DEFAULT_DISPLAY) {
                    addCategory(Intent.CATEGORY_SECONDARY_HOME)
                } else {
                    addCategory(Intent.CATEGORY_HOME)
                }
            }
        val options =
            ActivityOptions.makeBasic().apply {
                launchWindowingMode = WINDOWING_MODE_FULLSCREEN
                pendingIntentBackgroundActivityStartMode =
                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
                if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
                    launchDisplayId = displayId
                }
            }
        val pendingIntent =
            PendingIntent.getActivityAsUser(
                context,
                /* requestCode= */ 0,
                launchHomeIntent,
                PendingIntent.FLAG_IMMUTABLE,
                /* options= */ null,
                userHandle,
            )
        wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle())
        homeIntentProvider.addLaunchHomePendingIntent(wct, displayId, userId)
    }

    private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) {
Loading