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

Commit 4c12abc5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Ensure GameSession is not destroyed when restarting game." into tm-dev...

Merge "Ensure GameSession is not destroyed when restarting game." into tm-dev am: ae7d1beb am: ca100c4d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17956048



Change-Id: Ic819e0726038c99a40984f93219ac7348462082f
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents a05a6fd6 ca100c4d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerService;

@@ -62,6 +63,7 @@ final class GameServiceProviderInstanceFactoryImpl implements GameServiceProvide
                activityTaskManager,
                (WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
                LocalServices.getService(WindowManagerInternal.class),
                LocalServices.getService(ActivityTaskManagerInternal.class),
                new GameServiceConnector(mContext, configuration),
                new GameSessionServiceConnector(mContext, configuration),
                new ScreenshotHelper(mContext));
+29 −14
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.app.IProcessObserver;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -60,6 +59,7 @@ import com.android.internal.infra.ServiceConnector;
import com.android.internal.infra.ServiceConnector.ServiceLifecycleCallbacks;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
@@ -93,6 +93,9 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
                public void onBinderDied() {
                    mBackgroundExecutor.execute(() -> {
                        synchronized (mLock) {
                            if (DEBUG) {
                                Slog.d(TAG, "GameSessionService died. Destroying all sessions");
                            }
                            destroyAndClearAllGameSessionsLocked();
                        }
                    });
@@ -223,6 +226,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
    private final IActivityTaskManager mActivityTaskManager;
    private final WindowManagerService mWindowManagerService;
    private final WindowManagerInternal mWindowManagerInternal;
    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
    private final ScreenshotHelper mScreenshotHelper;
    private final ServiceConnector<IGameService> mGameServiceConnector;
    private final ServiceConnector<IGameSessionService> mGameSessionServiceConnector;
@@ -249,6 +253,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
            @NonNull IActivityTaskManager activityTaskManager,
            @NonNull WindowManagerService windowManagerService,
            @NonNull WindowManagerInternal windowManagerInternal,
            @NonNull ActivityTaskManagerInternal activityTaskManagerInternal,
            @NonNull ServiceConnector<IGameService> gameServiceConnector,
            @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector,
            @NonNull ScreenshotHelper screenshotHelper) {
@@ -261,6 +266,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
        mActivityTaskManager = activityTaskManager;
        mWindowManagerService = windowManagerService;
        mWindowManagerInternal = windowManagerInternal;
        mActivityTaskManagerInternal = activityTaskManagerInternal;
        mGameServiceConnector = gameServiceConnector;
        mGameSessionServiceConnector = gameSessionServiceConnector;
        mScreenshotHelper = screenshotHelper;
@@ -443,6 +449,11 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
                return;
            }


            if (DEBUG) {
                Slog.i(TAG, "onTaskRemoved() id: " + taskId);
            }

            removeAndDestroyGameSessionIfNecessaryLocked(taskId);
        }
    }
@@ -775,10 +786,20 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
            if (gameSessionRecord.getGameSession() != null && packageName.equals(
                    gameSessionRecord.getComponentName().getPackageName())) {
                if (DEBUG) {
                    Slog.d(TAG, "endGameSessionsForPackageLocked(): No more processes for "
                    Slog.i(TAG, "endGameSessionsForPackageLocked(): No more processes for "
                            + packageName + ", ending game session with taskId: "
                            + gameSessionRecord.getTaskId());
                }

                RunningTaskInfo runningTaskInfo =
                        mGameTaskInfoProvider.getRunningTaskInfo(gameSessionRecord.getTaskId());
                if (runningTaskInfo != null && (runningTaskInfo.isVisible)) {
                    if (DEBUG) {
                        Slog.i(TAG, "Found visible task. Ignoring end game session. taskId:"
                                + gameSessionRecord.getTaskId());
                    }
                    continue;
                }
                mGameSessions.put(gameSessionRecord.getTaskId(),
                        gameSessionRecord.withGameSessionEndedOnProcessDeath());
                destroyGameSessionFromRecordLocked(gameSessionRecord);
@@ -867,24 +888,18 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan

    private void restartGame(int taskId) {
        String packageName;

        synchronized (mLock) {
            boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
            if (!isTaskAssociatedWithGameSession) {
            GameSessionRecord gameSessionRecord = mGameSessions.get(taskId);
            if (gameSessionRecord == null) {
                return;
            }

            packageName = mGameSessions.get(taskId).getComponentName().getPackageName();
            packageName = gameSessionRecord.getComponentName().getPackageName();
        }

        try {
            mActivityManager.forceStopPackage(packageName, UserHandle.USER_CURRENT);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        if (packageName == null) {
            return;
        }

        Intent launchIntent =
                mContext.getPackageManager().getLaunchIntentForPackage(packageName);
        mContext.startActivity(launchIntent);
        mActivityTaskManagerInternal.restartTaskActivityProcessIfVisible(taskId, packageName);
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -693,4 +693,15 @@ public abstract class ActivityTaskManagerInternal {
     * @return a task ID if a valid task ID is found. Otherwise, return INVALID_TASK_ID
     */
    public abstract int getTaskToShowPermissionDialogOn(String pkgName, int uid);

    /**
     * Attempts to restart the process associated with the top most Activity associated with the
     * given {@code packageName} in the task associated with the given {@code taskId}.
     *
     * This will request the process of the activity to restart with its saved state (via
     * {@link android.app.Activity#onSaveInstanceState(Bundle)}) if possible. If the activity is in
     * background the process will be killed keeping its record.
     */
    public abstract void restartTaskActivityProcessIfVisible(
            int taskId, @NonNull String packageName);
}
+26 −0
Original line number Diff line number Diff line
@@ -6695,5 +6695,31 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                        .getTaskToShowPermissionDialogOn(pkgName, uid);
            }
        }

        @Override
        public void restartTaskActivityProcessIfVisible(int taskId, String packageName) {
            synchronized (ActivityTaskManagerService.this.mGlobalLock) {
                final Task task =
                        ActivityTaskManagerService.this.mRootWindowContainer
                                .anyTaskForId(taskId, MATCH_ATTACHED_TASK_ONLY);
                if (task == null) {
                    Slog.w(TAG, "Failed to restart Activity. No task found for id: " + taskId);
                    return;
                }

                final ActivityRecord activity = task.getActivity(activityRecord -> {
                    return packageName.equals(activityRecord.packageName)
                            && !activityRecord.finishing;
                });

                if (activity == null) {
                    Slog.w(TAG, "Failed to restart Activity. No Activity found for package name: "
                            + packageName + " in task: " + taskId);
                    return;
                }

                activity.restartProcessIfVisible();
            }
        }
    }
}
+14 −13
Original line number Diff line number Diff line
@@ -32,7 +32,9 @@ import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;

import android.Manifest;
import android.annotation.Nullable;
@@ -80,6 +82,7 @@ import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
@@ -125,6 +128,7 @@ public final class GameServiceProviderInstanceImplTest {


    private static final Bitmap TEST_BITMAP;

    static {
        Picture picture = new Picture();
        Canvas canvas = picture.beginRecording(200, 100);
@@ -146,6 +150,8 @@ public final class GameServiceProviderInstanceImplTest {
    @Mock
    private WindowManagerInternal mMockWindowManagerInternal;
    @Mock
    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
    @Mock
    private IActivityManager mMockActivityManager;
    @Mock
    private ScreenshotHelper mMockScreenshotHelper;
@@ -227,6 +233,7 @@ public final class GameServiceProviderInstanceImplTest {
                mMockActivityTaskManager,
                mMockWindowManagerService,
                mMockWindowManagerInternal,
                mActivityTaskManagerInternal,
                mFakeGameServiceConnector,
                mFakeGameSessionServiceConnector,
                mMockScreenshotHelper);
@@ -1134,8 +1141,9 @@ public final class GameServiceProviderInstanceImplTest {
        mFakeGameSessionService.getCapturedCreateInvocations().get(0)
                .mGameSessionController.restartGame(10);

        verify(mMockActivityManager).forceStopPackage(GAME_A_PACKAGE, UserHandle.USER_CURRENT);
        assertThat(mMockContext.getLastStartedIntent()).isEqualTo(launchIntent);
        verify(mActivityTaskManagerInternal).restartTaskActivityProcessIfVisible(
                10,
                GAME_A_PACKAGE);
    }

    @Test
@@ -1158,7 +1166,8 @@ public final class GameServiceProviderInstanceImplTest {

        verify(mMockActivityManager).registerProcessObserver(any());
        verifyNoMoreInteractions(mMockActivityManager);
        assertThat(mMockContext.getLastStartedIntent()).isNull();
        verify(mActivityTaskManagerInternal, never())
                .restartTaskActivityProcessIfVisible(anyInt(), anyString());
    }

    @Test
@@ -1172,6 +1181,8 @@ public final class GameServiceProviderInstanceImplTest {
        mockPermissionDenied(Manifest.permission.MANAGE_GAME_ACTIVITY);
        assertThrows(SecurityException.class,
                () -> gameSessionController.restartGame(10));
        verify(mActivityTaskManagerInternal, never())
                .restartTaskActivityProcessIfVisible(anyInt(), anyString());
    }

    private void startTask(int taskId, ComponentName componentName) {
@@ -1398,7 +1409,6 @@ public final class GameServiceProviderInstanceImplTest {
    }

    private final class MockContext extends ContextWrapper {
        private Intent mLastStartedIntent;
        // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
        private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();

@@ -1424,11 +1434,6 @@ public final class GameServiceProviderInstanceImplTest {
            return mMockPackageManager;
        }

        @Override
        public void startActivity(Intent intent) {
            mLastStartedIntent = intent;
        }

        @Override
        public void enforceCallingPermission(String permission, @Nullable String message) {
            final Integer granted = mMockedPermissions.get(permission);
@@ -1441,9 +1446,5 @@ public final class GameServiceProviderInstanceImplTest {
                throw new SecurityException("[Test] permission denied: " + permission);
            }
        }

        Intent getLastStartedIntent() {
            return mLastStartedIntent;
        }
    }
}