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

Commit bc4977a4 authored by Danae Savvidi's avatar Danae Savvidi
Browse files

Add atom logging for display events

To log display event type and client UID.

Bug: 433483856
Bug: 431149632
Flag: com.android.server.display.feature.flags.enable_logging_for_display_events
Test: atest DisplayServiceTests
Test: atest DisplayFrameworkStatsLoggerTest

Change-Id: I4914e4e7b33c48753ba4401cdf20e32228913329
parent 5341b953
Loading
Loading
Loading
Loading
+64 −0
Original line number 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;
        };
    }
}
+15 −1
Original line number Diff line number Diff line
@@ -308,6 +308,8 @@ public final class DisplayManagerService extends SystemService {
    private ActivityManagerInternal mActivityManagerInternal;
    private final UidImportanceListener mUidImportanceListener = new UidImportanceListener();

    private final DisplayFrameworkStatsLogger mStatsLogger = new DisplayFrameworkStatsLogger();

    @Nullable
    private IMediaProjectionManager mProjectionService;
    private DeviceStateManagerInternal mDeviceStateManager;
@@ -3719,11 +3721,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.
        for (int i = 0; i < mTempCallbacks.size(); 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();
    }

+7 −0
Original line number Diff line number Diff line
@@ -6,3 +6,10 @@ aconfig_declarations {
        "*.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 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());
    }
}