blob: 5128ae1f91309c3d1737e75b54d167a05457d3ca [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
Hui Yu03d12402018-12-06 18:00:37 -080019import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
20import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
21import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
22import static android.app.usage.UsageStatsManager.INTERVAL_MONTHLY;
23import static android.app.usage.UsageStatsManager.INTERVAL_WEEKLY;
24import static android.app.usage.UsageStatsManager.INTERVAL_YEARLY;
25
Adam Lesinski7f61e962014-09-02 16:43:52 -070026import android.app.usage.ConfigurationStats;
Suprabh Shukla60aa35b2018-04-24 18:52:46 -070027import android.app.usage.EventList;
Dianne Hackbornced54392018-02-26 13:07:42 -080028import android.app.usage.EventStats;
Adam Lesinski35168002014-07-21 15:25:30 -070029import android.app.usage.UsageEvents;
Hui Yu03d12402018-12-06 18:00:37 -080030import android.app.usage.UsageEvents.Event;
Adam Lesinski3c153512014-07-23 17:34:34 -070031import android.app.usage.UsageStats;
32import android.app.usage.UsageStatsManager;
Hui Yue361a232018-10-04 15:05:21 -070033import android.content.Context;
Adam Lesinski7f61e962014-09-02 16:43:52 -070034import android.content.res.Configuration;
Adam Lesinski66143fa2014-09-11 08:31:05 -070035import android.os.SystemClock;
Adam Lesinski1bb18c42014-08-18 12:21:34 -070036import android.text.format.DateUtils;
37import android.util.ArrayMap;
Adam Lesinski3c153512014-07-23 17:34:34 -070038import android.util.ArraySet;
39import android.util.Slog;
Hui Yu03d12402018-12-06 18:00:37 -080040import android.util.SparseIntArray;
Adam Lesinski3c153512014-07-23 17:34:34 -070041
Adam Lesinski1bb18c42014-08-18 12:21:34 -070042import com.android.internal.util.IndentingPrintWriter;
Adam Lesinski7f61e962014-09-02 16:43:52 -070043import com.android.server.usage.UsageStatsDatabase.StatCombiner;
44
Adam Lesinski3c153512014-07-23 17:34:34 -070045import java.io.File;
46import java.io.IOException;
47import java.text.SimpleDateFormat;
Adam Lesinski35168002014-07-21 15:25:30 -070048import java.util.ArrayList;
49import java.util.Arrays;
Adam Lesinski35168002014-07-21 15:25:30 -070050import java.util.List;
Adam Lesinski3c153512014-07-23 17:34:34 -070051
52/**
53 * A per-user UsageStatsService. All methods are meant to be called with the main lock held
54 * in UsageStatsService.
55 */
56class UserUsageStatsService {
57 private static final String TAG = "UsageStatsService";
58 private static final boolean DEBUG = UsageStatsService.DEBUG;
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -080059 private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Adam Lesinski1bb18c42014-08-18 12:21:34 -070060 private static final int sDateFormatFlags =
61 DateUtils.FORMAT_SHOW_DATE
62 | DateUtils.FORMAT_SHOW_TIME
63 | DateUtils.FORMAT_SHOW_YEAR
64 | DateUtils.FORMAT_NUMERIC_DATE;
Adam Lesinski3c153512014-07-23 17:34:34 -070065
Adam Lesinski1bb18c42014-08-18 12:21:34 -070066 private final Context mContext;
Adam Lesinski3c153512014-07-23 17:34:34 -070067 private final UsageStatsDatabase mDatabase;
Adam Lesinski35168002014-07-21 15:25:30 -070068 private final IntervalStats[] mCurrentStats;
Adam Lesinski3c153512014-07-23 17:34:34 -070069 private boolean mStatsChanged = false;
Adam Lesinskid26bea32014-09-03 16:49:59 -070070 private final UnixCalendar mDailyExpiryDate;
Adam Lesinski3c153512014-07-23 17:34:34 -070071 private final StatsUpdatedListener mListener;
72 private final String mLogPrefix;
Amith Yamasanibc813eb2018-03-20 19:37:46 -070073 private String mLastBackgroundedPackage;
Amith Yamasani55717a62015-04-03 17:22:36 -070074 private final int mUserId;
Adam Lesinski3c153512014-07-23 17:34:34 -070075
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -070076 // STOPSHIP: Temporary member variable for debugging b/110930764.
Hui Yu03d12402018-12-06 18:00:37 -080077 private Event mLastEvent;
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -070078
Adam Lesinski7cba1d42015-08-04 16:17:37 -070079 private static final long[] INTERVAL_LENGTH = new long[] {
80 UnixCalendar.DAY_IN_MILLIS, UnixCalendar.WEEK_IN_MILLIS,
81 UnixCalendar.MONTH_IN_MILLIS, UnixCalendar.YEAR_IN_MILLIS
82 };
83
Adam Lesinski3c153512014-07-23 17:34:34 -070084 interface StatsUpdatedListener {
85 void onStatsUpdated();
Adam Lesinskib2d3ffa2016-01-26 18:18:19 -080086 void onStatsReloaded();
Amith Yamasania93542f2016-02-03 18:02:06 -080087 /**
88 * Callback that a system update was detected
89 * @param mUserId user that needs to be initialized
90 */
91 void onNewUpdate(int mUserId);
Adam Lesinski3c153512014-07-23 17:34:34 -070092 }
93
Amith Yamasanib0ff3222015-03-04 09:56:14 -080094 UserUsageStatsService(Context context, int userId, File usageStatsDir,
95 StatsUpdatedListener listener) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -070096 mContext = context;
Adam Lesinskid26bea32014-09-03 16:49:59 -070097 mDailyExpiryDate = new UnixCalendar(0);
Adam Lesinski3c153512014-07-23 17:34:34 -070098 mDatabase = new UsageStatsDatabase(usageStatsDir);
Hui Yu03d12402018-12-06 18:00:37 -080099 mCurrentStats = new IntervalStats[INTERVAL_COUNT];
Adam Lesinski3c153512014-07-23 17:34:34 -0700100 mListener = listener;
101 mLogPrefix = "User[" + Integer.toString(userId) + "] ";
Amith Yamasani55717a62015-04-03 17:22:36 -0700102 mUserId = userId;
Adam Lesinski3c153512014-07-23 17:34:34 -0700103 }
104
Amith Yamasania93542f2016-02-03 18:02:06 -0800105 void init(final long currentTimeMillis) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700106 mDatabase.init(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700107
108 int nullCount = 0;
109 for (int i = 0; i < mCurrentStats.length; i++) {
110 mCurrentStats[i] = mDatabase.getLatestUsageStats(i);
111 if (mCurrentStats[i] == null) {
Adam Lesinski35168002014-07-21 15:25:30 -0700112 // Find out how many intervals we don't have data for.
113 // Ideally it should be all or none.
Adam Lesinski3c153512014-07-23 17:34:34 -0700114 nullCount++;
115 }
116 }
117
118 if (nullCount > 0) {
119 if (nullCount != mCurrentStats.length) {
120 // This is weird, but we shouldn't fail if something like this
121 // happens.
122 Slog.w(TAG, mLogPrefix + "Some stats have no latest available");
123 } else {
124 // This must be first boot.
125 }
126
127 // By calling loadActiveStats, we will
128 // generate new stats for each bucket.
Amith Yamasania93542f2016-02-03 18:02:06 -0800129 loadActiveStats(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700130 } else {
131 // Set up the expiry date to be one day from the latest daily stat.
132 // This may actually be today and we will rollover on the first event
133 // that is reported.
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700134 updateRolloverDeadline();
Adam Lesinski3c153512014-07-23 17:34:34 -0700135 }
136
Amith Yamasani55717a62015-04-03 17:22:36 -0700137 if (mDatabase.isNewUpdate()) {
Amith Yamasania93542f2016-02-03 18:02:06 -0800138 notifyNewUpdate();
Amith Yamasani55717a62015-04-03 17:22:36 -0700139 }
140 }
141
Amith Yamasania93542f2016-02-03 18:02:06 -0800142 void onTimeChanged(long oldTime, long newTime) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700143 persistActiveStats();
144 mDatabase.onTimeChanged(newTime - oldTime);
Amith Yamasania93542f2016-02-03 18:02:06 -0800145 loadActiveStats(newTime);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700146 }
147
Hui Yu03d12402018-12-06 18:00:37 -0800148 void reportEvent(Event event) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700149 if (DEBUG) {
Adam Lesinski9d960752014-08-25 14:48:12 -0700150 Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage
Adam Lesinski7f61e962014-09-02 16:43:52 -0700151 + "[" + event.mTimeStamp + "]: "
152 + eventToString(event.mEventType));
Adam Lesinski3c153512014-07-23 17:34:34 -0700153 }
154
Hui Yu03d12402018-12-06 18:00:37 -0800155 mLastEvent = new Event(event);
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700156
Adam Lesinski7f61e962014-09-02 16:43:52 -0700157 if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
Adam Lesinski3c153512014-07-23 17:34:34 -0700158 // Need to rollover
Amith Yamasania93542f2016-02-03 18:02:06 -0800159 rolloverStats(event.mTimeStamp);
Adam Lesinski3c153512014-07-23 17:34:34 -0700160 }
161
Hui Yu03d12402018-12-06 18:00:37 -0800162 final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
Adam Lesinski7f61e962014-09-02 16:43:52 -0700163
164 final Configuration newFullConfig = event.mConfiguration;
Hui Yu03d12402018-12-06 18:00:37 -0800165 if (event.mEventType == Event.CONFIGURATION_CHANGE
166 && currentDailyStats.activeConfiguration != null) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700167 // Make the event configuration a delta.
168 event.mConfiguration = Configuration.generateDelta(
169 currentDailyStats.activeConfiguration, newFullConfig);
Adam Lesinski35168002014-07-21 15:25:30 -0700170 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700171
Hui Yu03d12402018-12-06 18:00:37 -0800172 if (event.mEventType != Event.SYSTEM_INTERACTION
173 // ACTIVITY_DESTROYED is a private event. If there is preceding ACTIVITY_STOPPED
174 // ACTIVITY_DESTROYED will be dropped. Otherwise it will be converted to
175 // ACTIVITY_STOPPED.
176 && event.mEventType != Event.ACTIVITY_DESTROYED
177 // FLUSH_TO_DISK is a private event.
178 && event.mEventType != Event.FLUSH_TO_DISK) {
Michael Wachenschwanzc90bc152018-09-10 15:17:57 -0700179 currentDailyStats.addEvent(event);
Amith Yamasanib0ff3222015-03-04 09:56:14 -0800180 }
Adam Lesinski35168002014-07-21 15:25:30 -0700181
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700182 boolean incrementAppLaunch = false;
Hui Yu03d12402018-12-06 18:00:37 -0800183 if (event.mEventType == Event.ACTIVITY_RESUMED) {
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700184 if (event.mPackage != null && !event.mPackage.equals(mLastBackgroundedPackage)) {
185 incrementAppLaunch = true;
186 }
Hui Yu03d12402018-12-06 18:00:37 -0800187 } else if (event.mEventType == Event.ACTIVITY_PAUSED) {
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700188 if (event.mPackage != null) {
189 mLastBackgroundedPackage = event.mPackage;
190 }
191 }
192
Adam Lesinski35168002014-07-21 15:25:30 -0700193 for (IntervalStats stats : mCurrentStats) {
Dianne Hackbornced54392018-02-26 13:07:42 -0800194 switch (event.mEventType) {
Hui Yu03d12402018-12-06 18:00:37 -0800195 case Event.CONFIGURATION_CHANGE: {
Dianne Hackbornced54392018-02-26 13:07:42 -0800196 stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
197 } break;
Hui Yu03d12402018-12-06 18:00:37 -0800198 case Event.CHOOSER_ACTION: {
Dianne Hackbornced54392018-02-26 13:07:42 -0800199 stats.updateChooserCounts(event.mPackage, event.mContentType, event.mAction);
200 String[] annotations = event.mContentAnnotations;
201 if (annotations != null) {
202 for (String annotation : annotations) {
203 stats.updateChooserCounts(event.mPackage, annotation, event.mAction);
204 }
Kang Li53b43142016-11-14 14:38:25 -0800205 }
Dianne Hackbornced54392018-02-26 13:07:42 -0800206 } break;
Hui Yu03d12402018-12-06 18:00:37 -0800207 case Event.SCREEN_INTERACTIVE: {
Dianne Hackbornced54392018-02-26 13:07:42 -0800208 stats.updateScreenInteractive(event.mTimeStamp);
209 } break;
Hui Yu03d12402018-12-06 18:00:37 -0800210 case Event.SCREEN_NON_INTERACTIVE: {
Dianne Hackbornced54392018-02-26 13:07:42 -0800211 stats.updateScreenNonInteractive(event.mTimeStamp);
212 } break;
Hui Yu03d12402018-12-06 18:00:37 -0800213 case Event.KEYGUARD_SHOWN: {
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700214 stats.updateKeyguardShown(event.mTimeStamp);
215 } break;
Hui Yu03d12402018-12-06 18:00:37 -0800216 case Event.KEYGUARD_HIDDEN: {
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700217 stats.updateKeyguardHidden(event.mTimeStamp);
218 } break;
Dianne Hackbornced54392018-02-26 13:07:42 -0800219 default: {
Hui Yue361a232018-10-04 15:05:21 -0700220 stats.update(event.mPackage, event.getClassName(),
Hui Yu03d12402018-12-06 18:00:37 -0800221 event.mTimeStamp, event.mEventType, event.mInstanceId);
Dianne Hackbornced54392018-02-26 13:07:42 -0800222 if (incrementAppLaunch) {
223 stats.incrementAppLaunchCount(event.mPackage);
224 }
225 } break;
Adam Lesinski7f61e962014-09-02 16:43:52 -0700226 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700227 }
228
Amith Yamasanicf768722015-04-23 20:36:41 -0700229 notifyStatsChanged();
230 }
231
Adam Lesinski7f61e962014-09-02 16:43:52 -0700232 private static final StatCombiner<UsageStats> sUsageStatsCombiner =
233 new StatCombiner<UsageStats>() {
234 @Override
235 public void combine(IntervalStats stats, boolean mutable,
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700236 List<UsageStats> accResult) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700237 if (!mutable) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700238 accResult.addAll(stats.packageStats.values());
Adam Lesinski7f61e962014-09-02 16:43:52 -0700239 return;
240 }
241
Adam Lesinski37a46b42014-09-05 15:38:05 -0700242 final int statCount = stats.packageStats.size();
Adam Lesinski7f61e962014-09-02 16:43:52 -0700243 for (int i = 0; i < statCount; i++) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700244 accResult.add(new UsageStats(stats.packageStats.valueAt(i)));
Adam Lesinski7f61e962014-09-02 16:43:52 -0700245 }
246 }
247 };
248
249 private static final StatCombiner<ConfigurationStats> sConfigStatsCombiner =
250 new StatCombiner<ConfigurationStats>() {
251 @Override
252 public void combine(IntervalStats stats, boolean mutable,
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700253 List<ConfigurationStats> accResult) {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700254 if (!mutable) {
255 accResult.addAll(stats.configurations.values());
256 return;
257 }
258
259 final int configCount = stats.configurations.size();
260 for (int i = 0; i < configCount; i++) {
261 accResult.add(new ConfigurationStats(stats.configurations.valueAt(i)));
262 }
263 }
264 };
265
Dianne Hackbornced54392018-02-26 13:07:42 -0800266 private static final StatCombiner<EventStats> sEventStatsCombiner =
267 new StatCombiner<EventStats>() {
268 @Override
269 public void combine(IntervalStats stats, boolean mutable,
270 List<EventStats> accResult) {
271 stats.addEventStatsTo(accResult);
272 }
273 };
274
Adam Lesinski7f61e962014-09-02 16:43:52 -0700275 /**
276 * Generic query method that selects the appropriate IntervalStats for the specified time range
277 * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner}
278 * provided to select the stats to use from the IntervalStats object.
279 */
Adam Lesinskid26bea32014-09-03 16:49:59 -0700280 private <T> List<T> queryStats(int intervalType, final long beginTime, final long endTime,
Adam Lesinski7f61e962014-09-02 16:43:52 -0700281 StatCombiner<T> combiner) {
Hui Yu03d12402018-12-06 18:00:37 -0800282 if (intervalType == INTERVAL_BEST) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700283 intervalType = mDatabase.findBestFitBucket(beginTime, endTime);
284 if (intervalType < 0) {
285 // Nothing saved to disk yet, so every stat is just as equal (no rollover has
286 // occurred.
Hui Yu03d12402018-12-06 18:00:37 -0800287 intervalType = INTERVAL_DAILY;
Adam Lesinskid26bea32014-09-03 16:49:59 -0700288 }
Adam Lesinski35168002014-07-21 15:25:30 -0700289 }
290
Adam Lesinskid26bea32014-09-03 16:49:59 -0700291 if (intervalType < 0 || intervalType >= mCurrentStats.length) {
Adam Lesinski35168002014-07-21 15:25:30 -0700292 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700293 Slog.d(TAG, mLogPrefix + "Bad intervalType used " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700294 }
295 return null;
296 }
297
Adam Lesinskid26bea32014-09-03 16:49:59 -0700298 final IntervalStats currentStats = mCurrentStats[intervalType];
Adam Lesinski35168002014-07-21 15:25:30 -0700299
Adam Lesinski3c153512014-07-23 17:34:34 -0700300 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700301 Slog.d(TAG, mLogPrefix + "SELECT * FROM " + intervalType + " WHERE beginTime >= "
Adam Lesinski35168002014-07-21 15:25:30 -0700302 + beginTime + " AND endTime < " + endTime);
Adam Lesinski3c153512014-07-23 17:34:34 -0700303 }
304
Adam Lesinskid26bea32014-09-03 16:49:59 -0700305 if (beginTime >= currentStats.endTime) {
306 if (DEBUG) {
307 Slog.d(TAG, mLogPrefix + "Requesting stats after " + beginTime + " but latest is "
308 + currentStats.endTime);
309 }
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700310
311 // STOPSHIP: Temporary logging for b/110930764.
Hui Yu03d12402018-12-06 18:00:37 -0800312 if (intervalType == INTERVAL_DAILY
Michael Wachenschwanzbc9abc62018-07-19 12:02:19 -0700313 && mLastEvent != null && mLastEvent.mTimeStamp >= beginTime) {
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700314 final IntervalStats diskStats = mDatabase.getLatestUsageStats(
Hui Yu03d12402018-12-06 18:00:37 -0800315 INTERVAL_DAILY);
Michael Wachenschwanze4c818f2018-07-03 19:25:32 -0700316 StringBuilder sb = new StringBuilder(256);
317 sb.append("Last 24 hours of UsageStats missing! timeRange : ");
318 sb.append(beginTime);
319 sb.append(", ");
320 sb.append(endTime);
321 sb.append("\nLast reported Usage Event time : ");
322 sb.append(mLastEvent.mTimeStamp);
323 if (currentStats == null) {
324 sb.append("\nNo in memory event stats available.");
325 } else {
326 sb.append("\nLast in memory event time : ");
327 sb.append(currentStats.endTime);
328 sb.append("\nLast save time: ");
329 sb.append(currentStats.lastTimeSaved);
330 }
331 if (diskStats == null) {
332 sb.append("\nNo on disk event stats available.");
333 } else {
334 sb.append("\nLast on disk event time : ");
335 sb.append(diskStats.endTime);
336 }
337 Slog.wtf(TAG, sb.toString());
338 }
339
Adam Lesinskid26bea32014-09-03 16:49:59 -0700340 // Nothing newer available.
341 return null;
342 }
343
344 // Truncate the endTime to just before the in-memory stats. Then, we'll append the
345 // in-memory stats to the results (if necessary) so as to avoid writing to disk too
346 // often.
347 final long truncatedEndTime = Math.min(currentStats.beginTime, endTime);
348
349 // Get the stats from disk.
350 List<T> results = mDatabase.queryUsageStats(intervalType, beginTime,
351 truncatedEndTime, combiner);
Adam Lesinski3c153512014-07-23 17:34:34 -0700352 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700353 Slog.d(TAG, "Got " + (results != null ? results.size() : 0) + " results from disk");
354 Slog.d(TAG, "Current stats beginTime=" + currentStats.beginTime +
355 " endTime=" + currentStats.endTime);
356 }
357
358 // Now check if the in-memory stats match the range and add them if they do.
359 if (beginTime < currentStats.endTime && endTime > currentStats.beginTime) {
360 if (DEBUG) {
361 Slog.d(TAG, mLogPrefix + "Returning in-memory stats");
362 }
363
364 if (results == null) {
365 results = new ArrayList<>();
366 }
367 combiner.combine(currentStats, true, results);
368 }
369
370 if (DEBUG) {
371 Slog.d(TAG, mLogPrefix + "Results: " + (results != null ? results.size() : 0));
Adam Lesinski3c153512014-07-23 17:34:34 -0700372 }
373 return results;
374 }
375
Adam Lesinski7f61e962014-09-02 16:43:52 -0700376 List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) {
377 return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner);
378 }
379
380 List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) {
381 return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
382 }
383
Dianne Hackbornced54392018-02-26 13:07:42 -0800384 List<EventStats> queryEventStats(int bucketType, long beginTime, long endTime) {
385 return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
386 }
387
Makoto Onukiad623012017-05-15 09:29:34 -0700388 UsageEvents queryEvents(final long beginTime, final long endTime,
389 boolean obfuscateInstantApps) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700390 final ArraySet<String> names = new ArraySet<>();
Hui Yu03d12402018-12-06 18:00:37 -0800391 List<Event> results = queryStats(INTERVAL_DAILY,
392 beginTime, endTime, new StatCombiner<Event>() {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700393 @Override
394 public void combine(IntervalStats stats, boolean mutable,
Hui Yu03d12402018-12-06 18:00:37 -0800395 List<Event> accumulatedResult) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700396 if (stats.events == null) {
397 return;
398 }
Adam Lesinski35168002014-07-21 15:25:30 -0700399
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700400 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700401 final int size = stats.events.size();
402 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700403 if (stats.events.get(i).mTimeStamp >= endTime) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700404 return;
405 }
Adam Lesinski35168002014-07-21 15:25:30 -0700406
Hui Yu03d12402018-12-06 18:00:37 -0800407 Event event = stats.events.get(i);
Makoto Onukiad623012017-05-15 09:29:34 -0700408 if (obfuscateInstantApps) {
409 event = event.getObfuscatedIfInstantApp();
410 }
Hui Yu03d12402018-12-06 18:00:37 -0800411 if (event.mPackage != null) {
412 names.add(event.mPackage);
413 }
Adam Lesinskid26bea32014-09-03 16:49:59 -0700414 if (event.mClass != null) {
415 names.add(event.mClass);
416 }
417 accumulatedResult.add(event);
418 }
419 }
420 });
421
422 if (results == null || results.isEmpty()) {
423 return null;
Adam Lesinski35168002014-07-21 15:25:30 -0700424 }
425
Adam Lesinskid26bea32014-09-03 16:49:59 -0700426 String[] table = names.toArray(new String[names.size()]);
427 Arrays.sort(table);
428 return new UsageEvents(results, table);
Adam Lesinski35168002014-07-21 15:25:30 -0700429 }
430
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800431 UsageEvents queryEventsForPackage(final long beginTime, final long endTime,
432 final String packageName) {
433 final ArraySet<String> names = new ArraySet<>();
434 names.add(packageName);
Hui Yu03d12402018-12-06 18:00:37 -0800435 final List<Event> results = queryStats(INTERVAL_DAILY,
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800436 beginTime, endTime, (stats, mutable, accumulatedResult) -> {
437 if (stats.events == null) {
438 return;
439 }
440
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700441 final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800442 final int size = stats.events.size();
443 for (int i = startIndex; i < size; i++) {
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700444 if (stats.events.get(i).mTimeStamp >= endTime) {
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800445 return;
446 }
447
Hui Yu03d12402018-12-06 18:00:37 -0800448 final Event event = stats.events.get(i);
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800449 if (!packageName.equals(event.mPackage)) {
450 continue;
451 }
452 if (event.mClass != null) {
453 names.add(event.mClass);
454 }
455 accumulatedResult.add(event);
456 }
457 });
458
459 if (results == null || results.isEmpty()) {
460 return null;
461 }
462
463 final String[] table = names.toArray(new String[names.size()]);
464 Arrays.sort(table);
465 return new UsageEvents(results, table);
466 }
467
Adam Lesinski3c153512014-07-23 17:34:34 -0700468 void persistActiveStats() {
469 if (mStatsChanged) {
470 Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
471 try {
472 for (int i = 0; i < mCurrentStats.length; i++) {
473 mDatabase.putUsageStats(i, mCurrentStats[i]);
474 }
475 mStatsChanged = false;
476 } catch (IOException e) {
477 Slog.e(TAG, mLogPrefix + "Failed to persist active stats", e);
478 }
479 }
480 }
481
Amith Yamasania93542f2016-02-03 18:02:06 -0800482 private void rolloverStats(final long currentTimeMillis) {
Adam Lesinski66143fa2014-09-11 08:31:05 -0700483 final long startTime = SystemClock.elapsedRealtime();
Adam Lesinski3c153512014-07-23 17:34:34 -0700484 Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
485
Hui Yue361a232018-10-04 15:05:21 -0700486 // Finish any ongoing events with an END_OF_DAY or ROLLOVER_FOREGROUND_SERVICE event.
487 // Make a note of which components need a new CONTINUE_PREVIOUS_DAY or
488 // CONTINUING_FOREGROUND_SERVICE entry.
Adam Lesinski7f61e962014-09-02 16:43:52 -0700489 final Configuration previousConfig =
Hui Yu03d12402018-12-06 18:00:37 -0800490 mCurrentStats[INTERVAL_DAILY].activeConfiguration;
491 ArraySet<String> continuePkgs = new ArraySet<>();
492 ArrayMap<String, SparseIntArray> continueActivity =
Hui Yue361a232018-10-04 15:05:21 -0700493 new ArrayMap<>();
Hui Yu03d12402018-12-06 18:00:37 -0800494 ArrayMap<String, ArrayMap<String, Integer>> continueForegroundService =
Hui Yue361a232018-10-04 15:05:21 -0700495 new ArrayMap<>();
Adam Lesinski35168002014-07-21 15:25:30 -0700496 for (IntervalStats stat : mCurrentStats) {
Adam Lesinski37a46b42014-09-05 15:38:05 -0700497 final int pkgCount = stat.packageStats.size();
Adam Lesinski3c153512014-07-23 17:34:34 -0700498 for (int i = 0; i < pkgCount; i++) {
Hui Yue361a232018-10-04 15:05:21 -0700499 final UsageStats pkgStats = stat.packageStats.valueAt(i);
Hui Yu03d12402018-12-06 18:00:37 -0800500 if (pkgStats.mActivities.size() > 0
501 || !pkgStats.mForegroundServices.isEmpty()) {
502 if (pkgStats.mActivities.size() > 0) {
503 continueActivity.put(pkgStats.mPackageName,
504 pkgStats.mActivities);
Hui Yue361a232018-10-04 15:05:21 -0700505 stat.update(pkgStats.mPackageName, null,
506 mDailyExpiryDate.getTimeInMillis() - 1,
Hui Yu03d12402018-12-06 18:00:37 -0800507 Event.END_OF_DAY, 0);
Hui Yue361a232018-10-04 15:05:21 -0700508 }
Hui Yu03d12402018-12-06 18:00:37 -0800509 if (!pkgStats.mForegroundServices.isEmpty()) {
510 continueForegroundService.put(pkgStats.mPackageName,
511 pkgStats.mForegroundServices);
Hui Yue361a232018-10-04 15:05:21 -0700512 stat.update(pkgStats.mPackageName, null,
513 mDailyExpiryDate.getTimeInMillis() - 1,
Hui Yu03d12402018-12-06 18:00:37 -0800514 Event.ROLLOVER_FOREGROUND_SERVICE, 0);
Hui Yue361a232018-10-04 15:05:21 -0700515 }
Hui Yu03d12402018-12-06 18:00:37 -0800516 continuePkgs.add(pkgStats.mPackageName);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700517 notifyStatsChanged();
Adam Lesinski3c153512014-07-23 17:34:34 -0700518 }
519 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700520
Hui Yue361a232018-10-04 15:05:21 -0700521 stat.updateConfigurationStats(null,
522 mDailyExpiryDate.getTimeInMillis() - 1);
Dianne Hackbornced54392018-02-26 13:07:42 -0800523 stat.commitTime(mDailyExpiryDate.getTimeInMillis() - 1);
Adam Lesinski3c153512014-07-23 17:34:34 -0700524 }
525
526 persistActiveStats();
Adam Lesinski66143fa2014-09-11 08:31:05 -0700527 mDatabase.prune(currentTimeMillis);
Amith Yamasania93542f2016-02-03 18:02:06 -0800528 loadActiveStats(currentTimeMillis);
Adam Lesinski3c153512014-07-23 17:34:34 -0700529
Hui Yu03d12402018-12-06 18:00:37 -0800530 final int continueCount = continuePkgs.size();
Adam Lesinski3c153512014-07-23 17:34:34 -0700531 for (int i = 0; i < continueCount; i++) {
Hui Yu03d12402018-12-06 18:00:37 -0800532 String pkgName = continuePkgs.valueAt(i);
533 final long beginTime = mCurrentStats[INTERVAL_DAILY].beginTime;
Adam Lesinski35168002014-07-21 15:25:30 -0700534 for (IntervalStats stat : mCurrentStats) {
Hui Yu03d12402018-12-06 18:00:37 -0800535 if (continueActivity.containsKey(pkgName)) {
536 final SparseIntArray eventMap =
537 continueActivity.get(pkgName);
538 final int size = eventMap.size();
Hui Yue361a232018-10-04 15:05:21 -0700539 for (int j = 0; j < size; j++) {
Hui Yu03d12402018-12-06 18:00:37 -0800540 stat.update(pkgName, null, beginTime,
541 eventMap.valueAt(j), eventMap.keyAt(j));
Hui Yue361a232018-10-04 15:05:21 -0700542 }
543 }
Hui Yu03d12402018-12-06 18:00:37 -0800544 if (continueForegroundService.containsKey(pkgName)) {
545 final ArrayMap<String, Integer> eventMap =
546 continueForegroundService.get(pkgName);
547 final int size = eventMap.size();
Hui Yue361a232018-10-04 15:05:21 -0700548 for (int j = 0; j < size; j++) {
Hui Yu03d12402018-12-06 18:00:37 -0800549 stat.update(pkgName, eventMap.keyAt(j), beginTime,
550 eventMap.valueAt(j), 0);
Hui Yue361a232018-10-04 15:05:21 -0700551 }
552 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700553 stat.updateConfigurationStats(previousConfig, beginTime);
Adam Lesinski66143fa2014-09-11 08:31:05 -0700554 notifyStatsChanged();
Adam Lesinski3c153512014-07-23 17:34:34 -0700555 }
556 }
557 persistActiveStats();
558
Adam Lesinski66143fa2014-09-11 08:31:05 -0700559 final long totalTime = SystemClock.elapsedRealtime() - startTime;
Adam Lesinski3c153512014-07-23 17:34:34 -0700560 Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
561 + " milliseconds");
562 }
563
564 private void notifyStatsChanged() {
565 if (!mStatsChanged) {
566 mStatsChanged = true;
567 mListener.onStatsUpdated();
568 }
569 }
570
Amith Yamasania93542f2016-02-03 18:02:06 -0800571 private void notifyNewUpdate() {
572 mListener.onNewUpdate(mUserId);
573 }
574
575 private void loadActiveStats(final long currentTimeMillis) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700576 for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700577 final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
578 if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
579 currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
Adam Lesinski35168002014-07-21 15:25:30 -0700580 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700581 Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700582 sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +
Adam Lesinskid26bea32014-09-03 16:49:59 -0700583 ") for interval " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700584 }
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700585 mCurrentStats[intervalType] = stats;
Adam Lesinski3c153512014-07-23 17:34:34 -0700586 } else {
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700587 // No good fit remains.
Adam Lesinski35168002014-07-21 15:25:30 -0700588 if (DEBUG) {
Adam Lesinskid26bea32014-09-03 16:49:59 -0700589 Slog.d(TAG, "Creating new stats @ " +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700590 sDateFormat.format(currentTimeMillis) + "(" +
591 currentTimeMillis + ") for interval " + intervalType);
Adam Lesinski35168002014-07-21 15:25:30 -0700592 }
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700593
Adam Lesinskid26bea32014-09-03 16:49:59 -0700594 mCurrentStats[intervalType] = new IntervalStats();
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700595 mCurrentStats[intervalType].beginTime = currentTimeMillis;
596 mCurrentStats[intervalType].endTime = currentTimeMillis + 1;
Adam Lesinski3c153512014-07-23 17:34:34 -0700597 }
598 }
Adam Lesinskida4a3772016-01-07 18:24:53 -0800599
Adam Lesinski3c153512014-07-23 17:34:34 -0700600 mStatsChanged = false;
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700601 updateRolloverDeadline();
Adam Lesinskib2d3ffa2016-01-26 18:18:19 -0800602
603 // Tell the listener that the stats reloaded, which may have changed idle states.
604 mListener.onStatsReloaded();
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700605 }
606
607 private void updateRolloverDeadline() {
608 mDailyExpiryDate.setTimeInMillis(
Hui Yu03d12402018-12-06 18:00:37 -0800609 mCurrentStats[INTERVAL_DAILY].beginTime);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700610 mDailyExpiryDate.addDays(1);
Adam Lesinskid26bea32014-09-03 16:49:59 -0700611 Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " +
612 sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" +
Adam Lesinski7cba1d42015-08-04 16:17:37 -0700613 mDailyExpiryDate.getTimeInMillis() + ")");
Adam Lesinski3c153512014-07-23 17:34:34 -0700614 }
615
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700616 //
617 // -- DUMP related methods --
618 //
619
Amith Yamasania93542f2016-02-03 18:02:06 -0800620 void checkin(final IndentingPrintWriter pw) {
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700621 mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
622 @Override
623 public boolean checkin(IntervalStats stats) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800624 printIntervalStats(pw, stats, false, false, null);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700625 return true;
626 }
627 });
628 }
629
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700630 void dump(IndentingPrintWriter pw, String pkg) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800631 dump(pw, pkg, false);
632 }
633 void dump(IndentingPrintWriter pw, String pkg, boolean compact) {
634 printLast24HrEvents(pw, !compact, pkg);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700635 for (int interval = 0; interval < mCurrentStats.length; interval++) {
636 pw.print("In-memory ");
637 pw.print(intervalToString(interval));
638 pw.println(" stats");
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800639 printIntervalStats(pw, mCurrentStats[interval], !compact, true, pkg);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700640 }
641 }
642
643 private String formatDateTime(long dateTime, boolean pretty) {
644 if (pretty) {
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800645 return "\"" + sDateFormat.format(dateTime)+ "\"";
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700646 }
647 return Long.toString(dateTime);
648 }
649
650 private String formatElapsedTime(long elapsedTime, boolean pretty) {
651 if (pretty) {
652 return "\"" + DateUtils.formatElapsedTime(elapsedTime / 1000) + "\"";
653 }
654 return Long.toString(elapsedTime);
655 }
656
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800657
Hui Yu03d12402018-12-06 18:00:37 -0800658 void printEvent(IndentingPrintWriter pw, Event event, boolean prettyDates) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800659 pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
660 pw.printPair("type", eventToString(event.mEventType));
661 pw.printPair("package", event.mPackage);
662 if (event.mClass != null) {
663 pw.printPair("class", event.mClass);
664 }
665 if (event.mConfiguration != null) {
666 pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
667 }
668 if (event.mShortcutId != null) {
669 pw.printPair("shortcutId", event.mShortcutId);
670 }
Hui Yu03d12402018-12-06 18:00:37 -0800671 if (event.mEventType == Event.STANDBY_BUCKET_CHANGED) {
Amith Yamasani119be9a2018-02-18 22:23:00 -0800672 pw.printPair("standbyBucket", event.getStandbyBucket());
673 pw.printPair("reason", UsageStatsManager.reasonToString(event.getStandbyReason()));
Hui Yu03d12402018-12-06 18:00:37 -0800674 } else if (event.mEventType == Event.ACTIVITY_RESUMED
675 || event.mEventType == Event.ACTIVITY_PAUSED
676 || event.mEventType == Event.ACTIVITY_STOPPED) {
677 pw.printPair("instanceId", event.getInstanceId());
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800678 }
Hui Yu03d12402018-12-06 18:00:37 -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
Hui Yu03d12402018-12-06 18:00:37 -0800694 List<Event> events = queryStats(INTERVAL_DAILY,
695 beginTime, endTime, new StatCombiner<Event>() {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800696 @Override
697 public void combine(IntervalStats stats, boolean mutable,
Hui Yu03d12402018-12-06 18:00:37 -0800698 List<Event> accumulatedResult) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800699 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
Hui Yu03d12402018-12-06 18:00:37 -0800710 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();
Hui Yu03d12402018-12-06 18:00:37 -0800730 for (Event event : events) {
Michael Wachenschwanz78646e52018-02-27 15:54:27 -0800731 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);
Hui Yu03d12402018-12-06 18:00:37 -0800775 pw.printPair("totalTimeUsed",
Adam Lesinskic8e87292015-06-10 15:33:45 -0700776 formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
Hui Yu03d12402018-12-06 18:00:37 -0800777 pw.printPair("lastTimeUsed", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
778 pw.printPair("totalTimeVisible",
779 formatElapsedTime(usageStats.mTotalTimeVisible, prettyDates));
780 pw.printPair("lastTimeVisible",
781 formatDateTime(usageStats.mLastTimeVisible, prettyDates));
782 pw.printPair("totalTimeFS",
783 formatElapsedTime(usageStats.mTotalTimeForegroundServiceUsed, prettyDates));
784 pw.printPair("lastTimeFS",
785 formatDateTime(usageStats.mLastTimeForegroundServiceUsed, prettyDates));
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700786 pw.printPair("appLaunchCount", usageStats.mAppLaunchCount);
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700787 pw.println();
788 }
789 pw.decreaseIndent();
790
Kang Li53b43142016-11-14 14:38:25 -0800791 pw.println();
Kang Li53b43142016-11-14 14:38:25 -0800792 pw.println("ChooserCounts");
793 pw.increaseIndent();
794 for (UsageStats usageStats : pkgStats.values()) {
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700795 if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
796 continue;
797 }
Kang Li53b43142016-11-14 14:38:25 -0800798 pw.printPair("package", usageStats.mPackageName);
799 if (usageStats.mChooserCounts != null) {
800 final int chooserCountSize = usageStats.mChooserCounts.size();
801 for (int i = 0; i < chooserCountSize; i++) {
802 final String action = usageStats.mChooserCounts.keyAt(i);
803 final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
804 final int annotationSize = counts.size();
805 for (int j = 0; j < annotationSize; j++) {
806 final String key = counts.keyAt(j);
807 final int count = counts.valueAt(j);
808 if (count != 0) {
809 pw.printPair("ChooserCounts", action + ":" + key + " is " +
810 Integer.toString(count));
811 pw.println();
812 }
813 }
814 }
815 }
816 pw.println();
817 }
Amith Yamasani61d5fd72017-02-24 11:02:07 -0800818 pw.decreaseIndent();
Kang Li53b43142016-11-14 14:38:25 -0800819
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700820 if (pkg == null) {
821 pw.println("configurations");
822 pw.increaseIndent();
823 final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
824 final int configCount = configStats.size();
825 for (int i = 0; i < configCount; i++) {
826 final ConfigurationStats config = configStats.valueAt(i);
827 pw.printPair("config", Configuration.resourceQualifierString(
828 config.mConfiguration));
829 pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
830 pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
831 pw.printPair("count", config.mActivationCount);
832 pw.println();
833 }
834 pw.decreaseIndent();
Dianne Hackbornced54392018-02-26 13:07:42 -0800835 pw.println("event aggregations");
836 pw.increaseIndent();
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700837 printEventAggregation(pw, "screen-interactive", stats.interactiveTracker,
838 prettyDates);
839 printEventAggregation(pw, "screen-non-interactive", stats.nonInteractiveTracker,
840 prettyDates);
841 printEventAggregation(pw, "keyguard-shown", stats.keyguardShownTracker,
842 prettyDates);
843 printEventAggregation(pw, "keyguard-hidden", stats.keyguardHiddenTracker,
844 prettyDates);
Dianne Hackbornced54392018-02-26 13:07:42 -0800845 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700846 }
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700847
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800848 // The last 24 hours of events is already printed in the non checkin dump
849 // No need to repeat here.
Michael Wachenschwanz1088cbb2018-03-01 12:45:16 -0800850 if (!skipEvents) {
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800851 pw.println("events");
852 pw.increaseIndent();
Suprabh Shukla60aa35b2018-04-24 18:52:46 -0700853 final EventList events = stats.events;
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800854 final int eventCount = events != null ? events.size() : 0;
855 for (int i = 0; i < eventCount; i++) {
Hui Yu03d12402018-12-06 18:00:37 -0800856 final Event event = events.get(i);
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800857 if (pkg != null && !pkg.equals(event.mPackage)) {
858 continue;
859 }
860 printEvent(pw, event, prettyDates);
Dianne Hackbornc81983a2017-10-20 16:16:32 -0700861 }
Michael Wachenschwanz06e49402018-02-20 23:39:09 -0800862 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700863 }
864 pw.decreaseIndent();
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700865 }
866
867 private static String intervalToString(int interval) {
868 switch (interval) {
Hui Yu03d12402018-12-06 18:00:37 -0800869 case INTERVAL_DAILY:
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700870 return "daily";
Hui Yu03d12402018-12-06 18:00:37 -0800871 case INTERVAL_WEEKLY:
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700872 return "weekly";
Hui Yu03d12402018-12-06 18:00:37 -0800873 case INTERVAL_MONTHLY:
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700874 return "monthly";
Hui Yu03d12402018-12-06 18:00:37 -0800875 case INTERVAL_YEARLY:
Adam Lesinski1bb18c42014-08-18 12:21:34 -0700876 return "yearly";
877 default:
878 return "?";
879 }
880 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700881
882 private static String eventToString(int eventType) {
883 switch (eventType) {
Hui Yu03d12402018-12-06 18:00:37 -0800884 case Event.NONE:
Adam Lesinski3c153512014-07-23 17:34:34 -0700885 return "NONE";
Hui Yu03d12402018-12-06 18:00:37 -0800886 case Event.ACTIVITY_PAUSED:
887 return "ACTIVITY_PAUSED";
888 case Event.ACTIVITY_RESUMED:
889 return "ACTIVITY_RESUMED";
890 case Event.FOREGROUND_SERVICE_START:
Hui Yue361a232018-10-04 15:05:21 -0700891 return "FOREGROUND_SERVICE_START";
Hui Yu03d12402018-12-06 18:00:37 -0800892 case Event.FOREGROUND_SERVICE_STOP:
Hui Yue361a232018-10-04 15:05:21 -0700893 return "FOREGROUND_SERVICE_STOP";
Hui Yu03d12402018-12-06 18:00:37 -0800894 case Event.ACTIVITY_STOPPED:
895 return "ACTIVITY_STOPPED";
896 case Event.END_OF_DAY:
Adam Lesinski3c153512014-07-23 17:34:34 -0700897 return "END_OF_DAY";
Hui Yu03d12402018-12-06 18:00:37 -0800898 case Event.ROLLOVER_FOREGROUND_SERVICE:
Hui Yue361a232018-10-04 15:05:21 -0700899 return "ROLLOVER_FOREGROUND_SERVICE";
Hui Yu03d12402018-12-06 18:00:37 -0800900 case Event.CONTINUE_PREVIOUS_DAY:
Adam Lesinski3c153512014-07-23 17:34:34 -0700901 return "CONTINUE_PREVIOUS_DAY";
Hui Yu03d12402018-12-06 18:00:37 -0800902 case Event.CONTINUING_FOREGROUND_SERVICE:
Hui Yue361a232018-10-04 15:05:21 -0700903 return "CONTINUING_FOREGROUND_SERVICE";
Hui Yu03d12402018-12-06 18:00:37 -0800904 case Event.CONFIGURATION_CHANGE:
Adam Lesinski7f61e962014-09-02 16:43:52 -0700905 return "CONFIGURATION_CHANGE";
Hui Yu03d12402018-12-06 18:00:37 -0800906 case Event.SYSTEM_INTERACTION:
Adam Lesinskic8e87292015-06-10 15:33:45 -0700907 return "SYSTEM_INTERACTION";
Hui Yu03d12402018-12-06 18:00:37 -0800908 case Event.USER_INTERACTION:
Adam Lesinskic8e87292015-06-10 15:33:45 -0700909 return "USER_INTERACTION";
Hui Yu03d12402018-12-06 18:00:37 -0800910 case Event.SHORTCUT_INVOCATION:
Makoto Onukiac042502016-05-20 16:39:42 -0700911 return "SHORTCUT_INVOCATION";
Hui Yu03d12402018-12-06 18:00:37 -0800912 case Event.CHOOSER_ACTION:
Kang Li53b43142016-11-14 14:38:25 -0800913 return "CHOOSER_ACTION";
Hui Yu03d12402018-12-06 18:00:37 -0800914 case Event.NOTIFICATION_SEEN:
Amith Yamasani803eab692017-11-09 17:47:04 -0800915 return "NOTIFICATION_SEEN";
Hui Yu03d12402018-12-06 18:00:37 -0800916 case Event.STANDBY_BUCKET_CHANGED:
Amith Yamasanibfc4bf52018-01-19 06:55:08 -0800917 return "STANDBY_BUCKET_CHANGED";
Hui Yu03d12402018-12-06 18:00:37 -0800918 case Event.NOTIFICATION_INTERRUPTION:
Julia Reynolds1fac86e2018-03-07 08:30:37 -0500919 return "NOTIFICATION_INTERRUPTION";
Hui Yu03d12402018-12-06 18:00:37 -0800920 case Event.SLICE_PINNED:
Jason Monk1918ef72018-03-14 09:20:39 -0400921 return "SLICE_PINNED";
Hui Yu03d12402018-12-06 18:00:37 -0800922 case Event.SLICE_PINNED_PRIV:
Jason Monk1918ef72018-03-14 09:20:39 -0400923 return "SLICE_PINNED_PRIV";
Hui Yu03d12402018-12-06 18:00:37 -0800924 case Event.SCREEN_INTERACTIVE:
Dianne Hackbornced54392018-02-26 13:07:42 -0800925 return "SCREEN_INTERACTIVE";
Hui Yu03d12402018-12-06 18:00:37 -0800926 case Event.SCREEN_NON_INTERACTIVE:
Dianne Hackbornced54392018-02-26 13:07:42 -0800927 return "SCREEN_NON_INTERACTIVE";
Esteban Talavera917a71d2018-11-13 07:55:08 +0000928 case UsageEvents.Event.KEYGUARD_SHOWN:
929 return "KEYGUARD_SHOWN";
930 case UsageEvents.Event.KEYGUARD_HIDDEN:
931 return "KEYGUARD_HIDDEN";
Adam Lesinski3c153512014-07-23 17:34:34 -0700932 default:
Esteban Talavera917a71d2018-11-13 07:55:08 +0000933 return "UNKNOWN_TYPE_" + eventType;
Adam Lesinski3c153512014-07-23 17:34:34 -0700934 }
935 }
Ritesh Reddy8a6ce2c2015-12-17 17:03:54 +0000936
937 byte[] getBackupPayload(String key){
938 return mDatabase.getBackupPayload(key);
939 }
940
941 void applyRestoredPayload(String key, byte[] payload){
942 mDatabase.applyRestoredPayload(key, payload);
943 }
Adam Lesinski3c153512014-07-23 17:34:34 -0700944}