Snap for 9560500 from b4272c45d198d10d8a8acaa828a7be7b8ec66f13 to sdk-release

Change-Id: Ie20354fe064ddb9995ed804da30f21312974d3e7
diff --git a/Android.bp b/Android.bp
index 4895c50..face49d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -34,6 +34,7 @@
         include_dirs: ["external/protobuf/src"],
         type: "full",
     },
+    java_version: "11",
 }
 
 java_library_host {
@@ -51,6 +52,7 @@
         "guava",
         "javax-annotation-api-prebuilt-host-jar",
     ],
+    java_version: "11",
 }
 
 java_library_host {
@@ -73,6 +75,7 @@
         "guava",
         "javax-annotation-api-prebuilt-host-jar",
     ],
+    java_version: "11",
 }
 
 java_library_host {
@@ -90,6 +93,7 @@
         "guava",
         "javax-annotation-api-prebuilt-host-jar",
     ],
+    java_version: "11",
 }
 
 java_library_host {
@@ -107,6 +111,7 @@
         "guava",
         "javax-annotation-api-prebuilt-host-jar",
     ],
+    java_version: "11",
 }
 
 // Main Target to build tradefed jar
@@ -126,6 +131,7 @@
         "tradefed-test-framework",
     ],
     manifest: "MANIFEST.mf",
+    java_version: "11",
 }
 
 // Tradefed build target without the test framework statically linked
@@ -142,6 +148,7 @@
         "tradefed-test-framework",
     ],
     manifest: "MANIFEST.mf",
+    java_version: "11",
 }
 
 java_library_host {
@@ -195,6 +202,7 @@
     libs: [
         "loganalysis",
     ],
+    java_version: "11",
 }
 
 // Turn off various doclava warnings when generating
diff --git a/javatests/com/android/tradefed/device/TestDeviceTest.java b/javatests/com/android/tradefed/device/TestDeviceTest.java
index 0361d5f..37ff043 100644
--- a/javatests/com/android/tradefed/device/TestDeviceTest.java
+++ b/javatests/com/android/tradefed/device/TestDeviceTest.java
@@ -15,18 +15,17 @@
  */
 package com.android.tradefed.device;
 
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.junit.Assert.assertThrows;
-
 import static com.android.tradefed.device.DeviceProperties.BUILD_CODENAME;
 import static com.android.tradefed.device.DeviceProperties.SDK_VERSION;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.atLeastOnce;
@@ -2402,6 +2401,13 @@
         verify(mMockStateMonitor).waitForDeviceAvailable(Mockito.anyLong());
     }
 
+    private void verifyRebootAndRootExpectations() throws Exception {
+        verify(mMockStateMonitor, times(4)).waitForDeviceOnline();
+        verifyShellResponse("id", 4);
+        verifyGetPropertyExpectation("ro.crypto.state", "unsupported", 1);
+        verify(mMockStateMonitor).waitForDeviceAvailable(Mockito.anyLong());
+    }
+
     /** Test normal success case for {@link TestDevice#reboot()} */
     @Test
     public void testReboot() throws Exception {
@@ -3344,6 +3350,7 @@
     @Test
     public void testRemount_verityUnsupported() throws Exception {
         injectSystemProperty("partition.system.verified", "");
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
@@ -3358,6 +3365,7 @@
     @Test
     public void testRemountVendor_verityUnsupported() throws Exception {
         injectSystemProperty("partition.vendor.verified", "");
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
@@ -3375,11 +3383,12 @@
         setExecuteAdbCommandExpectations(
                 new CommandResult(CommandStatus.SUCCESS), "disable-verity");
         setRebootExpectations();
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
         mTestDevice.remountSystemWritable();
-        verifyRebootExpectations();
+        verifyRebootAndRootExpectations();
     }
     /**
      * Test that remount vendor works as expected on a device supporting dm verity v1
@@ -3392,11 +3401,12 @@
         setExecuteAdbCommandExpectations(
                 new CommandResult(CommandStatus.SUCCESS), "disable-verity");
         setRebootExpectations();
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
         mTestDevice.remountVendorWritable();
-        verifyRebootExpectations();
+        verifyRebootAndRootExpectations();
     }
 
     /**
@@ -3410,11 +3420,12 @@
         setExecuteAdbCommandExpectations(
                 new CommandResult(CommandStatus.SUCCESS), "disable-verity");
         setRebootExpectations();
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
         mTestDevice.remountSystemWritable();
-        verifyRebootExpectations();
+        verifyRebootAndRootExpectations();
     }
 
     /**
@@ -3428,11 +3439,12 @@
         setExecuteAdbCommandExpectations(
                 new CommandResult(CommandStatus.SUCCESS), "disable-verity");
         setRebootExpectations();
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
         mTestDevice.remountVendorWritable();
-        verifyRebootExpectations();
+        verifyRebootAndRootExpectations();
     }
 
     /**
@@ -3446,11 +3458,12 @@
         setExecuteAdbCommandExpectations(
                 new CommandResult(CommandStatus.SUCCESS), "disable-verity");
         setRebootExpectations();
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
         mTestDevice.remountSystemWritable();
-        verifyRebootExpectations();
+        verifyRebootAndRootExpectations();
     }
 
     /**
@@ -3465,11 +3478,12 @@
         setExecuteAdbCommandExpectations(
                 new CommandResult(CommandStatus.SUCCESS), "disable-verity");
         setRebootExpectations();
+        setEnableAdbRootExpectations();
         setExecuteAdbCommandExpectations(new CommandResult(CommandStatus.SUCCESS), "remount");
         when(mMockStateMonitor.waitForDeviceAvailable()).thenReturn(mMockIDevice);
 
         mTestDevice.remountVendorWritable();
-        verifyRebootExpectations();
+        verifyRebootAndRootExpectations();
     }
 
     /**
diff --git a/javatests/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java b/javatests/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java
index 107b844..42afdee 100644
--- a/javatests/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java
+++ b/javatests/com/android/tradefed/device/metric/ClangCodeCoverageCollectorTest.java
@@ -41,9 +41,11 @@
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.testtype.coverage.CoverageOptions;
+import com.android.tradefed.testtype.suite.ModuleDefinition;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.MultiMap;
 import com.android.tradefed.util.IRunUtil;
 import com.android.tradefed.util.TarUtil;
 import com.android.tradefed.util.proto.TfMetricProtoUtil;
@@ -127,6 +129,9 @@
         doReturn(mMockBuildInfo).when(mMockBuildProvider).getBuild();
 
         doReturn(ImmutableList.of(mMockDevice)).when(mMockContext).getDevices();
+        when(mMockContext.getAttributes())
+                .thenReturn(
+                        new MultiMap(ImmutableMap.of(ModuleDefinition.MODULE_NAME, "myModule")));
 
         doReturn(PS_OUTPUT).when(mMockDevice).executeShellCommand("ps -e");
 
@@ -228,6 +233,46 @@
     }
 
     @Test
+    public void testRun_noModuleName_logsCoverageFile() throws Exception {
+        mCoverageOptionsSetter.setOptionValue("coverage", "true");
+        mCoverageOptionsSetter.setOptionValue("coverage-toolchain", "CLANG");
+
+        // Setup mocks.
+        doReturn(true).when(mMockDevice).isAdbRoot();
+        File tarGz =
+                createTarGz(
+                        ImmutableMap.of(
+                                "path/to/coverage.profraw",
+                                ByteString.copyFromUtf8("coverage.profraw"),
+                                "path/to/.hidden/coverage2.profraw",
+                                ByteString.copyFromUtf8("coverage2.profraw")));
+        returnFileContentsOnShellCommand(mMockDevice, tarGz);
+        doReturn(createProfileToolZip()).when(mMockBuildInfo).getFile(anyString());
+        when(mMockContext.getAttributes()).thenReturn(new MultiMap(ImmutableMap.of()));
+
+        // Simulate a test run.
+        mListener.init(mMockContext, mFakeListener);
+        mListener.testRunStarted(RUN_NAME, TEST_COUNT);
+        mListener.testRunEnded(ELAPSED_TIME, mMetrics);
+        mListener.invocationEnded(ELAPSED_TIME);
+
+        // Verify that the command line contains the files above.
+        List<String> command = mCommandArgumentCaptor.getCommand();
+        checkListContainsSuffixes(
+                command,
+                ImmutableList.of(
+                        "llvm-profdata",
+                        "path/to/coverage.profraw",
+                        "path/to/.hidden/coverage2.profraw"));
+
+        // Verify testLog(..) was called with a single indexed profile data.
+        List<ByteString> logs = mFakeListener.getLogs();
+        assertThat(logs).hasSize(1);
+
+        FileUtil.deleteFile(tarGz);
+    }
+
+    @Test
     public void testRun_profraw_filter_option() throws Exception {
         mCoverageOptionsSetter.setOptionValue("coverage", "true");
         mCoverageOptionsSetter.setOptionValue("coverage-toolchain", "CLANG");
diff --git a/javatests/com/android/tradefed/device/metric/JavaCodeCoverageCollectorTest.java b/javatests/com/android/tradefed/device/metric/JavaCodeCoverageCollectorTest.java
index 3b90d2b..0a6e3b6 100644
--- a/javatests/com/android/tradefed/device/metric/JavaCodeCoverageCollectorTest.java
+++ b/javatests/com/android/tradefed/device/metric/JavaCodeCoverageCollectorTest.java
@@ -43,9 +43,11 @@
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.testtype.coverage.CoverageOptions;
+import com.android.tradefed.testtype.suite.ModuleDefinition;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.JavaCodeCoverageFlusher;
+import com.android.tradefed.util.MultiMap;
 import com.android.tradefed.util.TarUtil;
 import com.android.tradefed.util.proto.TfMetricProtoUtil;
 
@@ -128,6 +130,9 @@
         when(mMockConfiguration.getCoverageOptions()).thenReturn(mCoverageOptions);
 
         when(mMockContext.getDevices()).thenReturn(ImmutableList.of(mMockDevice));
+        when(mMockContext.getAttributes())
+                .thenReturn(
+                        new MultiMap(ImmutableMap.of(ModuleDefinition.MODULE_NAME, "myModule")));
 
         // Mock an unrooted device that has no issues enabling or disabling root.
         when(mMockDevice.isAdbRoot()).thenReturn(false);
@@ -182,6 +187,28 @@
     }
 
     @Test
+    public void testRunEnded_rootEnabled_noModuleName_logsCoverageMeasurement() throws Exception {
+        enableJavaCoverage();
+
+        // Setup mocks.
+        HashMap<String, Metric> runMetrics = createMetricsWithCoverageMeasurement(DEVICE_PATH);
+        mockCoverageFileOnDevice(DEVICE_PATH);
+        when(mMockDevice.isAdbRoot()).thenReturn(true);
+        when(mMockContext.getAttributes()).thenReturn(new MultiMap(ImmutableMap.of()));
+        doReturn("").when(mMockDevice).executeShellCommand(anyString());
+        returnFileContentsOnShellCommand(mMockDevice, createTarGz(ImmutableMap.of()));
+
+        // Simulate a test run.
+        mCodeCoverageCollector.init(mMockContext, mFakeListener);
+        mCodeCoverageCollector.testRunStarted(RUN_NAME, TEST_COUNT);
+        mCodeCoverageCollector.testRunEnded(ELAPSED_TIME, runMetrics);
+
+        // Verify testLog(..) was called with the coverage file.
+        verify(mFakeListener)
+                .testLog(anyString(), eq(LogDataType.COVERAGE), eq(COVERAGE_MEASUREMENT));
+    }
+
+    @Test
     public void testFailure_unableToPullFile() throws Exception {
         enableJavaCoverage();
         HashMap<String, Metric> runMetrics = createMetricsWithCoverageMeasurement(DEVICE_PATH);
diff --git a/javatests/com/android/tradefed/targetprep/sync/DeviceSyncHelperFuncTest.java b/javatests/com/android/tradefed/targetprep/sync/DeviceSyncHelperFuncTest.java
index 7f95dca..fd2fe83 100644
--- a/javatests/com/android/tradefed/targetprep/sync/DeviceSyncHelperFuncTest.java
+++ b/javatests/com/android/tradefed/targetprep/sync/DeviceSyncHelperFuncTest.java
@@ -17,7 +17,6 @@
 
 import static org.junit.Assert.assertTrue;
 
-import com.android.tradefed.command.remote.DeviceDescriptor;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -36,7 +35,8 @@
 
     @Test
     public void testSyncDevice() throws DeviceNotAvailableException {
-        DeviceDescriptor initialState = getDevice().getDeviceDescriptor();
+        String buildId = getDevice().getProperty("ro.system.build.version.incremental");
+        CLog.d("%s / buildid: %s", getDevice().getProperty("ro.build.fingerprint"), buildId);
 
         File targetFiles = getBuild().getFile("target_files");
         if (targetFiles == null || !targetFiles.exists() || !targetFiles.isDirectory()) {
@@ -47,11 +47,10 @@
         boolean success = syncHelper.sync();
         assertTrue(success);
 
-        DeviceDescriptor endState = getDevice().getDeviceDescriptor();
-        CLog.d(
-                "Initial build: %s. Final build: %s",
-                initialState.getBuildId(), endState.getBuildId());
+        String afterBuildId = getDevice().getProperty("ro.system.build.version.incremental");
+        CLog.d("Initial build: %s. Final build: %s", buildId, afterBuildId);
+        CLog.d("%s", getDevice().getProperty("ro.build.fingerprint"));
 
-        Truth.assertThat(endState.getBuildId()).isNotEqualTo(initialState.getBuildId());
+        Truth.assertThat(buildId).isNotEqualTo(afterBuildId);
     }
 }
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index feb17fd..aa486ce 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -4856,6 +4856,7 @@
             executeAdbCommand("disable-verity");
             reboot();
         }
+        enableAdbRoot();
         executeAdbCommand("remount");
         waitForDeviceAvailable();
     }
@@ -4870,6 +4871,7 @@
             executeAdbCommand("disable-verity");
             reboot();
         }
+        enableAdbRoot();
         executeAdbCommand("remount");
         waitForDeviceAvailable();
     }
diff --git a/src/com/android/tradefed/device/metric/ClangCodeCoverageCollector.java b/src/com/android/tradefed/device/metric/ClangCodeCoverageCollector.java
index d325c23..be7c87b 100644
--- a/src/com/android/tradefed/device/metric/ClangCodeCoverageCollector.java
+++ b/src/com/android/tradefed/device/metric/ClangCodeCoverageCollector.java
@@ -45,6 +45,7 @@
 import com.android.tradefed.util.ZipUtil;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -140,13 +141,22 @@
                 if (mConfiguration.getCoverageOptions().isCoverageFlushEnabled()) {
                     getCoverageFlusher(device).forceCoverageFlush();
                 }
-                logCoverageMeasurement(device, getRunName());
+                logCoverageMeasurement(device, generateMeasurementFileName());
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
         }
     }
 
+    /** Generate the .ec file prefix in format "$moduleName_MODULE_$runName". */
+    private String generateMeasurementFileName() {
+        String moduleName = Strings.nullToEmpty(getModuleName());
+        if (moduleName.length() > 0) {
+            moduleName += "_MODULE_";
+        }
+        return moduleName + getRunName().replace(' ', '_');
+    }
+
     /**
      * Logs Clang coverage measurements from the device.
      *
diff --git a/src/com/android/tradefed/device/metric/JavaCodeCoverageCollector.java b/src/com/android/tradefed/device/metric/JavaCodeCoverageCollector.java
index 993620b..1469016 100644
--- a/src/com/android/tradefed/device/metric/JavaCodeCoverageCollector.java
+++ b/src/com/android/tradefed/device/metric/JavaCodeCoverageCollector.java
@@ -41,6 +41,7 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
 
 import org.jacoco.core.tools.ExecFileLoader;
 
@@ -228,16 +229,23 @@
     /** Logs files as Java coverage measurements. */
     private void logCoverageMeasurement(File coverageFile) {
         try (FileInputStreamSource source = new FileInputStreamSource(coverageFile, true)) {
-            testLog(
-                    getRunName()
-                            + "_"
-                            + getNameWithoutExtension(coverageFile.getName())
-                            + "_runtime_coverage",
-                    LogDataType.COVERAGE,
-                    source);
+            testLog(generateMeasurementFileName(coverageFile), LogDataType.COVERAGE, source);
         }
     }
 
+    /** Generate the .ec file prefix in format "$moduleName_MODULE_$runName". */
+    private String generateMeasurementFileName(File coverageFile) {
+        String moduleName = Strings.nullToEmpty(getModuleName());
+        if (moduleName.length() > 0) {
+            moduleName += "_MODULE_";
+        }
+        return moduleName
+                + getRunName()
+                + "_"
+                + getNameWithoutExtension(coverageFile.getName())
+                + "_runtime_coverage";
+    }
+
     /** Cleans up .ec files in /data/misc/trace. */
     private void cleanUpDeviceCoverageFiles(ITestDevice device) throws DeviceNotAvailableException {
         try (AdbRootElevator root = new AdbRootElevator(device)) {
diff --git a/src/com/android/tradefed/targetprep/sync/DeviceSyncHelper.java b/src/com/android/tradefed/targetprep/sync/DeviceSyncHelper.java
index a61b72f..594904f 100644
--- a/src/com/android/tradefed/targetprep/sync/DeviceSyncHelper.java
+++ b/src/com/android/tradefed/targetprep/sync/DeviceSyncHelper.java
@@ -16,13 +16,20 @@
 package com.android.tradefed.targetprep.sync;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.IFileEntry;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.tracing.CloseableTraceScope;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.RunUtil;
+
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Helper that helps syncing a new device image to the device. Future improvements: compute files
@@ -40,7 +47,9 @@
 
     public boolean sync() throws DeviceNotAvailableException {
         try {
-            List<String> partitions = getPartitions(mTargetFilesFolder);
+            Set<String> partitions = getPartitions(mTargetFilesFolder);
+            partitions.add("data");
+            CLog.d("Partitions: %s", partitions);
             lowerCaseDirectory(mTargetFilesFolder);
             syncFiles(mDevice, partitions);
             return true;
@@ -50,10 +59,10 @@
         return false;
     }
 
-    private List<String> getPartitions(File rootFolder) throws IOException {
+    private Set<String> getPartitions(File rootFolder) throws IOException {
         File abPartitions = new File(rootFolder, "META/ab_partitions.txt");
         String partitionString = FileUtil.readStringFromFile(abPartitions);
-        return Arrays.asList(partitionString.split("\n"));
+        return new HashSet<>(Arrays.asList(partitionString.split("\n")));
     }
 
     private void lowerCaseDirectory(File rootFolder) {
@@ -66,11 +75,16 @@
         CLog.d("Directory content: %s", Arrays.asList(rootFolder.listFiles()));
     }
 
-    private void syncFiles(ITestDevice device, List<String> partitions)
+    private void syncFiles(ITestDevice device, Set<String> partitions)
             throws DeviceNotAvailableException, IOException {
         device.enableAdbRoot();
         device.remountSystemWritable();
+        device.enableAdbRoot();
+        String outputRemount = device.executeAdbCommand("remount", "-R");
+        CLog.d("%s", outputRemount);
+        device.waitForDeviceAvailable();
         device.executeAdbCommand("shell", "stop");
+        RunUtil.getDefault().sleep(20000L);
 
         for (String partition : partitions) {
             File localToPush = new File(mTargetFilesFolder, partition);
@@ -78,13 +92,64 @@
                 CLog.w("%s is in the partition but doesn't exist", partition);
                 continue;
             }
-            String output =
-                    device.executeAdbCommand(0L, "push", localToPush.getAbsolutePath(), "/");
-            if (output == null) {
-                throw new IOException("Failed to push " + localToPush);
+            try (CloseableTraceScope push = new CloseableTraceScope("push " + partition)) {
+                String output =
+                        device.executeAdbCommand(0L, "push", localToPush.getAbsolutePath(), "/");
+                if (output == null) {
+                    throw new IOException("Failed to push " + localToPush);
+                }
+            }
+            try (CloseableTraceScope delete = new CloseableTraceScope("delete_extra_files")) {
+                List<String> removeFiles = syncFiles(device, localToPush, "/" + partition);
+                CLog.d("Files to be removed from device: %s", removeFiles);
+                for (String deviceFile : removeFiles) {
+                    device.executeShellCommand(String.format("rm -rf %s", deviceFile));
+                }
             }
         }
 
-        device.reboot();
+        try (CloseableTraceScope reboot = new CloseableTraceScope("reboot")) {
+            device.executeAdbCommand("reboot");
+            device.waitForDeviceAvailable();
+        }
+        device.enableAdbRoot();
+    }
+
+    private List<String> syncFiles(ITestDevice device, File localFileDir, String deviceFilePath)
+            throws DeviceNotAvailableException {
+        CLog.i(
+                "Syncing %s to %s on device %s",
+                localFileDir.getAbsolutePath(), deviceFilePath, device.getSerialNumber());
+        IFileEntry remoteFileEntry = device.getFileEntry(deviceFilePath);
+        if (remoteFileEntry == null) {
+            CLog.e("Could not find remote file entry %s ", deviceFilePath);
+            remoteFileEntry = device.getFileEntry(deviceFilePath);
+            if (remoteFileEntry == null) {
+                CLog.e(
+                        "Could not find remote file entry %s a second time. doesExist: %s",
+                        deviceFilePath, device.doesFileExist(deviceFilePath, 0));
+                return new ArrayList<String>();
+            }
+        }
+        return syncFiles(device, localFileDir, remoteFileEntry);
+    }
+
+    private List<String> syncFiles(
+            ITestDevice device, File localFileDir, final IFileEntry remoteFileEntry)
+            throws DeviceNotAvailableException {
+        // find newer files to sync
+        // File[] localFiles = localFileDir.listFiles(new NoHiddenFilesFilter());
+        List<String> filePathsToRemove = new ArrayList<>();
+        for (IFileEntry entry : remoteFileEntry.getChildren(false)) {
+            File local = new File(localFileDir, entry.getName());
+            if (!local.exists()) {
+                filePathsToRemove.add(entry.getFullPath());
+            } else {
+                if (local.isDirectory()) {
+                    filePathsToRemove.addAll(syncFiles(device, local, entry));
+                }
+            }
+        }
+        return filePathsToRemove;
     }
 }