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

Commit ca100c4d 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 am: ae7d1beb

parents 20d4a1df ae7d1beb
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerService;
import com.android.server.wm.WindowManagerService;


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



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

            removeAndDestroyGameSessionIfNecessaryLocked(taskId);
            removeAndDestroyGameSessionIfNecessaryLocked(taskId);
        }
        }
    }
    }
@@ -775,10 +786,20 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
            if (gameSessionRecord.getGameSession() != null && packageName.equals(
            if (gameSessionRecord.getGameSession() != null && packageName.equals(
                    gameSessionRecord.getComponentName().getPackageName())) {
                    gameSessionRecord.getComponentName().getPackageName())) {
                if (DEBUG) {
                if (DEBUG) {
                    Slog.d(TAG, "endGameSessionsForPackageLocked(): No more processes for "
                    Slog.i(TAG, "endGameSessionsForPackageLocked(): No more processes for "
                            + packageName + ", ending game session with taskId: "
                            + packageName + ", ending game session with taskId: "
                            + gameSessionRecord.getTaskId());
                            + 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(),
                mGameSessions.put(gameSessionRecord.getTaskId(),
                        gameSessionRecord.withGameSessionEndedOnProcessDeath());
                        gameSessionRecord.withGameSessionEndedOnProcessDeath());
                destroyGameSessionFromRecordLocked(gameSessionRecord);
                destroyGameSessionFromRecordLocked(gameSessionRecord);
@@ -867,24 +888,18 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan


    private void restartGame(int taskId) {
    private void restartGame(int taskId) {
        String packageName;
        String packageName;

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

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


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


        Intent launchIntent =
        mActivityTaskManagerInternal.restartTaskActivityProcessIfVisible(taskId, packageName);
                mContext.getPackageManager().getLaunchIntentForPackage(packageName);
        mContext.startActivity(launchIntent);
    }
    }
}
}
+11 −0
Original line number Original line 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
     * @return a task ID if a valid task ID is found. Otherwise, return INVALID_TASK_ID
     */
     */
    public abstract int getTaskToShowPermissionDialogOn(String pkgName, int uid);
    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 Original line Diff line number Diff line
@@ -6695,5 +6695,31 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                        .getTaskToShowPermissionDialogOn(pkgName, uid);
                        .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 Original line 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.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;


import android.Manifest;
import android.Manifest;
import android.annotation.Nullable;
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.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
import com.android.server.wm.WindowManagerService;
@@ -125,6 +128,7 @@ public final class GameServiceProviderInstanceImplTest {




    private static final Bitmap TEST_BITMAP;
    private static final Bitmap TEST_BITMAP;

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


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


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


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


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


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


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


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


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

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

        Intent getLastStartedIntent() {
            return mLastStartedIntent;
        }
    }
    }
}
}