Create the first API for getting tombstones from device
API for a local device to get the tombstones off the device
Test: unit tests
Bug: 132908268
Change-Id: Ic4d18a2ecff8a8de56e60672ded6a66ee2b0336e
diff --git a/src/com/android/tradefed/device/INativeDevice.java b/src/com/android/tradefed/device/INativeDevice.java
index 79c6f8c..99a1b04 100644
--- a/src/com/android/tradefed/device/INativeDevice.java
+++ b/src/com/android/tradefed/device/INativeDevice.java
@@ -1313,4 +1313,16 @@
* returned by {@link System#currentTimeMillis()}.
*/
public long getLastExpectedRebootTimeMillis();
+
+ /**
+ * Fetch and return the list of tombstones from the devices. Requires root.
+ *
+ * <p>method is best-effort so if one tombstone fails to be pulled for any reason it will be
+ * missing from the list. Only a {@link DeviceNotAvailableException} will terminate the method
+ * early.
+ *
+ * @return A list of tombstone files, empty if no tombstone.
+ * @see <a href="https://source.android.com/devices/tech/debug">Tombstones documentation</a>
+ */
+ public List<File> getTombstones() throws DeviceNotAvailableException;
}
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index 5cd16be..92c2c83 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -183,6 +183,9 @@
/** Pattern to find an executable file. */
private static final Pattern EXE_FILE = Pattern.compile("^[-l]r.x.+");
+ /** Path of the device containing the tombstones */
+ private static final String TOMBSTONE_PATH = "/data/tombstones/";
+
/** The time in ms to wait for a command to complete. */
private long mCmdTimeout = 2 * 60 * 1000L;
/** The time in ms to wait for a 'long' command to complete. */
@@ -4364,6 +4367,23 @@
return mLastTradefedRebootTime;
}
+ /** {@inheritDoc} */
+ @Override
+ public List<File> getTombstones() throws DeviceNotAvailableException {
+ List<File> tombstones = new ArrayList<>();
+ if (!isAdbRoot()) {
+ CLog.w("Device was not root, cannot collect tombstones.");
+ return tombstones;
+ }
+ for (String tombName : getChildren(TOMBSTONE_PATH)) {
+ File tombFile = pullFile(TOMBSTONE_PATH + tombName);
+ if (tombFile != null) {
+ tombstones.add(tombFile);
+ }
+ }
+ return tombstones;
+ }
+
/** Validate that pid is an integer and not empty. */
private boolean checkValidPid(String output) {
if (output.isEmpty()) {
diff --git a/tests/src/com/android/tradefed/device/NativeDeviceTest.java b/tests/src/com/android/tradefed/device/NativeDeviceTest.java
index 28e24ab..27d5ce6 100644
--- a/tests/src/com/android/tradefed/device/NativeDeviceTest.java
+++ b/tests/src/com/android/tradefed/device/NativeDeviceTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import com.android.ddmlib.AdbCommandRejectedException;
@@ -2579,4 +2580,34 @@
};
assertFalse(mTestDevice.isExecutable("/system"));
}
+
+ /** Test {@link NativeDevice#getTombstones()}. */
+ @Test
+ public void testGetTombstones_notRoot() throws Exception {
+ TestableAndroidNativeDevice spy = Mockito.spy(mTestDevice);
+ doReturn(false).when(spy).isAdbRoot();
+
+ EasyMock.replay(mMockIDevice);
+ List<File> result = spy.getTombstones();
+ assertEquals(0, result.size());
+ EasyMock.verify(mMockIDevice);
+ }
+
+ /** Test {@link NativeDevice#getTombstones()}. */
+ @Test
+ public void testGetTombstones() throws Exception {
+ TestableAndroidNativeDevice spy = Mockito.spy(mTestDevice);
+ doReturn(true).when(spy).isAdbRoot();
+
+ String[] tombs = new String[] {"tomb1", "tomb2"};
+ doReturn(tombs).when(spy).getChildren("/data/tombstones/");
+
+ doReturn(new File("tomb1_test")).when(spy).pullFile("/data/tombstones/tomb1");
+ doReturn(new File("tomb2_test")).when(spy).pullFile("/data/tombstones/tomb2");
+
+ EasyMock.replay(mMockIDevice);
+ List<File> result = spy.getTombstones();
+ assertEquals(2, result.size());
+ EasyMock.verify(mMockIDevice);
+ }
}