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

Commit 27141f94 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Automerger Merge Worker
Browse files

Merge "Add some recent broadcast and notification events to the dumpsys." into...

Merge "Add some recent broadcast and notification events to the dumpsys." into tm-dev am: 2b49ffd6

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16987519

Change-Id: I7401a11dd5bb721ce3dff704072d834b497adbb6
parents 4f4bf6cf 2b49ffd6
Loading
Loading
Loading
Loading
+221 −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.usage;

import static android.app.ActivityManager.procStateToString;

import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_CANCELLED;
import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_POSTED;
import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_UPDATED;
import static com.android.server.usage.BroadcastResponseStatsTracker.TAG;
import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS;

import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessState;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
import android.util.TimeUtils;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.RingBuffer;
import com.android.server.usage.BroadcastResponseStatsTracker.NotificationEventType;

public class BroadcastResponseStatsLogger {

    private static final int MAX_LOG_SIZE =
            ActivityManager.isLowRamDeviceStatic() ? 20 : 50;

    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private final LogBuffer mBroadcastEventsBuffer = new LogBuffer(
            BroadcastEvent.class, MAX_LOG_SIZE);
    @GuardedBy("mLock")
    private final LogBuffer mNotificationEventsBuffer = new LogBuffer(
            NotificationEvent.class, MAX_LOG_SIZE);

    void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
            UserHandle targetUser, long idForResponseEvent,
            @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) {
        synchronized (mLock) {
            if (DEBUG_RESPONSE_STATS) {
                Slog.d(TAG, getBroadcastDispatchEventLog(sourceUid, targetPackage,
                        targetUser.getIdentifier(), idForResponseEvent, timeStampMs,
                        targetUidProcessState));
            }
            mBroadcastEventsBuffer.logBroadcastDispatchEvent(sourceUid, targetPackage,
                    targetUser, idForResponseEvent, timeStampMs, targetUidProcessState);
        }
    }

    void logNotificationEvent(@NotificationEventType int event,
            @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) {
        synchronized (mLock) {
            if (DEBUG_RESPONSE_STATS) {
                Slog.d(TAG, getNotificationEventLog(event, packageName, user.getIdentifier(),
                        timestampMs));
            }
            mNotificationEventsBuffer.logNotificationEvent(event, packageName, user, timestampMs);
        }
    }

    void dumpLogs(IndentingPrintWriter ipw) {
        synchronized (mLock) {
            ipw.println("Broadcast events (most recent first):");
            ipw.increaseIndent();
            mBroadcastEventsBuffer.reverseDump(ipw);
            ipw.decreaseIndent();

            ipw.println();
            ipw.println("Notification events (most recent first):");
            ipw.increaseIndent();
            mNotificationEventsBuffer.reverseDump(ipw);
            ipw.decreaseIndent();
        }
    }

    private static final class LogBuffer<T extends Data> extends RingBuffer<T> {

        LogBuffer(Class<T> classType, int capacity) {
            super(classType, capacity);
        }

        void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
                UserHandle targetUser, long idForResponseEvent,
                @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) {
            final Data data = getNextSlot();
            if (data == null) return;

            data.reset();
            final BroadcastEvent event = (BroadcastEvent) data;
            event.sourceUid = sourceUid;
            event.targetUserId = targetUser.getIdentifier();
            event.targetUidProcessState = targetUidProcessState;
            event.targetPackage = targetPackage;
            event.idForResponseEvent = idForResponseEvent;
            event.timestampMs = timeStampMs;
        }

        void logNotificationEvent(@NotificationEventType int type,
                @NonNull String packageName, UserHandle user,
                @ElapsedRealtimeLong long timestampMs) {
            final Data data = getNextSlot();
            if (data == null) return;

            data.reset();
            final NotificationEvent event = (NotificationEvent) data;
            event.type = type;
            event.packageName = packageName;
            event.userId = user.getIdentifier();
            event.timestampMs = timestampMs;
        }

        public void reverseDump(IndentingPrintWriter pw) {
            final Data[] allData = toArray();
            for (int i = allData.length - 1; i >= 0; --i) {
                if (allData[i] == null) {
                    continue;
                }
                pw.println(getContent(allData[i]));
            }
        }

        @NonNull
        public String getContent(Data data) {
            return data.toString();
        }
    }

    @NonNull
    private static String getBroadcastDispatchEventLog(int sourceUid, @NonNull String targetPackage,
            @UserIdInt int targetUserId, long idForResponseEvent,
            @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) {
        return TextUtils.formatSimple(
                "broadcast:%s; srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, state=%s",
                TimeUtils.formatDuration(timestampMs), sourceUid, targetPackage, targetUserId,
                idForResponseEvent, procStateToString(targetUidProcState));
    }

    @NonNull
    private static String getNotificationEventLog(@NotificationEventType int event,
            @NonNull String packageName, @UserIdInt int userId,
            @ElapsedRealtimeLong long timestampMs) {
        return TextUtils.formatSimple("notification:%s; event=<%s>, pkg=%s, usr=%d",
                TimeUtils.formatDuration(timestampMs), notificationEventToString(event),
                packageName, userId);
    }

    @NonNull
    private static String notificationEventToString(@NotificationEventType int event) {
        switch (event) {
            case NOTIFICATION_EVENT_TYPE_POSTED:
                return "posted";
            case NOTIFICATION_EVENT_TYPE_UPDATED:
                return "updated";
            case NOTIFICATION_EVENT_TYPE_CANCELLED:
                return "cancelled";
            default:
                return String.valueOf(event);
        }
    }

    public static final class BroadcastEvent implements Data {
        public int sourceUid;
        public int targetUserId;
        public int targetUidProcessState;
        public String targetPackage;
        public long idForResponseEvent;
        public long timestampMs;

        @Override
        public void reset() {
            targetPackage = null;
        }

        @Override
        public String toString() {
            return getBroadcastDispatchEventLog(sourceUid, targetPackage, targetUserId,
                    idForResponseEvent, timestampMs, targetUidProcessState);
        }
    }

    public static final class NotificationEvent implements Data {
        public int type;
        public String packageName;
        public int userId;
        public long timestampMs;

        @Override
        public void reset() {
            packageName = null;
        }

        @Override
        public String toString() {
            return getNotificationEventLog(type, packageName, userId, timestampMs);
        }
    }

    public interface Data {
        void reset();
    }
}
+23 −49
Original line number Diff line number Diff line
@@ -16,10 +16,6 @@

package com.android.server.usage;

import static android.app.ActivityManager.procStateToString;

import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS;

import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -29,11 +25,9 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager.ProcessState;
import android.app.usage.BroadcastResponseStats;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
@@ -44,19 +38,19 @@ import java.util.ArrayList;
import java.util.List;

class BroadcastResponseStatsTracker {
    private static final String TAG = "ResponseStatsTracker";
    static final String TAG = "ResponseStatsTracker";

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"NOTIFICATION_EVENT"}, value = {
            NOTIFICATION_EVENT_POSTED,
            NOTIFICATION_EVENT_UPDATED,
            NOTIFICATION_EVENT_CANCELLED
    @IntDef(prefix = {"NOTIFICATION_EVENT_TYPE_"}, value = {
            NOTIFICATION_EVENT_TYPE_POSTED,
            NOTIFICATION_EVENT_TYPE_UPDATED,
            NOTIFICATION_EVENT_TYPE_CANCELLED
    })
    public @interface NotificationEvent {}
    public @interface NotificationEventType {}

    private static final int NOTIFICATION_EVENT_POSTED = 0;
    private static final int NOTIFICATION_EVENT_UPDATED = 1;
    private static final int NOTIFICATION_EVENT_CANCELLED = 2;
    static final int NOTIFICATION_EVENT_TYPE_POSTED = 0;
    static final int NOTIFICATION_EVENT_TYPE_UPDATED = 1;
    static final int NOTIFICATION_EVENT_TYPE_CANCELLED = 2;

    private final Object mLock = new Object();

@@ -76,21 +70,19 @@ class BroadcastResponseStatsTracker {
            new SparseArray<>();

    private AppStandbyInternal mAppStandby;
    private BroadcastResponseStatsLogger mLogger;

    BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) {
        mAppStandby = appStandby;
        mLogger = new BroadcastResponseStatsLogger();
    }

    // TODO (206518114): Move all callbacks handling to a handler thread.
    void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
            UserHandle targetUser, long idForResponseEvent,
            @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) {
        if (DEBUG_RESPONSE_STATS) {
            Slog.d(TAG, TextUtils.formatSimple("reportBroadcastDispatchEvent; "
                            + "srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s, state=%s",
                    sourceUid, targetPackage, targetUser, idForResponseEvent,
                    TimeUtils.formatDuration(timestampMs), procStateToString(targetUidProcState)));
        }
        mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser,
                idForResponseEvent, timestampMs, targetUidProcState);
        if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) {
            // No need to track the broadcast response state while the target app is
            // in the foreground.
@@ -110,29 +102,23 @@ class BroadcastResponseStatsTracker {

    void reportNotificationPosted(@NonNull String packageName, UserHandle user,
            @ElapsedRealtimeLong long timestampMs) {
        reportNotificationEvent(NOTIFICATION_EVENT_POSTED, packageName, user, timestampMs);
        reportNotificationEvent(NOTIFICATION_EVENT_TYPE_POSTED, packageName, user, timestampMs);
    }

    void reportNotificationUpdated(@NonNull String packageName, UserHandle user,
            @ElapsedRealtimeLong long timestampMs) {
        reportNotificationEvent(NOTIFICATION_EVENT_UPDATED, packageName, user, timestampMs);
        reportNotificationEvent(NOTIFICATION_EVENT_TYPE_UPDATED, packageName, user, timestampMs);

    }

    void reportNotificationCancelled(@NonNull String packageName, UserHandle user,
            @ElapsedRealtimeLong long timestampMs) {
        reportNotificationEvent(NOTIFICATION_EVENT_CANCELLED, packageName, user, timestampMs);
        reportNotificationEvent(NOTIFICATION_EVENT_TYPE_CANCELLED, packageName, user, timestampMs);
    }

    private void reportNotificationEvent(@NotificationEvent int event,
    private void reportNotificationEvent(@NotificationEventType int event,
            @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) {
        if (DEBUG_RESPONSE_STATS) {
            Slog.d(TAG, TextUtils.formatSimple(
                    "reportNotificationEvent; event=<%s>, pkg=%s, usr=%d, ts=%s",
                    notificationEventToString(event), packageName, user.getIdentifier(),
                    TimeUtils.formatDuration(timestampMs)));
        }
        // TODO (206518114): Store last N events to dump for debugging purposes.
        mLogger.logNotificationEvent(event, packageName, user, timestampMs);
        synchronized (mLock) {
            final LongSparseArray<BroadcastEvent> broadcastEvents =
                    getBroadcastEventsLocked(packageName, user);
@@ -157,13 +143,13 @@ class BroadcastResponseStatsTracker {
                        continue;
                    }
                    switch (event) {
                        case NOTIFICATION_EVENT_POSTED:
                        case NOTIFICATION_EVENT_TYPE_POSTED:
                            responseStats.incrementNotificationsPostedCount(1);
                            break;
                        case NOTIFICATION_EVENT_UPDATED:
                        case NOTIFICATION_EVENT_TYPE_UPDATED:
                            responseStats.incrementNotificationsUpdatedCount(1);
                            break;
                        case NOTIFICATION_EVENT_CANCELLED:
                        case NOTIFICATION_EVENT_TYPE_CANCELLED:
                            responseStats.incrementNotificationsCancelledCount(1);
                            break;
                        default:
@@ -329,20 +315,6 @@ class BroadcastResponseStatsTracker {
        return userResponseStats.getOrCreateBroadcastResponseStats(broadcastEvent);
    }

    @NonNull
    private String notificationEventToString(@NotificationEvent int event) {
        switch (event) {
            case NOTIFICATION_EVENT_POSTED:
                return "posted";
            case NOTIFICATION_EVENT_UPDATED:
                return "updated";
            case NOTIFICATION_EVENT_CANCELLED:
                return "cancelled";
            default:
                return String.valueOf(event);
        }
    }

    void dump(@NonNull IndentingPrintWriter ipw) {
        ipw.println("Broadcast response stats:");
        ipw.increaseIndent();
@@ -351,6 +323,8 @@ class BroadcastResponseStatsTracker {
            dumpBroadcastEventsLocked(ipw);
            ipw.println();
            dumpResponseStatsLocked(ipw);
            ipw.println();
            mLogger.dumpLogs(ipw);
        }

        ipw.decreaseIndent();