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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user