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 Lesinskipackage com.android.server.usage; 173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 187f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.app.usage.ConfigurationStats; 193516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.TimeSparseArray; 203516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents; 213516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageStats; 227f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.content.res.Configuration; 233516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.util.ArrayMap; 249d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinskiimport android.util.ArraySet; 253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiclass IntervalStats { 273516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public long beginTime; 283516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public long endTime; 293516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public long lastTimeSaved; 3037a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>(); 317f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>(); 327f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski public Configuration activeConfiguration; 333516800b611a79339a3c188332d13a26e9086b09Adam Lesinski public TimeSparseArray<UsageEvents.Event> events; 343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 359d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski // A string cache. This is important as when we're parsing XML files, we don't want to 369d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski // keep hundreds of strings that have the same contents. We will read the string 379d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski // and only keep it if it's not in the cache. The GC will take care of the 389d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski // strings that had identical copies in the cache. 399d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski private final ArraySet<String> mStringCache = new ArraySet<>(); 403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 417f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski /** 427f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * Gets the UsageStats object for the given package, or creates one and adds it internally. 437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski */ 443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski UsageStats getOrCreateUsageStats(String packageName) { 4537a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski UsageStats usageStats = packageStats.get(packageName); 463516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (usageStats == null) { 473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski usageStats = new UsageStats(); 487f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski usageStats.mPackageName = getCachedStringRef(packageName); 493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski usageStats.mBeginTimeStamp = beginTime; 503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski usageStats.mEndTimeStamp = endTime; 5137a46b48dcb7e34ee3669cfb2ed78af08bfca3c7Adam Lesinski packageStats.put(usageStats.mPackageName, usageStats); 523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski return usageStats; 543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski /** 577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * Gets the ConfigurationStats object for the given configuration, or creates one and adds it 587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * internally. 597f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski */ 607f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski ConfigurationStats getOrCreateConfigurationStats(Configuration config) { 617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski ConfigurationStats configStats = configurations.get(config); 627f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (configStats == null) { 637f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats = new ConfigurationStats(); 647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mBeginTimeStamp = beginTime; 657f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mEndTimeStamp = endTime; 667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mConfiguration = config; 677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configurations.put(config, configStats); 687f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 697f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return configStats; 707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 717f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 727f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski /** 737f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski * Builds a UsageEvents.Event, but does not add it internally. 747f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski */ 757f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski UsageEvents.Event buildEvent(String packageName, String className) { 767f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski UsageEvents.Event event = new UsageEvents.Event(); 777f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski event.mPackage = getCachedStringRef(packageName); 787f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (className != null) { 797f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski event.mClass = getCachedStringRef(className); 807f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 817f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski return event; 827f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 837f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 84978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski private boolean isStatefulEvent(int eventType) { 85978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski switch (eventType) { 86978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski case UsageEvents.Event.MOVE_TO_FOREGROUND: 87978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski case UsageEvents.Event.MOVE_TO_BACKGROUND: 88978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski case UsageEvents.Event.END_OF_DAY: 89978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski case UsageEvents.Event.CONTINUE_PREVIOUS_DAY: 90978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski return true; 91978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski } 92978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski return false; 93978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski } 94978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski 953516800b611a79339a3c188332d13a26e9086b09Adam Lesinski void update(String packageName, long timeStamp, int eventType) { 963516800b611a79339a3c188332d13a26e9086b09Adam Lesinski UsageStats usageStats = getOrCreateUsageStats(packageName); 973516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski // TODO(adamlesinski): Ensure that we recover from incorrect event sequences 993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski // like double MOVE_TO_BACKGROUND, etc. 1003516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (eventType == UsageEvents.Event.MOVE_TO_BACKGROUND || 1013516800b611a79339a3c188332d13a26e9086b09Adam Lesinski eventType == UsageEvents.Event.END_OF_DAY) { 1023516800b611a79339a3c188332d13a26e9086b09Adam Lesinski if (usageStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND || 1033516800b611a79339a3c188332d13a26e9086b09Adam Lesinski usageStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) { 1043516800b611a79339a3c188332d13a26e9086b09Adam Lesinski usageStats.mTotalTimeInForeground += timeStamp - usageStats.mLastTimeUsed; 1053516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1063516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 107978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski 108978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski if (isStatefulEvent(eventType)) { 109978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski usageStats.mLastEvent = eventType; 110978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski } 111978a1ed5aa2752cd36ff51df91d2d2d8be2171d9Adam Lesinski 112c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski if (eventType != UsageEvents.Event.SYSTEM_INTERACTION) { 113c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski usageStats.mLastTimeUsed = timeStamp; 114c8e8729244d75584ce71a74d29c452fe538a22c5Adam Lesinski } 1153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski usageStats.mEndTimeStamp = timeStamp; 1167f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1177f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) { 1187f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski usageStats.mLaunchCount += 1; 1197f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1207f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1217f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski endTime = timeStamp; 1227f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1237f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1247f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski void updateConfigurationStats(Configuration config, long timeStamp) { 1257f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (activeConfiguration != null) { 1267f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski ConfigurationStats activeStats = configurations.get(activeConfiguration); 1277f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski activeStats.mTotalTimeActive += timeStamp - activeStats.mLastTimeActive; 1287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski activeStats.mLastTimeActive = timeStamp - 1; 1297f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1307f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1317f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski if (config != null) { 1327f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski ConfigurationStats configStats = getOrCreateConfigurationStats(config); 1337f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mLastTimeActive = timeStamp; 1347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski configStats.mActivationCount += 1; 1357f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski activeConfiguration = configStats.mConfiguration; 1367f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski } 1377f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski 1383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski endTime = timeStamp; 1393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski } 1403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski 1419d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski private String getCachedStringRef(String str) { 1429d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski final int index = mStringCache.indexOf(str); 1439d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski if (index < 0) { 1449d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski mStringCache.add(str); 1459d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski return str; 1469d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1479d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski return mStringCache.valueAt(index); 1489d9607527f5bbf49c96565b63b90e36276b0dda7Adam Lesinski } 1493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski} 150