Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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.NonNull; |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 20 | import android.annotation.Nullable; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 21 | import android.os.Handler; |
| 22 | import android.os.Looper; |
| 23 | import android.os.Message; |
| 24 | import android.os.SystemClock; |
| 25 | import android.util.SparseArray; |
| 26 | |
| 27 | import com.android.internal.annotations.GuardedBy; |
| 28 | |
| 29 | import java.util.ArrayList; |
| 30 | import java.util.List; |
| 31 | import java.util.concurrent.ConcurrentLinkedQueue; |
| 32 | import java.util.concurrent.ThreadLocalRandom; |
| 33 | |
| 34 | /** |
| 35 | * Collects aggregated telemetry data about Looper message dispatching. |
| 36 | * |
| 37 | * @hide Only for use within the system server. |
| 38 | */ |
| 39 | public class LooperStats implements Looper.Observer { |
Marcin Oczeretko | 9450171 | 2018-12-17 18:03:45 +0000 | [diff] [blame] | 40 | public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 41 | private static final int SESSION_POOL_SIZE = 50; |
Olivier Gaillard | 36b80ca | 2019-02-11 11:41:39 +0000 | [diff] [blame] | 42 | private static final boolean DISABLED_SCREEN_STATE_TRACKING_VALUE = false; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 43 | |
| 44 | @GuardedBy("mLock") |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 45 | private final SparseArray<Entry> mEntries = new SparseArray<>(512); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 46 | private final Object mLock = new Object(); |
| 47 | private final Entry mOverflowEntry = new Entry("OVERFLOW"); |
| 48 | private final Entry mHashCollisionEntry = new Entry("HASH_COLLISION"); |
| 49 | private final ConcurrentLinkedQueue<DispatchSession> mSessionPool = |
| 50 | new ConcurrentLinkedQueue<>(); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 51 | private final int mEntriesSizeCap; |
Marcin Oczeretko | 3680ae6 | 2018-08-23 16:33:34 +0100 | [diff] [blame] | 52 | private int mSamplingInterval; |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 53 | private CachedDeviceState.Readonly mDeviceState; |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 54 | private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; |
Olivier Gaillard | 28109b5 | 2018-12-14 15:14:14 +0000 | [diff] [blame] | 55 | private long mStartCurrentTime = System.currentTimeMillis(); |
| 56 | private long mStartElapsedTime = SystemClock.elapsedRealtime(); |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 57 | private boolean mAddDebugEntries = false; |
Olivier Gaillard | 36b80ca | 2019-02-11 11:41:39 +0000 | [diff] [blame] | 58 | private boolean mTrackScreenInteractive = false; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 59 | |
| 60 | public LooperStats(int samplingInterval, int entriesSizeCap) { |
| 61 | this.mSamplingInterval = samplingInterval; |
| 62 | this.mEntriesSizeCap = entriesSizeCap; |
| 63 | } |
| 64 | |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 65 | public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) { |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 66 | if (mBatteryStopwatch != null) { |
| 67 | mBatteryStopwatch.close(); |
| 68 | } |
| 69 | |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 70 | mDeviceState = deviceState; |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 71 | mBatteryStopwatch = deviceState.createTimeOnBatteryStopwatch(); |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 72 | } |
| 73 | |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 74 | public void setAddDebugEntries(boolean addDebugEntries) { |
| 75 | mAddDebugEntries = addDebugEntries; |
| 76 | } |
| 77 | |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 78 | @Override |
| 79 | public Object messageDispatchStarting() { |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 80 | if (deviceStateAllowsCollection() && shouldCollectDetailedData()) { |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 81 | DispatchSession session = mSessionPool.poll(); |
| 82 | session = session == null ? new DispatchSession() : session; |
| 83 | session.startTimeMicro = getElapsedRealtimeMicro(); |
| 84 | session.cpuStartMicro = getThreadTimeMicro(); |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 85 | session.systemUptimeMillis = getSystemUptimeMillis(); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 86 | return session; |
| 87 | } |
| 88 | |
| 89 | return DispatchSession.NOT_SAMPLED; |
| 90 | } |
| 91 | |
| 92 | @Override |
| 93 | public void messageDispatched(Object token, Message msg) { |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 94 | if (!deviceStateAllowsCollection()) { |
| 95 | return; |
| 96 | } |
| 97 | |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 98 | DispatchSession session = (DispatchSession) token; |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 99 | Entry entry = findEntry(msg, /* allowCreateNew= */session != DispatchSession.NOT_SAMPLED); |
| 100 | if (entry != null) { |
| 101 | synchronized (entry) { |
| 102 | entry.messageCount++; |
| 103 | if (session != DispatchSession.NOT_SAMPLED) { |
| 104 | entry.recordedMessageCount++; |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 105 | final long latency = getElapsedRealtimeMicro() - session.startTimeMicro; |
| 106 | final long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro; |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 107 | entry.totalLatencyMicro += latency; |
| 108 | entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency); |
| 109 | entry.cpuUsageMicro += cpuUsage; |
| 110 | entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage); |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 111 | if (msg.getWhen() > 0) { |
| 112 | final long delay = Math.max(0L, session.systemUptimeMillis - msg.getWhen()); |
| 113 | entry.delayMillis += delay; |
| 114 | entry.maxDelayMillis = Math.max(entry.maxDelayMillis, delay); |
| 115 | entry.recordedDelayMessageCount++; |
| 116 | } |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 117 | } |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 118 | } |
| 119 | } |
| 120 | |
| 121 | recycleSession(session); |
| 122 | } |
| 123 | |
| 124 | @Override |
| 125 | public void dispatchingThrewException(Object token, Message msg, Exception exception) { |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 126 | if (!deviceStateAllowsCollection()) { |
| 127 | return; |
| 128 | } |
| 129 | |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 130 | DispatchSession session = (DispatchSession) token; |
Olivier Gaillard | 99ab953 | 2019-02-04 10:47:48 +0000 | [diff] [blame] | 131 | Entry entry = findEntry(msg, /* allowCreateNew= */session != DispatchSession.NOT_SAMPLED); |
| 132 | if (entry != null) { |
| 133 | synchronized (entry) { |
| 134 | entry.exceptionCount++; |
| 135 | } |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 136 | } |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 137 | |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 138 | recycleSession(session); |
| 139 | } |
| 140 | |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 141 | private boolean deviceStateAllowsCollection() { |
| 142 | // Do not collect data if on charger or the state is not set. |
| 143 | return mDeviceState != null && !mDeviceState.isCharging(); |
| 144 | } |
| 145 | |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 146 | /** Returns an array of {@link ExportedEntry entries} with the aggregated statistics. */ |
| 147 | public List<ExportedEntry> getEntries() { |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 148 | final ArrayList<ExportedEntry> exportedEntries; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 149 | synchronized (mLock) { |
| 150 | final int size = mEntries.size(); |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 151 | exportedEntries = new ArrayList<>(size); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 152 | for (int i = 0; i < size; i++) { |
| 153 | Entry entry = mEntries.valueAt(i); |
| 154 | synchronized (entry) { |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 155 | exportedEntries.add(new ExportedEntry(entry)); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 156 | } |
| 157 | } |
| 158 | } |
| 159 | // Add the overflow and collision entries only if they have any data. |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 160 | maybeAddSpecialEntry(exportedEntries, mOverflowEntry); |
| 161 | maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry); |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 162 | // Debug entries added to help validate the data. |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 163 | if (mAddDebugEntries && mBatteryStopwatch != null) { |
Olivier Gaillard | 28109b5 | 2018-12-14 15:14:14 +0000 | [diff] [blame] | 164 | exportedEntries.add(createDebugEntry("start_time_millis", mStartElapsedTime)); |
| 165 | exportedEntries.add(createDebugEntry("end_time_millis", SystemClock.elapsedRealtime())); |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 166 | exportedEntries.add( |
| 167 | createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis())); |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 168 | } |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 169 | return exportedEntries; |
| 170 | } |
| 171 | |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 172 | private ExportedEntry createDebugEntry(String variableName, long value) { |
Marcin Oczeretko | 9450171 | 2018-12-17 18:03:45 +0000 | [diff] [blame] | 173 | final Entry entry = new Entry(DEBUG_ENTRY_PREFIX + variableName); |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 174 | entry.messageCount = 1; |
| 175 | entry.recordedMessageCount = 1; |
Marcin Oczeretko | 8d86174 | 2018-12-06 11:13:29 +0000 | [diff] [blame] | 176 | entry.totalLatencyMicro = value; |
Marcin Oczeretko | d32a5135 | 2018-11-20 18:11:37 +0000 | [diff] [blame] | 177 | return new ExportedEntry(entry); |
| 178 | } |
| 179 | |
Marcin Oczeretko | d464bcf | 2018-10-19 10:46:21 +0100 | [diff] [blame] | 180 | /** Returns a timestamp indicating when the statistics were last reset. */ |
| 181 | public long getStartTimeMillis() { |
Olivier Gaillard | 28109b5 | 2018-12-14 15:14:14 +0000 | [diff] [blame] | 182 | return mStartCurrentTime; |
| 183 | } |
| 184 | |
| 185 | public long getStartElapsedTimeMillis() { |
| 186 | return mStartElapsedTime; |
Marcin Oczeretko | d464bcf | 2018-10-19 10:46:21 +0100 | [diff] [blame] | 187 | } |
| 188 | |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 189 | public long getBatteryTimeMillis() { |
| 190 | return mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0; |
| 191 | } |
| 192 | |
Marcin Oczeretko | 3e6494e | 2018-09-10 18:06:52 +0100 | [diff] [blame] | 193 | private void maybeAddSpecialEntry(List<ExportedEntry> exportedEntries, Entry specialEntry) { |
| 194 | synchronized (specialEntry) { |
| 195 | if (specialEntry.messageCount > 0 || specialEntry.exceptionCount > 0) { |
| 196 | exportedEntries.add(new ExportedEntry(specialEntry)); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 197 | } |
| 198 | } |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | /** Removes all collected data. */ |
| 202 | public void reset() { |
| 203 | synchronized (mLock) { |
| 204 | mEntries.clear(); |
| 205 | } |
| 206 | synchronized (mHashCollisionEntry) { |
| 207 | mHashCollisionEntry.reset(); |
| 208 | } |
| 209 | synchronized (mOverflowEntry) { |
| 210 | mOverflowEntry.reset(); |
| 211 | } |
Olivier Gaillard | 28109b5 | 2018-12-14 15:14:14 +0000 | [diff] [blame] | 212 | mStartCurrentTime = System.currentTimeMillis(); |
| 213 | mStartElapsedTime = SystemClock.elapsedRealtime(); |
Marcin Oczeretko | 6a2e524 | 2018-11-28 11:08:50 +0000 | [diff] [blame] | 214 | if (mBatteryStopwatch != null) { |
| 215 | mBatteryStopwatch.reset(); |
| 216 | } |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 217 | } |
| 218 | |
Marcin Oczeretko | 3680ae6 | 2018-08-23 16:33:34 +0100 | [diff] [blame] | 219 | public void setSamplingInterval(int samplingInterval) { |
| 220 | mSamplingInterval = samplingInterval; |
| 221 | } |
| 222 | |
Olivier Gaillard | 36b80ca | 2019-02-11 11:41:39 +0000 | [diff] [blame] | 223 | public void setTrackScreenInteractive(boolean enabled) { |
| 224 | mTrackScreenInteractive = enabled; |
| 225 | } |
| 226 | |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 227 | @Nullable |
| 228 | private Entry findEntry(Message msg, boolean allowCreateNew) { |
Olivier Gaillard | 36b80ca | 2019-02-11 11:41:39 +0000 | [diff] [blame] | 229 | final boolean isInteractive = mTrackScreenInteractive |
| 230 | ? mDeviceState.isScreenInteractive() |
| 231 | : DISABLED_SCREEN_STATE_TRACKING_VALUE; |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 232 | final int id = Entry.idFor(msg, isInteractive); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 233 | Entry entry; |
| 234 | synchronized (mLock) { |
| 235 | entry = mEntries.get(id); |
| 236 | if (entry == null) { |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 237 | if (!allowCreateNew) { |
| 238 | return null; |
| 239 | } else if (mEntries.size() >= mEntriesSizeCap) { |
| 240 | // If over the size cap track totals under OVERFLOW entry. |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 241 | return mOverflowEntry; |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 242 | } else { |
| 243 | entry = new Entry(msg, isInteractive); |
| 244 | mEntries.put(id, entry); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 245 | } |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 246 | } |
| 247 | } |
| 248 | |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 249 | if (entry.workSourceUid != msg.workSourceUid |
| 250 | || entry.handler.getClass() != msg.getTarget().getClass() |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 251 | || entry.handler.getLooper().getThread() != msg.getTarget().getLooper().getThread() |
| 252 | || entry.isInteractive != isInteractive) { |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 253 | // If a hash collision happened, track totals under a single entry. |
| 254 | return mHashCollisionEntry; |
| 255 | } |
| 256 | return entry; |
| 257 | } |
| 258 | |
| 259 | private void recycleSession(DispatchSession session) { |
Marcin Oczeretko | a674bc9 | 2018-09-13 18:20:21 +0100 | [diff] [blame] | 260 | if (session != DispatchSession.NOT_SAMPLED && mSessionPool.size() < SESSION_POOL_SIZE) { |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 261 | mSessionPool.add(session); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | protected long getThreadTimeMicro() { |
| 266 | return SystemClock.currentThreadTimeMicro(); |
| 267 | } |
| 268 | |
| 269 | protected long getElapsedRealtimeMicro() { |
| 270 | return SystemClock.elapsedRealtimeNanos() / 1000; |
| 271 | } |
| 272 | |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 273 | protected long getSystemUptimeMillis() { |
| 274 | return SystemClock.uptimeMillis(); |
| 275 | } |
| 276 | |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 277 | protected boolean shouldCollectDetailedData() { |
| 278 | return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; |
| 279 | } |
| 280 | |
| 281 | private static class DispatchSession { |
| 282 | static final DispatchSession NOT_SAMPLED = new DispatchSession(); |
| 283 | public long startTimeMicro; |
| 284 | public long cpuStartMicro; |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 285 | public long systemUptimeMillis; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 286 | } |
| 287 | |
| 288 | private static class Entry { |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 289 | public final int workSourceUid; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 290 | public final Handler handler; |
| 291 | public final String messageName; |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 292 | public final boolean isInteractive; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 293 | public long messageCount; |
| 294 | public long recordedMessageCount; |
| 295 | public long exceptionCount; |
| 296 | public long totalLatencyMicro; |
| 297 | public long maxLatencyMicro; |
| 298 | public long cpuUsageMicro; |
| 299 | public long maxCpuUsageMicro; |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 300 | public long recordedDelayMessageCount; |
| 301 | public long delayMillis; |
| 302 | public long maxDelayMillis; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 303 | |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 304 | Entry(Message msg, boolean isInteractive) { |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 305 | this.workSourceUid = msg.workSourceUid; |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 306 | this.handler = msg.getTarget(); |
| 307 | this.messageName = handler.getMessageName(msg); |
| 308 | this.isInteractive = isInteractive; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 309 | } |
| 310 | |
| 311 | Entry(String specialEntryName) { |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 312 | this.workSourceUid = Message.UID_NONE; |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 313 | this.messageName = specialEntryName; |
| 314 | this.handler = null; |
| 315 | this.isInteractive = false; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 316 | } |
| 317 | |
| 318 | void reset() { |
| 319 | messageCount = 0; |
| 320 | recordedMessageCount = 0; |
| 321 | exceptionCount = 0; |
| 322 | totalLatencyMicro = 0; |
| 323 | maxLatencyMicro = 0; |
| 324 | cpuUsageMicro = 0; |
| 325 | maxCpuUsageMicro = 0; |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 326 | delayMillis = 0; |
| 327 | maxDelayMillis = 0; |
| 328 | recordedDelayMessageCount = 0; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 329 | } |
| 330 | |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 331 | static int idFor(Message msg, boolean isInteractive) { |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 332 | int result = 7; |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 333 | result = 31 * result + msg.workSourceUid; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 334 | result = 31 * result + msg.getTarget().getLooper().getThread().hashCode(); |
| 335 | result = 31 * result + msg.getTarget().getClass().hashCode(); |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 336 | result = 31 * result + (isInteractive ? 1231 : 1237); |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 337 | if (msg.getCallback() != null) { |
| 338 | return 31 * result + msg.getCallback().getClass().hashCode(); |
| 339 | } else { |
| 340 | return 31 * result + msg.what; |
| 341 | } |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | /** Aggregated data of Looper message dispatching in the in the current process. */ |
| 346 | public static class ExportedEntry { |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 347 | public final int workSourceUid; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 348 | public final String handlerClassName; |
| 349 | public final String threadName; |
| 350 | public final String messageName; |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 351 | public final boolean isInteractive; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 352 | public final long messageCount; |
| 353 | public final long recordedMessageCount; |
| 354 | public final long exceptionCount; |
| 355 | public final long totalLatencyMicros; |
| 356 | public final long maxLatencyMicros; |
| 357 | public final long cpuUsageMicros; |
| 358 | public final long maxCpuUsageMicros; |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 359 | public final long maxDelayMillis; |
| 360 | public final long delayMillis; |
| 361 | public final long recordedDelayMessageCount; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 362 | |
| 363 | ExportedEntry(Entry entry) { |
Marcin Oczeretko | ec75872 | 2018-09-12 12:53:47 +0100 | [diff] [blame] | 364 | this.workSourceUid = entry.workSourceUid; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 365 | if (entry.handler != null) { |
| 366 | this.handlerClassName = entry.handler.getClass().getName(); |
| 367 | this.threadName = entry.handler.getLooper().getThread().getName(); |
| 368 | } else { |
| 369 | // Overflow/collision entries do not have a handler set. |
| 370 | this.handlerClassName = ""; |
| 371 | this.threadName = ""; |
| 372 | } |
Marcin Oczeretko | c80c81a | 2018-08-30 20:15:52 +0100 | [diff] [blame] | 373 | this.isInteractive = entry.isInteractive; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 374 | this.messageName = entry.messageName; |
| 375 | this.messageCount = entry.messageCount; |
| 376 | this.recordedMessageCount = entry.recordedMessageCount; |
| 377 | this.exceptionCount = entry.exceptionCount; |
| 378 | this.totalLatencyMicros = entry.totalLatencyMicro; |
| 379 | this.maxLatencyMicros = entry.maxLatencyMicro; |
| 380 | this.cpuUsageMicros = entry.cpuUsageMicro; |
| 381 | this.maxCpuUsageMicros = entry.maxCpuUsageMicro; |
Marcin Oczeretko | 4427272 | 2018-09-19 11:01:32 +0100 | [diff] [blame] | 382 | this.delayMillis = entry.delayMillis; |
| 383 | this.maxDelayMillis = entry.maxDelayMillis; |
| 384 | this.recordedDelayMessageCount = entry.recordedDelayMessageCount; |
Marcin Oczeretko | d8cc859 | 2018-08-22 16:07:36 +0100 | [diff] [blame] | 385 | } |
| 386 | } |
| 387 | } |