blob: 94d7dbb49b742e3fee0734ad0218443a850cc248 [file] [log] [blame]
Adam Lesinski35168002014-07-21 15:25:30 -07001/**
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
Adam Lesinski3c153512014-07-23 17:34:34 -070017package com.android.server.usage;
18
Adam Lesinski7f61e962014-09-02 16:43:52 -070019import android.app.usage.ConfigurationStats;
Suprabh Shukla60aa35b2018-04-24 18:52:46 -070020import android.app.usage.EventList;
Dianne Hackbornced54392018-02-26 13:07:42 -080021import android.app.usage.EventStats;
Adam Lesinski35168002014-07-21 15:25:30 -070022import android.app.usage.UsageEvents;
Adam Lesinski3c153512014-07-23 17:34:34 -070023import android.app.usage.UsageStats;
24import android.app.usage.UsageStatsManager;
Hui Yue361a232018-10-04 15:05:21 -070025import android.content.Context;
Adam Lesinski7f61e962014-09-02 16:43:52 -070026import android.content.res.Configuration;
Adam Lesinski66143fa2014-09-11 08:31:05 -070027import android.os.SystemClock;
Adam Lesinski1bb18c42014-08-18 12:21:34 -070028import android.text.format.DateUtils;
29import android.util.ArrayMap;
Adam Lesinski3c153512014-07-23 17:34:34 -070030import android.util.ArraySet;
31import android.util.Slog;
32
Adam Lesinski1bb18c42014-08-18 12:21:34 -070033import com.android.internal.util.IndentingPrintWriter;
Adam Lesinski7f61e962014-09-02 16:43:52 -070034import com.android.server.usage.UsageStatsDatabase.StatCombiner;
35
Adam Lesinski3c153512014-07-23 17:34:34 -070036import java.io.File;
37import java.io.IOException;
38import java.text.SimpleDateFormat;
Adam Lesinski35168002014-07-21 15:25:30 -070039import java.util.ArrayList;
40import java.util.Arrays;
Adam Lesinski35168002014-07-21 15:25:30 -070041import java.util.List;
Adam Lesinski3c153512014-07-23 17:34:34 -070042
43/**
44 * A per-user UsageStatsService. All methods are meant to be called with the main lock held
45 * in UsageStatsService.
46 */
47class UserUsageStatsService {
48 private static final String TAG = "UsageStatsService";
49 private static final boolean DEBUG = UsageStatsService.DEBUG;
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -080050 private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Adam Lesinski1bb18c42014-08-18 12:21:34 -070051 private static final int sDateFormatFlags =
52 DateUtils.FORMAT_SHOW_DATE
53 | DateUtils.FORMAT_SHOW_TIME
54 | DateUtils.FORMAT_SHOW_YEAR
55 | DateUtils.FORMAT_NUMERIC_DATE;
Adam Lesinski3c153512014-07-23 17:34:34 -070056
Adam Lesinski1bb18c42014-08-18 12:21:34 -070057 private final Context mContext;
Adam Lesinski3c153512014-07-23 17:34:34 -070058 private final UsageStatsDatabase mDatabase;
Adam Lesinski35168002014-07-21 15:25:30 -070059 private final IntervalStats[] mCurrentStats;
Adam Lesinski3c153512014-07-23 17:34:34 -070060 private boolean mStatsChanged = false;
Adam Lesinskid26bea32014-09-03 16:49:59 -070061 private final UnixCalendar mDailyExpiryDate;
Adam Lesinski3c153512014-07-23 17:34:34 -070062 private final StatsUpdatedListener mListener;
63 private final String mLogPrefix;
Amith Yamasanibc813eb2018-03-20 19:37:46 -070064 private String mLastBackgroundedPackage;
Amith Yamasani55717a62015-04-03 17:22:36 -070065 private final int mUserId;
Adam Lesinski3c153512014-07-23 17:34:34 -070066
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -070067 // STOPSHIP: Temporary member variable for debugging b/110930764.
68 private UsageEvents.Event mLastEvent;
69
Adam Lesinski7cba1d42015-08-04 16:17:37 -070070 private static final long[] INTERVAL_LENGTH = new long[] {
71 UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS,
72 UnixCalendar.MONTH_IN_MILLIS, UnixCalendar.YEAR_IN_MILLIS
73 };
74
Adam Lesinski3c153512014-07-23 17:34:34 -070075 interface StatsUpdatedListener {
76 void onStatsUpdated();
Adam Lesinskib2d3ffa2016-01-26 18:18:19 -080077 void onStatsReloaded();
Amith Yamasania93542f2016-02-03 18:02:06 -080078 /**
79 * Callback that a system update was detected
80 * @param mUserId user that needs to be initialized
81 */
82 void onNewUpdate(int mUserId);
Adam Lesinski3c153512014-07-23 17:34:34 -070083 }
84
Amith Yamasanib0ff3222015-03-04 09:56:14 -080085 UserUsageStatsService(Context context, int userId, File usageStatsDir,
86 StatsUpdatedListener listener) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -070087 mContext = context;
Adam Lesinskid26bea32014-09-03 16:49:59 -070088 mDailyExpiryDate = new UnixCalendar(0);
Adam Lesinski3c153512014-07-23 17:34:34 -070089 mDatabase = new UsageStatsDatabase(usageStatsDir);
Adam Lesinski35168002014-07-21 15:25:30 -070090 mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT];
Adam Lesinski3c153512014-07-23 17:34:34 -070091 mListener = listener;
92 mLogPrefix = "User[" + Integer.toString(userId) + "] ";
Amith Yamasani55717a62015-04-03 17:22:36 -070093 mUserId = userId;
Adam Lesinski3c153512014-07-23 17:34:34 -070094 }
95
Amith Yamasania93542f2016-02-03 18:02:06 -080096 void init(final long currentTimeMillis) {
Adam Lesinski66143fa2014-09-11 08:31:05 -070097 mDatabase.init(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -070098
99 int nullCount = 0;
100 for (int i = 0; i < mCurrentStats.length; i++) {
101 mCurrentStats[i] = mDatabase.getLatestUsageStats(i);
102 if (mCurrentStats[i] == null) {
Adam Lesinski35168002014-07-21 15:25:30 -0700103 // Find out how many intervals we don't have data for.
104 // Ideally it should be all or none.
Adam Lesinski3c153512014-07-23 17:34:34 -0700105 nullCount++;
106 }
107 }
108
109 if (nullCount > 0) {
110 if (nullCount != mCurrentStats.length) {
111 // This is weird, but we shouldn't fail if something like this
112 // happens.
113 Slog.w(TAG, mLogPrefix + "Some stats have no latest available");
114 } else {
115 // This must be first boot.
116 }
117
118 // By calling loadActiveStats, we will
119 // generate new stats for each bucket.
Amith Yamasania93542f2016-02-03 18:02:06 -0800120 loadActiveStats(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700121 } else {
122 // Set up the expiry date to be one day from the latest daily stat.
123 // This may actually be today and we will rollover on the first event
124 // that is reported.
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700125 updateRolloverDeadline();
Adam Lesinski3c153512014-07-23 17:34:34 -0700126 }
127
128 // Now close off any events that were open at the time this was saved.
Adam Lesinski35168002014-07-21 15:25:30 -0700129 for (IntervalStats stat : mCurrentStats) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700130 final int pkgCount = stat.packageStats.size();
Adam Lesinski3c153512014-07-23 17:34:34 -0700131 for (int i = 0; i < pkgCount; i++) {
Hui Yue361a232018-10-04 15:05:21 -0700132 final UsageStats pkgStats = stat.packageStats.valueAt(i);
133 if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()
134 || !pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
135 if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()) {
136 stat.update(pkgStats.mPackageName, null, stat.lastTimeSaved,
137 UsageEvents.Event.END_OF_DAY);
138 }
139 if (!pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
140 stat.update(pkgStats.mPackageName, null , stat.lastTimeSaved,
141 UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE);
142 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700143 notifyStatsChanged();
144 }
145 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700146
147 stat.updateConfigurationStats(null, stat.lastTimeSaved);
Adam Lesinski3c153512014-07-23 17:34:34 -0700148 }
Amith Yamasani55717a62015-04-03 17:22:36 -0700149
150 if (mDatabase.isNewUpdate()) {
Amith Yamasania93542f2016-02-03 18:02:06 -0800151 notifyNewUpdate();
Amith Yamasani55717a62015-04-03 17:22:36 -0700152 }
153 }
154
Amith Yamasania93542f2016-02-03 18:02:06 -0800155 void onTimeChanged(long oldTime, long newTime) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700156 persistActiveStats();
157 mDatabase.onTimeChanged(newTime - oldTime);
Amith Yamasania93542f2016-02-03 18:02:06 -0800158 loadActiveStats(newTime);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700159 }
160
Amith Yamasania93542f2016-02-03 18:02:06 -0800161 void reportEvent(UsageEvents.Event event) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700162 if (DEBUG) {
Adam Lesinski9d960752014-08-25 14:48:12 -0700163 Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage
Adam Lesinski7f61e962014-09-02 16:43:52 -0700164 + "[" + event.mTimeStamp + "]: "
165 + eventToString(event.mEventType));
Adam Lesinski3c153512014-07-23 17:34:34 -0700166 }
167
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700168 mLastEvent = new UsageEvents.Event(event);
169
Adam Lesinski7f61e962014-09-02 16:43:52 -0700170 if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700171 // Need to rollover
Amith Yamasania93542f2016-02-03 18:02:06 -0800172 rolloverStats(event.mTimeStamp);
Adam Lesinski3c153512014-07-23 17:34:34 -0700173 }
174
Adam Lesinski7f61e962014-09-02 16:43:52 -0700175 final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
176
177 final Configuration newFullConfig = event.mConfiguration;
178 if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE &&
179 currentDailyStats.activeConfiguration != null) {
180 // Make the event configuration a delta.
181 event.mConfiguration = Configuration.generateDelta(
182 currentDailyStats.activeConfiguration, newFullConfig);
Adam Lesinski35168002014-07-21 15:25:30 -0700183 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700184
Adam Lesinskic8e87292015-06-10 15:33:45 -0700185 if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) {
Michael Wachenschwanzc90bc152018-09-10 15:17:57 -0700186 currentDailyStats.addEvent(event);
Amith Yamasanib0ff3222015-03-04 09:56:14 -0800187 }
Adam Lesinski35168002014-07-21 15:25:30 -0700188
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700189 boolean incrementAppLaunch = false;
190 if (event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
191 if (event.mPackage != null && !event.mPackage.equals(mLastBackgroundedPackage)) {
192 incrementAppLaunch = true;
193 }
194 } else if (event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND) {
195 if (event.mPackage != null) {
196 mLastBackgroundedPackage = event.mPackage;
197 }
198 }
199
Adam Lesinski35168002014-07-21 15:25:30 -0700200 for (IntervalStats stats : mCurrentStats) {
Dianne Hackbornced54392018-02-26 13:07:42 -0800201 switch (event.mEventType) {
202 case UsageEvents.Event.CONFIGURATION_CHANGE: {
203 stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
204 } break;
205 case UsageEvents.Event.CHOOSER_ACTION: {
206 stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction);
207 String[] annotations = event.mContentAnnotations;
208 if (annotations != null) {
209 for (String annotation : annotations) {
210 stats.updateChooserCounts(event.mPackage, annotation, event.mAction);
211 }
Kang Li53b43142016-11-14 14:38:25 -0800212 }
Dianne Hackbornced54392018-02-26 13:07:42 -0800213 } break;
214 case UsageEvents.Event.SCREEN_INTERACTIVE: {
215 stats.updateScreenInteractive(event.mTimeStamp);
216 } break;
217 case UsageEvents.Event.SCREEN_NON_INTERACTIVE: {
218 stats.updateScreenNonInteractive(event.mTimeStamp);
219 } break;
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700220 case UsageEvents.Event.KEYGUARD_SHOWN: {
221 stats.updateKeyguardShown(event.mTimeStamp);
222 } break;
223 case UsageEvents.Event.KEYGUARD_HIDDEN: {
224 stats.updateKeyguardHidden(event.mTimeStamp);
225 } break;
Dianne Hackbornced54392018-02-26 13:07:42 -0800226 default: {
Hui Yue361a232018-10-04 15:05:21 -0700227 stats.update(event.mPackage, event.getClassName(),
228 event.mTimeStamp, event.mEventType);
Dianne Hackbornced54392018-02-26 13:07:42 -0800229 if (incrementAppLaunch) {
230 stats.incrementAppLaunchCount(event.mPackage);
231 }
232 } break;
Adam Lesinski7f61e962014-09-02 16:43:52 -0700233 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700234 }
235
Amith Yamasanicf768722015-04-23 20:36:41 -0700236 notifyStatsChanged();
237 }
238
Adam Lesinski7f61e962014-09-02 16:43:52 -0700239 private static final StatCombiner<UsageStats> sUsageStatsCombiner =
240 new StatCombiner<UsageStats>() {
241 @Override
242 public void combine(IntervalStats stats, boolean mutable,
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700243 List<UsageStats> accResult) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700244 if (!mutable) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700245 accResult.addAll(stats.packageStats.values());
Adam Lesinski7f61e962014-09-02 16:43:52 -0700246 return;
247 }
248
Adam Lesinski37a46b42014-09-05 15:38:05 -0700249 final int statCount = stats.packageStats.size();
Adam Lesinski7f61e962014-09-02 16:43:52 -0700250 for (int i = 0; i < statCount; i++) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700251 accResult.add(new UsageStats(stats.packageStats.valueAt(i)));
Adam Lesinski7f61e962014-09-02 16:43:52 -0700252 }
253 }
254 };
255
256 private static final StatCombiner<ConfigurationStats> sConfigStatsCombiner =
257 new StatCombiner<ConfigurationStats>() {
258 @Override
259 public void combine(IntervalStats stats, boolean mutable,
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700260 List<ConfigurationStats> accResult) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700261 if (!mutable) {
262 accResult.addAll(stats.configurations.values());
263 return;
264 }
265
266 final int configCount = stats.configurations.size();
267 for (int i = 0; i < configCount; i++) {
268 accResult.add(new ConfigurationStats(stats.configurations.valueAt(i)));
269 }
270 }
271 };
272
Dianne Hackbornced54392018-02-26 13:07:42 -0800273 private static final StatCombiner<EventStats> sEventStatsCombiner =
274 new StatCombiner<EventStats>() {
275 @Override
276 public void combine(IntervalStats stats, boolean mutable,
277 List<EventStats> accResult) {
278 stats.addEventStatsTo(accResult);
279 }
280 };
281
Adam Lesinski7f61e962014-09-02 16:43:52 -0700282 /**
283 * Generic query method that selects the appropriate IntervalStats for the specified time range
284 * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner}
285 * provided to select the stats to use from the IntervalStats object.
286 */
Adam Lesinskid26bea32014-09-03 16:49:59 -0700287 private <T> List<T> queryStats(int intervalType, final long beginTime, final long endTime,
Adam Lesinski7f61e962014-09-02 16:43:52 -0700288 StatCombiner<T> combiner) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700289 if (intervalType == UsageStatsManager.INTERVAL_BEST) {
290 intervalType = mDatabase.findBestFitBucket(beginTime, endTime);
291 if (intervalType < 0) {
292 // Nothing saved to disk yet, so every stat is just as equal (no rollover has
293 // occurred.
294 intervalType = UsageStatsManager.INTERVAL_DAILY;
295 }
Adam Lesinski35168002014-07-21 15:25:30 -0700296 }
297
Adam Lesinskid26bea32014-09-03 16:49:59 -0700298 if (intervalType < 0 || intervalType >= mCurrentStats.length) {
Adam Lesinski35168002014-07-21 15:25:30 -0700299 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700300 Slog.d(TAG, mLogPrefix + "Bad intervalType used " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700301 }
302 return null;
303 }
304
Adam Lesinskid26bea32014-09-03 16:49:59 -0700305 final IntervalStats currentStats = mCurrentStats[intervalType];
Adam Lesinski35168002014-07-21 15:25:30 -0700306
Adam Lesinski3c153512014-07-23 17:34:34 -0700307 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700308 Slog.d(TAG, mLogPrefix + "SELECT * FROM " + intervalType + " WHERE beginTime >= "
Adam Lesinski35168002014-07-21 15:25:30 -0700309 + beginTime + " AND endTime < " + endTime);
Adam Lesinski3c153512014-07-23 17:34:34 -0700310 }
311
Adam Lesinskid26bea32014-09-03 16:49:59 -0700312 if (beginTime >= currentStats.endTime) {
313 if (DEBUG) {
314 Slog.d(TAG, mLogPrefix + "Requesting stats after " + beginTime + " but latest is "
315 + currentStats.endTime);
316 }
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700317
318 // STOPSHIP: Temporary logging for b/110930764.
319 if (intervalType == UsageStatsManager.INTERVAL_DAILY
Michael Wachenschwanzbc9abc62018-07-19 12:02:19 -0700320 && mLastEvent != null && mLastEvent.mTimeStamp >= beginTime) {
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700321 final IntervalStats diskStats = mDatabase.getLatestUsageStats(
322 UsageStatsManager.INTERVAL_DAILY);
323 StringBuilder sb = new StringBuilder(256);
324 sb.append("Last 24 hours of UsageStats missing! timeRange : ");
325 sb.append(beginTime);
326 sb.append(", ");
327 sb.append(endTime);
328 sb.append("\nLast reported Usage Event time : ");
329 sb.append(mLastEvent.mTimeStamp);
330 if (currentStats == null) {
331 sb.append("\nNo in memory event stats available.");
332 } else {
333 sb.append("\nLast in memory event time : ");
334 sb.append(currentStats.endTime);
335 sb.append("\nLast save time: ");
336 sb.append(currentStats.lastTimeSaved);
337 }
338 if (diskStats == null) {
339 sb.append("\nNo on disk event stats available.");
340 } else {
341 sb.append("\nLast on disk event time : ");
342 sb.append(diskStats.endTime);
343 }
344 Slog.wtf(TAG, sb.toString());
345 }
346
Adam Lesinskid26bea32014-09-03 16:49:59 -0700347 // Nothing newer available.
348 return null;
349 }
350
351 // Truncate the endTime to just before the in-memory stats. Then, we'll append the
352 // in-memory stats to the results (if necessary) so as to avoid writing to disk too
353 // often.
354 final long truncatedEndTime = Math.min(currentStats.beginTime, endTime);
355
356 // Get the stats from disk.
357 List<T> results = mDatabase.queryUsageStats(intervalType, beginTime,
358 truncatedEndTime, combiner);
Adam Lesinski3c153512014-07-23 17:34:34 -0700359 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700360 Slog.d(TAG, "Got " + (results != null ? results.size() : 0) + " results from disk");
361 Slog.d(TAG, "Current stats beginTime=" + currentStats.beginTime +
362 " endTime=" + currentStats.endTime);
363 }
364
365 // Now check if the in-memory stats match the range and add them if they do.
366 if (beginTime < currentStats.endTime && endTime > currentStats.beginTime) {
367 if (DEBUG) {
368 Slog.d(TAG, mLogPrefix + "Returning in-memory stats");
369 }
370
371 if (results == null) {
372 results = new ArrayList<>();
373 }
374 combiner.combine(currentStats, true, results);
375 }
376
377 if (DEBUG) {
378 Slog.d(TAG, mLogPrefix + "Results: " + (results != null ? results.size() : 0));
Adam Lesinski3c153512014-07-23 17:34:34 -0700379 }
380 return results;
381 }
382
Adam Lesinski7f61e962014-09-02 16:43:52 -0700383 List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) {
384 return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner);
385 }
386
387 List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) {
388 return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
389 }
390
Dianne Hackbornced54392018-02-26 13:07:42 -0800391 List<EventStats> queryEventStats(int bucketType, long beginTime, long endTime) {
392 return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
393 }
394
Makoto Onukiad623012017-05-15 09:29:34 -0700395 UsageEvents queryEvents(final long beginTime, final long endTime,
396 boolean obfuscateInstantApps) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700397 final ArraySet<String> names = new ArraySet<>();
398 List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
399 beginTime, endTime, new StatCombiner<UsageEvents.Event>() {
400 @Override
401 public void combine(IntervalStats stats, boolean mutable,
402 List<UsageEvents.Event> accumulatedResult) {
403 if (stats.events == null) {
404 return;
405 }
Adam Lesinski35168002014-07-21 15:25:30 -0700406
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700407 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700408 final int size = stats.events.size();
409 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700410 if (stats.events.get(i).mTimeStamp >= endTime) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700411 return;
412 }
Adam Lesinski35168002014-07-21 15:25:30 -0700413
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700414 UsageEvents.Event event = stats.events.get(i);
Makoto Onukiad623012017-05-15 09:29:34 -0700415 if (obfuscateInstantApps) {
416 event = event.getObfuscatedIfInstantApp();
417 }
Adam Lesinskid26bea32014-09-03 16:49:59 -0700418 names.add(event.mPackage);
419 if (event.mClass != null) {
420 names.add(event.mClass);
421 }
422 accumulatedResult.add(event);
423 }
424 }
425 });
426
427 if (results == null || results.isEmpty()) {
428 return null;
Adam Lesinski35168002014-07-21 15:25:30 -0700429 }
430
Adam Lesinskid26bea32014-09-03 16:49:59 -0700431 String[] table = names.toArray(new String[names.size()]);
432 Arrays.sort(table);
433 return new UsageEvents(results, table);
Adam Lesinski35168002014-07-21 15:25:30 -0700434 }
435
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800436 UsageEvents queryEventsForPackage(final long beginTime, final long endTime,
437 final String packageName) {
438 final ArraySet<String> names = new ArraySet<>();
439 names.add(packageName);
440 final List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
441 beginTime, endTime, (stats, mutable, accumulatedResult) -> {
442 if (stats.events == null) {
443 return;
444 }
445
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700446 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800447 final int size = stats.events.size();
448 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700449 if (stats.events.get(i).mTimeStamp >= endTime) {
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800450 return;
451 }
452
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700453 final UsageEvents.Event event = stats.events.get(i);
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800454 if (!packageName.equals(event.mPackage)) {
455 continue;
456 }
457 if (event.mClass != null) {
458 names.add(event.mClass);
459 }
460 accumulatedResult.add(event);
461 }
462 });
463
464 if (results == null || results.isEmpty()) {
465 return null;
466 }
467
468 final String[] table = names.toArray(new String[names.size()]);
469 Arrays.sort(table);
470 return new UsageEvents(results, table);
471 }
472
Adam Lesinski3c153512014-07-23 17:34:34 -0700473 void persistActiveStats() {
474 if (mStatsChanged) {
475 Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
476 try {
477 for (int i = 0; i < mCurrentStats.length; i++) {
478 mDatabase.putUsageStats(i, mCurrentStats[i]);
479 }
480 mStatsChanged = false;
481 } catch (IOException e) {
482 Slog.e(TAG, mLogPrefix + "Failed to persist active stats", e);
483 }
484 }
485 }
486
Amith Yamasania93542f2016-02-03 18:02:06 -0800487 private void rolloverStats(final long currentTimeMillis) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700488 final long startTime = SystemClock.elapsedRealtime();
Adam Lesinski3c153512014-07-23 17:34:34 -0700489 Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
490
Hui Yue361a232018-10-04 15:05:21 -0700491 // Finish any ongoing events with an END_OF_DAY or ROLLOVER_FOREGROUND_SERVICE event.
492 // Make a note of which components need a new CONTINUE_PREVIOUS_DAY or
493 // CONTINUING_FOREGROUND_SERVICE entry.
Adam Lesinski7f61e962014-09-02 16:43:52 -0700494 final Configuration previousConfig =
495 mCurrentStats[UsageStatsManager.INTERVAL_DAILY].activeConfiguration;
Adam Lesinski3c153512014-07-23 17:34:34 -0700496 ArraySet<String> continuePreviousDay = new ArraySet<>();
Hui Yue361a232018-10-04 15:05:21 -0700497 ArrayMap<String, ArrayMap<String, Integer>> continuePreviousDayForegroundActivity =
498 new ArrayMap<>();
499 ArrayMap<String, ArrayMap<String, Integer>> continuePreviousDayForegroundService =
500 new ArrayMap<>();
Adam Lesinski35168002014-07-21 15:25:30 -0700501 for (IntervalStats stat : mCurrentStats) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700502 final int pkgCount = stat.packageStats.size();
Adam Lesinski3c153512014-07-23 17:34:34 -0700503 for (int i = 0; i < pkgCount; i++) {
Hui Yue361a232018-10-04 15:05:21 -0700504 final UsageStats pkgStats = stat.packageStats.valueAt(i);
505 if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()
506 || !pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
507 if (!pkgStats.mLastForegroundActivityEventMap.isEmpty()) {
508 continuePreviousDayForegroundActivity.put(pkgStats.mPackageName,
509 pkgStats.mLastForegroundActivityEventMap);
510 stat.update(pkgStats.mPackageName, null,
511 mDailyExpiryDate.getTimeInMillis() - 1,
512 UsageEvents.Event.END_OF_DAY);
513 }
514 if (!pkgStats.mLastForegroundServiceEventMap.isEmpty()) {
515 continuePreviousDayForegroundService.put(pkgStats.mPackageName,
516 pkgStats.mLastForegroundServiceEventMap);
517 stat.update(pkgStats.mPackageName, null,
518 mDailyExpiryDate.getTimeInMillis() - 1,
519 UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE);
520 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700521 continuePreviousDay.add(pkgStats.mPackageName);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700522 notifyStatsChanged();
Adam Lesinski3c153512014-07-23 17:34:34 -0700523 }
524 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700525
Hui Yue361a232018-10-04 15:05:21 -0700526 stat.updateConfigurationStats(null,
527 mDailyExpiryDate.getTimeInMillis() - 1);
Dianne Hackbornced54392018-02-26 13:07:42 -0800528 stat.commitTime(mDailyExpiryDate.getTimeInMillis() - 1);
Adam Lesinski3c153512014-07-23 17:34:34 -0700529 }
530
531 persistActiveStats();
Adam Lesinski66143fa2014-09-11 08:31:05 -0700532 mDatabase.prune(currentTimeMillis);
Amith Yamasania93542f2016-02-03 18:02:06 -0800533 loadActiveStats(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700534
535 final int continueCount = continuePreviousDay.size();
536 for (int i = 0; i < continueCount; i++) {
Hui Yue361a232018-10-04 15:05:21 -0700537 String pkgName = continuePreviousDay.valueAt(i);
Adam Lesinski7f61e962014-09-02 16:43:52 -0700538 final long beginTime = mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime;
Adam Lesinski35168002014-07-21 15:25:30 -0700539 for (IntervalStats stat : mCurrentStats) {
Hui Yue361a232018-10-04 15:05:21 -0700540 if (continuePreviousDayForegroundActivity.containsKey(pkgName)) {
541 final ArrayMap<String, Integer> foregroundActivityEventMap =
542 continuePreviousDayForegroundActivity.get(pkgName);
543 final int size = foregroundActivityEventMap.size();
544 for (int j = 0; j < size; j++) {
545 stat.update(pkgName, foregroundActivityEventMap.keyAt(j), beginTime,
546 UsageEvents.Event.CONTINUE_PREVIOUS_DAY);
547 }
548 }
549 if (continuePreviousDayForegroundService.containsKey(pkgName)) {
550 final ArrayMap<String, Integer> foregroundServiceEventMap =
551 continuePreviousDayForegroundService.get(pkgName);
552 final int size = foregroundServiceEventMap.size();
553 for (int j = 0; j < size; j++) {
554 stat.update(pkgName, foregroundServiceEventMap.keyAt(j), beginTime,
555 UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE);
556 }
557 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700558 stat.updateConfigurationStats(previousConfig, beginTime);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700559 notifyStatsChanged();
Adam Lesinski3c153512014-07-23 17:34:34 -0700560 }
561 }
562 persistActiveStats();
563
Adam Lesinski66143fa2014-09-11 08:31:05 -0700564 final long totalTime = SystemClock.elapsedRealtime() - startTime;
Adam Lesinski3c153512014-07-23 17:34:34 -0700565 Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
566 + " milliseconds");
567 }
568
569 private void notifyStatsChanged() {
570 if (!mStatsChanged) {
571 mStatsChanged = true;
572 mListener.onStatsUpdated();
573 }
574 }
575
Amith Yamasania93542f2016-02-03 18:02:06 -0800576 private void notifyNewUpdate() {
577 mListener.onNewUpdate(mUserId);
578 }
579
580 private void loadActiveStats(final long currentTimeMillis) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700581 for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700582 final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
583 if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
584 currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
Adam Lesinski35168002014-07-21 15:25:30 -0700585 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700586 Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700587 sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +
Adam Lesinskid26bea32014-09-03 16:49:59 -0700588 ") for interval " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700589 }
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700590 mCurrentStats[intervalType] = stats;
Adam Lesinski3c153512014-07-23 17:34:34 -0700591 } else {
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700592 // No good fit remains.
Adam Lesinski35168002014-07-21 15:25:30 -0700593 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700594 Slog.d(TAG, "Creating new stats @ " +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700595 sDateFormat.format(currentTimeMillis) + "(" +
596 currentTimeMillis + ") for interval " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700597 }
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700598
Adam Lesinskid26bea32014-09-03 16:49:59 -0700599 mCurrentStats[intervalType] = new IntervalStats();
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700600 mCurrentStats[intervalType].beginTime = currentTimeMillis;
601 mCurrentStats[intervalType].endTime = currentTimeMillis + 1;
Adam Lesinski3c153512014-07-23 17:34:34 -0700602 }
603 }
Adam Lesinskida4a3772016-01-07 18:24:53 -0800604
Adam Lesinski3c153512014-07-23 17:34:34 -0700605 mStatsChanged = false;
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700606 updateRolloverDeadline();
Adam Lesinskib2d3ffa2016-01-26 18:18:19 -0800607
608 // Tell the listener that the stats reloaded, which may have changed idle states.
609 mListener.onStatsReloaded();
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700610 }
611
612 private void updateRolloverDeadline() {
613 mDailyExpiryDate.setTimeInMillis(
614 mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700615 mDailyExpiryDate.addDays(1);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700616 Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " +
617 sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700618 mDailyExpiryDate.getTimeInMillis() + ")");
Adam Lesinski3c153512014-07-23 17:34:34 -0700619 }
620
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700621 //
622 // -- DUMP related methods --
623 //
624
Amith Yamasania93542f2016-02-03 18:02:06 -0800625 void checkin(final IndentingPrintWriter pw) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700626 mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
627 @Override
628 public boolean checkin(IntervalStats stats) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800629 printIntervalStats(pw, stats, false, false, null);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700630 return true;
631 }
632 });
633 }
634
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700635 void dump(IndentingPrintWriter pw, String pkg) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800636 dump(pw, pkg, false);
637 }
638 void dump(IndentingPrintWriter pw, String pkg, boolean compact) {
639 printLast24HrEvents(pw, !compact, pkg);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700640 for (int interval = 0; interval < mCurrentStats.length; interval++) {
641 pw.print("In-memory ");
642 pw.print(intervalToString(interval));
643 pw.println(" stats");
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800644 printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700645 }
646 }
647
648 private String formatDateTime(long dateTime, boolean pretty) {
649 if (pretty) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800650 return "\"" + sDateFormat.format(dateTime)+ "\"";
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700651 }
652 return Long.toString(dateTime);
653 }
654
655 private String formatElapsedTime(long elapsedTime, boolean pretty) {
656 if (pretty) {
657 return "\"" + DateUtils.formatElapsedTime(elapsedTime / 1000) + "\"";
658 }
659 return Long.toString(elapsedTime);
660 }
661
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800662
663 void printEvent(IndentingPrintWriter pw, UsageEvents.Event event, boolean prettyDates) {
664 pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
665 pw.printPair("type", eventToString(event.mEventType));
666 pw.printPair("package", event.mPackage);
667 if (event.mClass != null) {
668 pw.printPair("class", event.mClass);
669 }
670 if (event.mConfiguration != null) {
671 pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
672 }
673 if (event.mShortcutId != null) {
674 pw.printPair("shortcutId", event.mShortcutId);
675 }
676 if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800677 pw.printPair("standbyBucket", event.getStandbyBucket());
678 pw.printPair("reason", UsageStatsManager.reasonToString(event.getStandbyReason()));
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800679 }
Julia Reynolds5dc1edf2018-06-12 10:19:02 -0400680 if (event.mNotificationChannelId != null) {
681 pw.printPair("channelId", event.mNotificationChannelId);
682 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800683 pw.printHexPair("flags", event.mFlags);
684 pw.println();
685 }
686
687 void printLast24HrEvents(IndentingPrintWriter pw, boolean prettyDates, final String pkg) {
688 final long endTime = System.currentTimeMillis();
689 UnixCalendar yesterday = new UnixCalendar(endTime);
690 yesterday.addDays(-1);
691
692 final long beginTime = yesterday.getTimeInMillis();
693
694 List<UsageEvents.Event> events = queryStats(UsageStatsManager.INTERVAL_DAILY,
695 beginTime, endTime, new StatCombiner<UsageEvents.Event>() {
696 @Override
697 public void combine(IntervalStats stats, boolean mutable,
698 List<UsageEvents.Event> accumulatedResult) {
699 if (stats.events == null) {
700 return;
701 }
702
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700703 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800704 final int size = stats.events.size();
705 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700706 if (stats.events.get(i).mTimeStamp >= endTime) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800707 return;
708 }
709
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700710 UsageEvents.Event event = stats.events.get(i);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800711 if (pkg != null && !pkg.equals(event.mPackage)) {
712 continue;
713 }
714 accumulatedResult.add(event);
715 }
716 }
717 });
718
719 pw.print("Last 24 hour events (");
720 if (prettyDates) {
721 pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
722 beginTime, endTime, sDateFormatFlags) + "\"");
723 } else {
724 pw.printPair("beginTime", beginTime);
725 pw.printPair("endTime", endTime);
726 }
727 pw.println(")");
Michael Wachenschwanz78646e52018-02-27 15:54:27 -0800728 if (events != null) {
729 pw.increaseIndent();
730 for (UsageEvents.Event event : events) {
731 printEvent(pw, event, prettyDates);
732 }
733 pw.decreaseIndent();
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800734 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800735 }
736
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700737 void printEventAggregation(IndentingPrintWriter pw, String label,
738 IntervalStats.EventTracker tracker, boolean prettyDates) {
739 if (tracker.count != 0 || tracker.duration != 0) {
Dianne Hackbornced54392018-02-26 13:07:42 -0800740 pw.print(label);
741 pw.print(": ");
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700742 pw.print(tracker.count);
Dianne Hackbornced54392018-02-26 13:07:42 -0800743 pw.print("x for ");
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700744 pw.print(formatElapsedTime(tracker.duration, prettyDates));
745 if (tracker.curStartTime != 0) {
746 pw.print(" (now running, started at ");
747 formatDateTime(tracker.curStartTime, prettyDates);
748 pw.print(")");
749 }
Dianne Hackbornced54392018-02-26 13:07:42 -0800750 pw.println();
751 }
752 }
753
Amith Yamasania93542f2016-02-03 18:02:06 -0800754 void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800755 boolean prettyDates, boolean skipEvents, String pkg) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700756 if (prettyDates) {
757 pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
758 stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
759 } else {
760 pw.printPair("beginTime", stats.beginTime);
761 pw.printPair("endTime", stats.endTime);
762 }
763 pw.println();
764 pw.increaseIndent();
765 pw.println("packages");
766 pw.increaseIndent();
767 final ArrayMap<String, UsageStats> pkgStats = stats.packageStats;
768 final int pkgCount = pkgStats.size();
769 for (int i = 0; i < pkgCount; i++) {
770 final UsageStats usageStats = pkgStats.valueAt(i);
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700771 if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
772 continue;
773 }
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700774 pw.printPair("package", usageStats.mPackageName);
Adam Lesinskic8e87292015-06-10 15:33:45 -0700775 pw.printPair("totalTime",
776 formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700777 pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700778 pw.printPair("appLaunchCount", usageStats.mAppLaunchCount);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700779 pw.println();
780 }
781 pw.decreaseIndent();
782
Kang Li53b43142016-11-14 14:38:25 -0800783 pw.println();
Kang Li53b43142016-11-14 14:38:25 -0800784 pw.println("ChooserCounts");
785 pw.increaseIndent();
786 for (UsageStats usageStats : pkgStats.values()) {
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700787 if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
788 continue;
789 }
Kang Li53b43142016-11-14 14:38:25 -0800790 pw.printPair("package", usageStats.mPackageName);
791 if (usageStats.mChooserCounts != null) {
792 final int chooserCountSize = usageStats.mChooserCounts.size();
793 for (int i = 0; i < chooserCountSize; i++) {
794 final String action = usageStats.mChooserCounts.keyAt(i);
795 final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
796 final int annotationSize = counts.size();
797 for (int j = 0; j < annotationSize; j++) {
798 final String key = counts.keyAt(j);
799 final int count = counts.valueAt(j);
800 if (count != 0) {
801 pw.printPair("ChooserCounts", action + ":" + key + " is " +
802 Integer.toString(count));
803 pw.println();
804 }
805 }
806 }
807 }
808 pw.println();
809 }
Amith Yamasani61d5fd72017-02-24 11:02:07 -0800810 pw.decreaseIndent();
Kang Li53b43142016-11-14 14:38:25 -0800811
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700812 if (pkg == null) {
813 pw.println("configurations");
814 pw.increaseIndent();
815 final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
816 final int configCount = configStats.size();
817 for (int i = 0; i < configCount; i++) {
818 final ConfigurationStats config = configStats.valueAt(i);
819 pw.printPair("config", Configuration.resourceQualifierString(
820 config.mConfiguration));
821 pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
822 pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
823 pw.printPair("count", config.mActivationCount);
824 pw.println();
825 }
826 pw.decreaseIndent();
Dianne Hackbornced54392018-02-26 13:07:42 -0800827 pw.println("event aggregations");
828 pw.increaseIndent();
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700829 printEventAggregation(pw, "screen-interactive", stats.interactiveTracker,
830 prettyDates);
831 printEventAggregation(pw, "screen-non-interactive", stats.nonInteractiveTracker,
832 prettyDates);
833 printEventAggregation(pw, "keyguard-shown", stats.keyguardShownTracker,
834 prettyDates);
835 printEventAggregation(pw, "keyguard-hidden", stats.keyguardHiddenTracker,
836 prettyDates);
Dianne Hackbornced54392018-02-26 13:07:42 -0800837 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700838 }
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700839
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800840 // The last 24 hours of events is already printed in the non checkin dump
841 // No need to repeat here.
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800842 if (!skipEvents) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800843 pw.println("events");
844 pw.increaseIndent();
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700845 final EventList events = stats.events;
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800846 final int eventCount = events != null ? events.size() : 0;
847 for (int i = 0; i < eventCount; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700848 final UsageEvents.Event event = events.get(i);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800849 if (pkg != null && !pkg.equals(event.mPackage)) {
850 continue;
851 }
852 printEvent(pw, event, prettyDates);
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700853 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800854 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700855 }
856 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700857 }
858
859 private static String intervalToString(int interval) {
860 switch (interval) {
861 case UsageStatsManager.INTERVAL_DAILY:
862 return "daily";
863 case UsageStatsManager.INTERVAL_WEEKLY:
864 return "weekly";
865 case UsageStatsManager.INTERVAL_MONTHLY:
866 return "monthly";
867 case UsageStatsManager.INTERVAL_YEARLY:
868 return "yearly";
869 default:
870 return "?";
871 }
872 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700873
874 private static String eventToString(int eventType) {
875 switch (eventType) {
Adam Lesinski35168002014-07-21 15:25:30 -0700876 case UsageEvents.Event.NONE:
Adam Lesinski3c153512014-07-23 17:34:34 -0700877 return "NONE";
Adam Lesinski35168002014-07-21 15:25:30 -0700878 case UsageEvents.Event.MOVE_TO_BACKGROUND:
Adam Lesinski3c153512014-07-23 17:34:34 -0700879 return "MOVE_TO_BACKGROUND";
Adam Lesinski35168002014-07-21 15:25:30 -0700880 case UsageEvents.Event.MOVE_TO_FOREGROUND:
Adam Lesinski3c153512014-07-23 17:34:34 -0700881 return "MOVE_TO_FOREGROUND";
Hui Yue361a232018-10-04 15:05:21 -0700882 case UsageEvents.Event.FOREGROUND_SERVICE_START:
883 return "FOREGROUND_SERVICE_START";
884 case UsageEvents.Event.FOREGROUND_SERVICE_STOP:
885 return "FOREGROUND_SERVICE_STOP";
Adam Lesinski35168002014-07-21 15:25:30 -0700886 case UsageEvents.Event.END_OF_DAY:
Adam Lesinski3c153512014-07-23 17:34:34 -0700887 return "END_OF_DAY";
Hui Yue361a232018-10-04 15:05:21 -0700888 case UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE:
889 return "ROLLOVER_FOREGROUND_SERVICE";
Adam Lesinski35168002014-07-21 15:25:30 -0700890 case UsageEvents.Event.CONTINUE_PREVIOUS_DAY:
Adam Lesinski3c153512014-07-23 17:34:34 -0700891 return "CONTINUE_PREVIOUS_DAY";
Hui Yue361a232018-10-04 15:05:21 -0700892 case UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE:
893 return "CONTINUING_FOREGROUND_SERVICE";
Adam Lesinski7f61e962014-09-02 16:43:52 -0700894 case UsageEvents.Event.CONFIGURATION_CHANGE:
895 return "CONFIGURATION_CHANGE";
Adam Lesinskic8e87292015-06-10 15:33:45 -0700896 case UsageEvents.Event.SYSTEM_INTERACTION:
897 return "SYSTEM_INTERACTION";
898 case UsageEvents.Event.USER_INTERACTION:
899 return "USER_INTERACTION";
Makoto Onukiac042502016-05-20 16:39:42 -0700900 case UsageEvents.Event.SHORTCUT_INVOCATION:
901 return "SHORTCUT_INVOCATION";
Kang Li53b43142016-11-14 14:38:25 -0800902 case UsageEvents.Event.CHOOSER_ACTION:
903 return "CHOOSER_ACTION";
Amith Yamasani803eab692017-11-09 17:47:04 -0800904 case UsageEvents.Event.NOTIFICATION_SEEN:
905 return "NOTIFICATION_SEEN";
Amith Yamasanibfc4bf52018-01-19 06:55:08 -0800906 case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
907 return "STANDBY_BUCKET_CHANGED";
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500908 case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
909 return "NOTIFICATION_INTERRUPTION";
Jason Monk1918ef72018-03-14 09:20:39 -0400910 case UsageEvents.Event.SLICE_PINNED:
911 return "SLICE_PINNED";
912 case UsageEvents.Event.SLICE_PINNED_PRIV:
913 return "SLICE_PINNED_PRIV";
Dianne Hackbornced54392018-02-26 13:07:42 -0800914 case UsageEvents.Event.SCREEN_INTERACTIVE:
915 return "SCREEN_INTERACTIVE";
916 case UsageEvents.Event.SCREEN_NON_INTERACTIVE:
917 return "SCREEN_NON_INTERACTIVE";
Esteban Talavera917a71d2018-11-13 07:55:08 +0000918 case UsageEvents.Event.KEYGUARD_SHOWN:
919 return "KEYGUARD_SHOWN";
920 case UsageEvents.Event.KEYGUARD_HIDDEN:
921 return "KEYGUARD_HIDDEN";
Adam Lesinski3c153512014-07-23 17:34:34 -0700922 default:
Esteban Talavera917a71d2018-11-13 07:55:08 +0000923 return "UNKNOWN_TYPE_" + eventType;
Adam Lesinski3c153512014-07-23 17:34:34 -0700924 }
925 }
Ritesh Reddy8a6ce2c2015-12-17 17:03:54 +0000926
927 byte[] getBackupPayload(String key){
928 return mDatabase.getBackupPayload(key);
929 }
930
931 void applyRestoredPayload(String key, byte[] payload){
932 mDatabase.applyRestoredPayload(key, payload);
933 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700934}