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

Commit 43fcac1a authored by Biswarup Pal's avatar Biswarup Pal
Browse files

Add missing information in ANR message from BroadcastQueueModernImpl

This keeps the broadcast ANR message consistent with the old broadcast
queue, and fixes trace analysis pipelines that consume messages in
this format. This unstructured format is brittle but should keeps things
working, pending a longer term fix to with structured (proto) format.
This CL also adds tests for TimeoutRecord to validate ANR timeout
records.

Test: m
Bug: 254452238
Change-Id: Ifd0fb8d4a1d0add3e762b8327defb3f25d5aa0c2
parent 5358d473
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.os;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.Intent;
import android.os.SystemClock;

import com.android.internal.os.anr.AnrLatencyTracker;
@@ -92,7 +93,17 @@ public class TimeoutRecord {

    /** Record for a broadcast receiver timeout. */
    @NonNull
    public static TimeoutRecord forBroadcastReceiver(@NonNull String reason) {
    public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent) {
        String reason = "Broadcast of " + intent.toString();
        return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason);
    }

    /** Record for a broadcast receiver timeout. */
    @NonNull
    public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent,
            long timeoutDurationMs) {
        String reason = "Broadcast of " + intent.toString() + ", waited " + timeoutDurationMs
                + "ms";
        return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason);
    }

+2 −4
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import android.content.ContentResolver;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
@@ -1639,9 +1638,8 @@ public class BroadcastQueueImpl extends BroadcastQueue {
            }
            Slog.w(TAG, "Receiver during timeout of " + r + " : " + curReceiver);
            logBroadcastReceiverDiscardLocked(r);
            String anrMessage =
                    "Broadcast of " + r.intent.toString() + ", waited " + timeoutDurationMs + "ms";
            TimeoutRecord timeoutRecord = TimeoutRecord.forBroadcastReceiver(anrMessage);
            TimeoutRecord timeoutRecord = TimeoutRecord.forBroadcastReceiver(r.intent,
                    timeoutDurationMs);
            if (curReceiver != null && curReceiver instanceof BroadcastFilter) {
                BroadcastFilter bf = (BroadcastFilter) curReceiver;
                if (bf.receiverList.pid != 0
+1 −2
Original line number Diff line number Diff line
@@ -907,8 +907,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            r.anrCount++;
            if (app != null && !app.isDebugging()) {
                mService.appNotResponding(queue.app, TimeoutRecord
                        .forBroadcastReceiver("Broadcast of " + r.toShortString()));
                mService.appNotResponding(queue.app, TimeoutRecord.forBroadcastReceiver(r.intent));
            }
        } else {
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
+131 −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.internal.os;

import android.content.ComponentName;
import android.content.Intent;
import android.platform.test.annotations.Presubmit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import androidx.test.filters.SmallTest;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for {@link TimeoutRecord}. */
@SmallTest
@Presubmit
@RunWith(JUnit4.class)
public class TimeoutRecordTest {

    @Test
    public void forBroadcastReceiver_returnsCorrectTimeoutRecord() {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setComponent(ComponentName.createRelative("com.example.app", "ExampleClass"));

        TimeoutRecord record = TimeoutRecord.forBroadcastReceiver(intent);

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.BROADCAST_RECEIVER);
        assertEquals(record.mReason,
                "Broadcast of Intent { act=android.intent.action.MAIN cmp=com.example"
                        + ".app/ExampleClass }");
        assertTrue(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forBroadcastReceiver_withTimeoutDurationMs_returnsCorrectTimeoutRecord() {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setComponent(ComponentName.createRelative("com.example.app", "ExampleClass"));

        TimeoutRecord record = TimeoutRecord.forBroadcastReceiver(intent, 1000L);

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.BROADCAST_RECEIVER);
        assertEquals(record.mReason,
                "Broadcast of Intent { act=android.intent.action.MAIN cmp=com.example"
                        + ".app/ExampleClass }, waited 1000ms");
        assertTrue(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forInputDispatchNoFocusedWindow_returnsCorrectTimeoutRecord() {
        TimeoutRecord record = TimeoutRecord.forInputDispatchNoFocusedWindow("Test ANR reason");

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.INPUT_DISPATCH_NO_FOCUSED_WINDOW);
        assertEquals(record.mReason,
                "Test ANR reason");
        assertTrue(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forInputDispatchWindowUnresponsive_returnsCorrectTimeoutRecord() {
        TimeoutRecord record = TimeoutRecord.forInputDispatchWindowUnresponsive("Test ANR reason");

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.INPUT_DISPATCH_WINDOW_UNRESPONSIVE);
        assertEquals(record.mReason, "Test ANR reason");
        assertTrue(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forServiceExec_returnsCorrectTimeoutRecord() {
        TimeoutRecord record = TimeoutRecord.forServiceExec("Test ANR reason");

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.SERVICE_EXEC);
        assertEquals(record.mReason, "Test ANR reason");
        assertTrue(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forServiceStartWithEndTime_returnsCorrectTimeoutRecord() {
        TimeoutRecord record = TimeoutRecord.forServiceStartWithEndTime("Test ANR reason", 1000L);

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.SERVICE_START);
        assertEquals(record.mReason, "Test ANR reason");
        assertEquals(record.mEndUptimeMillis, 1000L);
        assertTrue(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forContentProvider_returnsCorrectTimeoutRecord() {
        TimeoutRecord record = TimeoutRecord.forContentProvider("Test ANR reason");

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.CONTENT_PROVIDER);
        assertEquals(record.mReason, "Test ANR reason");
        assertFalse(record.mEndTakenBeforeLocks);
    }

    @Test
    public void forApp_returnsCorrectTimeoutRecord() {
        TimeoutRecord record = TimeoutRecord.forApp("Test ANR reason");

        assertNotNull(record);
        assertEquals(record.mKind, TimeoutRecord.TimeoutKind.APP_REGISTERED);
        assertEquals(record.mReason, "Test ANR reason");
        assertFalse(record.mEndTakenBeforeLocks);
    }
}