Loading services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); Loading services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java +29 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(); } }); Loading Loading @@ -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; Loading @@ -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) { Loading @@ -261,6 +266,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan mActivityTaskManager = activityTaskManager; mWindowManagerService = windowManagerService; mWindowManagerInternal = windowManagerInternal; mActivityTaskManagerInternal = activityTaskManagerInternal; mGameServiceConnector = gameServiceConnector; mGameSessionServiceConnector = gameSessionServiceConnector; mScreenshotHelper = screenshotHelper; Loading Loading @@ -443,6 +449,11 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan return; } if (DEBUG) { Slog.i(TAG, "onTaskRemoved() id: " + taskId); } removeAndDestroyGameSessionIfNecessaryLocked(taskId); } } Loading Loading @@ -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); Loading Loading @@ -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); } } services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +11 −0 Original line number Diff line number Diff line Loading @@ -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); } services/core/java/com/android/server/wm/ActivityTaskManagerService.java +26 −0 Original line number Diff line number Diff line Loading @@ -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(); } } } } services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java +14 −13 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -146,6 +150,8 @@ public final class GameServiceProviderInstanceImplTest { @Mock private WindowManagerInternal mMockWindowManagerInternal; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock private IActivityManager mMockActivityManager; @Mock private ScreenshotHelper mMockScreenshotHelper; Loading Loading @@ -227,6 +233,7 @@ public final class GameServiceProviderInstanceImplTest { mMockActivityTaskManager, mMockWindowManagerService, mMockWindowManagerInternal, mActivityTaskManagerInternal, mFakeGameServiceConnector, mFakeGameSessionServiceConnector, mMockScreenshotHelper); Loading Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading Loading @@ -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<>(); Loading @@ -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); Loading @@ -1441,9 +1446,5 @@ public final class GameServiceProviderInstanceImplTest { throw new SecurityException("[Test] permission denied: " + permission); } } Intent getLastStartedIntent() { return mLastStartedIntent; } } } Loading
services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); Loading
services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java +29 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(); } }); Loading Loading @@ -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; Loading @@ -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) { Loading @@ -261,6 +266,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan mActivityTaskManager = activityTaskManager; mWindowManagerService = windowManagerService; mWindowManagerInternal = windowManagerInternal; mActivityTaskManagerInternal = activityTaskManagerInternal; mGameServiceConnector = gameServiceConnector; mGameSessionServiceConnector = gameSessionServiceConnector; mScreenshotHelper = screenshotHelper; Loading Loading @@ -443,6 +449,11 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan return; } if (DEBUG) { Slog.i(TAG, "onTaskRemoved() id: " + taskId); } removeAndDestroyGameSessionIfNecessaryLocked(taskId); } } Loading Loading @@ -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); Loading Loading @@ -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); } }
services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +11 −0 Original line number Diff line number Diff line Loading @@ -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); }
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +26 −0 Original line number Diff line number Diff line Loading @@ -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(); } } } }
services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java +14 −13 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -146,6 +150,8 @@ public final class GameServiceProviderInstanceImplTest { @Mock private WindowManagerInternal mMockWindowManagerInternal; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock private IActivityManager mMockActivityManager; @Mock private ScreenshotHelper mMockScreenshotHelper; Loading Loading @@ -227,6 +233,7 @@ public final class GameServiceProviderInstanceImplTest { mMockActivityTaskManager, mMockWindowManagerService, mMockWindowManagerInternal, mActivityTaskManagerInternal, mFakeGameServiceConnector, mFakeGameSessionServiceConnector, mMockScreenshotHelper); Loading Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading Loading @@ -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<>(); Loading @@ -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); Loading @@ -1441,9 +1446,5 @@ public final class GameServiceProviderInstanceImplTest { throw new SecurityException("[Test] permission denied: " + permission); } } Intent getLastStartedIntent() { return mLastStartedIntent; } } }