Loading services/core/java/com/android/server/wm/ActivityStarter.java +6 −2 Original line number Diff line number Diff line Loading @@ -1319,7 +1319,9 @@ class ActivityStarter { // don't abort if the callingUid has a visible window or is a persistent system process final int callingUidProcState = mService.mActiveUids.getUidState(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(callingUid) || mService.mActiveUids.hasNonAppVisibleWindow(callingUid); final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow || callingUidProcState == ActivityManager.PROCESS_STATE_TOP || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; Loading Loading @@ -1348,7 +1350,9 @@ class ActivityStarter { : mService.mActiveUids.getUidState(realCallingUid); final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid) ? callingUidHasAnyVisibleWindow : mService.hasActiveVisibleWindow(realCallingUid); : mService.mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity( realCallingUid) || mService.mActiveUids.hasNonAppVisibleWindow(realCallingUid); final boolean isRealCallingUidForeground = (callingUid == realCallingUid) ? isCallingUidForeground : realCallingUidHasAnyVisibleWindow Loading services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +5 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_DISALLOW; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -75,7 +75,8 @@ class BackgroundLaunchProcessController { boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, int appSwitchState, boolean isCheckingForFgsStart, boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges, boolean hasActivityInVisibleTask, boolean inPinnedWindow, boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime, long lastActivityLaunchTime, long lastActivityFinishTime) { // If app switching is not allowed, we ignore all the start activity grace period Loading Loading @@ -115,8 +116,8 @@ class BackgroundLaunchProcessController { return true; } // Allow if the caller has an activity in any foreground task. if (hasActivityInVisibleTask && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) { if ((isCheckingForFgsStart || !inPinnedWindow) && hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process has activity in foreground task"); Loading services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java +11 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import java.util.function.Predicate; * host process with foreground (resumed) activity. */ class VisibleActivityProcessTracker { private static final Predicate<WindowProcessController> ALWAYS_TRUE = wpc -> true; @GuardedBy("mProcMap") private final ArrayMap<WindowProcessController, CpuTimeRecord> mProcMap = new ArrayMap<>(); final Executor mBgExecutor = BackgroundThread.getExecutor(); Loading Loading @@ -80,14 +81,22 @@ class VisibleActivityProcessTracker { * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true. */ boolean hasVisibleActivity(int uid) { return match(uid, null /* predicate */); return match(uid, ALWAYS_TRUE); } /** * Returns {@code true} if the uid has a process that contains an activity with * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true. */ boolean hasVisibleNotPinnedActivity(int uid) { return match(uid, wpc -> !wpc.inPinnedWindowingMode()); } private boolean match(int uid, Predicate<WindowProcessController> predicate) { synchronized (mProcMap) { for (int i = mProcMap.size() - 1; i >= 0; i--) { final WindowProcessController wpc = mProcMap.keyAt(i); if (wpc.mUid == uid && (predicate == null || predicate.test(wpc))) { if (wpc.mUid == uid && predicate.test(wpc)) { return true; } } Loading services/core/java/com/android/server/wm/WindowProcessController.java +1 −0 Original line number Diff line number Diff line Loading @@ -525,6 +525,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio boolean isCheckingForFgsStart) { return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName, appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(), inPinnedWindowingMode(), mInstrumentingWithBackgroundActivityStartPrivileges, mAtm.getLastStopAppSwitchesTime(), mLastActivityLaunchTime, mLastActivityFinishTime); Loading services/tests/wmtests/src/com/android/server/wm/VisibleActivityProcessTrackerTests.java 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.server.wm; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import android.app.IApplicationThread; import android.app.WindowConfiguration; import android.content.pm.ApplicationInfo; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for the {@link com.android.server.wm.VisibleActivityProcessTracker} class. * * Build/Install/Run: * atest WmTests:VisibleActivityProcessTrackerTests */ @SmallTest @Presubmit @RunWith(WindowTestRunner.class) public class VisibleActivityProcessTrackerTests extends WindowTestsBase { private VisibleActivityProcessTracker mTracker; @Before public void setup() { mTracker = mAtm.mVisibleActivityProcessTracker; } @Test public void testVisibleActivity() { WindowProcessController wpc = createWindowProcessController(); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isFalse(); mTracker.onAnyActivityVisible(wpc); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isTrue(); mTracker.onAllActivitiesInvisible(wpc); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isFalse(); } @Test public void testVisibleNotPinnedActivity() { WindowProcessController wpc = createWindowProcessController(); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); mTracker.onAnyActivityVisible(wpc); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isTrue(); mTracker.onAllActivitiesInvisible(wpc); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); } @Test public void testVisiblePinnedActivity() { WindowProcessController wpc = createWindowProcessController(); wpc.getConfiguration().windowConfiguration.setWindowingMode( WindowConfiguration.WINDOWING_MODE_PINNED); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); mTracker.onAnyActivityVisible(wpc); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isTrue(); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); mTracker.onAllActivitiesInvisible(wpc); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); } WindowProcessController createWindowProcessController() { WindowProcessListener mMockListener = mock(WindowProcessListener.class); ApplicationInfo info = mock(ApplicationInfo.class); info.packageName = "test.package.name"; WindowProcessController mWpc = new WindowProcessController( mAtm, info, null, 0, -1, null, mMockListener); mWpc.setThread(mock(IApplicationThread.class)); return mWpc; } } Loading
services/core/java/com/android/server/wm/ActivityStarter.java +6 −2 Original line number Diff line number Diff line Loading @@ -1319,7 +1319,9 @@ class ActivityStarter { // don't abort if the callingUid has a visible window or is a persistent system process final int callingUidProcState = mService.mActiveUids.getUidState(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity(callingUid) || mService.mActiveUids.hasNonAppVisibleWindow(callingUid); final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow || callingUidProcState == ActivityManager.PROCESS_STATE_TOP || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; Loading Loading @@ -1348,7 +1350,9 @@ class ActivityStarter { : mService.mActiveUids.getUidState(realCallingUid); final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid) ? callingUidHasAnyVisibleWindow : mService.hasActiveVisibleWindow(realCallingUid); : mService.mVisibleActivityProcessTracker.hasVisibleNotPinnedActivity( realCallingUid) || mService.mActiveUids.hasNonAppVisibleWindow(realCallingUid); final boolean isRealCallingUidForeground = (callingUid == realCallingUid) ? isCallingUidForeground : realCallingUidHasAnyVisibleWindow Loading
services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +5 −4 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_DISALLOW; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -75,7 +75,8 @@ class BackgroundLaunchProcessController { boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, int appSwitchState, boolean isCheckingForFgsStart, boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges, boolean hasActivityInVisibleTask, boolean inPinnedWindow, boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime, long lastActivityLaunchTime, long lastActivityFinishTime) { // If app switching is not allowed, we ignore all the start activity grace period Loading Loading @@ -115,8 +116,8 @@ class BackgroundLaunchProcessController { return true; } // Allow if the caller has an activity in any foreground task. if (hasActivityInVisibleTask && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) { if ((isCheckingForFgsStart || !inPinnedWindow) && hasActivityInVisibleTask && appSwitchState != APP_SWITCH_DISALLOW) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start allowed: process has activity in foreground task"); Loading
services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java +11 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import java.util.function.Predicate; * host process with foreground (resumed) activity. */ class VisibleActivityProcessTracker { private static final Predicate<WindowProcessController> ALWAYS_TRUE = wpc -> true; @GuardedBy("mProcMap") private final ArrayMap<WindowProcessController, CpuTimeRecord> mProcMap = new ArrayMap<>(); final Executor mBgExecutor = BackgroundThread.getExecutor(); Loading Loading @@ -80,14 +81,22 @@ class VisibleActivityProcessTracker { * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true. */ boolean hasVisibleActivity(int uid) { return match(uid, null /* predicate */); return match(uid, ALWAYS_TRUE); } /** * Returns {@code true} if the uid has a process that contains an activity with * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true. */ boolean hasVisibleNotPinnedActivity(int uid) { return match(uid, wpc -> !wpc.inPinnedWindowingMode()); } private boolean match(int uid, Predicate<WindowProcessController> predicate) { synchronized (mProcMap) { for (int i = mProcMap.size() - 1; i >= 0; i--) { final WindowProcessController wpc = mProcMap.keyAt(i); if (wpc.mUid == uid && (predicate == null || predicate.test(wpc))) { if (wpc.mUid == uid && predicate.test(wpc)) { return true; } } Loading
services/core/java/com/android/server/wm/WindowProcessController.java +1 −0 Original line number Diff line number Diff line Loading @@ -525,6 +525,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio boolean isCheckingForFgsStart) { return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName, appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(), inPinnedWindowingMode(), mInstrumentingWithBackgroundActivityStartPrivileges, mAtm.getLastStopAppSwitchesTime(), mLastActivityLaunchTime, mLastActivityFinishTime); Loading
services/tests/wmtests/src/com/android/server/wm/VisibleActivityProcessTrackerTests.java 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.server.wm; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import android.app.IApplicationThread; import android.app.WindowConfiguration; import android.content.pm.ApplicationInfo; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for the {@link com.android.server.wm.VisibleActivityProcessTracker} class. * * Build/Install/Run: * atest WmTests:VisibleActivityProcessTrackerTests */ @SmallTest @Presubmit @RunWith(WindowTestRunner.class) public class VisibleActivityProcessTrackerTests extends WindowTestsBase { private VisibleActivityProcessTracker mTracker; @Before public void setup() { mTracker = mAtm.mVisibleActivityProcessTracker; } @Test public void testVisibleActivity() { WindowProcessController wpc = createWindowProcessController(); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isFalse(); mTracker.onAnyActivityVisible(wpc); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isTrue(); mTracker.onAllActivitiesInvisible(wpc); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isFalse(); } @Test public void testVisibleNotPinnedActivity() { WindowProcessController wpc = createWindowProcessController(); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); mTracker.onAnyActivityVisible(wpc); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isTrue(); mTracker.onAllActivitiesInvisible(wpc); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); } @Test public void testVisiblePinnedActivity() { WindowProcessController wpc = createWindowProcessController(); wpc.getConfiguration().windowConfiguration.setWindowingMode( WindowConfiguration.WINDOWING_MODE_PINNED); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); mTracker.onAnyActivityVisible(wpc); assertThat(mTracker.hasVisibleActivity(wpc.mUid)).isTrue(); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); mTracker.onAllActivitiesInvisible(wpc); assertThat(mTracker.hasVisibleNotPinnedActivity(wpc.mUid)).isFalse(); } WindowProcessController createWindowProcessController() { WindowProcessListener mMockListener = mock(WindowProcessListener.class); ApplicationInfo info = mock(ApplicationInfo.class); info.packageName = "test.package.name"; WindowProcessController mWpc = new WindowProcessController( mAtm, info, null, 0, -1, null, mMockListener); mWpc.setThread(mock(IApplicationThread.class)); return mWpc; } }