aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Nguyen <olivernguyen@google.com>2019-07-02 15:48:43 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-07-02 15:48:43 -0700
commitf445f4dc3cd65a6064260b2c79ca622bcd2ef875 (patch)
treeba88d3fff73ff9d326093f3605bd1df84190e424
parent3fa684e12962bbdddf2766d63cb01e37219b2a10 (diff)
parent98826bcbc670b2e03492f8e6991db46660fdcb76 (diff)
downloadtradefederation-f445f4dc3cd65a6064260b2c79ca622bcd2ef875.tar.gz
Merge "Add utility class to handle clearing and flushing native coverage data." into qt-dev
am: 98826bcbc6 Change-Id: Ic156f767b3010f2cba6aba9d49ce88cc0a90de2c
-rw-r--r--src/com/android/tradefed/util/NativeCodeCoverageFlusher.java85
-rw-r--r--tests/src/com/android/tradefed/UnitTests.java2
-rw-r--r--tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java121
3 files changed, 208 insertions, 0 deletions
diff --git a/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java b/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java
new file mode 100644
index 000000000..b53542a9e
--- /dev/null
+++ b/src/com/android/tradefed/util/NativeCodeCoverageFlusher.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.util.List;
+import java.util.StringJoiner;
+
+/**
+ * A utility class that clears native coverage measurements and forces a flush of native coverage
+ * data from processes on the device.
+ */
+public final class NativeCodeCoverageFlusher {
+
+ private static final String COVERAGE_FLUSH_COMMAND_FORMAT = "kill -37 %s";
+ private static final String CLEAR_NATIVE_COVERAGE_FILES = "rm -rf /data/misc/trace/*";
+
+ private final ITestDevice mDevice;
+
+ public NativeCodeCoverageFlusher(ITestDevice device) {
+ mDevice = device;
+ }
+
+ /**
+ * Clears coverage measurements from disk on the device. Device must be in adb root.
+ *
+ * @throws DeviceNotAvailableException
+ */
+ public void clearCoverageMeasurements() throws DeviceNotAvailableException {
+ checkState(mDevice.isAdbRoot(), "adb root is required to clear coverage files.");
+ mDevice.executeShellCommand(CLEAR_NATIVE_COVERAGE_FILES);
+ }
+
+ /**
+ * Forces a flush of native coverage data from processes running on the device. Device must be
+ * in adb root.
+ *
+ * @param processNames the name of processes to target for flushing; if empty, flushes from all
+ * running native processes on the device.
+ * @throws DeviceNotAvailableException
+ */
+ public void forceCoverageFlush(List<String> processNames) throws DeviceNotAvailableException {
+ checkState(mDevice.isAdbRoot(), "adb root is required to flush native coverage data.");
+
+ if ((processNames == null) || processNames.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 : processNames) {
+ String pid = mDevice.getProcessPid(processName);
+ if (pid == null) {
+ CLog.w("Did not find pid for process \"%s\".", processName);
+ } else {
+ pidString.add(pid);
+ }
+ }
+
+ if (pidString.length() > 0) {
+ mDevice.executeShellCommand(
+ String.format(COVERAGE_FLUSH_COMMAND_FORMAT, pidString.toString()));
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java
index 422933f78..2b855a306 100644
--- a/tests/src/com/android/tradefed/UnitTests.java
+++ b/tests/src/com/android/tradefed/UnitTests.java
@@ -308,6 +308,7 @@ import com.android.tradefed.util.ListInstrumentationParserTest;
import com.android.tradefed.util.LocalRunInstructionBuilderTest;
import com.android.tradefed.util.LogcatEventParserTest;
import com.android.tradefed.util.MultiMapTest;
+import com.android.tradefed.util.NativeCodeCoverageFlusherTest;
import com.android.tradefed.util.NullUtilTest;
import com.android.tradefed.util.PairTest;
import com.android.tradefed.util.PropertyChangerTest;
@@ -747,6 +748,7 @@ import org.junit.runners.Suite.SuiteClasses;
ListInstrumentationParserTest.class,
LogcatEventParserTest.class,
MultiMapTest.class,
+ NativeCodeCoverageFlusherTest.class,
NullUtilTest.class,
PairTest.class,
PsParserTest.class,
diff --git a/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java b/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java
new file mode 100644
index 000000000..523655c85
--- /dev/null
+++ b/tests/src/com/android/tradefed/util/NativeCodeCoverageFlusherTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.IllegalStateException;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public final class NativeCodeCoverageFlusherTest {
+
+ @Mock ITestDevice mMockDevice;
+
+ // Object under test
+ NativeCodeCoverageFlusher mFlusher;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mFlusher = new NativeCodeCoverageFlusher(mMockDevice);
+ }
+
+ @Test
+ public void testClearCoverageMeasurements_rmCommandCalled() throws DeviceNotAvailableException {
+ doReturn(true).when(mMockDevice).isAdbRoot();
+
+ mFlusher.clearCoverageMeasurements();
+
+ // Verify that the rm command was executed.
+ verify(mMockDevice).executeShellCommand("rm -rf /data/misc/trace/*");
+ }
+
+ @Test
+ public void testNoAdbRootClearCoverageMeasurements_noOp() throws DeviceNotAvailableException {
+ doReturn(false).when(mMockDevice).isAdbRoot();
+
+ try {
+ mFlusher.clearCoverageMeasurements();
+ fail("Should have thrown an exception");
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ // Verify that no shell command was executed.
+ verify(mMockDevice, never()).executeShellCommand(anyString());
+ }
+
+ @Test
+ public void testFlushCoverageAllProcesses_flushAllCommandCalled()
+ throws DeviceNotAvailableException {
+ doReturn(true).when(mMockDevice).isAdbRoot();
+
+ mFlusher.forceCoverageFlush(ImmutableList.of());
+
+ // Verify that the flush command for all processes was called.
+ verify(mMockDevice).executeShellCommand("kill -37 -1");
+ }
+
+ @Test
+ public void testFlushCoverageSpecificProcesses_flushSpecificCommandCalled()
+ throws DeviceNotAvailableException {
+ List<String> processes = ImmutableList.of("mediaserver", "mediaextractor");
+
+ doReturn(true).when(mMockDevice).isAdbRoot();
+ doReturn("12").when(mMockDevice).getProcessPid(processes.get(0));
+ doReturn("789").when(mMockDevice).getProcessPid(processes.get(1));
+
+ mFlusher.forceCoverageFlush(processes);
+
+ // Verify that the flush command for the specific processes was called.
+ verify(mMockDevice).executeShellCommand("kill -37 12 789");
+ }
+
+ @Test
+ public void testNoAdbRootFlush_noOp() throws DeviceNotAvailableException {
+ doReturn(false).when(mMockDevice).isAdbRoot();
+
+ try {
+ mFlusher.forceCoverageFlush(ImmutableList.of("mediaserver"));
+ fail("Should have thrown an exception");
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ // Verify no shell commands or pid lookups were executed.
+ verify(mMockDevice, never()).executeShellCommand(anyString());
+ verify(mMockDevice, never()).getProcessPid(anyString());
+ }
+}