1 /*
2  * Copyright (C) 2015 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.compatibility.common.tradefed.targetprep;
18 
19 import com.android.compatibility.common.util.DeviceInfo;
20 import com.android.compatibility.common.util.DevicePropertyInfo;
21 import com.android.tradefed.build.IBuildInfo;
22 import com.android.tradefed.config.Option;
23 import com.android.tradefed.config.OptionClass;
24 import com.android.tradefed.device.DeviceNotAvailableException;
25 import com.android.tradefed.device.ITestDevice;
26 import com.android.tradefed.invoker.TestInformation;
27 import com.android.tradefed.log.ITestLogger;
28 import com.android.tradefed.log.LogUtil.CLog;
29 import com.android.tradefed.result.FileInputStreamSource;
30 import com.android.tradefed.result.ITestLoggerReceiver;
31 import com.android.tradefed.result.LogDataType;
32 import com.android.tradefed.targetprep.BuildError;
33 import com.android.tradefed.targetprep.TargetSetupError;
34 import com.android.tradefed.util.FileUtil;
35 
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.Map.Entry;
39 
40 /** An {@link ApkInstrumentationPreparer} that collects device info. */
41 @OptionClass(alias = "device-info-collector")
42 public class DeviceInfoCollector extends ApkInstrumentationPreparer implements ITestLoggerReceiver {
43 
44     public static final String DEVICE_INFO_DIR = "device_info_dir";
45     public static final String SKIP_DEVICE_INFO_OPTION = "skip-device-info";
46 
47     private static final String ABI = "ro.product.cpu.abi";
48     private static final String ABI2 = "ro.product.cpu.abi2";
49     private static final String ABIS = "ro.product.cpu.abilist";
50     private static final String ABIS_32 = "ro.product.cpu.abilist32";
51     private static final String ABIS_64 = "ro.product.cpu.abilist64";
52     private static final String BOARD = "ro.product.board";
53     private static final String BRAND = "ro.product.brand";
54     private static final String DEVICE = "ro.product.device";
55     private static final String FINGERPRINT = "ro.build.fingerprint";
56     private static final String VENDOR_FINGERPRINT = "ro.vendor.build.fingerprint";
57     private static final String BOOTIMAGE_FINGERPRINT = "ro.bootimage.build.fingerprint";
58     private static final String ID = "ro.build.id";
59     private static final String MANUFACTURER = "ro.product.manufacturer";
60     private static final String MODEL = "ro.product.model";
61     private static final String PRODUCT = "ro.product.name";
62     private static final String REFERENCE_FINGERPRINT = "ro.build.reference.fingerprint";
63     private static final String SERIAL = "ro.serialno";
64     private static final String TAGS = "ro.build.tags";
65     private static final String TYPE = "ro.build.type";
66     private static final String VERSION_BASE_OS = "ro.build.version.base_os";
67     private static final String VERSION_RELEASE = "ro.build.version.release";
68     private static final String VERSION_SDK = "ro.build.version.sdk";
69     private static final String VERSION_SECURITY_PATCH = "ro.build.version.security_patch";
70     private static final String VERSION_INCREMENTAL = "ro.build.version.incremental";
71 
72     private static final String PREFIX_TAG = "cts:build_";
73 
74     @Option(name = SKIP_DEVICE_INFO_OPTION,
75             shortName = 'd',
76             description = "Whether device info collection should be skipped")
77     private boolean mSkipDeviceInfo = false;
78 
79     @Option(
80             name = "force-collect-device-info",
81             description =
82                     "Force device info collection. If set to true, "
83                             + SKIP_DEVICE_INFO_OPTION
84                             + " is ignored.")
85     private boolean mForceCollectDeviceInfo = false;
86 
87     @Option(name= "src-dir", description = "The directory to copy to the results dir")
88     private String mSrcDir;
89 
90     @Option(name = "dest-dir", description = "The directory under the result to store the files")
91     private String mDestDir = DeviceInfo.RESULT_DIR_NAME;
92 
93     @Deprecated
94     @Option(name = "temp-dir", description = "The directory containing host-side device info files")
95     private String mTempDir;
96 
97     private ITestLogger mLogger;
98     private File deviceInfoDir = null;
99 
DeviceInfoCollector()100     public DeviceInfoCollector() {
101         mWhen = When.BEFORE;
102     }
103 
104     @Override
setUp(TestInformation testInfo)105     public void setUp(TestInformation testInfo)
106             throws TargetSetupError, BuildError, DeviceNotAvailableException {
107         if (testInfo.getBuildInfo().getFile(DEVICE_INFO_DIR) != null) {
108             CLog.i("Device info already collected, skipping DeviceInfoCollector.");
109             return;
110         }
111         if (mSkipDeviceInfo && !mForceCollectDeviceInfo) {
112             return;
113         }
114         ITestDevice device = testInfo.getDevice();
115         IBuildInfo buildInfo = testInfo.getBuildInfo();
116         DevicePropertyInfo devicePropertyInfo =
117                 new DevicePropertyInfo(
118                         ABI,
119                         ABI2,
120                         ABIS,
121                         ABIS_32,
122                         ABIS_64,
123                         BOARD,
124                         BRAND,
125                         DEVICE,
126                         FINGERPRINT,
127                         VENDOR_FINGERPRINT,
128                         ID,
129                         MANUFACTURER,
130                         MODEL,
131                         PRODUCT,
132                         REFERENCE_FINGERPRINT,
133                         SERIAL,
134                         TAGS,
135                         TYPE,
136                         VERSION_BASE_OS,
137                         VERSION_RELEASE,
138                         VERSION_SDK,
139                         VERSION_SECURITY_PATCH,
140                         VERSION_INCREMENTAL,
141                         BOOTIMAGE_FINGERPRINT);
142 
143         // add device properties to the result with a prefix tag for each key
144         for (Entry<String, String> entry :
145                 devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) {
146             String property = nullToEmpty(device.getProperty(entry.getValue()));
147             buildInfo.addBuildAttribute(entry.getKey(), property);
148         }
149         run(testInfo);
150         try {
151             deviceInfoDir = FileUtil.createTempDir(DeviceInfo.RESULT_DIR_NAME);
152             if (device.pullDir(mSrcDir, deviceInfoDir)) {
153                 if (!deviceInfoDir.exists() || deviceInfoDir.listFiles() == null) {
154                     CLog.e(
155                             "Pulled device-info, but local dir '%s' is not valid. "
156                                     + "[exists=%s, isDir=%s].",
157                             deviceInfoDir, deviceInfoDir.exists(), deviceInfoDir.isDirectory());
158                 } else {
159                     for (File deviceInfoFile : deviceInfoDir.listFiles()) {
160                         try (FileInputStreamSource source =
161                                 new FileInputStreamSource(deviceInfoFile)) {
162                             mLogger.testLog(deviceInfoFile.getName(), LogDataType.TEXT, source);
163                         }
164                     }
165                     // Some host tests depends on this code. E.g. SELinuxHostTestCases reads device
166                     // info files by querying DEVICE_INFO_DIR against buildInfo. Change this with
167                     // caution.
168                     buildInfo.setFile(
169                             DEVICE_INFO_DIR,
170                             deviceInfoDir,
171                             /** version */
172                             "v1");
173                 }
174             } else {
175                 CLog.e("Failed to pull device-info files from device %s", device.getSerialNumber());
176             }
177         } catch (IOException e) {
178             CLog.e("Failed to pull device-info files from device %s", device.getSerialNumber());
179             CLog.e(e);
180         }
181     }
182 
183     @Override
tearDown(TestInformation testInfo, Throwable e)184     public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException {
185         FileUtil.recursiveDelete(deviceInfoDir);
186         super.tearDown(testInfo, e);
187     }
188 
189     @Override
setTestLogger(ITestLogger testLogger)190     public void setTestLogger(ITestLogger testLogger) {
191         mLogger = testLogger;
192     }
193 
nullToEmpty(String value)194     private static String nullToEmpty(String value) {
195         return value == null ? "" : value;
196     }
197 }
198