blob: e73ec1c40d199d6db5f13c432eabafab48cb7b9c [file] [log] [blame]
Dianne Hackborn2aec55a2018-06-26 10:35:35 -07001/*
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
17package com.android.internal.app.procstats;
18
19
20import android.os.Parcel;
21import android.os.SystemClock;
22import android.os.UserHandle;
23import android.util.ArrayMap;
24import android.util.TimeUtils;
25
26import java.io.PrintWriter;
27import java.util.Objects;
28
29public final class AssociationState {
30 private static final String TAG = "ProcessStats";
31 private static final boolean DEBUG = false;
32
33 private final String mPackage;
34 private final String mProcessName;
35 private final String mName;
36 private final DurationsTable mDurations;
37
38 public final class SourceState {
39 public void stop() {
40 mNesting--;
41 if (mNesting == 0) {
42 mDuration += SystemClock.uptimeMillis() - mStartTime;
43 mNumActive--;
44 }
45 }
46
47 int mNesting;
48 int mCount;
49 long mStartTime;
50 long mDuration;
51 }
52
53 final static class SourceKey {
54 int mUid;
55 String mProcess;
56
57 SourceKey(int uid, String process) {
58 mUid = uid;
59 mProcess = process;
60 }
61
62 public boolean equals(Object o) {
63 if (!(o instanceof SourceKey)) {
64 return false;
65 }
66 SourceKey s = (SourceKey) o;
67 return s.mUid == mUid && Objects.equals(s.mProcess, mProcess);
68 }
69
70 @Override
71 public int hashCode() {
72 return Integer.hashCode(mUid) ^ (mProcess == null ? 0 : mProcess.hashCode());
73 }
74
75 @Override
76 public String toString() {
77 StringBuilder sb = new StringBuilder(64);
78 sb.append("SourceKey{");
79 UserHandle.formatUid(sb, mUid);
80 sb.append(' ');
81 sb.append(mProcess);
82 sb.append('}');
83 return sb.toString();
84 }
85
86 }
87
88 /**
89 * All known sources for this target component... uid -> process name -> source state.
90 */
91 private final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>();
92
93 private final SourceKey mTmpSourceKey = new SourceKey(0, null);
94
95 private int mNumActive;
96
97 public AssociationState(ProcessStats processStats, String pkg, String name,
98 String processName) {
99 mPackage = pkg;
100 mName = name;
101 mProcessName = processName;
102 mDurations = new DurationsTable(processStats.mTableData);
103 }
104
105 public String getPackage() {
106 return mPackage;
107 }
108
109 public String getProcessName() {
110 return mProcessName;
111 }
112
113 public String getName() {
114 return mName;
115 }
116
117 public SourceState startSource(int uid, String processName) {
118 mTmpSourceKey.mUid = uid;
119 mTmpSourceKey.mProcess = processName;
120 SourceState src = mSources.get(mTmpSourceKey);
121 if (src == null) {
122 src = new SourceState();
123 mSources.put(new SourceKey(uid, processName), src);
124 }
125 src.mNesting++;
126 if (src.mNesting == 1) {
127 src.mCount++;
128 src.mStartTime = SystemClock.uptimeMillis();
129 mNumActive++;
130 }
131 return src;
132 }
133
134 public void add(AssociationState other) {
135 mDurations.addDurations(other.mDurations);
136 for (int isrc = other.mSources.size() - 1; isrc >= 0; isrc--) {
137 final SourceKey key = other.mSources.keyAt(isrc);
138 final SourceState otherSrc = other.mSources.valueAt(isrc);
139 SourceState mySrc = mSources.get(key);
140 if (mySrc == null) {
141 mySrc = new SourceState();
142 mSources.put(key, mySrc);
143 }
144 mySrc.mCount += otherSrc.mCount;
145 mySrc.mDuration += otherSrc.mDuration;
146 }
147 }
148
149 public boolean isInUse() {
150 return mNumActive > 0;
151 }
152
153 public void resetSafely(long now) {
154 mDurations.resetTable();
155 if (!isInUse()) {
156 mSources.clear();
157 } else {
158 // We have some active sources... clear out everything but those.
159 for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
160 SourceState src = mSources.valueAt(isrc);
161 if (src.mNesting > 0) {
162 src.mCount = 1;
163 src.mStartTime = now;
164 src.mDuration = 0;
165 } else {
166 mSources.removeAt(isrc);
167 }
168 }
169 }
170 }
171
172 public void writeToParcel(ProcessStats stats, Parcel out, long now) {
173 mDurations.writeToParcel(out);
174 final int NSRC = mSources.size();
175 out.writeInt(NSRC);
176 for (int isrc = 0; isrc < NSRC; isrc++) {
177 final SourceKey key = mSources.keyAt(isrc);
178 final SourceState src = mSources.valueAt(isrc);
179 out.writeInt(key.mUid);
180 stats.writeCommonString(out, key.mProcess);
181 out.writeInt(src.mCount);
182 out.writeLong(src.mDuration);
183 }
184 }
185
186 public String readFromParcel(ProcessStats stats, Parcel in, int parcelVersion) {
187 if (!mDurations.readFromParcel(in)) {
188 return "Duration table corrupt";
189 }
190 final int NSRC = in.readInt();
191 if (NSRC < 0 || NSRC > 100000) {
192 return "Association with bad src count: " + NSRC;
193 }
194 for (int isrc = 0; isrc < NSRC; isrc++) {
195 final int uid = in.readInt();
196 final String procName = stats.readCommonString(in, parcelVersion);
197 final SourceKey key = new SourceKey(uid, procName);
198 final SourceState src = new SourceState();
199 src.mCount = in.readInt();
200 src.mDuration = in.readLong();
201 mSources.put(key, src);
202 }
203 return null;
204 }
205
206 public void commitStateTime(long now) {
207 if (isInUse()) {
208 for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
209 SourceState src = mSources.valueAt(isrc);
210 if (src.mNesting > 0) {
211 src.mDuration += now - src.mStartTime;
212 src.mStartTime = now;
213 }
214 }
215 }
216 }
217
218 public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix,
219 long now, long totalTime, boolean dumpSummary, boolean dumpAll) {
220 if (dumpAll) {
221 pw.print(prefix);
222 pw.print("mNumActive=");
223 pw.println(mNumActive);
224 }
225 final int NSRC = mSources.size();
226 for (int isrc = 0; isrc < NSRC; isrc++) {
227 final SourceKey key = mSources.keyAt(isrc);
228 final SourceState src = mSources.valueAt(isrc);
229 pw.print(prefixInner);
230 pw.print("<- ");
231 pw.print(key.mProcess);
232 pw.print(" / ");
233 UserHandle.formatUid(pw, key.mUid);
234 pw.println(":");
235 pw.print(prefixInner);
236 pw.print(" Count ");
237 pw.print(src.mCount);
238 long duration = src.mDuration;
239 if (src.mNesting > 0) {
240 duration += now - src.mStartTime;
241 }
242 if (dumpAll) {
243 pw.print(" / Duration ");
244 TimeUtils.formatDuration(duration, pw);
245 pw.print(" / ");
246 } else {
247 pw.print(" / time ");
248 }
249 DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
250 if (src.mNesting > 0) {
251 pw.print(" (running)");
252 }
253 pw.println();
254 }
255 }
256
257 public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers,
258 String associationName, long now) {
259 final int NSRC = mSources.size();
260 for (int isrc = 0; isrc < NSRC; isrc++) {
261 final SourceKey key = mSources.keyAt(isrc);
262 final SourceState src = mSources.valueAt(isrc);
263 pw.print("pkgasc");
264 pw.print(",");
265 pw.print(pkgName);
266 pw.print(",");
267 pw.print(uid);
268 pw.print(",");
269 pw.print(vers);
270 pw.print(",");
271 pw.print(associationName);
272 pw.print(",");
273 pw.print(key.mProcess);
274 pw.print(",");
275 pw.print(key.mUid);
276 pw.print(",");
277 pw.print(src.mCount);
278 long duration = src.mDuration;
279 if (src.mNesting > 0) {
280 duration += now - src.mStartTime;
281 }
282 pw.print(",");
283 pw.print(duration);
284 pw.println();
285 }
286 }
287
288 public String toString() {
289 return "AssociationState{" + Integer.toHexString(System.identityHashCode(this))
290 + " " + mName + " pkg=" + mPackage + " proc="
291 + Integer.toHexString(System.identityHashCode(this)) + "}";
292 }
293}