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

Commit e13d4767 authored by Li Li's avatar Li Li Committed by Android (Google) Code Review
Browse files

Merge "Defer sending display events to cached apps"

parents 63e1365f 78fecfcf
Loading
Loading
Loading
Loading
+125 −4
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
import static android.hardware.display.DisplayManager.EventsMask;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
@@ -43,7 +45,10 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
import android.companion.virtual.IVirtualDevice;
@@ -234,6 +239,9 @@ public final class DisplayManagerService extends SystemService {
    private final DisplayModeDirector mDisplayModeDirector;
    private WindowManagerInternal mWindowManagerInternal;
    private InputManagerInternal mInputManagerInternal;
    private ActivityManagerInternal mActivityManagerInternal;
    private ActivityManager mActivityManager;
    private UidImportanceListener mUidImportanceListener = new UidImportanceListener();
    private IMediaProjectionManager mProjectionService;
    private DeviceStateManagerInternal mDeviceStateManager;
    @GuardedBy("mSyncRoot")
@@ -415,6 +423,11 @@ public final class DisplayManagerService extends SystemService {
    // May be used outside of the lock but only on the handler thread.
    private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();

    // Pending callback records indexed by calling process uid.
    // Must be used outside of the lock mSyncRoot and should be selflocked.
    @GuardedBy("mPendingCallbackSelfLocked")
    public final SparseArray<PendingCallback> mPendingCallbackSelfLocked = new SparseArray<>();

    // Temporary viewports, used when sending new viewport information to the
    // input system.  May be used outside of the lock but only on the handler thread.
    private final ArrayList<DisplayViewport> mTempViewports = new ArrayList<>();
@@ -622,11 +635,18 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    // TODO: Use dependencies or a boot phase
    /**
     * The 2nd stage initialization
     * TODO: Use dependencies or a boot phase
     */
    @SuppressLint("AndroidFrameworkRequiresPermission")
    public void windowManagerAndInputReady() {
        synchronized (mSyncRoot) {
            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
            mActivityManager = mContext.getSystemService(ActivityManager.class);
            mActivityManager.addOnUidImportanceListener(mUidImportanceListener, IMPORTANCE_CACHED);

            mDeviceStateManager = LocalServices.getService(DeviceStateManagerInternal.class);
            mContext.getSystemService(DeviceStateManager.class).registerCallback(
@@ -828,6 +848,36 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
        @Override
        public void onUidImportance(int uid, int importance) {
            synchronized (mPendingCallbackSelfLocked) {
                if (importance >= IMPORTANCE_GONE) {
                    // Clean up as the app is already gone
                    Slog.d(TAG, "Drop pending events for gone uid " + uid);
                    mPendingCallbackSelfLocked.delete(uid);
                    return;
                } else if (importance >= IMPORTANCE_CACHED) {
                    // Nothing to do as the app is still in cached mode
                    return;
                }

                // Do we care about this uid?
                PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
                if (pendingCallback == null) {
                    return;
                }

                // Send the pending events out when a certain uid becomes non-cached
                if (DEBUG) {
                    Slog.d(TAG, "Uid " + uid + " becomes " + importance);
                }
                pendingCallback.sendPendingDisplayEvent();
                mPendingCallbackSelfLocked.delete(uid);
            }
        }
    }

    private class SettingsObserver extends ContentObserver {
        SettingsObserver() {
            super(mHandler);
@@ -2609,6 +2659,16 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    // Check if the target app is in cached mode
    private boolean isUidCached(int uid) {
        if (mActivityManagerInternal == null) {
            return false;
        }
        int procState = mActivityManagerInternal.getUidProcessState(uid);
        int importance = ActivityManager.RunningAppProcessInfo.procStateToImportance(procState);
        return importance >= IMPORTANCE_CACHED;
    }

    // Runs on Handler thread.
    // Delivers display event notifications to callbacks.
    private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids,
@@ -2632,7 +2692,22 @@ public final class DisplayManagerService extends SystemService {

        // After releasing the lock, send the notifications out.
        for (int i = 0; i < mTempCallbacks.size(); i++) {
            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
            CallbackRecord callbackRecord = mTempCallbacks.get(i);
            final int uid = callbackRecord.mUid;
            if (isUidCached(uid)) {
                // For cached apps, save the pending event until it becomes non-cached
                synchronized (mPendingCallbackSelfLocked) {
                    PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
                    if (pendingCallback == null) {
                        mPendingCallbackSelfLocked.put(uid,
                                new PendingCallback(callbackRecord, displayId, event));
                    } else {
                        pendingCallback.addDisplayEvent(displayId, event);
                    }
                }
            } else {
                callbackRecord.notifyDisplayEventAsync(displayId, event);
            }
        }
        mTempCallbacks.clear();
    }
@@ -3076,17 +3151,22 @@ public final class DisplayManagerService extends SystemService {
            onCallbackDied(this);
        }

        public void notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
        /**
         * @return {@code false} if RemoteException happens; otherwise {@code true} for success.
         */
        public boolean notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
            if (!shouldSendEvent(event)) {
                return;
                return true;
            }

            try {
                mCallback.onDisplayEvent(displayId, event);
                return true;
            } catch (RemoteException ex) {
                Slog.w(TAG, "Failed to notify process "
                        + mPid + " that displays changed, assuming it died.", ex);
                binderDied();
                return false;
            }
        }

@@ -3111,6 +3191,47 @@ public final class DisplayManagerService extends SystemService {
        }
    }

    private static final class PendingCallback {
        private final CallbackRecord mCallbackRecord;
        private final ArrayList<Pair<Integer, Integer>> mDisplayEvents;

        PendingCallback(CallbackRecord cr, int displayId, int event) {
            mCallbackRecord = cr;
            mDisplayEvents = new ArrayList<>();
            mDisplayEvents.add(new Pair<>(displayId, event));
        }

        public void addDisplayEvent(int displayId, int event) {
            // Ignore redundant events. Further optimization is possible by merging adjacent events.
            Pair<Integer, Integer> last = mDisplayEvents.get(mDisplayEvents.size() - 1);
            if (last.first == displayId && last.second == event) {
                Slog.d(TAG,
                        "Ignore redundant display event " + displayId + "/" + event + " to "
                                + mCallbackRecord.mUid + "/" + mCallbackRecord.mPid);
                return;
            }

            mDisplayEvents.add(new Pair<>(displayId, event));
        }

        public void sendPendingDisplayEvent() {
            for (int i = 0; i < mDisplayEvents.size(); i++) {
                Pair<Integer, Integer> displayEvent = mDisplayEvents.get(i);
                if (DEBUG) {
                    Slog.d(TAG, "Send pending display event #" + i + " " + displayEvent.first + "/"
                            + displayEvent.second + " to " + mCallbackRecord.mUid + "/"
                            + mCallbackRecord.mPid);
                }
                if (!mCallbackRecord.notifyDisplayEventAsync(displayEvent.first,
                        displayEvent.second)) {
                    Slog.d(TAG, "Drop pending events for dead process " + mCallbackRecord.mPid);
                    break;
                }
            }
            mDisplayEvents.clear();
        }
    }

    @VisibleForTesting
    final class BinderService extends IDisplayManager.Stub {
        /**