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
This commit is contained in:
Biswarup Pal
2022-10-27 09:59:13 +00:00
parent 5358d473cb
commit 43fcac1ad5
4 changed files with 146 additions and 7 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);

View File

@@ -0,0 +1,131 @@
/*
* 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);
}
}