1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.startop.test;
18 
19 import android.app.Activity;
20 import android.app.ActivityManager;
21 import android.app.AppOpsManager;
22 import android.app.PendingIntent;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.PackageManager;
28 import android.content.pm.PackageManager.NameNotFoundException;
29 import android.net.ConnectivityManager;
30 import android.os.AsyncTask;
31 import android.os.PowerManager;
32 import android.os.Process;
33 import android.os.UserManager;
34 
35 /**
36  * An interface for running benchmarks and collecting results. Used so we can have both an
37  * interactive runner and a non-interactive runner.
38  */
39 interface BenchmarkRunner {
addBenchmark(CharSequence name, Runnable thunk)40     void addBenchmark(CharSequence name, Runnable thunk);
41 }
42 
43 interface ResultListener {
44     /**
45      * Called when a benchmark result is ready
46      *
47      * @param mean  The average iteration time in nanoseconds
48      * @param stdev The standard deviation of iteration times in nanoseconds
49      */
onResult(double mean, double stdev)50     void onResult(double mean, double stdev);
51 }
52 
53 class SystemServerBenchmarks {
54     // Time limit to run benchmarks in seconds
55     public static final int TIME_LIMIT = 5;
56 
initializeBenchmarks(Activity parent, BenchmarkRunner benchmarks)57     static void initializeBenchmarks(Activity parent, BenchmarkRunner benchmarks) {
58         final String packageName = parent.getPackageName();
59 
60         PackageManager pm = parent.getPackageManager();
61         benchmarks.addBenchmark("getInstalledApplications", () -> {
62             pm.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY);
63         });
64 
65         benchmarks.addBenchmark("getInstalledPackages", () -> {
66             pm.getInstalledPackages(PackageManager.GET_ACTIVITIES);
67         });
68 
69         benchmarks.addBenchmark("getPackageInfo", () -> {
70             try {
71                 pm.getPackageInfo(packageName, 0);
72             } catch (NameNotFoundException e) {
73                 throw new RuntimeException(e);
74             }
75         });
76 
77         benchmarks.addBenchmark("getApplicationInfo", () -> {
78             try {
79                 pm.getApplicationInfo(packageName, 0);
80             } catch (NameNotFoundException e) {
81                 throw new RuntimeException(e);
82             }
83         });
84 
85         try {
86             ApplicationInfo app = pm.getApplicationInfo(packageName, 0);
87             benchmarks.addBenchmark("getResourcesForApplication", () -> {
88                 try {
89                     pm.getResourcesForApplication(app);
90                 } catch (NameNotFoundException e) {
91                     throw new RuntimeException(e);
92                 }
93             });
94 
95             benchmarks.addBenchmark("getPackagesForUid", () -> {
96                 pm.getPackagesForUid(app.uid);
97             });
98         } catch (NameNotFoundException e) {
99             throw new RuntimeException(e);
100         }
101 
102         ComponentName component = new ComponentName(parent, parent.getClass());
103         benchmarks.addBenchmark("getActivityInfo", () -> {
104             try {
105                 pm.getActivityInfo(component, PackageManager.GET_META_DATA);
106             } catch (NameNotFoundException e) {
107                 throw new RuntimeException(e);
108             }
109         });
110 
111         benchmarks.addBenchmark("getLaunchIntentForPackage", () -> {
112             pm.getLaunchIntentForPackage(packageName);
113         });
114 
115         benchmarks.addBenchmark("getPackageUid", () -> {
116             try {
117                 pm.getPackageUid(packageName, 0);
118             } catch (NameNotFoundException e) {
119                 throw new RuntimeException(e);
120             }
121         });
122 
123         benchmarks.addBenchmark("checkPermission", () -> {
124             // Check for the first permission I could find.
125             pm.checkPermission("android.permission.SEND_SMS", packageName);
126         });
127 
128         benchmarks.addBenchmark("checkSignatures", () -> {
129             // Compare with settings, since settings is on both AOSP and Master builds
130             pm.checkSignatures("com.android.settings", packageName);
131         });
132 
133         Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
134         benchmarks.addBenchmark("queryBroadcastReceivers", () -> {
135             pm.queryBroadcastReceivers(intent, 0);
136         });
137 
138         benchmarks.addBenchmark("hasSystemFeature", () -> {
139             pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
140         });
141 
142         benchmarks.addBenchmark("resolveService", () -> {
143             pm.resolveService(intent, 0);
144         });
145 
146         ActivityManager am = (ActivityManager) parent.getSystemService(Context.ACTIVITY_SERVICE);
147         benchmarks.addBenchmark("getRunningAppProcesses", () -> {
148             am.getRunningAppProcesses();
149         });
150 
151         // We use PendingIntent.getCreatorPackage, since
152         // getPackageIntentForSender is not public to us, but getCreatorPackage
153         // is just a thin wrapper around it.
154         PendingIntent pi = PendingIntent.getActivity(parent, 0, new Intent(), 0);
155         benchmarks.addBenchmark("getPackageIntentForSender", () -> {
156             pi.getCreatorPackage();
157         });
158 
159         PowerManager pwr = (PowerManager) parent.getSystemService(Context.POWER_SERVICE);
160         PowerManager.WakeLock wl = pwr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "benchmark tag");
161         benchmarks.addBenchmark("WakeLock Acquire/Release", () -> {
162             wl.acquire();
163             wl.release();
164         });
165 
166         AppOpsManager appOps = (AppOpsManager) parent.getSystemService(Context.APP_OPS_SERVICE);
167         int uid = Process.myUid();
168         benchmarks.addBenchmark("AppOpsService.checkOperation", () -> {
169             appOps.checkOp(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, uid, packageName);
170         });
171 
172         benchmarks.addBenchmark("AppOpsService.checkPackage", () -> {
173             appOps.checkPackage(uid, packageName);
174         });
175 
176         benchmarks.addBenchmark("AppOpsService.noteOperation", () -> {
177             appOps.noteOp(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, uid, packageName);
178         });
179 
180         benchmarks.addBenchmark("AppOpsService.noteProxyOperation", () -> {
181             appOps.noteProxyOp(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, packageName);
182         });
183 
184         UserManager userManager = (UserManager) parent.getSystemService(Context.USER_SERVICE);
185         benchmarks.addBenchmark("isUserUnlocked", () -> {
186             userManager.isUserUnlocked();
187         });
188 
189         benchmarks.addBenchmark("getIntentSender", () -> {
190             pi.getIntentSender();
191         });
192 
193         ConnectivityManager cm = (ConnectivityManager) parent
194                 .getSystemService(Context.CONNECTIVITY_SERVICE);
195         benchmarks.addBenchmark("getActiveNetworkInfo", () -> {
196             cm.getActiveNetworkInfo();
197         });
198     }
199 
200     /**
201      * A helper method for benchark runners to actually run the benchmark and gather stats
202      *
203      * @param thunk    The code whose performance we want to measure
204      * @param reporter What to do with the results
205      */
runBenchmarkInBackground(Runnable thunk, ResultListener reporter)206     static void runBenchmarkInBackground(Runnable thunk, ResultListener reporter) {
207         new AsyncTask() {
208             double resultMean = 0;
209             double resultStdev = 0;
210 
211             @Override
212             protected Object doInBackground(Object... _args) {
213                 long startTime = System.nanoTime();
214                 int count = 0;
215 
216                 // Run benchmark
217                 while (true) {
218                     long elapsed = -System.nanoTime();
219                     thunk.run();
220                     elapsed += System.nanoTime();
221 
222                     count++;
223                     double elapsedVariance = (double) elapsed - resultMean;
224                     resultMean += elapsedVariance / count;
225                     resultStdev += elapsedVariance * ((double) elapsed - resultMean);
226 
227                     if (System.nanoTime() - startTime > TIME_LIMIT * 1e9) {
228                         break;
229                     }
230                 }
231                 resultStdev = Math.sqrt(resultStdev / (count - 1));
232 
233                 return null;
234             }
235 
236             @Override
237             protected void onPostExecute(Object _result) {
238                 reporter.onResult(resultMean, resultStdev);
239             }
240         }.execute(new Object());
241     }
242 }
243