diff --git a/core/java/com/android/internal/os/TimeoutRecord.java b/core/java/com/android/internal/os/TimeoutRecord.java index be3f1720acdd4..680f8fe6535f9 100644 --- a/core/java/com/android/internal/os/TimeoutRecord.java +++ b/core/java/com/android/internal/os/TimeoutRecord.java @@ -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); } diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index 454b28402ced7..fb7e0be69d787 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -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 diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 008d95a51cd92..a7d843361762b 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -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); diff --git a/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java b/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java new file mode 100644 index 0000000000000..0f9663442740c --- /dev/null +++ b/tests/Internal/src/com/android/internal/os/TimeoutRecordTest.java @@ -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); + } +}