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

Commit 4c285a7f authored by Danae Savvidi's avatar Danae Savvidi Committed by Android (Google) Code Review
Browse files

Merge changes from topic "display-event-atom-431149632" into main

* changes:
  Add atom logging for display events
  Change return value of notifyDisplayEventAsync function
parents 6bf4a7e3 bc4977a4
Loading
Loading
Loading
Loading
+64 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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.display;

import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.util.SparseIntArray;

import com.android.internal.util.FrameworkStatsLog;

public final class DisplayFrameworkStatsLogger {

    /** Logs DisplayEventCallbackOccurred push atom */
    public void logDisplayEvent(@DisplayManagerGlobal.DisplayEvent int event,
            SparseIntArray notifiedUids) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED,
                toProtoEventType(event),
                notifiedUids.copyKeys());
    }

    /**
     * Maps DisplayEvent to atom. Default case "unknown" is required when defining an atom.
     * Currently private display events {@link DisplayManager.PrivateEventType} are marked as
     * unknown.
     */
    private int toProtoEventType(@DisplayManagerGlobal.DisplayEvent int event) {
        return switch (event) {
            case DisplayManagerGlobal.EVENT_DISPLAY_ADDED ->
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_ADDED;
            case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED ->
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_REMOVED;
            case DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED ->
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_CHANGED;
            case DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED ->
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_REFRESH_RATE_CHANGED;
            case DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED ->
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_STATE_CHANGED;
            case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED ->
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_BRIGHTNESS_CHANGED;
            default -> FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_UNKNOWN;
        };
    }
}
+20 −6
Original line number Original line Diff line number Diff line
@@ -307,6 +307,8 @@ public final class DisplayManagerService extends SystemService {
    private ActivityManagerInternal mActivityManagerInternal;
    private ActivityManagerInternal mActivityManagerInternal;
    private final UidImportanceListener mUidImportanceListener = new UidImportanceListener();
    private final UidImportanceListener mUidImportanceListener = new UidImportanceListener();


    private final DisplayFrameworkStatsLogger mStatsLogger = new DisplayFrameworkStatsLogger();

    @Nullable
    @Nullable
    private IMediaProjectionManager mProjectionService;
    private IMediaProjectionManager mProjectionService;
    private DeviceStateManagerInternal mDeviceStateManager;
    private DeviceStateManagerInternal mDeviceStateManager;
@@ -3715,11 +3717,23 @@ public final class DisplayManagerService extends SystemService {
            }
            }
        }
        }


        // Map that maps a uid to the number of times it was notified
        SparseIntArray notifiedUids = new SparseIntArray();

        // After releasing the lock, send the notifications out.
        // After releasing the lock, send the notifications out.
        for (int i = 0; i < mTempCallbacks.size(); i++) {
        for (int i = 0; i < mTempCallbacks.size(); i++) {
            CallbackRecord callbackRecord = mTempCallbacks.get(i);
            CallbackRecord callbackRecord = mTempCallbacks.get(i);
            callbackRecord.notifyDisplayEventAsync(displayId, event);
            boolean notified = callbackRecord.notifyDisplayEventAsync(displayId, event);
            if (notified) {
                int uid = callbackRecord.mUid;
                notifiedUids.put(uid, notifiedUids.get(uid, 0) + 1);
            }
        }
        }

        if (mFlags.isDisplayEventsLoggingEnabled()) {
            mStatsLogger.logDisplayEvent(event, notifiedUids);
        }

        mTempCallbacks.clear();
        mTempCallbacks.clear();
    }
    }


@@ -4497,9 +4511,9 @@ public final class DisplayManagerService extends SystemService {
        }
        }


        /**
        /**
         * @return {@code false} if RemoteException happens; otherwise {@code true} for
         * @return {@code true} if the notification was processed (sent, queued).
         * success.  This returns true even if the event was deferred because the remote client is
         * Returns {@code false} if the notification was not sent e.g. because client is
         * cached or frozen.
         * not registered for this event.
         */
         */
        public boolean notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
        public boolean notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
            if (!shouldSendDisplayEvent(event)) {
            if (!shouldSendDisplayEvent(event)) {
@@ -4515,7 +4529,7 @@ public final class DisplayManagerService extends SystemService {
                                    + ",uid" + mUid);
                                    + ",uid" + mUid);
                }
                }
                // The client is not interested in this event, so do nothing.
                // The client is not interested in this event, so do nothing.
                return true;
                return false;
            }
            }


            synchronized (mCallback) {
            synchronized (mCallback) {
@@ -4535,7 +4549,7 @@ public final class DisplayManagerService extends SystemService {


            if (!shouldReceiveRefreshRateWithChangeUpdate(event)) {
            if (!shouldReceiveRefreshRateWithChangeUpdate(event)) {
                // The client is not visible to the user and is not a system service, so do nothing.
                // The client is not visible to the user and is not a system service, so do nothing.
                return true;
                return false;
            }
            }


            try {
            try {
+7 −0
Original line number Original line Diff line number Diff line
@@ -6,3 +6,10 @@ aconfig_declarations {
        "*.aconfig",
        "*.aconfig",
    ],
    ],
}
}

java_aconfig_library {
    name: "display_flags_lib_host",
    aconfig_declarations: "display_flags",
    host_supported: true,
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+118 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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.display;

import static org.mockito.Mockito.verify;

import android.hardware.display.DisplayManagerGlobal;
import android.util.SparseIntArray;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.internal.util.FrameworkStatsLog;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/**
 * Tests for {@link com.android.server.display.DisplayFrameworkStatsLogger}.
 *
 * <p>Build with: atest DisplayFrameworkStatsLoggerTest
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayFrameworkStatsLoggerTest {

    @InjectMocks private DisplayFrameworkStatsLogger mLogger;

    @Mock private FrameworkStatsLog mFrameworkStatsLogMock;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testLogDisplayEvent_displayAdded_writesToStatsLog() {
        final int event = DisplayManagerGlobal.EVENT_DISPLAY_ADDED;
        final SparseIntArray uidMap =
                new SparseIntArray() {
                    {
                        put(1001, 1);
                        put(1002, 3);
                    }
                };
        final int expectedProtoType =
                FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_ADDED;

        mLogger.logDisplayEvent(event, uidMap);

        verify(mFrameworkStatsLogMock)
                .write(
                        FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED,
                        expectedProtoType,
                        uidMap.copyKeys());
    }

    @Test
    public void testLogDisplayEvent_brightnessChanged_writesToStatsLog() {
        final int event = DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED;
        final SparseIntArray uidMap =
                new SparseIntArray() {
                    {
                        put(1005, 1);
                    }
                };
        final int expectedProtoType =
                FrameworkStatsLog
                    .DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_DISPLAY_BRIGHTNESS_CHANGED;

        mLogger.logDisplayEvent(event, uidMap);

        verify(mFrameworkStatsLogMock)
                .write(
                        FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED,
                        expectedProtoType,
                        uidMap.copyKeys());
    }

    @Test
    public void testLogDisplayEvent_unknownEvent_writesUnknownTypeToStatsLog() {
        final int event = -1;
        final SparseIntArray uidMap =
                new SparseIntArray() {
                    {
                        put(9999, 6);
                    }
                };
        final int expectedProtoType =
                FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED__EVENT_TYPE__TYPE_UNKNOWN;

        mLogger.logDisplayEvent(event, uidMap);

        verify(mFrameworkStatsLogMock)
                .write(
                        FrameworkStatsLog.DISPLAY_EVENT_CALLBACK_OCCURRED,
                        expectedProtoType,
                        uidMap.copyKeys());
    }
}