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

Commit f6e3f127 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Provide window visibility of uid without WM lock

The problems:
- ActivityTaskManagerInternal#isUidForeground is called frequently
  from request of bind/start service. It is too heavy to acquire
  WM lock each time.
- The isUidForeground calls isAnyNonToastWindowVisibleForUid. It is
  inefficient to iterate entire window hierarchy. Especially the
  calling uid usually doesn't have a window.

This change:
- Replace isAnyNonToastWindowVisibleForUid with hasActiveVisibleWindow
  that queries VisibleActivityProcessTracker for activity, and
  MirrorActiveUids for non-app (exclude toast) window. The separation
  also makes it simpler to apply special rule to activity window for
  background activity launch restriction in the future.
- Both the container have their own lock so WM lock is not needed for
  ActivityTaskManagerService#hasActiveVisibleWindow.
- To reflect the latest state, if ActivityRecord#mVisibleRequested or
  mVisible is changed, the process and uid state also need be updated.
- Launch a dozen activities after booting. With the same total
  invocation count of isUidForegound, the total time becomes 20~30x
  faster. While the state update time is negligible because the
  structure is very simple and the frequency of change is not high.
- Remove a legacy workaround in WPC#computeProcessActivityState
  that checks whether the activity belongs to the process. Because
  it was fixed by ActivityRecord#detachFromProcess that ensures
  the two-way relation.

Bug: 171490517
Test: WindowStateTests#testHasActiveVisibleWindow
      ActivityStarterTests#testBackgroundActivityStarts*
      ActivityManagerFgsBgStartTest
      BackgroundActivityLaunchTest
Change-Id: Iadca2b79e8971c1a8633e2557f2e8a4184857650
parent e12c50e0
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -52,9 +52,8 @@ final class ActiveUids {

    void clear() {
        mActiveUids.clear();
        if (mPostChangesToAtm) {
            mService.mAtmInternal.onActiveUidsCleared();
        }
        // It is only called for a temporal container with mPostChangesToAtm == false or test case.
        // So there is no need to notify activity task manager.
    }

    UidRecord get(int uid) {
+21 −8
Original line number Diff line number Diff line
@@ -1557,10 +1557,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
        }

        // Application tokens start out hidden.
        setVisible(false);
        mVisibleRequested = false;

        ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
                ColorDisplayService.ColorDisplayServiceInternal.class);
        cds.attachColorTransformController(packageName, mUserId,
@@ -3507,7 +3503,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                }
                if (fromActivity.isVisible()) {
                    setVisible(true);
                    mVisibleRequested = true;
                    setVisibleRequested(true);
                    mVisibleSetFromTransferredStartingWindow = true;
                }
                setClientVisible(fromActivity.mClientVisible);
@@ -4123,10 +4119,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    void setVisible(boolean visible) {
        if (visible != mVisible) {
            mVisible = visible;
            if (app != null) {
                mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
            }
            scheduleAnimation();
        }
    }

    /**
     * This is the only place that writes {@link #mVisibleRequested} (except unit test). The caller
     * outside of this class should use {@link #setVisibility}.
     */
    private void setVisibleRequested(boolean visible) {
        if (visible == mVisibleRequested) {
            return;
        }
        mVisibleRequested = visible;
        if (app != null) {
            mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
        }
    }

    /**
     * Set visibility on this {@link ActivityRecord}
     *
@@ -4190,7 +4203,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        displayContent.mOpeningApps.remove(this);
        displayContent.mClosingApps.remove(this);
        waitingToShow = false;
        mVisibleRequested = visible;
        setVisibleRequested(visible);
        mLastDeferHidingClient = deferHidingClient;

        if (!visible) {
@@ -4332,7 +4345,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                    ANIMATION_TYPE_APP_TRANSITION));
        }
        setVisible(visible);
        mVisibleRequested = visible;
        setVisibleRequested(visible);
        if (!visible) {
            stopFreezingScreen(true, true);
        } else {
@@ -4520,7 +4533,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            detachChildren();
        }
        if (app != null) {
            app.computeProcessActivityState();
            mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
        }

        switch (state) {
+4 −5
Original line number Diff line number Diff line
@@ -1292,9 +1292,8 @@ class ActivityStarter {
        final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed();

        // don't abort if the callingUid has a visible window or is a persistent system process
        final int callingUidProcState = mService.getUidState(callingUid);
        final boolean callingUidHasAnyVisibleWindow =
                mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
        final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
        final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
        final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
                || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
                || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
@@ -1312,10 +1311,10 @@ class ActivityStarter {
        // take realCallingUid into consideration
        final int realCallingUidProcState = (callingUid == realCallingUid)
                ? callingUidProcState
                : mService.getUidState(realCallingUid);
                : mService.mActiveUids.getUidState(realCallingUid);
        final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
                ? callingUidHasAnyVisibleWindow
                : mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(realCallingUid);
                : mService.hasActiveVisibleWindow(realCallingUid);
        final boolean isRealCallingUidForeground = (callingUid == realCallingUid)
                ? isCallingUidForeground
                : realCallingUidHasAnyVisibleWindow
+0 −1
Original line number Diff line number Diff line
@@ -514,7 +514,6 @@ public abstract class ActivityTaskManagerInternal {

    public abstract void onUidActive(int uid, int procState);
    public abstract void onUidInactive(int uid);
    public abstract void onActiveUidsCleared();
    public abstract void onUidProcStateChanged(int uid, int procState);

    public abstract void onUidAddedToPendingTempAllowlist(int uid, String tag);
+10 −17
Original line number Diff line number Diff line
@@ -392,7 +392,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
    private UserManagerService mUserManager;
    private AppOpsManager mAppOpsManager;
    /** All active uids in the system. */
    private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
    final MirrorActiveUids mActiveUids = new MirrorActiveUids();
    private final SparseArray<String> mPendingTempAllowlist = new SparseArray<>();
    /** All processes currently running that might have a window organized by name. */
    final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
@@ -4958,6 +4958,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
            printedAnything = true;
            mTaskSupervisor.dump(pw, "  ");
            mTaskOrganizerController.dump(pw, "  ");
            mVisibleActivityProcessTracker.dump(pw, "  ");
            mActiveUids.dump(pw, "  ");
        }

        if (!printedAnything) {
@@ -5988,13 +5990,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
        return null;
    }

    int getUidState(int uid) {
        return mActiveUids.getUidState(uid);
    /** A uid is considered to be foreground if it has a visible non-toast window. */
    boolean hasActiveVisibleWindow(int uid) {
        if (mVisibleActivityProcessTracker.hasVisibleActivity(uid)) {
            return true;
        }

    boolean isUidForeground(int uid) {
        // A uid is considered to be foreground if it has a visible non-toast window.
        return mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
        return mActiveUids.hasNonAppVisibleWindow(uid);
    }

    boolean isDeviceOwner(int uid) {
@@ -7284,12 +7285,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
            mActiveUids.onUidInactive(uid);
        }

        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
        @Override
        public void onActiveUidsCleared() {
            mActiveUids.onActiveUidsCleared();
        }

        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
        @Override
        public void onUidProcStateChanged(int uid, int procState) {
@@ -7435,9 +7430,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {

        @Override
        public boolean isUidForeground(int uid) {
            synchronized (mGlobalLock) {
                return ActivityTaskManagerService.this.isUidForeground(uid);
            }
            return ActivityTaskManagerService.this.hasActiveVisibleWindow(uid);
        }

        @Override
Loading