1 /* 2 * Copyright (C) 2016 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 package com.android.tradefed.invoker; 17 18 import com.android.tradefed.build.BuildInfo; 19 import com.android.tradefed.build.BuildSerializedVersion; 20 import com.android.tradefed.build.IBuildInfo; 21 import com.android.tradefed.config.ConfigurationDescriptor; 22 import com.android.tradefed.device.ITestDevice; 23 import com.android.tradefed.device.ITestDevice.RecoveryMode; 24 import com.android.tradefed.log.LogUtil.CLog; 25 import com.android.tradefed.testtype.suite.ITestSuite; 26 import com.android.tradefed.util.MultiMap; 27 import com.android.tradefed.util.UniqueMultiMap; 28 29 import java.io.IOException; 30 import java.io.ObjectInputStream; 31 import java.util.ArrayList; 32 import java.util.LinkedHashMap; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Map.Entry; 36 37 /** 38 * Generic implementation of a {@link IInvocationContext}. 39 */ 40 public class InvocationContext implements IInvocationContext { 41 private static final long serialVersionUID = BuildSerializedVersion.VERSION; 42 43 // Transient field are not serialized 44 private transient Map<ITestDevice, IBuildInfo> mAllocatedDeviceAndBuildMap; 45 /** Map of the configuration device name and the actual {@link ITestDevice} * */ 46 private transient Map<String, ITestDevice> mNameAndDeviceMap; 47 private Map<String, IBuildInfo> mNameAndBuildinfoMap; 48 private final UniqueMultiMap<String, String> mInvocationAttributes = 49 new UniqueMultiMap<String, String>(); 50 private Map<IInvocationContext.TimingEvent, Long> mInvocationTimingMetrics; 51 /** Invocation test-tag **/ 52 private String mTestTag; 53 /** configuration descriptor */ 54 private ConfigurationDescriptor mConfigurationDescriptor; 55 /** module invocation context (when running as part of a {@link ITestSuite} */ 56 private IInvocationContext mModuleContext; 57 /** 58 * List of map the device serials involved in the sharded invocation, empty if not a sharded 59 * invocation. 60 */ 61 private Map<Integer, List<String>> mShardSerials; 62 63 private boolean mLocked; 64 65 /** 66 * Creates a {@link BuildInfo} using default attribute values. 67 */ InvocationContext()68 public InvocationContext() { 69 mInvocationTimingMetrics = new LinkedHashMap<>(); 70 mAllocatedDeviceAndBuildMap = new LinkedHashMap<ITestDevice, IBuildInfo>(); 71 // Use LinkedHashMap to ensure key ordering by insertion order 72 mNameAndDeviceMap = new LinkedHashMap<String, ITestDevice>(); 73 mNameAndBuildinfoMap = new LinkedHashMap<String, IBuildInfo>(); 74 mShardSerials = new LinkedHashMap<Integer, List<String>>(); 75 } 76 77 /** 78 * {@inheritDoc} 79 */ 80 @Override getNumDevicesAllocated()81 public int getNumDevicesAllocated() { 82 return mAllocatedDeviceAndBuildMap.size(); 83 } 84 85 /** 86 * {@inheritDoc} 87 */ 88 @Override addAllocatedDevice(String devicename, ITestDevice testDevice)89 public void addAllocatedDevice(String devicename, ITestDevice testDevice) { 90 mNameAndDeviceMap.put(devicename, testDevice); 91 // back fill the information if possible 92 if (mNameAndBuildinfoMap.get(devicename) != null) { 93 mAllocatedDeviceAndBuildMap.put(testDevice, mNameAndBuildinfoMap.get(devicename)); 94 } 95 } 96 97 /** 98 * {@inheritDoc} 99 */ 100 @Override addAllocatedDevice(Map<String, ITestDevice> deviceWithName)101 public void addAllocatedDevice(Map<String, ITestDevice> deviceWithName) { 102 mNameAndDeviceMap.putAll(deviceWithName); 103 // back fill the information if possible 104 for (Entry<String, ITestDevice> entry : deviceWithName.entrySet()) { 105 if (mNameAndBuildinfoMap.get(entry.getKey()) != null) { 106 mAllocatedDeviceAndBuildMap.put( 107 entry.getValue(), mNameAndBuildinfoMap.get(entry.getKey())); 108 } 109 } 110 } 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override getDeviceBuildMap()116 public Map<ITestDevice, IBuildInfo> getDeviceBuildMap() { 117 return mAllocatedDeviceAndBuildMap; 118 } 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override getDevices()124 public List<ITestDevice> getDevices() { 125 return new ArrayList<ITestDevice>(mNameAndDeviceMap.values()); 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override getBuildInfos()132 public List<IBuildInfo> getBuildInfos() { 133 return new ArrayList<IBuildInfo>(mNameAndBuildinfoMap.values()); 134 } 135 136 /** 137 * {@inheritDoc} 138 */ 139 @Override getSerials()140 public List<String> getSerials() { 141 List<String> listSerials = new ArrayList<String>(); 142 for (ITestDevice testDevice : mNameAndDeviceMap.values()) { 143 listSerials.add(testDevice.getSerialNumber()); 144 } 145 return listSerials; 146 } 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override getDeviceConfigNames()152 public List<String> getDeviceConfigNames() { 153 List<String> listNames = new ArrayList<String>(); 154 listNames.addAll(mNameAndDeviceMap.keySet()); 155 return listNames; 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 @Override getDevice(String deviceName)162 public ITestDevice getDevice(String deviceName) { 163 return mNameAndDeviceMap.get(deviceName); 164 } 165 166 /** 167 * {@inheritDoc} 168 */ 169 @Override getBuildInfo(String deviceName)170 public IBuildInfo getBuildInfo(String deviceName) { 171 return mNameAndBuildinfoMap.get(deviceName); 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override addDeviceBuildInfo(String deviceName, IBuildInfo buildinfo)178 public void addDeviceBuildInfo(String deviceName, IBuildInfo buildinfo) { 179 mNameAndBuildinfoMap.put(deviceName, buildinfo); 180 mAllocatedDeviceAndBuildMap.put(getDevice(deviceName), buildinfo); 181 } 182 183 /** 184 * {@inheritDoc} 185 */ 186 @Override getBuildInfo(ITestDevice testDevice)187 public IBuildInfo getBuildInfo(ITestDevice testDevice) { 188 return mAllocatedDeviceAndBuildMap.get(testDevice); 189 } 190 191 /** 192 * {@inheritDoc} 193 */ 194 @Override addInvocationAttribute(String attributeName, String attributeValue)195 public void addInvocationAttribute(String attributeName, String attributeValue) { 196 if (mLocked) { 197 throw new IllegalStateException( 198 "Attempting to add invocation attribute during a test."); 199 } 200 mInvocationAttributes.put(attributeName, attributeValue); 201 } 202 203 /** {@inheritDoc} */ 204 @Override addInvocationAttributes(UniqueMultiMap<String, String> attributesMap)205 public void addInvocationAttributes(UniqueMultiMap<String, String> attributesMap) { 206 if (mLocked) { 207 throw new IllegalStateException( 208 "Attempting to add invocation attribute during a test."); 209 } 210 mInvocationAttributes.putAll(attributesMap); 211 } 212 213 /** {@inheritDoc} */ 214 @Override getAttributes()215 public MultiMap<String, String> getAttributes() { 216 // Return a copy of the map to avoid unwanted modifications. 217 UniqueMultiMap<String, String> copy = new UniqueMultiMap<>(); 218 copy.putAll(mInvocationAttributes); 219 return copy; 220 } 221 222 223 /** {@inheritDoc} */ 224 @Override getInvocationTimingMetrics()225 public Map<IInvocationContext.TimingEvent, Long> getInvocationTimingMetrics() { 226 return mInvocationTimingMetrics; 227 } 228 229 /** 230 * {@inheritDoc} 231 */ 232 @Override addInvocationTimingMetric(IInvocationContext.TimingEvent timingEvent, Long durationMillis)233 public void addInvocationTimingMetric(IInvocationContext.TimingEvent timingEvent, 234 Long durationMillis) { 235 mInvocationTimingMetrics.put(timingEvent, durationMillis); 236 } 237 238 /** 239 * {@inheritDoc} 240 */ 241 @Override getDeviceBySerial(String serial)242 public ITestDevice getDeviceBySerial(String serial) { 243 for (ITestDevice testDevice : mNameAndDeviceMap.values()) { 244 if (testDevice.getSerialNumber().equals(serial)) { 245 return testDevice; 246 } 247 } 248 CLog.d("Device with serial '%s', not found in the metadata", serial); 249 return null; 250 } 251 252 /** {@inheritDoc} */ 253 @Override getDeviceName(ITestDevice device)254 public String getDeviceName(ITestDevice device) { 255 for (String name : mNameAndDeviceMap.keySet()) { 256 if (device.equals(getDevice(name))) { 257 return name; 258 } 259 } 260 CLog.d( 261 "Device with serial '%s' doesn't match a name in the metadata", 262 device.getSerialNumber()); 263 return null; 264 } 265 266 /** {@inheritDoc} */ 267 @Override getTestTag()268 public String getTestTag() { 269 return mTestTag; 270 } 271 272 /** 273 * {@inheritDoc} 274 */ 275 @Override setTestTag(String testTag)276 public void setTestTag(String testTag) { 277 mTestTag = testTag; 278 } 279 280 /** 281 * {@inheritDoc} 282 */ 283 @Override setRecoveryModeForAllDevices(RecoveryMode mode)284 public void setRecoveryModeForAllDevices(RecoveryMode mode) { 285 for (ITestDevice device : getDevices()) { 286 device.setRecoveryMode(mode); 287 } 288 } 289 290 /** {@inheritDoc} */ 291 @Override setConfigurationDescriptor(ConfigurationDescriptor configurationDescriptor)292 public void setConfigurationDescriptor(ConfigurationDescriptor configurationDescriptor) { 293 mConfigurationDescriptor = configurationDescriptor; 294 } 295 296 /** {@inheritDoc} */ 297 @Override getConfigurationDescriptor()298 public ConfigurationDescriptor getConfigurationDescriptor() { 299 return mConfigurationDescriptor; 300 } 301 302 /** {@inheritDoc} */ 303 @Override setModuleInvocationContext(IInvocationContext invocationContext)304 public void setModuleInvocationContext(IInvocationContext invocationContext) { 305 mModuleContext = invocationContext; 306 } 307 308 /** {@inheritDoc} */ 309 @Override getModuleInvocationContext()310 public IInvocationContext getModuleInvocationContext() { 311 return mModuleContext; 312 } 313 314 /** Lock the context to prevent more invocation attributes to be added. */ lockAttributes()315 public void lockAttributes() { 316 mLocked = true; 317 } 318 319 /** {@inheritDoc} */ 320 @Override addSerialsFromShard(Integer index, List<String> serials)321 public void addSerialsFromShard(Integer index, List<String> serials) { 322 if (mLocked) { 323 throw new IllegalStateException( 324 "Attempting to add serial from shard attribute during a test."); 325 } 326 mShardSerials.put(index, serials); 327 } 328 329 /** {@inheritDoc} */ 330 @Override getShardsSerials()331 public Map<Integer, List<String>> getShardsSerials() { 332 return new LinkedHashMap<>(mShardSerials); 333 } 334 335 /** Special java method that allows for custom deserialization. */ readObject(ObjectInputStream in)336 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 337 // our "pseudo-constructor" 338 in.defaultReadObject(); 339 // now we are a "live" object again, so let's init the transient field 340 mAllocatedDeviceAndBuildMap = new LinkedHashMap<ITestDevice, IBuildInfo>(); 341 mNameAndDeviceMap = new LinkedHashMap<String, ITestDevice>(); 342 // For compatibility, when parent TF does not have the invocation timing yet. 343 if (mInvocationTimingMetrics == null) { 344 mInvocationTimingMetrics = new LinkedHashMap<>(); 345 } 346 } 347 } 348