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

Commit 1740af50 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

BroadcastQueue: more debugging information.

Offer to configure the size of the historical broadcasts retained
for debugging.  Migrate DeviceConfig constants into the "native boot"
namespace so they're available early during system boot when we
allocate structures that can't dynamically change.  Emit all current
constant values during dump.

Misc tests to improve code coverage.

Bug: 250666387
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Change-Id: I01257b4a7e3e21b3c16f34673746df77e9fd9288
parent 2d8ec53e
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -2440,8 +2440,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mEnableOffloadQueue = SystemProperties.getBoolean(
                "persist.device_config.activity_manager_native_boot.offload_queue_enabled", true);
        mEnableModernQueue = SystemProperties.getBoolean(
                "persist.device_config.activity_manager_native_boot.modern_queue_enabled", false);
        mEnableModernQueue = foreConstants.MODERN_QUEUE_ENABLED;
        if (mEnableModernQueue) {
            mBroadcastQueues = new BroadcastQueue[1];
+130 −41
Original line number Diff line number Diff line
@@ -16,8 +16,11 @@

package com.android.server.am;

import static android.provider.DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.Overridable;
@@ -26,13 +29,14 @@ import android.database.ContentObserver;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.TimeUtils;

import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@@ -121,11 +125,20 @@ public class BroadcastConstants {
    // started its process can start a background activity.
    public long ALLOW_BG_ACTIVITY_START_TIMEOUT = DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT;

    /**
     * Flag indicating if we should use {@link BroadcastQueueModernImpl} instead
     * of the default {@link BroadcastQueueImpl}.
     */
    public boolean MODERN_QUEUE_ENABLED = DEFAULT_MODERN_QUEUE_ENABLED;
    private static final String KEY_MODERN_QUEUE_ENABLED = "modern_queue_enabled";
    private static final boolean DEFAULT_MODERN_QUEUE_ENABLED = false;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of process queues to
     * dispatch broadcasts to simultaneously.
     */
    public int MAX_RUNNING_PROCESS_QUEUES = DEFAULT_MAX_RUNNING_PROCESS_QUEUES;
    private static final String KEY_MAX_RUNNING_PROCESS_QUEUES = "bcast_max_running_process_queues";
    private static final int DEFAULT_MAX_RUNNING_PROCESS_QUEUES = 4;

    /**
@@ -134,6 +147,7 @@ public class BroadcastConstants {
     * being "runnable" to give other processes a chance to run.
     */
    public int MAX_RUNNING_ACTIVE_BROADCASTS = DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS;
    private static final String KEY_MAX_RUNNING_ACTIVE_BROADCASTS = "bcast_max_running_active_broadcasts";
    private static final int DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS = 16;

    /**
@@ -142,22 +156,43 @@ public class BroadcastConstants {
     * might have applied to that process.
     */
    public int MAX_PENDING_BROADCASTS = DEFAULT_MAX_PENDING_BROADCASTS;
    private static final String KEY_MAX_PENDING_BROADCASTS = "bcast_max_pending_broadcasts";
    private static final int DEFAULT_MAX_PENDING_BROADCASTS = 256;

    /**
     * For {@link BroadcastQueueModernImpl}: Default delay to apply to normal
     * For {@link BroadcastQueueModernImpl}: Delay to apply to normal
     * broadcasts, giving a chance for debouncing of rapidly changing events.
     */
    public long DELAY_NORMAL_MILLIS = DEFAULT_DELAY_NORMAL_MILLIS;
    private static final String KEY_DELAY_NORMAL_MILLIS = "bcast_delay_normal_millis";
    private static final long DEFAULT_DELAY_NORMAL_MILLIS = 10_000 * Build.HW_TIMEOUT_MULTIPLIER;

    /**
     * For {@link BroadcastQueueModernImpl}: Default delay to apply to
     * broadcasts targeting cached applications.
     * For {@link BroadcastQueueModernImpl}: Delay to apply to broadcasts
     * targeting cached applications.
     */
    public long DELAY_CACHED_MILLIS = DEFAULT_DELAY_CACHED_MILLIS;
    private static final String KEY_DELAY_CACHED_MILLIS = "bcast_delay_cached_millis";
    private static final long DEFAULT_DELAY_CACHED_MILLIS = 30_000 * Build.HW_TIMEOUT_MULTIPLIER;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of complete
     * historical broadcasts to retain for debugging purposes.
     */
    public int MAX_HISTORY_COMPLETE_SIZE = DEFAULT_MAX_HISTORY_COMPLETE_SIZE;
    private static final String KEY_MAX_HISTORY_COMPLETE_SIZE = "bcast_max_history_complete_size";
    private static final int DEFAULT_MAX_HISTORY_COMPLETE_SIZE =
            ActivityManager.isLowRamDeviceStatic() ? 10 : 50;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of summarized
     * historical broadcasts to retain for debugging purposes.
     */
    public int MAX_HISTORY_SUMMARY_SIZE = DEFAULT_MAX_HISTORY_SUMMARY_SIZE;
    private static final String KEY_MAX_HISTORY_SUMMARY_SIZE = "bcast_max_history_summary_size";
    private static final int DEFAULT_MAX_HISTORY_SUMMARY_SIZE =
            ActivityManager.isLowRamDeviceStatic() ? 25 : 300;

    // Settings override tracking for this instance
    private String mSettingsKey;
    private SettingsObserver mSettingsObserver;
@@ -179,6 +214,9 @@ public class BroadcastConstants {
    // that instance's values are drawn.
    public BroadcastConstants(String settingsKey) {
        mSettingsKey = settingsKey;

        // Load initial values at least once before we start observing below
        updateDeviceConfigConstants();
    }

    /**
@@ -193,14 +231,13 @@ public class BroadcastConstants {
                false, mSettingsObserver);
        updateSettingsConstants();

        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                new HandlerExecutor(handler), this::updateDeviceConfigConstants);
        updateDeviceConfigConstants(
                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER));
        updateDeviceConfigConstants();
    }

    private void updateSettingsConstants() {
        synchronized (mParser) {
        synchronized (this) {
            try {
                mParser.setString(Settings.Global.getString(mResolver, mSettingsKey));
            } catch (IllegalArgumentException e) {
@@ -220,51 +257,103 @@ public class BroadcastConstants {
        }
    }

    /**
     * Return the {@link SystemProperty} name for the given key in our
     * {@link DeviceConfig} namespace.
     */
    private @NonNull String propertyFor(@NonNull String key) {
        return "persist.device_config." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key;
    }

    /**
     * Return the {@link SystemProperty} name for the given key in our
     * {@link DeviceConfig} namespace, but with a different prefix that can be
     * used to locally override the {@link DeviceConfig} value.
     */
    private @NonNull String propertyOverrideFor(@NonNull String key) {
        return "persist.sys." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key;
    }

    private boolean getDeviceConfigBoolean(@NonNull String key, boolean def) {
        return SystemProperties.getBoolean(propertyOverrideFor(key),
                SystemProperties.getBoolean(propertyFor(key), def));
    }

    private int getDeviceConfigInt(@NonNull String key, int def) {
        return SystemProperties.getInt(propertyOverrideFor(key),
                SystemProperties.getInt(propertyFor(key), def));
    }

    private long getDeviceConfigLong(@NonNull String key, long def) {
        return SystemProperties.getLong(propertyOverrideFor(key),
                SystemProperties.getLong(propertyFor(key), def));
    }

    private void updateDeviceConfigConstants(@NonNull DeviceConfig.Properties properties) {
        MAX_RUNNING_PROCESS_QUEUES = properties.getInt("bcast_max_running_process_queues",
        updateDeviceConfigConstants();
    }

    /**
     * Since our values are stored in a "native boot" namespace, we load them
     * directly from the system properties.
     */
    private void updateDeviceConfigConstants() {
        synchronized (this) {
            MODERN_QUEUE_ENABLED = getDeviceConfigBoolean(KEY_MODERN_QUEUE_ENABLED,
                    DEFAULT_MODERN_QUEUE_ENABLED);
            MAX_RUNNING_PROCESS_QUEUES = getDeviceConfigInt(KEY_MAX_RUNNING_PROCESS_QUEUES,
                    DEFAULT_MAX_RUNNING_PROCESS_QUEUES);
        MAX_RUNNING_ACTIVE_BROADCASTS = properties.getInt("bcast_max_running_active_broadcasts",
            MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS,
                    DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
        MAX_PENDING_BROADCASTS = properties.getInt("bcast_max_pending_broadcasts",
            MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS,
                    DEFAULT_MAX_PENDING_BROADCASTS);
        DELAY_NORMAL_MILLIS = properties.getLong("bcast_delay_normal_millis",
            DELAY_NORMAL_MILLIS = getDeviceConfigLong(KEY_DELAY_NORMAL_MILLIS,
                    DEFAULT_DELAY_NORMAL_MILLIS);
        DELAY_CACHED_MILLIS = properties.getLong("bcast_delay_cached_millis",
            DELAY_CACHED_MILLIS = getDeviceConfigLong(KEY_DELAY_CACHED_MILLIS,
                    DEFAULT_DELAY_CACHED_MILLIS);
            MAX_HISTORY_COMPLETE_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_COMPLETE_SIZE,
                    DEFAULT_MAX_HISTORY_COMPLETE_SIZE);
            MAX_HISTORY_SUMMARY_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_SUMMARY_SIZE,
                    DEFAULT_MAX_HISTORY_SUMMARY_SIZE);
        }
    }

    /**
     * Standard dumpsys support; invoked from BroadcastQueue dump
     */
    public void dump(PrintWriter pw) {
        synchronized (mParser) {
            pw.println();
    public void dump(@NonNull IndentingPrintWriter pw) {
        synchronized (this) {
            pw.print("Broadcast parameters (key=");
            pw.print(mSettingsKey);
            pw.print(", observing=");
            pw.print(mSettingsObserver != null);
            pw.println("):");

            pw.print("    "); pw.print(KEY_TIMEOUT); pw.print(" = ");
            TimeUtils.formatDuration(TIMEOUT, pw);
            pw.increaseIndent();
            pw.print(KEY_TIMEOUT, TimeUtils.formatDuration(TIMEOUT)).println();
            pw.print(KEY_SLOW_TIME, TimeUtils.formatDuration(SLOW_TIME)).println();
            pw.print(KEY_DEFERRAL, TimeUtils.formatDuration(DEFERRAL)).println();
            pw.print(KEY_DEFERRAL_DECAY_FACTOR, DEFERRAL_DECAY_FACTOR).println();
            pw.print(KEY_DEFERRAL_FLOOR, DEFERRAL_FLOOR).println();
            pw.print(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT,
                    TimeUtils.formatDuration(ALLOW_BG_ACTIVITY_START_TIMEOUT)).println();
            pw.decreaseIndent();
            pw.println();

            pw.print("    "); pw.print(KEY_SLOW_TIME); pw.print(" = ");
            TimeUtils.formatDuration(SLOW_TIME, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_DEFERRAL); pw.print(" = ");
            TimeUtils.formatDuration(DEFERRAL, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_DEFERRAL_DECAY_FACTOR); pw.print(" = ");
            pw.println(DEFERRAL_DECAY_FACTOR);

            pw.print("    "); pw.print(KEY_DEFERRAL_FLOOR); pw.print(" = ");
            TimeUtils.formatDuration(DEFERRAL_FLOOR, pw);

            pw.print("    "); pw.print(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT); pw.print(" = ");
            TimeUtils.formatDuration(ALLOW_BG_ACTIVITY_START_TIMEOUT, pw);
            pw.print("Broadcast parameters (namespace=");
            pw.print(NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT);
            pw.println("):");
            pw.increaseIndent();
            pw.print(KEY_MODERN_QUEUE_ENABLED, MODERN_QUEUE_ENABLED).println();
            pw.print(KEY_MAX_RUNNING_PROCESS_QUEUES, MAX_RUNNING_PROCESS_QUEUES).println();
            pw.print(KEY_MAX_RUNNING_ACTIVE_BROADCASTS, MAX_RUNNING_ACTIVE_BROADCASTS).println();
            pw.print(KEY_MAX_PENDING_BROADCASTS, MAX_PENDING_BROADCASTS).println();
            pw.print(KEY_DELAY_NORMAL_MILLIS,
                    TimeUtils.formatDuration(DELAY_NORMAL_MILLIS)).println();
            pw.print(KEY_DELAY_CACHED_MILLIS,
                    TimeUtils.formatDuration(DELAY_CACHED_MILLIS)).println();
            pw.print(KEY_MAX_HISTORY_COMPLETE_SIZE, MAX_HISTORY_COMPLETE_SIZE).println();
            pw.print(KEY_MAX_HISTORY_SUMMARY_SIZE, MAX_HISTORY_SUMMARY_SIZE).println();
            pw.decreaseIndent();
            pw.println();
        }
    }
+19 −9
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.server.am;

import android.app.ActivityManager;
import android.annotation.NonNull;
import android.content.Intent;
import android.os.Bundle;
import android.util.TimeUtils;
@@ -31,22 +31,32 @@ import java.util.Date;
 * for debugging purposes. Automatically trims itself over time.
 */
public class BroadcastHistory {
    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
    static final int MAX_BROADCAST_SUMMARY_HISTORY
            = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
    private final int MAX_BROADCAST_HISTORY;
    private final int MAX_BROADCAST_SUMMARY_HISTORY;

    public BroadcastHistory(@NonNull BroadcastConstants constants) {
        MAX_BROADCAST_HISTORY = constants.MAX_HISTORY_COMPLETE_SIZE;
        MAX_BROADCAST_SUMMARY_HISTORY = constants.MAX_HISTORY_SUMMARY_SIZE;

        mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
        mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
        mSummaryHistoryEnqueueTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
        mSummaryHistoryDispatchTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
        mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
    }

    /**
     * Historical data of past broadcasts, for debugging.  This is a ring buffer
     * whose last element is at mHistoryNext.
     */
    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
    final BroadcastRecord[] mBroadcastHistory;
    int mHistoryNext = 0;

    /**
     * Summary of historical data of past broadcasts, for debugging.  This is a
     * ring buffer whose last element is at mSummaryHistoryNext.
     */
    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
    final Intent[] mBroadcastSummaryHistory;
    int mSummaryHistoryNext = 0;

    /**
@@ -54,9 +64,9 @@ public class BroadcastHistory {
     * buffer, also tracked via the mSummaryHistoryNext index.  These are all in wall
     * clock time, not elapsed.
     */
    final long[] mSummaryHistoryEnqueueTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
    final long[] mSummaryHistoryDispatchTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
    final long[] mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
    final long[] mSummaryHistoryEnqueueTime;
    final long[] mSummaryHistoryDispatchTime;
    final long[] mSummaryHistoryFinishTime;

    public void addBroadcastToHistoryLocked(BroadcastRecord original) {
        // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
+13 −0
Original line number Diff line number Diff line
@@ -636,6 +636,19 @@ class BroadcastProcessQueue {
        }
        pw.print(" because ");
        pw.print(reasonToString(mRunnableAtReason));
        if (mRunnableAtReason == REASON_BLOCKED) {
            final SomeArgs next = mPending.peekFirst();
            if (next != null) {
                final BroadcastRecord r = (BroadcastRecord) next.arg1;
                final int blockedUntilTerminalCount = next.argi2;
                pw.print(" waiting for ");
                pw.print(blockedUntilTerminalCount);
                pw.print(" at ");
                pw.print(r.terminalCount);
                pw.print(" of ");
                pw.print(r.receivers.size());
            }
        }
        pw.println();
        pw.increaseIndent();
        if (mActive != null) {
+1 −0
Original line number Diff line number Diff line
@@ -214,6 +214,7 @@ public abstract class BroadcastQueue {
    @GuardedBy("mService")
    public abstract @NonNull String describeStateLocked();

    @GuardedBy("mService")
    public abstract void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);

    @GuardedBy("mService")
Loading