13516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/** 23516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Copyright (C) 2014 The Android Open Source Project 33516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 43516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not 53516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * use this file except in compliance with the License. You may obtain a copy 63516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * of the License at 73516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 83516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 93516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * 103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Unless required by applicable law or agreed to in writing, software 113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * License for the specific language governing permissions and limitations 143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * under the License. 153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */ 163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 173c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskipackage com.android.server.usage; 183c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 197f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.app.usage.ConfigurationStats; 203516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.TimeSparseArray; 213516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents; 223c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport android.app.usage.UsageStats; 233c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport android.app.usage.UsageStatsManager; 247f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.content.res.Configuration; 2566143fa5b34eea7413335111838fb692987b611aAdam Lesinskiimport android.os.SystemClock; 261bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinskiimport android.content.Context; 271bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinskiimport android.text.format.DateUtils; 281bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinskiimport android.util.ArrayMap; 293c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport android.util.ArraySet; 303c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport android.util.Slog; 313c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 321bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinskiimport com.android.internal.util.IndentingPrintWriter; 337f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport com.android.server.usage.UsageStatsDatabase.StatCombiner; 347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 353c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport java.io.File; 363c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport java.io.IOException; 373c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiimport java.text.SimpleDateFormat; 383516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.util.ArrayList; 393516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.util.Arrays; 403516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.util.List; 413c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 423c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski/** 433c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * A per-user UsageStatsService. All methods are meant to be called with the main lock held 443c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski * in UsageStatsService. 453c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski */ 463c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinskiclass UserUsageStatsService { 473c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private static final String TAG = "UsageStatsService"; 483c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private static final boolean DEBUG = UsageStatsService.DEBUG; 493c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 501bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski private static final int sDateFormatFlags = 511bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski DateUtils.FORMAT_SHOW_DATE 521bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski | DateUtils.FORMAT_SHOW_TIME 531bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski | DateUtils.FORMAT_SHOW_YEAR 541bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski | DateUtils.FORMAT_NUMERIC_DATE; 553c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 561bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski private final Context mContext; 573c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private final UsageStatsDatabase mDatabase; 583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski private final IntervalStats[] mCurrentStats; 593c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private boolean mStatsChanged = false; 60d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski private final UnixCalendar mDailyExpiryDate; 613c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private final StatsUpdatedListener mListener; 623c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private final String mLogPrefix; 633c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 643c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski interface StatsUpdatedListener { 653c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski void onStatsUpdated(); 663c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 673c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 681bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski UserUsageStatsService(Context context, int userId, File usageStatsDir, StatsUpdatedListener listener) { 691bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski mContext = context; 70d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mDailyExpiryDate = new UnixCalendar(0); 713c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mDatabase = new UsageStatsDatabase(usageStatsDir); 723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT]; 733c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mListener = listener; 743c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mLogPrefix = "User[" + Integer.toString(userId) + "] "; 753c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 763c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 7766143fa5b34eea7413335111838fb692987b611aAdam Lesinski void init(final long currentTimeMillis) { 7866143fa5b34eea7413335111838fb692987b611aAdam Lesinski mDatabase.init(currentTimeMillis); 793c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 803c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski int nullCount = 0; 813c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski for (int i = 0; i < mCurrentStats.length; i++) { 823c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mCurrentStats[i] = mDatabase.getLatestUsageStats(i); 833c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (mCurrentStats[i] == null) { 843516800b611a79339a3c188332d13a26e9086b09Adam Lesinski // Find out how many intervals we don't have data for. 853516800b611a79339a3c188332d13a26e9086b09Adam Lesinski // Ideally it should be all or none. 863c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski nullCount++; 873c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 883c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 893c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 903c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (nullCount > 0) { 913c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (nullCount != mCurrentStats.length) { 923c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // This is weird, but we shouldn't fail if something like this 933c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // happens. 943c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski Slog.w(TAG, mLogPrefix + "Some stats have no latest available"); 953c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } else { 963c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // This must be first boot. 973c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 983c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 993c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // By calling loadActiveStats, we will 1003c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // generate new stats for each bucket. 10166143fa5b34eea7413335111838fb692987b611aAdam Lesinski loadActiveStats(currentTimeMillis, false); 1023c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } else { 1033c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // Set up the expiry date to be one day from the latest daily stat. 1043c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // This may actually be today and we will rollover on the first event 1053c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // that is reported. 1063c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mDailyExpiryDate.setTimeInMillis( 1073516800b611a79339a3c188332d13a26e9086b09Adam Lesinski mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime); 108d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mDailyExpiryDate.addDays(1); 109d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mDailyExpiryDate.truncateToDay(); 110d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " + 111d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + 112d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski "(" + mDailyExpiryDate.getTimeInMillis() + ")"); 1133c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1143c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 1153c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // Now close off any events that were open at the time this was saved. 1163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski for (IntervalStats stat : mCurrentStats) { 11737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final int pkgCount = stat.packageStats.size(); 1183c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski for (int i = 0; i < pkgCount; i++) { 11937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski UsageStats pkgStats = stat.packageStats.valueAt(i); 1203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND || 1213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) { 1223516800b611a79339a3c188332d13a26e9086b09Adam Lesinski stat.update(pkgStats.mPackageName, stat.lastTimeSaved, 1233516800b611a79339a3c188332d13a26e9086b09Adam Lesinski UsageEvents.Event.END_OF_DAY); 1243c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski notifyStatsChanged(); 1253c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1263c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1277f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stat.updateConfigurationStats(null, stat.lastTimeSaved); 1293c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1303c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1313c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 13266143fa5b34eea7413335111838fb692987b611aAdam Lesinski void onTimeChanged(long oldTime, long newTime) { 13366143fa5b34eea7413335111838fb692987b611aAdam Lesinski persistActiveStats(); 13466143fa5b34eea7413335111838fb692987b611aAdam Lesinski mDatabase.onTimeChanged(newTime - oldTime); 13566143fa5b34eea7413335111838fb692987b611aAdam Lesinski loadActiveStats(newTime, true); 13666143fa5b34eea7413335111838fb692987b611aAdam Lesinski } 13766143fa5b34eea7413335111838fb692987b611aAdam Lesinski 1383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski void reportEvent(UsageEvents.Event event) { 1393c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (DEBUG) { 1409d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage 1417f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski + "[" + event.mTimeStamp + "]: " 1427f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski + eventToString(event.mEventType)); 1433c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1443c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 1457f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) { 1463c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // Need to rollover 14766143fa5b34eea7413335111838fb692987b611aAdam Lesinski rolloverStats(event.mTimeStamp); 1483c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1493c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 1507f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY]; 1517f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1527f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final Configuration newFullConfig = event.mConfiguration; 1537f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE && 1547f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski currentDailyStats.activeConfiguration != null) { 1557f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski // Make the event configuration a delta. 1567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski event.mConfiguration = Configuration.generateDelta( 1577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski currentDailyStats.activeConfiguration, newFullConfig); 1587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1597f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1607f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski // Add the event to the daily list. 1617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (currentDailyStats.events == null) { 1627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski currentDailyStats.events = new TimeSparseArray<>(); 1633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski currentDailyStats.events.put(event.mTimeStamp, event); 1653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1663516800b611a79339a3c188332d13a26e9086b09Adam Lesinski for (IntervalStats stats : mCurrentStats) { 1677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) { 1687f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stats.updateConfigurationStats(newFullConfig, event.mTimeStamp); 1697f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } else { 1707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stats.update(event.mPackage, event.mTimeStamp, event.mEventType); 1717f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1723c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1733c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 1743c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski notifyStatsChanged(); 1753c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 1763c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 1777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static final StatCombiner<UsageStats> sUsageStatsCombiner = 1787f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski new StatCombiner<UsageStats>() { 1797f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski @Override 1807f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski public void combine(IntervalStats stats, boolean mutable, 1817f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski List<UsageStats> accResult) { 1827f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (!mutable) { 18337a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski accResult.addAll(stats.packageStats.values()); 1847f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return; 1857f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1867f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 18737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final int statCount = stats.packageStats.size(); 1887f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski for (int i = 0; i < statCount; i++) { 18937a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski accResult.add(new UsageStats(stats.packageStats.valueAt(i))); 1907f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1917f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1927f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski }; 1937f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1947f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski private static final StatCombiner<ConfigurationStats> sConfigStatsCombiner = 1957f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski new StatCombiner<ConfigurationStats>() { 1967f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski @Override 1977f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski public void combine(IntervalStats stats, boolean mutable, 1987f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski List<ConfigurationStats> accResult) { 1997f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (!mutable) { 2007f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski accResult.addAll(stats.configurations.values()); 2017f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return; 2027f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 2037f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 2047f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final int configCount = stats.configurations.size(); 2057f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski for (int i = 0; i < configCount; i++) { 2067f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski accResult.add(new ConfigurationStats(stats.configurations.valueAt(i))); 2077f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 2087f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 2097f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski }; 2107f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 2117f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski /** 2127f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * Generic query method that selects the appropriate IntervalStats for the specified time range 2137f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner} 2147f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * provided to select the stats to use from the IntervalStats object. 2157f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski */ 216d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski private <T> List<T> queryStats(int intervalType, final long beginTime, final long endTime, 2177f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski StatCombiner<T> combiner) { 218d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (intervalType == UsageStatsManager.INTERVAL_BEST) { 219d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski intervalType = mDatabase.findBestFitBucket(beginTime, endTime); 220d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (intervalType < 0) { 221d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // Nothing saved to disk yet, so every stat is just as equal (no rollover has 222d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // occurred. 223d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski intervalType = UsageStatsManager.INTERVAL_DAILY; 224d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 2253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 227d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (intervalType < 0 || intervalType >= mCurrentStats.length) { 2283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (DEBUG) { 229d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, mLogPrefix + "Bad intervalType used " + intervalType); 2303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return null; 2323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 2333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 234d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final IntervalStats currentStats = mCurrentStats[intervalType]; 235d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 236d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (DEBUG) { 237d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, mLogPrefix + "SELECT * FROM " + intervalType + " WHERE beginTime >= " 238d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski + beginTime + " AND endTime < " + endTime); 239d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 240d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 241d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (beginTime >= currentStats.endTime) { 2423c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (DEBUG) { 2433c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski Slog.d(TAG, mLogPrefix + "Requesting stats after " + beginTime + " but latest is " 244d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski + currentStats.endTime); 2453c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 2463c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // Nothing newer available. 2473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return null; 2483c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 2493c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 250d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // Truncate the endTime to just before the in-memory stats. Then, we'll append the 251d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // in-memory stats to the results (if necessary) so as to avoid writing to disk too 252d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // often. 253d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final long truncatedEndTime = Math.min(currentStats.beginTime, endTime); 2543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 255d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // Get the stats from disk. 256d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski List<T> results = mDatabase.queryUsageStats(intervalType, beginTime, 257d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski truncatedEndTime, combiner); 2583c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (DEBUG) { 259d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, "Got " + (results != null ? results.size() : 0) + " results from disk"); 260d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, "Current stats beginTime=" + currentStats.beginTime + 261d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski " endTime=" + currentStats.endTime); 262d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 263d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 264d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski // Now check if the in-memory stats match the range and add them if they do. 265d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (beginTime < currentStats.endTime && endTime > currentStats.beginTime) { 266d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (DEBUG) { 267d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, mLogPrefix + "Returning in-memory stats"); 268d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 269d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 270d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (results == null) { 271d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski results = new ArrayList<>(); 272d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 273d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski combiner.combine(currentStats, true, results); 2743c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 2753c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 2763c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (DEBUG) { 277d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, mLogPrefix + "Results: " + (results != null ? results.size() : 0)); 2783c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 2793c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return results; 2803c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 2813c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 2827f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) { 2837f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner); 2847f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 2857f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 2867f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) { 2877f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner); 2887f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 2897f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 290d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski UsageEvents queryEvents(final long beginTime, final long endTime) { 291d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final ArraySet<String> names = new ArraySet<>(); 292d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY, 293d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski beginTime, endTime, new StatCombiner<UsageEvents.Event>() { 294d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski @Override 295d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski public void combine(IntervalStats stats, boolean mutable, 296d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski List<UsageEvents.Event> accumulatedResult) { 297d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (stats.events == null) { 298d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski return; 299d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 300d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 301d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final int startIndex = stats.events.closestIndexOnOrAfter(beginTime); 302d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (startIndex < 0) { 303d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski return; 304d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 305d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 306d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final int size = stats.events.size(); 307d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski for (int i = startIndex; i < size; i++) { 308d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (stats.events.keyAt(i) >= endTime) { 309d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski return; 310d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 311d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski 312d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final UsageEvents.Event event = stats.events.valueAt(i); 313d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski names.add(event.mPackage); 314d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (event.mClass != null) { 315d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski names.add(event.mClass); 316d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 317d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski accumulatedResult.add(event); 318d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 319d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski } 320d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski }); 3213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 322d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (results == null || results.isEmpty()) { 323d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski return null; 3243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 326d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski String[] table = names.toArray(new String[names.size()]); 327d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Arrays.sort(table); 328d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski return new UsageEvents(results, table); 3293516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 3303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 3313c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski void persistActiveStats() { 3323c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (mStatsChanged) { 3333c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk"); 3343c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski try { 3353c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski for (int i = 0; i < mCurrentStats.length; i++) { 3363c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mDatabase.putUsageStats(i, mCurrentStats[i]); 3373c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3383c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mStatsChanged = false; 3393c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } catch (IOException e) { 3403c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski Slog.e(TAG, mLogPrefix + "Failed to persist active stats", e); 3413c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3423c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3433c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3443c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 34566143fa5b34eea7413335111838fb692987b611aAdam Lesinski private void rolloverStats(final long currentTimeMillis) { 34666143fa5b34eea7413335111838fb692987b611aAdam Lesinski final long startTime = SystemClock.elapsedRealtime(); 3473c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski Slog.i(TAG, mLogPrefix + "Rolling over usage stats"); 3483c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 3493c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // Finish any ongoing events with an END_OF_DAY event. Make a note of which components 3503c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // need a new CONTINUE_PREVIOUS_DAY entry. 3517f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final Configuration previousConfig = 3527f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski mCurrentStats[UsageStatsManager.INTERVAL_DAILY].activeConfiguration; 3533c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski ArraySet<String> continuePreviousDay = new ArraySet<>(); 3543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski for (IntervalStats stat : mCurrentStats) { 35537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski final int pkgCount = stat.packageStats.size(); 3563c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski for (int i = 0; i < pkgCount; i++) { 35737a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski UsageStats pkgStats = stat.packageStats.valueAt(i); 3583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND || 3593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) { 3603c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski continuePreviousDay.add(pkgStats.mPackageName); 3617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stat.update(pkgStats.mPackageName, mDailyExpiryDate.getTimeInMillis() - 1, 3627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski UsageEvents.Event.END_OF_DAY); 36366143fa5b34eea7413335111838fb692987b611aAdam Lesinski notifyStatsChanged(); 3643c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3653c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 3677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stat.updateConfigurationStats(null, mDailyExpiryDate.getTimeInMillis() - 1); 3683c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3693c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 3703c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski persistActiveStats(); 37166143fa5b34eea7413335111838fb692987b611aAdam Lesinski mDatabase.prune(currentTimeMillis); 37266143fa5b34eea7413335111838fb692987b611aAdam Lesinski loadActiveStats(currentTimeMillis, false); 3733c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 3743c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski final int continueCount = continuePreviousDay.size(); 3753c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski for (int i = 0; i < continueCount; i++) { 3763c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski String name = continuePreviousDay.valueAt(i); 3777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski final long beginTime = mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime; 3783516800b611a79339a3c188332d13a26e9086b09Adam Lesinski for (IntervalStats stat : mCurrentStats) { 3797f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stat.update(name, beginTime, UsageEvents.Event.CONTINUE_PREVIOUS_DAY); 3807f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski stat.updateConfigurationStats(previousConfig, beginTime); 38166143fa5b34eea7413335111838fb692987b611aAdam Lesinski notifyStatsChanged(); 3823c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3833c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3843c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski persistActiveStats(); 3853c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 38666143fa5b34eea7413335111838fb692987b611aAdam Lesinski final long totalTime = SystemClock.elapsedRealtime() - startTime; 3873c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime 3883c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski + " milliseconds"); 3893c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3903c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 3913c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private void notifyStatsChanged() { 3923c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski if (!mStatsChanged) { 3933c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mStatsChanged = true; 3943c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mListener.onStatsUpdated(); 3953c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3963c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 3973c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 39866143fa5b34eea7413335111838fb692987b611aAdam Lesinski /** 39966143fa5b34eea7413335111838fb692987b611aAdam Lesinski * @param force To force all in-memory stats to be reloaded. 40066143fa5b34eea7413335111838fb692987b611aAdam Lesinski */ 40166143fa5b34eea7413335111838fb692987b611aAdam Lesinski private void loadActiveStats(final long currentTimeMillis, boolean force) { 402d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final UnixCalendar tempCal = mDailyExpiryDate; 403d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) { 40466143fa5b34eea7413335111838fb692987b611aAdam Lesinski tempCal.setTimeInMillis(currentTimeMillis); 405d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski UnixCalendar.truncateTo(tempCal, intervalType); 4063c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 40766143fa5b34eea7413335111838fb692987b611aAdam Lesinski if (!force && mCurrentStats[intervalType] != null && 408d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mCurrentStats[intervalType].beginTime == tempCal.getTimeInMillis()) { 4093c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // These are the same, no need to load them (in memory stats are always newer 4103c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski // than persisted stats). 4113c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski continue; 4123c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 4133c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 414d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski final long lastBeginTime = mDatabase.getLatestUsageStatsBeginTime(intervalType); 41566143fa5b34eea7413335111838fb692987b611aAdam Lesinski if (lastBeginTime >= tempCal.getTimeInMillis()) { 4163516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (DEBUG) { 417d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, mLogPrefix + "Loading existing stats @ " + 418d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski sDateFormat.format(lastBeginTime) + "(" + lastBeginTime + 419d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski ") for interval " + intervalType); 4203516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 421d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mCurrentStats[intervalType] = mDatabase.getLatestUsageStats(intervalType); 4223c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } else { 423d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mCurrentStats[intervalType] = null; 4243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 4253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 426d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski if (mCurrentStats[intervalType] == null) { 4273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (DEBUG) { 428d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.d(TAG, "Creating new stats @ " + 429d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski sDateFormat.format(tempCal.getTimeInMillis()) + "(" + 430d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski tempCal.getTimeInMillis() + ") for interval " + intervalType); 4313516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 4323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 433d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mCurrentStats[intervalType] = new IntervalStats(); 434d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mCurrentStats[intervalType].beginTime = tempCal.getTimeInMillis(); 43566143fa5b34eea7413335111838fb692987b611aAdam Lesinski mCurrentStats[intervalType].endTime = currentTimeMillis; 4363c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 4373c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 4383c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski mStatsChanged = false; 43966143fa5b34eea7413335111838fb692987b611aAdam Lesinski mDailyExpiryDate.setTimeInMillis(currentTimeMillis); 440d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mDailyExpiryDate.addDays(1); 441d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski mDailyExpiryDate.truncateToDay(); 442d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " + 443d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" + 444d26bea3a1498d1b327ae37cc796fb8cd67e9c977Adam Lesinski tempCal.getTimeInMillis() + ")"); 4453c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 4463c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 4471bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski // 4481bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski // -- DUMP related methods -- 4491bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski // 4501bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 4511bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski void checkin(final IndentingPrintWriter pw) { 4521bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() { 4531bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski @Override 4541bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski public boolean checkin(IntervalStats stats) { 4551bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski printIntervalStats(pw, stats, false); 4561bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return true; 4571bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4581bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski }); 4591bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4601bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 4611bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski void dump(IndentingPrintWriter pw) { 4621bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski // This is not a check-in, only dump in-memory stats. 4631bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski for (int interval = 0; interval < mCurrentStats.length; interval++) { 4641bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.print("In-memory "); 4651bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.print(intervalToString(interval)); 4661bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println(" stats"); 4671bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski printIntervalStats(pw, mCurrentStats[interval], true); 4681bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4691bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4701bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 4711bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski private String formatDateTime(long dateTime, boolean pretty) { 4721bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski if (pretty) { 4731bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "\"" + DateUtils.formatDateTime(mContext, dateTime, sDateFormatFlags) + "\""; 4741bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4751bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return Long.toString(dateTime); 4761bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4771bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 4781bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski private String formatElapsedTime(long elapsedTime, boolean pretty) { 4791bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski if (pretty) { 4801bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "\"" + DateUtils.formatElapsedTime(elapsedTime / 1000) + "\""; 4811bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4821bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return Long.toString(elapsedTime); 4831bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4841bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 4851bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, boolean prettyDates) { 4861bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski if (prettyDates) { 4871bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext, 4881bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski stats.beginTime, stats.endTime, sDateFormatFlags) + "\""); 4891bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } else { 4901bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("beginTime", stats.beginTime); 4911bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("endTime", stats.endTime); 4921bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 4931bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println(); 4941bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.increaseIndent(); 4951bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println("packages"); 4961bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.increaseIndent(); 4971bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final ArrayMap<String, UsageStats> pkgStats = stats.packageStats; 4981bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final int pkgCount = pkgStats.size(); 4991bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski for (int i = 0; i < pkgCount; i++) { 5001bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final UsageStats usageStats = pkgStats.valueAt(i); 5011bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("package", usageStats.mPackageName); 5021bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("totalTime", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates)); 5031bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates)); 5041bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println(); 5051bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5061bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.decreaseIndent(); 5071bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 5081bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println("configurations"); 5091bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.increaseIndent(); 5101bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final ArrayMap<Configuration, ConfigurationStats> configStats = 5111bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski stats.configurations; 5121bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final int configCount = configStats.size(); 5131bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski for (int i = 0; i < configCount; i++) { 5141bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final ConfigurationStats config = configStats.valueAt(i); 5151bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("config", Configuration.resourceQualifierString(config.mConfiguration)); 5161bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates)); 5171bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates)); 5181bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("count", config.mActivationCount); 5191bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println(); 5201bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5211bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.decreaseIndent(); 5221bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 5231bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println("events"); 5241bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.increaseIndent(); 5251bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final TimeSparseArray<UsageEvents.Event> events = stats.events; 5261bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final int eventCount = events != null ? events.size() : 0; 5271bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski for (int i = 0; i < eventCount; i++) { 5281bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski final UsageEvents.Event event = events.valueAt(i); 5291bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates)); 5301bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("type", eventToString(event.mEventType)); 5311bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("package", event.mPackage); 5321bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski if (event.mClass != null) { 5331bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("class", event.mClass); 5341bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5351bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski if (event.mConfiguration != null) { 5361bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration)); 5371bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5381bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.println(); 5391bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5401bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.decreaseIndent(); 5411bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski pw.decreaseIndent(); 5421bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5431bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski 5441bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski private static String intervalToString(int interval) { 5451bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski switch (interval) { 5461bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski case UsageStatsManager.INTERVAL_DAILY: 5471bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "daily"; 5481bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski case UsageStatsManager.INTERVAL_WEEKLY: 5491bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "weekly"; 5501bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski case UsageStatsManager.INTERVAL_MONTHLY: 5511bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "monthly"; 5521bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski case UsageStatsManager.INTERVAL_YEARLY: 5531bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "yearly"; 5541bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski default: 5551bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski return "?"; 5561bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5571bb18c435dbf967f3a9bc9d680411471b8bab4acAdam Lesinski } 5583c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski 5593c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski private static String eventToString(int eventType) { 5603c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski switch (eventType) { 5613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski case UsageEvents.Event.NONE: 5623c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return "NONE"; 5633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski case UsageEvents.Event.MOVE_TO_BACKGROUND: 5643c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return "MOVE_TO_BACKGROUND"; 5653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski case UsageEvents.Event.MOVE_TO_FOREGROUND: 5663c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return "MOVE_TO_FOREGROUND"; 5673516800b611a79339a3c188332d13a26e9086b09Adam Lesinski case UsageEvents.Event.END_OF_DAY: 5683c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return "END_OF_DAY"; 5693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski case UsageEvents.Event.CONTINUE_PREVIOUS_DAY: 5703c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return "CONTINUE_PREVIOUS_DAY"; 5717f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski case UsageEvents.Event.CONFIGURATION_CHANGE: 5727f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return "CONFIGURATION_CHANGE"; 5733c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski default: 5743c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski return "UNKNOWN"; 5753c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 5763c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski } 5773c153519ca5f2b66b88901374383f943c9d77df7Adam Lesinski} 578