Snap for 7132927 from df3091a0e5bad5d41e6dad8653298ec5910af7b7 to mainline-documentsui-release
Change-Id: Ic40c672bba048af2a3bc66eb3595865c87a66727
diff --git a/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java b/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java
index 151ea6b..c755d7f 100644
--- a/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java
+++ b/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java
@@ -22,6 +22,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.StringJoiner;
@@ -31,6 +32,9 @@
*/
public final class NativeCodeCoverageFlusher {
+ private static final String EXTRACT_SIGCGT_FORMAT =
+ "cat /proc/%d/status | grep SigCgt | awk '{ print $2 }'";
+ private static final long SIGNAL_37_BIT = 1 << (37 - 1);
private static final String COVERAGE_FLUSH_COMMAND_FORMAT = "kill -37 %s";
private static final String CLEAR_CLANG_COVERAGE_FILES =
"find /data/misc/trace -name '*.profraw' -delete";
@@ -66,28 +70,59 @@
public void forceCoverageFlush() throws DeviceNotAvailableException {
checkState(mDevice.isAdbRoot(), "adb root is required to flush native coverage data.");
- if ((mProcessNames == null) || mProcessNames.isEmpty()) {
- // Use the special pid -1 to trigger a coverage flush of all running processes.
- mDevice.executeShellCommand(String.format(COVERAGE_FLUSH_COMMAND_FORMAT, "-1"));
- } else {
- // Look up the pid of the processes to send them the coverage flush signal.
- StringJoiner pidString = new StringJoiner(" ");
- for (String processName : mProcessNames) {
- String pid = mDevice.getProcessPid(processName);
- if (pid == null) {
- CLog.w("Did not find pid for process \"%s\".", processName);
- } else {
- pidString.add(pid);
- }
- }
+ List<Integer> signalHandlingPids = findSignalHandlingPids(mProcessNames);
+ StringJoiner pidString = new StringJoiner(" ");
- if (pidString.length() > 0) {
- mDevice.executeShellCommand(
- String.format(COVERAGE_FLUSH_COMMAND_FORMAT, pidString.toString()));
- }
+ CLog.d("Signal handling pids: %s", signalHandlingPids.toString());
+
+ for (Integer pid : signalHandlingPids) {
+ pidString.add(pid.toString());
+ }
+
+ if (pidString.length() > 0) {
+ mDevice.executeShellCommand(
+ String.format(COVERAGE_FLUSH_COMMAND_FORMAT, pidString.toString()));
}
// Wait up to 5 minutes for the device to be available after flushing coverage data.
mDevice.waitForDeviceAvailable(5 * 60 * 1000);
}
+
+ /** Finds processes that handle the native coverage flush signal (37). */
+ private List<Integer> findSignalHandlingPids(List<String> processNames)
+ throws DeviceNotAvailableException {
+ // Get a list of all running pids.
+ List<ProcessInfo> allProcessInfo =
+ PsParser.getProcesses(mDevice.executeShellCommand("ps -e"));
+ ImmutableList.Builder<Integer> signalHandlingPids = ImmutableList.builder();
+
+ // Check SigCgt from /proc/<pid>/status to see if the bit for signal 37 is set.
+ for (ProcessInfo processInfo : allProcessInfo) {
+ CommandResult result =
+ mDevice.executeShellV2Command(
+ String.format(EXTRACT_SIGCGT_FORMAT, processInfo.getPid()));
+
+ if (!result.getStatus().equals(CommandStatus.SUCCESS) || (result.getExitCode() != 0)) {
+ CLog.w(
+ "Failed to read /proc/%d/status for %s",
+ processInfo.getPid(), processInfo.getName());
+ } else if (result.getStdout().trim().isEmpty()) {
+ CLog.w(
+ "Empty string when retrieving SigCgt for %s (pid %d)",
+ processInfo.getName(), processInfo.getPid());
+ } else {
+ long sigCgt = Long.parseLong(result.getStdout().trim(), 16);
+
+ // Check the signal bit is set and either no processes are set, or this specific
+ // process is in the process list.
+ if ((sigCgt & SIGNAL_37_BIT) == SIGNAL_37_BIT
+ && (processNames.isEmpty()
+ || processNames.contains(processInfo.getName()))) {
+ signalHandlingPids.add(processInfo.getPid());
+ }
+ }
+ }
+
+ return signalHandlingPids.build();
+ }
}
diff --git a/tests/src/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java b/tests/src/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java
index c7545a2..f355326 100644
--- a/tests/src/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java
+++ b/tests/src/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java
@@ -89,6 +89,10 @@
private static final int TEST_COUNT = 5;
private static final long ELAPSED_TIME = 1000;
+ private static final String PS_OUTPUT =
+ "USER PID PPID VSZ RSS WCHAN PC S NAME\n"
+ + "shell 123 1366 123 456 SyS_epoll+ 0 S adbd\n";
+
@Rule public TemporaryFolder folder = new TemporaryFolder();
private HashMap<String, MetricMeasurement.Metric> mMetrics;
@@ -127,6 +131,13 @@
doReturn(ImmutableList.of(mMockDevice)).when(mMockContext).getDevices();
+ doReturn(PS_OUTPUT).when(mMockDevice).executeShellCommand("ps -e");
+
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("ffffffffff\n");
+ result.setExitCode(0);
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
mListener = new ClangCodeCoverageCollector();
mListener.setConfiguration(mMockConfiguration);
mListener.setRunUtil(mCommandArgumentCaptor);
@@ -175,9 +186,9 @@
mListener.testRunEnded(ELAPSED_TIME, mMetrics);
mListener.invocationEnded(ELAPSED_TIME);
- // Verify the flush-all-coverage command was called twice - once on init() and once during
+ // Verify the flush-coverage command was called twice - once on init() and once during
// the end of the test run.
- verify(mMockDevice, times(2)).executeShellCommand("kill -37 -1");
+ verify(mMockDevice, times(2)).executeShellCommand("kill -37 123");
}
@Test
@@ -383,7 +394,9 @@
InOrder inOrder = Mockito.inOrder(mMockDevice);
inOrder.verify(mMockDevice).isAdbRoot();
inOrder.verify(mMockDevice).enableAdbRoot();
- inOrder.verify(mMockDevice).executeShellCommand("kill -37 -1");
+ inOrder.verify(mMockDevice).executeShellCommand("ps -e");
+ inOrder.verify(mMockDevice).executeShellV2Command(anyString());
+ inOrder.verify(mMockDevice).executeShellCommand("kill -37 123");
inOrder.verify(mMockDevice, times(2)).executeShellCommand(anyString());
inOrder.verify(mMockDevice).disableAdbRoot();
}
diff --git a/tests/src/com/android/tradefed/device/metric/GcovCodeCoverageCollectorTest.java b/tests/src/com/android/tradefed/device/metric/GcovCodeCoverageCollectorTest.java
index 4dc8562..66159e2 100644
--- a/tests/src/com/android/tradefed/device/metric/GcovCodeCoverageCollectorTest.java
+++ b/tests/src/com/android/tradefed/device/metric/GcovCodeCoverageCollectorTest.java
@@ -34,6 +34,8 @@
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.testtype.coverage.CoverageOptions;
import com.android.tradefed.util.proto.TfMetricProtoUtil;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -76,6 +78,10 @@
private static final int TEST_COUNT = 5;
private static final long ELAPSED_TIME = 1000;
+ private static final String PS_OUTPUT =
+ "USER PID PPID VSZ RSS WCHAN PC S NAME\n"
+ + "shell 123 1366 123 456 SyS_epoll+ 0 S adbd\n";
+
@Rule public TemporaryFolder folder = new TemporaryFolder();
@Mock IConfiguration mMockConfiguration;
@@ -93,7 +99,7 @@
GcovCodeCoverageCollector mCodeCoverageListener;
@Before
- public void setUp() throws ConfigurationException {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mCoverageOptions = new CoverageOptions();
@@ -102,6 +108,13 @@
doReturn(mCoverageOptions).when(mMockConfiguration).getCoverageOptions();
doReturn(ImmutableList.of(mMockDevice)).when(mMockContext).getDevices();
+ doReturn(PS_OUTPUT).when(mMockDevice).executeShellCommand("ps -e");
+
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("ffffffffffff\n");
+ result.setExitCode(0);
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
mCodeCoverageListener = new GcovCodeCoverageCollector();
mCodeCoverageListener.setConfiguration(mMockConfiguration);
}
@@ -185,9 +198,9 @@
Map<String, String> metric = new HashMap<>();
mCodeCoverageListener.testRunEnded(ELAPSED_TIME, TfMetricProtoUtil.upgradeConvert(metric));
- // Verify the flush-all-coverage command was called twice - once on init(...) and once
+ // Verify the flush-coverage command was called twice - once on init(...) and once
// on test run end.
- verify(mMockDevice, times(2)).executeShellCommand("kill -37 -1");
+ verify(mMockDevice, times(2)).executeShellCommand("kill -37 123");
}
@Test
@@ -198,8 +211,6 @@
mCoverageOptionsSetter.setOptionValue("coverage-processes", "adbd");
doReturn(true).when(mMockDevice).isAdbRoot();
- doReturn("123").when(mMockDevice).getProcessPid("mediaserver");
- doReturn("56789").when(mMockDevice).getProcessPid("adbd");
doReturn(createTar(ImmutableMap.of())).when(mMockDevice).pullFile(anyString());
// Simulate a test run.
@@ -210,7 +221,7 @@
// Verify the flush-coverage command was called with the specific pids twice - once on
// init(...) and once on test run end.
- verify(mMockDevice, times(2)).executeShellCommand("kill -37 123 56789");
+ verify(mMockDevice, times(2)).executeShellCommand("kill -37 123");
}
@Test
@@ -289,7 +300,7 @@
InOrder inOrder = Mockito.inOrder(mMockDevice);
inOrder.verify(mMockDevice).isAdbRoot();
inOrder.verify(mMockDevice).enableAdbRoot();
- inOrder.verify(mMockDevice).executeShellCommand("kill -37 -1");
+ inOrder.verify(mMockDevice).executeShellCommand("kill -37 123");
inOrder.verify(mMockDevice, times(2)).executeShellCommand(anyString());
inOrder.verify(mMockDevice).disableAdbRoot();
}
diff --git a/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java b/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java
index 481b0ef..6c2ff47 100644
--- a/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java
+++ b/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java
@@ -18,9 +18,11 @@
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -39,20 +41,32 @@
@RunWith(JUnit4.class)
public final class NativeCodeCoverageFlusherTest {
+ private static final String PS_OUTPUT =
+ "USER PID PPID VSZ RSS WCHAN PC S NAME\n"
+ + "shell 123 1366 123 456 SyS_epoll+ 0 S adbd\n"
+ + "root 234 1 7890 123 binder_io+ 0 S logcat\n"
+ + "root 456 1234 567 890 binder_io+ 0 S media.swcodec\n";
@Mock ITestDevice mMockDevice;
// Object under test
NativeCodeCoverageFlusher mFlusher;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ doReturn(PS_OUTPUT).when(mMockDevice).executeShellCommand("ps -e");
}
@Test
public void testClearCoverageMeasurements_rmCommandCalled() throws DeviceNotAvailableException {
doReturn(true).when(mMockDevice).isAdbRoot();
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("ffffffffffff\n");
+ result.setExitCode(0);
+
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
mFlusher = new NativeCodeCoverageFlusher(mMockDevice, ImmutableList.of());
mFlusher.resetCoverage();
@@ -82,27 +96,120 @@
throws DeviceNotAvailableException {
doReturn(true).when(mMockDevice).isAdbRoot();
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("ffffffffffff\n");
+ result.setExitCode(0);
+
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
mFlusher = new NativeCodeCoverageFlusher(mMockDevice, ImmutableList.of());
mFlusher.forceCoverageFlush();
- // Verify that the flush command for all processes was called.
- verify(mMockDevice).executeShellCommand("kill -37 -1");
+ // Verify that the flush command for all individual processes was called.
+ verify(mMockDevice).executeShellCommand("kill -37 123 234 456");
}
@Test
public void testFlushCoverageSpecificProcesses_flushSpecificCommandCalled()
throws DeviceNotAvailableException {
- List<String> processes = ImmutableList.of("mediaserver", "mediaextractor");
+ List<String> processes = ImmutableList.of("adbd", "logcat");
doReturn(true).when(mMockDevice).isAdbRoot();
- doReturn("12").when(mMockDevice).getProcessPid(processes.get(0));
- doReturn("789").when(mMockDevice).getProcessPid(processes.get(1));
+
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("ffffffffffff\n");
+ result.setExitCode(0);
+
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
mFlusher = new NativeCodeCoverageFlusher(mMockDevice, processes);
mFlusher.forceCoverageFlush();
// Verify that the flush command for the specific processes was called.
- verify(mMockDevice).executeShellCommand("kill -37 12 789");
+ verify(mMockDevice).executeShellCommand("kill -37 123 234");
+ }
+
+ @Test
+ public void testFlushNotHandled_flushNotCalled() throws DeviceNotAvailableException {
+ List<String> processes = ImmutableList.of("adbd");
+
+ doReturn(true).when(mMockDevice).isAdbRoot();
+
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("0000000000\n");
+ result.setExitCode(0);
+
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
+ mFlusher = new NativeCodeCoverageFlusher(mMockDevice, processes);
+ mFlusher.forceCoverageFlush();
+
+ // Verify that the flush command was not called.
+ verify(mMockDevice, never()).executeShellCommand("kill -37 123");
+ }
+
+ @Test
+ public void testFlushStatusReadFailed_flushNotCalled() throws DeviceNotAvailableException {
+ List<String> processes = ImmutableList.of("adbd");
+
+ doReturn(true).when(mMockDevice).isAdbRoot();
+
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setExitCode(-1);
+
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
+ mFlusher = new NativeCodeCoverageFlusher(mMockDevice, processes);
+ mFlusher.forceCoverageFlush();
+
+ // Verify that the flush command was not called.
+ verify(mMockDevice, never()).executeShellCommand("kill -37 123");
+ }
+
+ @Test
+ public void testFlushStatusReadEmpty_flushNotCalled() throws DeviceNotAvailableException {
+ List<String> processes = ImmutableList.of("adbd");
+
+ doReturn(true).when(mMockDevice).isAdbRoot();
+
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("");
+ result.setExitCode(0);
+
+ when(mMockDevice.executeShellV2Command(anyString())).thenReturn(result);
+
+ mFlusher = new NativeCodeCoverageFlusher(mMockDevice, processes);
+ mFlusher.forceCoverageFlush();
+
+ // Verify that the flush command was not called.
+ verify(mMockDevice, never()).executeShellCommand("kill -37 123");
+ }
+
+ @Test
+ public void testFlushOnlySigCgt_flushSpecificProcesses() throws DeviceNotAvailableException {
+ doReturn(true).when(mMockDevice).isAdbRoot();
+
+ CommandResult resultNotHandled = new CommandResult(CommandStatus.SUCCESS);
+ resultNotHandled.setStdout("0000000000\n");
+ resultNotHandled.setExitCode(0);
+
+ CommandResult resultHandled = new CommandResult(CommandStatus.SUCCESS);
+ resultHandled.setStdout("ffffffffffff\n");
+ resultHandled.setExitCode(0);
+
+ CommandResult resultEmpty = new CommandResult(CommandStatus.SUCCESS);
+ resultEmpty.setStdout("\n");
+ resultEmpty.setExitCode(0);
+
+ when(mMockDevice.executeShellV2Command(contains("123"))).thenReturn(resultNotHandled);
+ when(mMockDevice.executeShellV2Command(contains("234"))).thenReturn(resultHandled);
+ when(mMockDevice.executeShellV2Command(contains("456"))).thenReturn(resultEmpty);
+
+ mFlusher = new NativeCodeCoverageFlusher(mMockDevice, ImmutableList.of());
+ mFlusher.forceCoverageFlush();
+
+ // Verify that the flush command was only called for pid 234.
+ verify(mMockDevice).executeShellCommand("kill -37 234");
}
@Test