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

Commit 620bd16a authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

BroadcastQueue: periodic internal health check.

Devices might end up in an unexpected state, so periodically run
an internal health check dump the current state if any expected
constraints are violated.

Bug: 245771249
Test: atest FrameworksMockingServicesTests:BroadcastRecordTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Change-Id: I1870a952c12f4a030243405c52b29e0618055d55
parent a792fea0
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -34,7 +34,15 @@ public abstract class DropBoxManagerInternal {
     * to dynamically generate the entry contents.
     */
    public interface EntrySource extends Closeable {
        public @BytesLong long length();
        public void writeTo(@NonNull FileDescriptor fd) throws IOException;

        public default @BytesLong long length() {
            // By default, length is unknown
            return 0;
        }

        public default void close() throws IOException {
            // By default, no resources to close
        }
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -10692,6 +10692,8 @@ public class ActivityManagerService extends IActivityManager.Stub
    @NeverCompile
    void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
            int opti, boolean dumpAll, String dumpPackage) {
        boolean dumpConstants = true;
        boolean dumpHistory = true;
        boolean needSep = false;
        boolean onlyHistory = false;
        boolean printedAnything = false;
@@ -10776,7 +10778,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (!onlyReceivers) {
            for (BroadcastQueue q : mBroadcastQueues) {
                needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
                needSep = q.dumpLocked(fd, pw, args, opti,
                        dumpConstants, dumpHistory, dumpAll, dumpPackage, needSep);
                printedAnything |= needSep;
            }
        }
+19 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.am;

import static com.android.internal.util.Preconditions.checkState;
import static com.android.server.am.BroadcastRecord.deliveryStateToString;
import static com.android.server.am.BroadcastRecord.isDeliveryStateTerminal;
import static com.android.server.am.BroadcastRecord.isReceiverEquals;
@@ -25,8 +26,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UptimeMillisLong;
import android.content.pm.ResolveInfo;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.IndentingPrintWriter;
import android.util.TimeUtils;

@@ -555,6 +558,22 @@ class BroadcastProcessQueue {
        }
    }

    /**
     * Check overall health, confirming things are in a reasonable state and
     * that we're not wedged.
     */
    public void checkHealthLocked() {
        if (mRunnableAtReason == REASON_BLOCKED) {
            final SomeArgs next = mPending.peekFirst();
            Objects.requireNonNull(next, "peekFirst");

            // If blocked more than 10 minutes, we're likely wedged
            final BroadcastRecord r = (BroadcastRecord) next.arg1;
            final long waitingTime = SystemClock.uptimeMillis() - r.enqueueTime;
            checkState(waitingTime < (10 * DateUtils.MINUTE_IN_MILLIS), "waitingTime");
        }
    }

    /**
     * Insert the given queue into a sorted linked list of "runnable" queues.
     *
+23 −10
Original line number Diff line number Diff line
@@ -22,15 +22,17 @@ import android.annotation.UptimeMillisLong;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Handler;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;

import dalvik.annotation.optimization.NeverCompile;
import com.android.server.DropBoxManagerInternal;
import com.android.server.LocalServices;

import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Objects;
import java.util.Set;
@@ -40,6 +42,7 @@ import java.util.Set;
 */
public abstract class BroadcastQueue {
    public static final String TAG = "BroadcastQueue";
    public static final String TAG_DUMP = "broadcast_queue_dump";

    final @NonNull ActivityManagerService mService;
    final @NonNull Handler mHandler;
@@ -57,12 +60,6 @@ public abstract class BroadcastQueue {
        mHistory = Objects.requireNonNull(history);
    }

    static void checkState(boolean state, String msg) {
        if (!state) {
            Slog.wtf(TAG, msg, new Throwable());
        }
    }

    static void logw(@NonNull String msg) {
        Slog.w(TAG, msg);
    }
@@ -221,6 +218,22 @@ public abstract class BroadcastQueue {

    @GuardedBy("mService")
    public abstract boolean dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
            @NonNull String[] args, int opti, boolean dumpAll, @Nullable String dumpPackage,
            boolean needSep);
            @NonNull String[] args, int opti, boolean dumpConstants, boolean dumpHistory,
            boolean dumpAll, @Nullable String dumpPackage, boolean needSep);

    /**
     * Execute {@link #dumpLocked} and store the output into
     * {@link DropBoxManager} for later inspection.
     */
    public void dumpToDropBoxLocked(@Nullable String msg) {
        LocalServices.getService(DropBoxManagerInternal.class).addEntry(TAG_DUMP, (fd) -> {
            try (FileOutputStream out = new FileOutputStream(fd);
                    PrintWriter pw = new PrintWriter(out)) {
                pw.print("Message: ");
                pw.println(msg);
                dumpLocked(fd, pw, null, 0, false, false, false, null, false);
                pw.flush();
            }
        }, DropBoxManager.IS_TEXT);
    }
}
+8 −3
Original line number Diff line number Diff line
@@ -1849,7 +1849,8 @@ public class BroadcastQueueImpl extends BroadcastQueue {

    @NeverCompile
    public boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
            int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
            int opti, boolean dumpConstants, boolean dumpHistory, boolean dumpAll,
            String dumpPackage, boolean needSep) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        if (!mParallelBroadcasts.isEmpty() || !mDispatcher.isEmpty()
                || mPendingBroadcast != null) {
@@ -1885,8 +1886,12 @@ public class BroadcastQueueImpl extends BroadcastQueue {
                needSep = true;
            }
        }
        if (dumpConstants) {
            mConstants.dump(new IndentingPrintWriter(pw));
        }
        if (dumpHistory) {
            needSep = mHistory.dumpLocked(pw, dumpPackage, mQueueName, sdf, dumpAll, needSep);
        }
        return needSep;
    }
}
Loading