Push pocs in the test instead of AndroidTest.xml

This will remove test conflicts in AndroidTest.xml

Bug: 171320823
Test: run all of STS
Change-Id: I45de7af4a70685928cb0cf385b40a792b0ee793b
Merged-In: I45de7af4a70685928cb0cf385b40a792b0ee793b
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index df30010..3746e1d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -153,8 +153,11 @@
      * @param arguments input arguments for the poc
      * @param receiver the type of receiver to run against
      */
-    public static void runPoc(String pocName, ITestDevice device, int timeout,
+    public static int runPoc(String pocName, ITestDevice device, int timeout,
             String arguments, IShellOutputReceiver receiver) throws Exception {
+        String remoteFile = String.format("%s%s", TMP_PATH, pocName);
+        SecurityTestCase.getPocPusher(device).pushFile(pocName, remoteFile);
+
         assertPocExecutable(pocName, device);
         if (receiver == null) {
             receiver = new NullOutputReceiver();
@@ -176,8 +179,9 @@
 
         MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
         reportLog.addValue("poc_name", pocName, ResultType.NEUTRAL, ResultUnit.NONE);
+        int exitStatus = -1;
         try {
-            int exitStatus = Integer.parseInt(exitStatusString);
+            exitStatus = Integer.parseInt(exitStatusString);
             reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
         } catch (NumberFormatException e) {
             // Getting the exit status is a bonus. We can continue without it.
@@ -186,6 +190,7 @@
         reportLog.submit();
 
         runCommandLine("rm " + exitStatusFilepath, device);
+        return exitStatus;
     }
 
     /**
@@ -399,26 +404,7 @@
      */
     public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device,
             int timeout) throws Exception {
-        assertPocExecutable(pocName, device);
-        CollectingOutputReceiver receiver = new CollectingOutputReceiver();
-        String cmd = TMP_PATH + pocName + " " + arguments + " > /dev/null 2>&1; echo $?";
-        long time = System.currentTimeMillis();
-        device.executeShellCommand(cmd, receiver, timeout, TimeUnit.SECONDS, 0);
-        time = System.currentTimeMillis() - time;
-        String exitStatusString = receiver.getOutput().trim();
-
-        try {
-            int exitStatus = Integer.parseInt(exitStatusString);
-            MetricsReportLog reportLog = SecurityTestCase.buildMetricsReportLog(device);
-            reportLog.addValue("poc_name", pocName, ResultType.NEUTRAL, ResultUnit.NONE);
-            reportLog.addValue("exit_status", exitStatus, ResultType.NEUTRAL, ResultUnit.NONE);
-            reportLog.submit();
-            return exitStatus;
-        } catch (NumberFormatException e) {
-            throw new IllegalArgumentException(String.format(
-                    "Could not get the exit status (%s) for '%s' (%d ms).",
-                    exitStatusString, cmd, time));
-        }
+        return runPoc(pocName, device, timeout, arguments, null);
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java b/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
new file mode 100644
index 0000000..74cae76
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/PocPusher.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 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 android.security.cts;
+
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import org.junit.runner.Description;
+import org.junit.rules.TestWatcher;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.IAbi;
+
+import static org.junit.Assume.*;
+import static org.junit.Assert.*;
+
+public class PocPusher extends TestWatcher {
+    private ITestDevice device = null;
+    private CompatibilityBuildHelper buildHelper = null;
+    private IAbi abi = null;
+
+    private Set<String> filesToCleanup = new HashSet();
+    public boolean bitness32 = true;
+    public boolean bitness64 = true;
+    public boolean appendBitness = true;
+    public boolean cleanup = true;
+
+    @Override
+    protected void starting(Description d) {
+        bothBitness();
+        appendBitness = true;
+        cleanup = true;
+    }
+
+    @Override
+    protected void finished(Description d) {
+        for (Iterator<String> it = filesToCleanup.iterator(); it.hasNext();) {
+            String file = it.next();
+            try {
+                CLog.i("Cleaning up %s", file);
+                device.executeShellCommand(String.format("rm %s", file));
+            } catch (DeviceNotAvailableException e) {
+                CLog.e("Device unavailable when cleaning up %s", file);
+                continue; // try to remove next time
+            }
+            it.remove();
+        }
+    }
+
+    public PocPusher setDevice(ITestDevice device) {
+        this.device = device;
+        return this;
+    }
+
+    public PocPusher setAbi(IAbi abi) {
+        this.abi = abi;
+        return this;
+    }
+
+    public PocPusher setBuild(IBuildInfo buildInfo) {
+        buildHelper = new CompatibilityBuildHelper(buildInfo);
+        return this;
+    }
+
+    public PocPusher appendBitness(boolean append) {
+        this.appendBitness = append;
+        return this;
+    }
+
+    public PocPusher cleanup(boolean cleanup) {
+        this.cleanup = cleanup;
+        return this;
+    }
+
+    public PocPusher only32() {
+        bitness32 = true;
+        bitness64 = false;
+        return this;
+    }
+
+    public PocPusher only64() {
+        bitness32 = false;
+        bitness64 = true;
+        return this;
+    }
+
+    public PocPusher bothBitness() {
+        bitness32 = true;
+        bitness64 = true;
+        return this;
+    }
+
+    public void pushFile(String testFile, String remoteFile)
+            throws FileNotFoundException, DeviceNotAvailableException {
+        if (appendBitness) {
+            // if neither 32 or 64, nothing would ever be pushed.
+            assertTrue("bitness must be 32, 64, or both.", bitness32 || bitness64);
+
+            String bitness = SecurityTestCase.getAbi(device).getBitness().trim();
+
+            // 32-bit doesn't have a 64-bit compatibility layer; skipping.
+            assumeFalse(bitness.equals("32") && !bitness32);
+
+            // push the 32-bit file on 64-bit device if a 64-bit file doesn't exist.
+            if (bitness.equals("64") && !bitness64) {
+                bitness = "32";
+                CLog.i("Pushing a 32-bit file onto a 64-bit device.");
+            }
+            testFile += bitness;
+        }
+        File localFile = buildHelper.getTestFile(testFile);
+        CLog.i("Pushing local: %s to remote: %s", testFile.toString(), remoteFile);
+        device.pushFile(localFile, remoteFile);
+        if (cleanup) {
+            filesToCleanup.add(remoteFile);
+        }
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 57e054d..f31f1e7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -61,10 +61,12 @@
     private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
 
     @Rule public TestName testName = new TestName();
+    @Rule public PocPusher pocPusher = new PocPusher();
 
     private static Map<ITestDevice, IBuildInfo> sBuildInfo = new HashMap<>();
     private static Map<ITestDevice, IAbi> sAbi = new HashMap<>();
     private static Map<ITestDevice, String> sTestName = new HashMap<>();
+    private static Map<ITestDevice, PocPusher> sPocPusher = new HashMap<>();
 
     /**
      * Waits for device to be online, marks the most recent boottime of the device
@@ -81,6 +83,9 @@
         sBuildInfo.put(getDevice(), mBuild);
         sAbi.put(getDevice(), mAbi);
         sTestName.put(getDevice(), testName.getMethodName());
+
+        pocPusher.setDevice(getDevice()).setBuild(mBuild).setAbi(mAbi);
+        sPocPusher.put(getDevice(), pocPusher);
     }
 
     /**
@@ -134,6 +139,10 @@
         return sTestName.get(device);
     }
 
+    public static PocPusher getPocPusher(ITestDevice device) {
+        return sPocPusher.get(device);
+    }
+
     // TODO convert existing assertMatches*() to RegexUtils.assertMatches*()
     // b/123237827
     @Deprecated