1 /*
2  * Copyright (C) 2018 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 of
6  * 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 under
14  * the License.
15  */
16 
17 package com.android.frameworks.perftests.usage.tests;
18 
19 import static junit.framework.Assert.assertEquals;
20 
21 import android.app.usage.UsageEvents;
22 import android.app.usage.UsageStatsManager;
23 import android.content.Context;
24 import android.os.SystemClock;
25 import android.perftests.utils.ManualBenchmarkState;
26 import android.perftests.utils.PerfManualStatusReporter;
27 
28 import androidx.test.InstrumentationRegistry;
29 import androidx.test.filters.LargeTest;
30 import androidx.test.runner.AndroidJUnit4;
31 
32 import com.android.server.usage.IntervalStats;
33 import com.android.server.usage.UsageStatsDatabase;
34 import com.android.server.usage.UsageStatsDatabase.StatCombiner;
35 
36 import org.junit.BeforeClass;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.io.File;
42 import java.io.IOException;
43 import java.util.List;
44 
45 @RunWith(AndroidJUnit4.class)
46 @LargeTest
47 public class UsageStatsDatabasePerfTest {
48     protected static Context sContext;
49     private static UsageStatsDatabase sUsageStatsDatabase;
50     private static File mTestDir;
51 
52     // Represents how many apps might have used in a day by a user with a few apps
53     final static int FEW_PKGS = 10;
54     // Represent how many apps might have used in a day by a user with many apps
55     final static int MANY_PKGS = 50;
56     // Represents how many usage events per app a device might have with light usage
57     final static int LIGHT_USE = 10;
58     // Represents how many usage events per app a device might have with heavy usage
59     final static int HEAVY_USE = 50;
60 
61     private static final StatCombiner<UsageEvents.Event> sUsageStatsCombiner =
62             new StatCombiner<UsageEvents.Event>() {
63                 @Override
64                 public void combine(IntervalStats stats, boolean mutable,
65                         List<UsageEvents.Event> accResult) {
66                     final int size = stats.events.size();
67                     for (int i = 0; i < size; i++) {
68                         accResult.add(stats.events.get(i));
69                     }
70                 }
71             };
72 
73 
74     @Rule
75     public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
76 
77     @BeforeClass
setUpOnce()78     public static void setUpOnce() {
79         sContext = InstrumentationRegistry.getTargetContext();
80         mTestDir = new File(sContext.getFilesDir(), "UsageStatsDatabasePerfTest");
81         sUsageStatsDatabase = new UsageStatsDatabase(mTestDir);
82         sUsageStatsDatabase.init(1);
83     }
84 
populateIntervalStats(IntervalStats intervalStats, int packageCount, int eventsPerPackage)85     private static void populateIntervalStats(IntervalStats intervalStats, int packageCount,
86             int eventsPerPackage) {
87         for (int pkg = 0; pkg < packageCount; pkg++) {
88             UsageEvents.Event event = new UsageEvents.Event();
89             event.mPackage = "fake.package.name" + pkg;
90             event.mClass = event.mPackage + ".class1";
91             event.mTimeStamp = 1;
92             event.mEventType = UsageEvents.Event.ACTIVITY_RESUMED;
93             for (int evt = 0; evt < eventsPerPackage; evt++) {
94                 intervalStats.events.insert(event);
95                 intervalStats.update(event.mPackage, event.mClass, event.mTimeStamp,
96                         event.mEventType, 1);
97             }
98         }
99     }
100 
clearUsageStatsFiles()101     private static void clearUsageStatsFiles() {
102         File[] intervalDirs = mTestDir.listFiles();
103         for (File intervalDir : intervalDirs) {
104             if (intervalDir.isDirectory()) {
105                 File[] usageFiles = intervalDir.listFiles();
106                 for (File f : usageFiles) {
107                     f.delete();
108                 }
109             }
110         }
111     }
112 
runQueryUsageStatsTest(int packageCount, int eventsPerPackage)113     private void runQueryUsageStatsTest(int packageCount, int eventsPerPackage) throws IOException {
114         final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
115         IntervalStats intervalStats = new IntervalStats();
116         populateIntervalStats(intervalStats, packageCount, eventsPerPackage);
117         sUsageStatsDatabase.putUsageStats(0, intervalStats);
118         long elapsedTimeNs = 0;
119         while (benchmarkState.keepRunning(elapsedTimeNs)) {
120             final long startTime = SystemClock.elapsedRealtimeNanos();
121             List<UsageEvents.Event> temp = sUsageStatsDatabase.queryUsageStats(
122                     UsageStatsManager.INTERVAL_DAILY, 0, 2, sUsageStatsCombiner);
123             final long endTime = SystemClock.elapsedRealtimeNanos();
124             elapsedTimeNs = endTime - startTime;
125             assertEquals(packageCount * eventsPerPackage, temp.size());
126         }
127     }
128 
runPutUsageStatsTest(int packageCount, int eventsPerPackage)129     private void runPutUsageStatsTest(int packageCount, int eventsPerPackage) throws IOException {
130         final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
131         IntervalStats intervalStats = new IntervalStats();
132         populateIntervalStats(intervalStats, packageCount, eventsPerPackage);
133         long elapsedTimeNs = 0;
134         while (benchmarkState.keepRunning(elapsedTimeNs)) {
135             final long startTime = SystemClock.elapsedRealtimeNanos();
136             sUsageStatsDatabase.putUsageStats(0, intervalStats);
137             final long endTime = SystemClock.elapsedRealtimeNanos();
138             elapsedTimeNs = endTime - startTime;
139             clearUsageStatsFiles();
140         }
141     }
142 
143     @Test
testQueryUsageStats_FewPkgsLightUse()144     public void testQueryUsageStats_FewPkgsLightUse() throws IOException {
145         runQueryUsageStatsTest(FEW_PKGS, LIGHT_USE);
146     }
147 
148     @Test
testPutUsageStats_FewPkgsLightUse()149     public void testPutUsageStats_FewPkgsLightUse() throws IOException {
150         runPutUsageStatsTest(FEW_PKGS, LIGHT_USE);
151     }
152 
153     @Test
testQueryUsageStats_FewPkgsHeavyUse()154     public void testQueryUsageStats_FewPkgsHeavyUse() throws IOException {
155         runQueryUsageStatsTest(FEW_PKGS, HEAVY_USE);
156     }
157 
158     @Test
testPutUsageStats_FewPkgsHeavyUse()159     public void testPutUsageStats_FewPkgsHeavyUse() throws IOException {
160         runPutUsageStatsTest(FEW_PKGS, HEAVY_USE);
161     }
162 
163     @Test
testQueryUsageStats_ManyPkgsLightUse()164     public void testQueryUsageStats_ManyPkgsLightUse() throws IOException {
165         runQueryUsageStatsTest(MANY_PKGS, LIGHT_USE);
166     }
167 
168     @Test
testPutUsageStats_ManyPkgsLightUse()169     public void testPutUsageStats_ManyPkgsLightUse() throws IOException {
170         runPutUsageStatsTest(MANY_PKGS, LIGHT_USE);
171     }
172 
173     @Test
testQueryUsageStats_ManyPkgsHeavyUse()174     public void testQueryUsageStats_ManyPkgsHeavyUse() throws IOException {
175         runQueryUsageStatsTest(MANY_PKGS, HEAVY_USE);
176     }
177 
178     @Test
testPutUsageStats_ManyPkgsHeavyUse()179     public void testPutUsageStats_ManyPkgsHeavyUse() throws IOException {
180         runPutUsageStatsTest(MANY_PKGS, HEAVY_USE);
181     }
182 }
183