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

Commit 6c6aaf77 authored by mayankkk's avatar mayankkk Committed by Mayank Dandwani
Browse files

Log BroadcastProcessed atom.

BUG: 387576580
Test: atest BroadcastQueueImplTest && atest BroadcastProcessEventRecortTest & atest BroadcastRecordTest & statsd_testdrive 1028
Flag: com.android.server.am.log_broadcast_processed_event
Change-Id: I6210ed7606154dead4ec009c5c15b7d567d47d23
parent e3d73be4
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1961,7 +1961,9 @@ class BroadcastController {

    private void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
        mService.mProcessList.sendPackageBroadcastLocked(cmd, packages, userId);
    }private List<ResolveInfo> collectReceiverComponents(
    }

    private List<ResolveInfo> collectReceiverComponents(
            Intent intent, String resolvedType, int callingUid, int callingPid,
            int[] users, int[] broadcastAllowList) {
        // TODO: come back and remove this assumption to triage all broadcasts
+142 −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.am;

import static com.android.internal.util.FrameworkStatsLog.BROADCAST_PROCESSED;

import android.annotation.NonNull;
import android.annotation.Nullable;

import com.android.internal.util.FrameworkStatsLog;

final class BroadcastProcessedEventRecord {

    /**
     * Minimum threshold for logging the broadcast processed event.
     */
    private static final int MIN_THRESHOLD_FOR_LOGGING_TIME_MILLIS = 10;

    @Nullable
    private String mIntentAction;

    private int mSenderUid;

    private int mReceiverUid;

    private int mNumberOfReceivers;

    @NonNull
    private String mReceiverProcessName;

    private long mTotalBroadcastFinishTimeMillis;

    private long mMaxReceiverFinishTimeMillis = Long.MIN_VALUE;

    @NonNull
    private int[] mBroadcastTypes;

    @NonNull
    public BroadcastProcessedEventRecord setBroadcastTypes(@NonNull int[] broadcastTypes) {
        this.mBroadcastTypes = broadcastTypes;
        return this;
    }

    @NonNull
    public BroadcastProcessedEventRecord setReceiverProcessName(
            @NonNull String receiverProcessName) {
        mReceiverProcessName = receiverProcessName;
        return this;
    }

    @NonNull
    public BroadcastProcessedEventRecord setIntentAction(@Nullable String intentAction) {
        mIntentAction = intentAction;
        return this;
    }

    @NonNull
    public BroadcastProcessedEventRecord setSenderUid(int uid) {
        mSenderUid = uid;
        return this;
    }

    @NonNull
    public BroadcastProcessedEventRecord setReceiverUid(int uid) {
        mReceiverUid = uid;
        return this;
    }

    public void addReceiverFinishTime(long timeMillis) {
        mTotalBroadcastFinishTimeMillis += timeMillis;
        mMaxReceiverFinishTimeMillis = Math.max(mMaxReceiverFinishTimeMillis, timeMillis);
        mNumberOfReceivers++;
    }

    @Nullable
    String getIntentActionForTest() {
        return mIntentAction;
    }

    int getSenderUidForTest() {
        return mSenderUid;
    }

    int getReceiverUidForTest() {
        return mReceiverUid;
    }

    int getNumberOfReceiversForTest() {
        return mNumberOfReceivers;
    }

    @NonNull
    String getReceiverProcessNameForTest() {
        return mReceiverProcessName;
    }

    long getTotalBroadcastFinishTimeMillisForTest() {
        return mTotalBroadcastFinishTimeMillis;
    }

    long getMaxReceiverFinishTimeMillisForTest() {
        return mMaxReceiverFinishTimeMillis;
    }

    @NonNull
    int[] getBroadcastTypesForTest() {
        return mBroadcastTypes;
    }

    public void logToStatsD() {
        // We do not care about the processes where total time to process the
        // broadcast is less than 10ms/ are quick to process the broadcast.
        if (mTotalBroadcastFinishTimeMillis <= MIN_THRESHOLD_FOR_LOGGING_TIME_MILLIS) {
            return;
        }

        FrameworkStatsLog.write(
                BROADCAST_PROCESSED,
                mIntentAction,
                mSenderUid,
                mReceiverUid,
                mNumberOfReceivers,
                mReceiverProcessName,
                mTotalBroadcastFinishTimeMillis,
                mMaxReceiverFinishTimeMillis,
                mBroadcastTypes);
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -2189,6 +2189,11 @@ class BroadcastQueueImpl extends BroadcastQueue {
            logBroadcastDeliveryEventReported(queue, app, r, index, receiver);
        }

        if (!r.isAssumedDelivered(index) && r.wasDelivered(index)) {
            r.updateBroadcastProcessedEventRecord(receiver,
                    r.terminalTime[index] - r.scheduledTime[index]);
        }

        final boolean recordFinished = (r.terminalCount == r.receivers.size());
        if (recordFinished) {
            notifyFinishBroadcast(r);
@@ -2254,6 +2259,7 @@ class BroadcastQueueImpl extends BroadcastQueue {
        mHistory.onBroadcastFinishedLocked(r);

        logBootCompletedBroadcastCompletionLatencyIfPossible(r);
        r.logBroadcastProcessedEventRecord();

        if (r.intent.getComponent() == null && r.intent.getPackage() == null
                && (r.intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
+61 −0
Original line number Diff line number Diff line
@@ -167,6 +167,12 @@ final class BroadcastRecord extends Binder {
    @Nullable
    private ArrayMap<BroadcastRecord, Boolean> mMatchingRecordsCache;

    // Stores the {@link BroadcastProcessedEventRecord} for each process associated with this
    // record.
    @NonNull
    private ArrayMap<String, BroadcastProcessedEventRecord> mBroadcastProcessedRecords =
            new ArrayMap<>();

    private @Nullable String mCachedToString;
    private @Nullable String mCachedToShortString;

@@ -654,6 +660,17 @@ final class BroadcastRecord extends Binder {
        }
    }

    boolean wasDelivered(int index) {
        final int deliveryState = getDeliveryState(index);
        switch (deliveryState) {
            case DELIVERY_DELIVERED:
            case DELIVERY_TIMEOUT:
                return true;
            default:
                return false;
        }
    }

    void copyEnqueueTimeFrom(@NonNull BroadcastRecord replacedBroadcast) {
        originalEnqueueClockTime = enqueueClockTime;
        enqueueTime = replacedBroadcast.enqueueTime;
@@ -1327,4 +1344,48 @@ final class BroadcastRecord extends Binder {
        proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction());
        proto.end(token);
    }

    /**
     * Uses the {@link BroadcastProcessedEventRecord} pojo to store the logging information related
     * to {@param receiver} object.
     */
    public void updateBroadcastProcessedEventRecord(@NonNull Object receiver, long timeMillis) {
        if (!Flags.logBroadcastProcessedEvent()) {
            return;
        }

        final String receiverProcessName = getReceiverProcessName(receiver);
        BroadcastProcessedEventRecord broadcastProcessedEventRecord =
                mBroadcastProcessedRecords.get(receiverProcessName);
        if (broadcastProcessedEventRecord == null) {
            broadcastProcessedEventRecord = new BroadcastProcessedEventRecord()
                    .setBroadcastTypes(calculateTypesForLogging())
                    .setIntentAction(intent.getAction())
                    .setReceiverProcessName(receiverProcessName)
                    .setReceiverUid(getReceiverUid(receiver))
                    .setSenderUid(callingUid);

            mBroadcastProcessedRecords.put(receiverProcessName, broadcastProcessedEventRecord);
        }

        broadcastProcessedEventRecord.addReceiverFinishTime(timeMillis);
    }

    public void logBroadcastProcessedEventRecord() {
        if (!Flags.logBroadcastProcessedEvent()) {
            return;
        }

        int size = mBroadcastProcessedRecords.size();
        for (int i = 0; i < size; i++) {
            mBroadcastProcessedRecords.valueAt(i).logToStatsD();
        }
        mBroadcastProcessedRecords.clear();
    }

    @VisibleForTesting
    @NonNull
    ArrayMap<String, BroadcastProcessedEventRecord> getBroadcastProcessedRecordsForTest() {
        return mBroadcastProcessedRecords;
    }
}
+12 −1
Original line number Diff line number Diff line
@@ -27,3 +27,14 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "log_broadcast_processed_event"
    namespace: "backstage_power"
    description: "Log the broadcast processed event to Statsd"
    bug: "387576580"
    is_fixed_read_only: true
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
Loading