/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.startop.test; import android.app.Activity; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.os.AsyncTask; import android.os.PowerManager; import android.os.Process; import android.os.UserManager; /** * An interface for running benchmarks and collecting results. Used so we can have both an * interactive runner and a non-interactive runner. */ interface BenchmarkRunner { void addBenchmark(CharSequence name, Runnable thunk); } interface ResultListener { /** * Called when a benchmark result is ready * * @param mean The average iteration time in nanoseconds * @param stdev The standard deviation of iteration times in nanoseconds */ void onResult(double mean, double stdev); } class SystemServerBenchmarks { // Time limit to run benchmarks in seconds public static final int TIME_LIMIT = 5; static void initializeBenchmarks(Activity parent, BenchmarkRunner benchmarks) { final String packageName = parent.getPackageName(); PackageManager pm = parent.getPackageManager(); benchmarks.addBenchmark("getInstalledApplications", () -> { pm.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY); }); benchmarks.addBenchmark("getInstalledPackages", () -> { pm.getInstalledPackages(PackageManager.GET_ACTIVITIES); }); benchmarks.addBenchmark("getPackageInfo", () -> { try { pm.getPackageInfo(packageName, 0); } catch (NameNotFoundException e) { throw new RuntimeException(e); } }); benchmarks.addBenchmark("getApplicationInfo", () -> { try { pm.getApplicationInfo(packageName, 0); } catch (NameNotFoundException e) { throw new RuntimeException(e); } }); try { ApplicationInfo app = pm.getApplicationInfo(packageName, 0); benchmarks.addBenchmark("getResourcesForApplication", () -> { try { pm.getResourcesForApplication(app); } catch (NameNotFoundException e) { throw new RuntimeException(e); } }); benchmarks.addBenchmark("getPackagesForUid", () -> { pm.getPackagesForUid(app.uid); }); } catch (NameNotFoundException e) { throw new RuntimeException(e); } ComponentName component = new ComponentName(parent, parent.getClass()); benchmarks.addBenchmark("getActivityInfo", () -> { try { pm.getActivityInfo(component, PackageManager.GET_META_DATA); } catch (NameNotFoundException e) { throw new RuntimeException(e); } }); benchmarks.addBenchmark("getLaunchIntentForPackage", () -> { pm.getLaunchIntentForPackage(packageName); }); benchmarks.addBenchmark("getPackageUid", () -> { try { pm.getPackageUid(packageName, 0); } catch (NameNotFoundException e) { throw new RuntimeException(e); } }); benchmarks.addBenchmark("checkPermission", () -> { // Check for the first permission I could find. pm.checkPermission("android.permission.SEND_SMS", packageName); }); benchmarks.addBenchmark("checkSignatures", () -> { // Compare with settings, since settings is on both AOSP and Master builds pm.checkSignatures("com.android.settings", packageName); }); Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED); benchmarks.addBenchmark("queryBroadcastReceivers", () -> { pm.queryBroadcastReceivers(intent, 0); }); benchmarks.addBenchmark("hasSystemFeature", () -> { pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); }); benchmarks.addBenchmark("resolveService", () -> { pm.resolveService(intent, 0); }); ActivityManager am = (ActivityManager) parent.getSystemService(Context.ACTIVITY_SERVICE); benchmarks.addBenchmark("getRunningAppProcesses", () -> { am.getRunningAppProcesses(); }); // We use PendingIntent.getCreatorPackage, since // getPackageIntentForSender is not public to us, but getCreatorPackage // is just a thin wrapper around it. PendingIntent pi = PendingIntent.getActivity(parent, 0, new Intent(), 0); benchmarks.addBenchmark("getPackageIntentForSender", () -> { pi.getCreatorPackage(); }); PowerManager pwr = (PowerManager) parent.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pwr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "benchmark tag"); benchmarks.addBenchmark("WakeLock Acquire/Release", () -> { wl.acquire(); wl.release(); }); AppOpsManager appOps = (AppOpsManager) parent.getSystemService(Context.APP_OPS_SERVICE); int uid = Process.myUid(); benchmarks.addBenchmark("AppOpsService.checkOperation", () -> { appOps.checkOp(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, uid, packageName); }); benchmarks.addBenchmark("AppOpsService.checkPackage", () -> { appOps.checkPackage(uid, packageName); }); benchmarks.addBenchmark("AppOpsService.noteOperation", () -> { appOps.noteOp(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, uid, packageName); }); benchmarks.addBenchmark("AppOpsService.noteProxyOperation", () -> { appOps.noteProxyOp(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, packageName); }); UserManager userManager = (UserManager) parent.getSystemService(Context.USER_SERVICE); benchmarks.addBenchmark("isUserUnlocked", () -> { userManager.isUserUnlocked(); }); benchmarks.addBenchmark("getIntentSender", () -> { pi.getIntentSender(); }); ConnectivityManager cm = (ConnectivityManager) parent .getSystemService(Context.CONNECTIVITY_SERVICE); benchmarks.addBenchmark("getActiveNetworkInfo", () -> { cm.getActiveNetworkInfo(); }); } /** * A helper method for benchark runners to actually run the benchmark and gather stats * * @param thunk The code whose performance we want to measure * @param reporter What to do with the results */ static void runBenchmarkInBackground(Runnable thunk, ResultListener reporter) { new AsyncTask() { double resultMean = 0; double resultStdev = 0; @Override protected Object doInBackground(Object... _args) { long startTime = System.nanoTime(); int count = 0; // Run benchmark while (true) { long elapsed = -System.nanoTime(); thunk.run(); elapsed += System.nanoTime(); count++; double elapsedVariance = (double) elapsed - resultMean; resultMean += elapsedVariance / count; resultStdev += elapsedVariance * ((double) elapsed - resultMean); if (System.nanoTime() - startTime > TIME_LIMIT * 1e9) { break; } } resultStdev = Math.sqrt(resultStdev / (count - 1)); return null; } @Override protected void onPostExecute(Object _result) { reporter.onResult(resultMean, resultStdev); } }.execute(new Object()); } }