blob: 50ac676cb5730a38045a370ae2358cf025c66100 [file] [log] [blame]
/*
* 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.tradefed.device.metric;
import com.android.annotations.VisibleForTesting;
import com.android.tradefed.device.ILogcatReceiver;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.LogcatReceiver;
import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.RunUtil;
import java.util.HashMap;
import java.util.Map;
/** Collector that will capture and log a logcat when a test case fails. */
public class LogcatOnFailureCollector extends BaseDeviceMetricCollector {
private static final int MAX_LOGAT_SIZE_BYTES = 4 * 1024 * 1024;
/** Always include a bit of prior data to capture what happened before */
private static final int OFFSET_CORRECTION = 20000;
private static final String NAME_FORMAT = "logcat-on-failure-%s-%s#%s";
private Map<ITestDevice, ILogcatReceiver> mLogcatReceivers = new HashMap<>();
private Map<ITestDevice, Integer> mOffset = new HashMap<>();
@Override
public void onTestRunStart(DeviceMetricData runData) {
for (ITestDevice device : getDevices()) {
// In case of multiple runs for the same test runner, re-init the receiver.
initReceiver(device);
// Get the current offset of the buffer to be able to query later
int offset = (int) mLogcatReceivers.get(device).getLogcatData().size();
if (offset > OFFSET_CORRECTION) {
offset -= OFFSET_CORRECTION;
}
mOffset.put(device, offset);
}
}
@Override
public void onTestStart(DeviceMetricData testData) {
// TODO: Handle the buffer to reset it at the test start
}
@Override
public void onTestFail(DeviceMetricData testData, TestDescription test) {
for (ITestDevice device : getDevices()) {
// Delay slightly for the error to get in the logcat
getRunUtil().sleep(100);
try (InputStreamSource logcatSource =
mLogcatReceivers
.get(device)
.getLogcatData(MAX_LOGAT_SIZE_BYTES, mOffset.get(device))) {
String name =
String.format(
NAME_FORMAT,
device.getSerialNumber(),
test.getClassName(),
test.getTestName());
super.testLog(name, LogDataType.LOGCAT, logcatSource);
}
}
}
@Override
public void onTestRunEnd(DeviceMetricData runData, Map<String, Metric> currentRunMetrics) {
clearReceivers();
}
@VisibleForTesting
ILogcatReceiver createLogcatReceiver(ITestDevice device) {
return new LogcatReceiver(device, "logcat", device.getOptions().getMaxLogcatDataSize(), 0);
}
@VisibleForTesting
IRunUtil getRunUtil() {
return RunUtil.getDefault();
}
private void initReceiver(ITestDevice device) {
if (mLogcatReceivers.get(device) == null) {
ILogcatReceiver receiver = createLogcatReceiver(device);
mLogcatReceivers.put(device, receiver);
receiver.start();
}
}
private void clearReceivers() {
for (ILogcatReceiver receiver : mLogcatReceivers.values()) {
receiver.stop();
receiver.clear();
}
mLogcatReceivers.clear();
mOffset.clear();
}
}