• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
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 package com.android.server.usage;
17 
18 import android.app.usage.ConfigurationStats;
19 import android.app.usage.TimeSparseArray;
20 import android.app.usage.UsageEvents;
21 import android.app.usage.UsageStats;
22 import android.content.res.Configuration;
23 import android.util.ArrayMap;
24 import android.util.ArraySet;
25 
26 class IntervalStats {
27     public long beginTime;
28     public long endTime;
29     public long lastTimeSaved;
30     public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
31     public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
32     public Configuration activeConfiguration;
33     public TimeSparseArray<UsageEvents.Event> events;
34 
35     // A string cache. This is important as when we're parsing XML files, we don't want to
36     // keep hundreds of strings that have the same contents. We will read the string
37     // and only keep it if it's not in the cache. The GC will take care of the
38     // strings that had identical copies in the cache.
39     private final ArraySet<String> mStringCache = new ArraySet<>();
40 
41     /**
42      * Gets the UsageStats object for the given package, or creates one and adds it internally.
43      */
getOrCreateUsageStats(String packageName)44     UsageStats getOrCreateUsageStats(String packageName) {
45         UsageStats usageStats = packageStats.get(packageName);
46         if (usageStats == null) {
47             usageStats = new UsageStats();
48             usageStats.mPackageName = getCachedStringRef(packageName);
49             usageStats.mBeginTimeStamp = beginTime;
50             usageStats.mEndTimeStamp = endTime;
51             packageStats.put(usageStats.mPackageName, usageStats);
52         }
53         return usageStats;
54     }
55 
56     /**
57      * Gets the ConfigurationStats object for the given configuration, or creates one and adds it
58      * internally.
59      */
getOrCreateConfigurationStats(Configuration config)60     ConfigurationStats getOrCreateConfigurationStats(Configuration config) {
61         ConfigurationStats configStats = configurations.get(config);
62         if (configStats == null) {
63             configStats = new ConfigurationStats();
64             configStats.mBeginTimeStamp = beginTime;
65             configStats.mEndTimeStamp = endTime;
66             configStats.mConfiguration = config;
67             configurations.put(config, configStats);
68         }
69         return configStats;
70     }
71 
72     /**
73      * Builds a UsageEvents.Event, but does not add it internally.
74      */
buildEvent(String packageName, String className)75     UsageEvents.Event buildEvent(String packageName, String className) {
76         UsageEvents.Event event = new UsageEvents.Event();
77         event.mPackage = getCachedStringRef(packageName);
78         if (className != null) {
79             event.mClass = getCachedStringRef(className);
80         }
81         return event;
82     }
83 
isStatefulEvent(int eventType)84     private boolean isStatefulEvent(int eventType) {
85         switch (eventType) {
86             case UsageEvents.Event.MOVE_TO_FOREGROUND:
87             case UsageEvents.Event.MOVE_TO_BACKGROUND:
88             case UsageEvents.Event.END_OF_DAY:
89             case UsageEvents.Event.CONTINUE_PREVIOUS_DAY:
90                 return true;
91         }
92         return false;
93     }
94 
update(String packageName, long timeStamp, int eventType)95     void update(String packageName, long timeStamp, int eventType) {
96         UsageStats usageStats = getOrCreateUsageStats(packageName);
97 
98         // TODO(adamlesinski): Ensure that we recover from incorrect event sequences
99         // like double MOVE_TO_BACKGROUND, etc.
100         if (eventType == UsageEvents.Event.MOVE_TO_BACKGROUND ||
101                 eventType == UsageEvents.Event.END_OF_DAY) {
102             if (usageStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND ||
103                     usageStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) {
104                 usageStats.mTotalTimeInForeground += timeStamp - usageStats.mLastTimeUsed;
105             }
106         }
107 
108         if (isStatefulEvent(eventType)) {
109             usageStats.mLastEvent = eventType;
110         }
111 
112         if (eventType != UsageEvents.Event.SYSTEM_INTERACTION) {
113             usageStats.mLastTimeUsed = timeStamp;
114         }
115         usageStats.mEndTimeStamp = timeStamp;
116 
117         if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
118             usageStats.mLaunchCount += 1;
119         }
120 
121         endTime = timeStamp;
122     }
123 
updateChooserCounts(String packageName, String category, String action)124     void updateChooserCounts(String packageName, String category, String action) {
125         UsageStats usageStats = getOrCreateUsageStats(packageName);
126         if (usageStats.mChooserCounts == null) {
127             usageStats.mChooserCounts = new ArrayMap<>();
128         }
129         ArrayMap<String, Integer> chooserCounts;
130         final int idx = usageStats.mChooserCounts.indexOfKey(action);
131         if (idx < 0) {
132             chooserCounts = new ArrayMap<>();
133             usageStats.mChooserCounts.put(action, chooserCounts);
134         } else {
135             chooserCounts = usageStats.mChooserCounts.valueAt(idx);
136         }
137         int currentCount = chooserCounts.getOrDefault(category, 0);
138         chooserCounts.put(category, currentCount + 1);
139     }
140 
updateConfigurationStats(Configuration config, long timeStamp)141     void updateConfigurationStats(Configuration config, long timeStamp) {
142         if (activeConfiguration != null) {
143             ConfigurationStats activeStats = configurations.get(activeConfiguration);
144             activeStats.mTotalTimeActive += timeStamp - activeStats.mLastTimeActive;
145             activeStats.mLastTimeActive = timeStamp - 1;
146         }
147 
148         if (config != null) {
149             ConfigurationStats configStats = getOrCreateConfigurationStats(config);
150             configStats.mLastTimeActive = timeStamp;
151             configStats.mActivationCount += 1;
152             activeConfiguration = configStats.mConfiguration;
153         }
154 
155         endTime = timeStamp;
156     }
157 
getCachedStringRef(String str)158     private String getCachedStringRef(String str) {
159         final int index = mStringCache.indexOf(str);
160         if (index < 0) {
161             mStringCache.add(str);
162             return str;
163         }
164         return mStringCache.valueAt(index);
165     }
166 }
167