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