1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.os; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.ComponentName; 23 import android.content.Intent; 24 import android.os.SystemClock; 25 26 import com.android.internal.os.anr.AnrLatencyTracker; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** 32 * A timeout that has triggered on the system. 33 * 34 * @hide 35 */ 36 public class TimeoutRecord { 37 /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */ 38 @IntDef(value = { 39 TimeoutKind.INPUT_DISPATCH_NO_FOCUSED_WINDOW, 40 TimeoutKind.INPUT_DISPATCH_WINDOW_UNRESPONSIVE, 41 TimeoutKind.BROADCAST_RECEIVER, 42 TimeoutKind.SERVICE_START, 43 TimeoutKind.SERVICE_EXEC, 44 TimeoutKind.CONTENT_PROVIDER, 45 TimeoutKind.APP_REGISTERED, 46 TimeoutKind.SHORT_FGS_TIMEOUT, 47 TimeoutKind.JOB_SERVICE, 48 }) 49 50 @Retention(RetentionPolicy.SOURCE) 51 public @interface TimeoutKind { 52 int INPUT_DISPATCH_NO_FOCUSED_WINDOW = 1; 53 int INPUT_DISPATCH_WINDOW_UNRESPONSIVE = 2; 54 int BROADCAST_RECEIVER = 3; 55 int SERVICE_START = 4; 56 int SERVICE_EXEC = 5; 57 int CONTENT_PROVIDER = 6; 58 int APP_REGISTERED = 7; 59 int SHORT_FGS_TIMEOUT = 8; 60 int JOB_SERVICE = 9; 61 int APP_START = 10; 62 } 63 64 /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */ 65 @TimeoutKind 66 public final int mKind; 67 68 /** Reason for the timeout. */ 69 public final String mReason; 70 71 /** System uptime in millis when the timeout was triggered. */ 72 public final long mEndUptimeMillis; 73 74 /** 75 * Was the end timestamp taken right after the timeout triggered, before any potentially 76 * expensive operations such as taking locks? 77 */ 78 public final boolean mEndTakenBeforeLocks; 79 80 /** Latency tracker associated with this instance. */ 81 public final AnrLatencyTracker mLatencyTracker; 82 TimeoutRecord(@imeoutKind int kind, @NonNull String reason, long endUptimeMillis, boolean endTakenBeforeLocks)83 private TimeoutRecord(@TimeoutKind int kind, @NonNull String reason, long endUptimeMillis, 84 boolean endTakenBeforeLocks) { 85 this.mKind = kind; 86 this.mReason = reason; 87 this.mEndUptimeMillis = endUptimeMillis; 88 this.mEndTakenBeforeLocks = endTakenBeforeLocks; 89 this.mLatencyTracker = new AnrLatencyTracker(kind, endUptimeMillis); 90 } 91 endingNow(@imeoutKind int kind, String reason)92 private static TimeoutRecord endingNow(@TimeoutKind int kind, String reason) { 93 long endUptimeMillis = SystemClock.uptimeMillis(); 94 return new TimeoutRecord(kind, reason, endUptimeMillis, /* endTakenBeforeLocks */ true); 95 } 96 endingApproximatelyNow(@imeoutKind int kind, String reason)97 private static TimeoutRecord endingApproximatelyNow(@TimeoutKind int kind, String reason) { 98 long endUptimeMillis = SystemClock.uptimeMillis(); 99 return new TimeoutRecord(kind, reason, endUptimeMillis, /* endTakenBeforeLocks */ false); 100 } 101 102 /** Record for a broadcast receiver timeout. */ 103 @NonNull forBroadcastReceiver(@onNull Intent intent, @Nullable String packageName, @Nullable String className)104 public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent, 105 @Nullable String packageName, @Nullable String className) { 106 final Intent logIntent; 107 if (packageName != null) { 108 if (className != null) { 109 logIntent = new Intent(intent); 110 logIntent.setComponent(new ComponentName(packageName, className)); 111 } else { 112 logIntent = new Intent(intent); 113 logIntent.setPackage(packageName); 114 } 115 } else { 116 logIntent = intent; 117 } 118 return forBroadcastReceiver(logIntent); 119 } 120 121 /** Record for a broadcast receiver timeout. */ 122 @NonNull forBroadcastReceiver(@onNull Intent intent)123 public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent) { 124 final StringBuilder reason = new StringBuilder("Broadcast of "); 125 intent.toString(reason); 126 return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason.toString()); 127 } 128 129 /** Record for a broadcast receiver timeout. */ 130 @NonNull forBroadcastReceiver(@onNull Intent intent, long timeoutDurationMs)131 public static TimeoutRecord forBroadcastReceiver(@NonNull Intent intent, 132 long timeoutDurationMs) { 133 final StringBuilder reason = new StringBuilder("Broadcast of "); 134 intent.toString(reason); 135 reason.append(", waited "); 136 reason.append(timeoutDurationMs); 137 reason.append("ms"); 138 return TimeoutRecord.endingNow(TimeoutKind.BROADCAST_RECEIVER, reason.toString()); 139 } 140 141 /** Record for an input dispatch no focused window timeout */ 142 @NonNull forInputDispatchNoFocusedWindow(@onNull String reason)143 public static TimeoutRecord forInputDispatchNoFocusedWindow(@NonNull String reason) { 144 return TimeoutRecord.endingNow(TimeoutKind.INPUT_DISPATCH_NO_FOCUSED_WINDOW, reason); 145 } 146 147 /** Record for an input dispatch window unresponsive timeout. */ 148 @NonNull forInputDispatchWindowUnresponsive(@onNull String reason)149 public static TimeoutRecord forInputDispatchWindowUnresponsive(@NonNull String reason) { 150 return TimeoutRecord.endingNow(TimeoutKind.INPUT_DISPATCH_WINDOW_UNRESPONSIVE, reason); 151 } 152 153 /** Record for a service exec timeout. */ 154 @NonNull forServiceExec(@onNull String reason)155 public static TimeoutRecord forServiceExec(@NonNull String reason) { 156 return TimeoutRecord.endingNow(TimeoutKind.SERVICE_EXEC, reason); 157 } 158 159 /** Record for a service start timeout. */ 160 @NonNull forServiceStartWithEndTime(@onNull String reason, long endUptimeMillis)161 public static TimeoutRecord forServiceStartWithEndTime(@NonNull String reason, 162 long endUptimeMillis) { 163 return new TimeoutRecord(TimeoutKind.SERVICE_START, reason, 164 endUptimeMillis, /* endTakenBeforeLocks */ true); 165 } 166 167 /** Record for a content provider timeout. */ 168 @NonNull forContentProvider(@onNull String reason)169 public static TimeoutRecord forContentProvider(@NonNull String reason) { 170 return TimeoutRecord.endingApproximatelyNow(TimeoutKind.CONTENT_PROVIDER, reason); 171 } 172 173 /** Record for an app registered timeout. */ 174 @NonNull forApp(@onNull String reason)175 public static TimeoutRecord forApp(@NonNull String reason) { 176 return TimeoutRecord.endingApproximatelyNow(TimeoutKind.APP_REGISTERED, reason); 177 } 178 179 /** Record for a "short foreground service" timeout. */ 180 @NonNull forShortFgsTimeout(String reason)181 public static TimeoutRecord forShortFgsTimeout(String reason) { 182 return TimeoutRecord.endingNow(TimeoutKind.SHORT_FGS_TIMEOUT, reason); 183 } 184 185 /** Record for a job related timeout. */ 186 @NonNull forJobService(String reason)187 public static TimeoutRecord forJobService(String reason) { 188 return TimeoutRecord.endingNow(TimeoutKind.JOB_SERVICE, reason); 189 } 190 191 /** Record for app startup timeout. */ 192 @NonNull forAppStart(String reason)193 public static TimeoutRecord forAppStart(String reason) { 194 return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason); 195 } 196 } 197