1 /* 2 * Copyright (C) 2021 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.performance.tests; 18 19 import com.android.tradefed.device.DeviceNotAvailableException; 20 import com.android.tradefed.device.IManagedTestDevice; 21 import com.android.tradefed.device.ITestDevice; 22 import com.android.tradefed.invoker.TestInformation; 23 import com.android.tradefed.log.LogUtil; 24 import com.android.tradefed.result.ITestInvocationListener; 25 import com.android.tradefed.targetprep.BaseEmulatorPreparer; 26 import com.android.tradefed.testtype.AndroidJUnitTest; 27 import com.android.tradefed.util.RunUtil; 28 29 import java.io.IOException; 30 import java.nio.file.Path; 31 import java.util.List; 32 33 /** A performance test that does repeated emulator launches and measures timings. */ 34 public class EmulatorStartupPerfTest extends BaseEmulatorPerfTest { 35 36 public static class EmulatorLauncher extends BaseEmulatorPreparer { 37 38 /** 39 * Launches emulator with args provided via Configuration. 40 * 41 * <p>We want to launch emulator directly rather than going through 42 * DeviceManager#launchEmulator in order to measure timing accurately: DeviceManager 43 * performs several time consuming steps before returning 44 */ launchEmulator(ITestDevice device)45 public void launchEmulator(ITestDevice device) throws IOException { 46 List<String> args = buildEmulatorLaunchArgs(); 47 48 args.add("-read-only"); 49 String port = device.getSerialNumber().replace("emulator-", ""); 50 args.add("-port"); 51 args.add(port); 52 53 RunUtil runUtil = buildRunUtilForEmulatorLaunch(); 54 55 Process p = runUtil.runCmdInBackground(args); 56 ((IManagedTestDevice) device).setEmulatorProcess(p); 57 } 58 } 59 60 @Override performIteration( TestInformation testInfo, BaseEmulatorPreparer baseEmulatorPreparer, AndroidJUnitTest delegateTest, Path apkPath, DataRecorder timingsRecorder, ITestInvocationListener listener)61 protected void performIteration( 62 TestInformation testInfo, 63 BaseEmulatorPreparer baseEmulatorPreparer, 64 AndroidJUnitTest delegateTest, 65 Path apkPath, 66 DataRecorder timingsRecorder, 67 ITestInvocationListener listener) 68 throws Exception { 69 70 EmulatorLauncher emulatorLauncher = (EmulatorLauncher) baseEmulatorPreparer; 71 72 ITestDevice device = testInfo.getDevice(); 73 long startTimeMs = System.currentTimeMillis(); 74 timingsRecorder.captureTime( 75 "online_time", 76 () -> { 77 emulatorLauncher.launchEmulator(device); 78 device.waitForDeviceOnline(1 * 60 * 1000); 79 return null; 80 }); 81 82 timingsRecorder.captureTime( 83 "boot_time", 84 () -> { 85 waitForBootComplete(device, startTimeMs + 3 * 60 * 1000); 86 return null; 87 }); 88 89 timingsRecorder.captureTime( 90 "install_time", 91 () -> { 92 // direcly install package instead of using 93 // ITestDevice.installPackage 94 // to avoid overhead of the expensive aapt parsing checks it 95 // does every time 96 String result = device.executeAdbCommand("install", apkPath.toString()); 97 LogUtil.CLog.i("Install returned " + result); 98 return null; 99 }); 100 101 timingsRecorder.captureTime( 102 "test_time", 103 () -> { 104 delegateTest.run(testInfo, listener); 105 return null; 106 }); 107 108 timingsRecorder.recordMetric("total_time", System.currentTimeMillis() - startTimeMs); 109 110 LogUtil.CLog.i("Metrics: %s", timingsRecorder.toString()); 111 } 112 waitForBootComplete(ITestDevice device, long quitAfterTime)113 private void waitForBootComplete(ITestDevice device, long quitAfterTime) 114 throws DeviceNotAvailableException { 115 // we don't want to use waitForDeviceAvailable, as that has a 3 second sleep 116 // so directly query for boot complete 117 while (System.currentTimeMillis() < quitAfterTime) { 118 String result = device.executeShellCommand("getprop dev.bootcomplete"); 119 if (result.trim().equals("1")) { 120 return; 121 } 122 RunUtil.getDefault().sleep(50); 123 } 124 } 125 } 126