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.config.GlobalConfiguration;
20 import com.android.tradefed.config.IConfiguration;
21 import com.android.tradefed.config.IConfigurationReceiver;
22 import com.android.tradefed.config.Option;
23 import com.android.tradefed.device.DeviceNotAvailableException;
24 import com.android.tradefed.device.TestDeviceState;
25 import com.android.tradefed.invoker.TestInformation;
26 import com.android.tradefed.log.LogUtil;
27 import com.android.tradefed.result.ITestInvocationListener;
28 import com.android.tradefed.targetprep.BaseEmulatorPreparer;
29 import com.android.tradefed.testtype.AndroidJUnitTest;
30 import com.android.tradefed.testtype.IRemoteTest;
31 import com.android.tradefed.util.AaptParser;
32 
33 import com.google.common.base.Preconditions;
34 
35 import java.io.File;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.util.HashMap;
39 import java.util.Map;
40 
41 /**
42  * A base call for emulator performance tests that does repeated emulator launches, and runs
43  * instrumentation tests
44  */
45 public abstract class BaseEmulatorPerfTest implements IRemoteTest, IConfigurationReceiver {
46     @Option(name = "iterations", description = "number of launch iterations to perform")
47     private int mIterations = 1;
48 
49     @Option(name = "test-apk-name", description = "File name of test apk install", mandatory = true)
50     private String mInstallApkName;
51 
52     @Option(name = "test-dir-path", description = "File system path to test apks")
53     private File mTestDirPath;
54 
55     @Option(
56             name = "emulator-metrics-key",
57             description = "The test run name to use to report metrics",
58             mandatory = true)
59     private String mRunName;
60 
61     private IConfiguration mConfig;
62 
63     @Override
setConfiguration(IConfiguration configuration)64     public void setConfiguration(IConfiguration configuration) {
65         mConfig = configuration;
66     }
67 
68     @Override
run(TestInformation testInfo, ITestInvocationListener listener)69     public void run(TestInformation testInfo, ITestInvocationListener listener)
70             throws DeviceNotAvailableException {
71         Preconditions.checkArgument(testInfo.getDevice().getIDevice().isEmulator());
72         Preconditions.checkArgument(
73                 testInfo.getDevice().getDeviceState() == TestDeviceState.NOT_AVAILABLE);
74         Preconditions.checkNotNull(mTestDirPath, "--test-dir-path was not set");
75         Path apkPath = mTestDirPath.toPath().resolve(mInstallApkName);
76         Preconditions.checkArgument(Files.exists(apkPath), apkPath.toString() + " does not exist");
77 
78         // Pull the objects to perform the emulator launch amd run tests
79         // They are stored in config in order to support receiving Options.
80         BaseEmulatorPreparer emulatorLauncher =
81                 (BaseEmulatorPreparer) mConfig.getConfigurationObject("emulator_launcher");
82 
83         AndroidJUnitTest delegateTest =
84                 (AndroidJUnitTest) mConfig.getConfigurationObject("delegate_test");
85         delegateTest.setDevice(testInfo.getDevice());
86         // auto find package name of test apk
87         AaptParser parser = AaptParser.parse(apkPath.toFile());
88         delegateTest.setPackageName(parser.getPackageName());
89 
90         DataRecorder dataRecorder = new DataRecorder(mRunName);
91 
92         try {
93             for (int i = 1; i <= mIterations; i++) {
94                 LogUtil.CLog.i("Performing %d iteration of %d", i, mIterations);
95 
96                 performIteration(
97                         testInfo, emulatorLauncher, delegateTest, apkPath, dataRecorder, listener);
98 
99                 // let tradefed kill emulator for last iteration
100                 if (i < mIterations) {
101                     GlobalConfiguration.getDeviceManagerInstance()
102                             .killEmulator(testInfo.getDevice());
103                 }
104             }
105 
106             Map<String, String> buildMetrics = getBuildMetrics(testInfo);
107             dataRecorder.reportMetrics(listener, buildMetrics);
108 
109         } catch (Exception e) {
110             LogUtil.CLog.e(e);
111             listener.invocationFailed(e);
112         }
113     }
114 
getBuildMetrics(TestInformation testInfo)115     private Map<String, String> getBuildMetrics(TestInformation testInfo) {
116         Map<String, String> metrics = new HashMap<>();
117         // add 'emulator_build_id' to data to report if it exists
118         String emuBuildId = testInfo.getBuildInfo().getBuildAttributes().get("emulator-build-id");
119         if (emuBuildId != null) {
120             metrics.put("emulator_build_id", emuBuildId);
121         }
122         return metrics;
123     }
124 
performIteration( TestInformation device, BaseEmulatorPreparer emulatorLauncher, AndroidJUnitTest delegateTest, Path apkPath, DataRecorder dataRecorder, ITestInvocationListener listener)125     protected abstract void performIteration(
126             TestInformation device,
127             BaseEmulatorPreparer emulatorLauncher,
128             AndroidJUnitTest delegateTest,
129             Path apkPath,
130             DataRecorder dataRecorder,
131             ITestInvocationListener listener)
132             throws Exception;
133 }
134