[RESTRICT AUTOMERGE]: Added Media Test methods

Bug: 136588894
Test: sts-tradefed

Change-Id: Ie5b1bc73b51382d0c2f485b3620a2ccc314703c2
(cherry picked from commit aecac9e47c4061fdfd9cfeeb509eb8319a589d08)
(cherry picked from commit 79a9e684dac9d601c5cf9378a0298d3db1e13f8b)
(cherry picked from commit 1f63aa98aa5afc23a8db72576902f60336ac382b)
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
new file mode 100644
index 0000000..85b8422
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
@@ -0,0 +1,144 @@
+/**
+ * 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.
+ */
+#include "omxUtils.h"
+
+sp<IMediaPlayerService> mediaPlayerService = NULL;
+sp<IOMXNode> mOMXNode = 0;
+sp<IOMX> mOMX;
+omx_message msg;
+Mutex mLock;
+Condition mMessageAddedCondition;
+int32_t mLastMsgGeneration;
+int32_t mCurGeneration;
+List<omx_message> mMessageQueue;
+
+struct CodecObserver : public BnOMXObserver {
+ public:
+    CodecObserver(int32_t gen)
+            : mGeneration(gen) {
+    }
+
+    void onMessages(const std::list<omx_message> &messages) override;
+    int32_t mGeneration;
+
+ protected:
+    virtual ~CodecObserver() {
+    }
+};
+void handleMessages(int32_t gen, const std::list<omx_message> &messages) {
+    Mutex::Autolock autoLock(mLock);
+    for (std::list<omx_message>::const_iterator it = messages.cbegin();
+            it != messages.cend();) {
+        mMessageQueue.push_back(*it++);
+        mLastMsgGeneration = gen;
+    }
+    mMessageAddedCondition.signal();
+}
+void CodecObserver::onMessages(const std::list<omx_message> &messages) {
+    handleMessages(mGeneration, messages);
+}
+
+status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs) {
+    int64_t finishBy = ALooper::GetNowUs() + timeoutUs;
+    status_t err = OK;
+
+    while (err != TIMED_OUT) {
+        Mutex::Autolock autoLock(mLock);
+        if (mLastMsgGeneration < mCurGeneration) {
+            mMessageQueue.clear();
+        }
+        // Messages are queued in batches, if the last batch queued is
+        // from a node that already expired, discard those messages.
+        List<omx_message>::iterator it = mMessageQueue.begin();
+        while (it != mMessageQueue.end()) {
+            *msg = *it;
+            mMessageQueue.erase(it);
+            return OK;
+        }
+        if (timeoutUs < 0) {
+            err = mMessageAddedCondition.wait(mLock);
+        } else {
+            err = mMessageAddedCondition.waitRelative(
+                    mLock, (finishBy - ALooper::GetNowUs()) * 1000);
+        }
+    }
+    return err;
+}
+void omxUtilsCheckCmdExecution(char *name) {
+    status_t err = dequeueMessageForNode(&msg, DEFAULT_TIMEOUT);
+    if (err == TIMED_OUT) {
+        ALOGE("[omxUtils] OMX command timed out for %s, exiting the app", name);
+        exit (EXIT_FAILURE);
+    }
+}
+void omxExitOnError(status_t ret) {
+    if (ret != OK) {
+        exit (EXIT_FAILURE);
+    }
+}
+status_t omxUtilsInit(char *codecName) {
+    android::ProcessState::self()->startThreadPool();
+    using namespace ::android::hardware::media::omx::V1_0;
+    sp<IOmx> tOmx = IOmx::getService();
+    if (tOmx == nullptr) {
+        return NO_INIT;
+    }
+    mOMX = new utils::LWOmx(tOmx);
+    sp<CodecObserver> observer = new CodecObserver(++mCurGeneration);
+    return mOMX->allocateNode(codecName, observer, &mOMXNode);
+}
+status_t omxUtilsGetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params) {
+    InitOMXParams(params);
+    params->nPortIndex = portIndex;
+    return mOMXNode->getParameter(OMX_IndexParamPortDefinition, params,
+                                  sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+}
+status_t omxUtilsSetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params) {
+    InitOMXParams(params);
+    params->nPortIndex = portIndex;
+    return mOMXNode->setParameter(OMX_IndexParamPortDefinition, params,
+                                  sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+}
+status_t omxUtilsSetPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
+    return mOMXNode->setPortMode(portIndex, mode);
+}
+status_t omxUtilsUseBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuf,
+                           android::BnOMX::buffer_id *buffer) {
+    return mOMXNode->useBuffer(portIndex, omxBuf, buffer);
+}
+status_t omxUtilsSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    int ret = mOMXNode->sendCommand(cmd, param);
+    omxUtilsCheckCmdExecution((char *) __FUNCTION__);
+    return ret;
+}
+status_t omxUtilsEmptyBuffer(android::BnOMX::buffer_id buffer,
+                             const OMXBuffer &omxBuf, OMX_U32 flags,
+                             OMX_TICKS timestamp, int fenceFd) {
+    return mOMXNode->emptyBuffer(buffer, omxBuf, flags, timestamp, fenceFd);
+}
+status_t omxUtilsFillBuffer(android::BnOMX::buffer_id buffer,
+                            const OMXBuffer &omxBuf, int fenceFd) {
+    return mOMXNode->fillBuffer(buffer, omxBuf, fenceFd);
+}
+status_t omxUtilsFreeBuffer(OMX_U32 portIndex,
+                            android::BnOMX::buffer_id buffer) {
+    return mOMXNode->freeBuffer(portIndex, buffer);
+}
+status_t omxUtilsFreeNode() {
+    return mOMXNode->freeNode();
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.h b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.h
new file mode 100644
index 0000000..16d7978
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.h
@@ -0,0 +1,87 @@
+/**
+ * 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.
+ */
+#include <jni.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+#include <ui/GraphicBuffer.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+#include <media/omx/1.0/WOmx.h>
+#include <binder/MemoryDealer.h>
+#include "HardwareAPI.h"
+#include "OMX_Component.h"
+#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include <inttypes.h>
+#include <utils/Log.h>
+
+#define DEFAULT_TIMEOUT   5000000
+#define OMX_UTILS_IP_PORT 0
+#define OMX_UTILS_OP_PORT 1
+
+using namespace android;
+typedef hidl::allocator::V1_0::IAllocator IAllocator;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+struct Buffer {
+    IOMX::buffer_id mID;
+    sp<IMemory> mMemory;
+    hidl_memory mHidlMemory;
+    uint32_t mFlags;
+};
+
+status_t omxUtilsInit(char *codecName);
+status_t omxUtilsGetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params);
+status_t omxUtilsSetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params);
+status_t omxUtilsSetPortMode(OMX_U32 port_index, IOMX::PortMode mode);
+status_t omxUtilsUseBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuf,
+                           android::BnOMX::buffer_id *buffer);
+status_t omxUtilsSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
+status_t omxUtilsEmptyBuffer(android::BnOMX::buffer_id buffer,
+                             const OMXBuffer &omxBuf, OMX_U32 flags,
+                             OMX_TICKS timestamp, int fenceFd);
+status_t omxUtilsFillBuffer(android::BnOMX::buffer_id buffer,
+                            const OMXBuffer &omxBuf, int fenceFd);
+status_t omxUtilsFreeBuffer(OMX_U32 portIndex,
+                            android::BnOMX::buffer_id buffer);
+status_t omxUtilsFreeNode();
+status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs);
+void omxExitOnError(status_t ret);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 3cbf4e2..2c7c121 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -39,7 +39,10 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.util.regex.Pattern;
+import java.lang.Thread;
 import static org.junit.Assert.*;
+import junit.framework.Assert;
 
 public class AdbUtils {
 
@@ -56,7 +59,7 @@
     /**
      * Pushes and runs a binary to the selected device
      *
-     * @param pathToPoc a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @return the console output from the binary
      */
@@ -68,15 +71,35 @@
     /**
      * Pushes and runs a binary to the selected device
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @return the console output from the binary
      */
     public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
+        return runPoc(pocName, device, timeout, null);
+    }
+
+    /**
+     * Pushes and runs a binary to the selected device
+     *
+     * @param pocName name of the poc binary
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     * @param arguments the input arguments for the poc
+     * @return the console output from the binary
+     */
+    public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments)
+            throws Exception {
         device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout, TimeUnit.SECONDS, 0);
+        if (arguments != null) {
+            device.executeShellCommand("/data/local/tmp/" + pocName + " " + arguments, receiver,
+                    timeout, TimeUnit.SECONDS, 0);
+        } else {
+            device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
+                    TimeUnit.SECONDS, 0);
+        }
         String output = receiver.getOutput();
         return output;
     }
@@ -84,16 +107,35 @@
     /**
      * Pushes and runs a binary to the selected device and ignores any of its output.
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
     public static void runPocNoOutput(String pocName, ITestDevice device, int timeout)
             throws Exception {
+        runPocNoOutput(pocName, device, timeout, null);
+    }
+
+    /**
+     * Pushes and runs a binary with arguments to the selected device and
+     * ignores any of its output.
+     *
+     * @param pocName name of the poc binary
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     * @param arguments input arguments for the poc
+     */
+    public static void runPocNoOutput(String pocName, ITestDevice device, int timeout,
+            String arguments) throws Exception {
         device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
         NullOutputReceiver receiver = new NullOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
-                TimeUnit.SECONDS, 0);
+        if (arguments != null) {
+            device.executeShellCommand("/data/local/tmp/" + pocName + " " + arguments, receiver,
+                    timeout, TimeUnit.SECONDS, 0);
+        } else {
+            device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
+                    TimeUnit.SECONDS, 0);
+        }
     }
 
     /**
@@ -335,5 +377,55 @@
             } catch (JSONException e) {}
         }
         fail(error.toString());
+     }
+
+    /**
+     * Executes a given poc within a given timeout. Returns error if the
+     * given poc doesnt complete its execution within timeout. It also deletes
+     * the list of files provided.
+     *
+     * @param runner the thread which will be run
+     * @param timeout the timeout within which the thread's execution should
+     *        complete
+     * @param device device to be ran on
+     * @param inputFiles list of files to be deleted
+     */
+    public static void runWithTimeoutDeleteFiles(Runnable runner, int timeout, ITestDevice device,
+            String[] inputFiles) throws Exception {
+        Thread t = new Thread(runner);
+        t.start();
+        boolean test_failed = false;
+        try {
+            t.join(timeout);
+        } catch (InterruptedException e) {
+            test_failed = true;
+        } finally {
+            if (inputFiles != null) {
+                for (String tempFile : inputFiles) {
+                    AdbUtils.runCommandLine("rm /data/local/tmp/" + tempFile, device);
+                }
+            }
+            if (test_failed == true) {
+                Assert.fail("PoC was interrupted");
+            }
+        }
+        if (t.isAlive()) {
+            Assert.fail("PoC not completed within timeout of " + timeout + " ms");
+        }
+    }
+
+    /**
+     * Raises assert exception upon crash/error occurence
+     *
+     * @param crashPatternList array of crash log patterns to be checked for
+     * @param logcat String to be parsed
+     */
+    public static void checkCrash(String crashPatternList[], String logcat)
+            throws Exception {
+        for (String crashPattern : crashPatternList) {
+            assertFalse("Crash log pattern found!",
+                    Pattern.compile(crashPattern, Pattern.MULTILINE)
+                            .matcher(logcat).find());
+        }
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
new file mode 100644
index 0000000..bbfd78e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -0,0 +1,119 @@
+/*
+ * 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 android.security.cts;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import android.platform.test.annotations.SecurityTest;
+import java.util.regex.Pattern;
+
+@SecurityTest
+public class TestMedia extends SecurityTestCase {
+
+    final static int TIMEOUT_SEC = 9 * 60;
+    final static String RESOURCE_ROOT = "/";
+    final static String TMP_FILE_PATH = "/data/local/tmp/";
+
+    /****************************************************************
+     * To prevent merge conflicts, add tests for N below this comment,
+     * before any existing test methods
+     ****************************************************************/
+
+
+    /****************************************************************
+     * To prevent merge conflicts, add tests for O below this comment,
+     * before any existing test methods
+     ****************************************************************/
+
+
+    /****************************************************************
+     * To prevent merge conflicts, add tests for P below this comment,
+     * before any existing test methods
+     ****************************************************************/
+
+
+    /**
+     * Checks for linker errors
+     *
+     * @param binaryName name of the binary
+     * @param logcat String to be parsed
+     */
+    public static boolean isLinkerErrorPresent(String binaryName, String logcat)
+            throws Exception {
+        return Pattern
+                .compile("CANNOT LINK EXECUTABLE \"" + TMP_FILE_PATH
+                        + binaryName + "\"", Pattern.MULTILINE)
+                .matcher(logcat).find();
+    }
+
+    /**
+     * Checks for crash
+     *
+     * @param binaryName Name of the binary
+     * @param errPattern error patterns to be checked for
+     * @param logcat String to be parsed
+     */
+    public static void checkCrash(String binaryName, String errPattern[],
+            String logcat) throws Exception {
+        String genericCrashPattern[] = {
+                "name: " + binaryName + "  >>> " + TMP_FILE_PATH + binaryName
+                        + " <<<\n.*?SIGABRT",
+                "name: " + binaryName + "  >>> " + TMP_FILE_PATH + binaryName
+                        + " <<<\n.*?SIGSEGV"};
+        AdbUtils.checkCrash(genericCrashPattern, logcat);
+        if (errPattern != null) {
+            AdbUtils.checkCrash(errPattern, logcat);
+        }
+    }
+
+    /**
+     * Pushes input files, runs the PoC and checks for crash and hang
+     *
+     * @param binaryName name of the binary
+     * @param inputFiles files required as input
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     * @param errPattern error patterns to be checked for
+     */
+    public static void runMediaTest(String binaryName,
+            String inputFiles[], String arguments, ITestDevice device,
+            String errPattern[]) throws Exception {
+        if (inputFiles != null) {
+            for (String tempFile : inputFiles) {
+                AdbUtils.pushResource(RESOURCE_ROOT + tempFile,
+                        TMP_FILE_PATH + tempFile, device);
+            }
+        }
+        AdbUtils.runCommandLine("logcat -c", device);
+        AdbUtils.runWithTimeoutDeleteFiles(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    AdbUtils.runPocNoOutput(binaryName, device,
+                            TIMEOUT_SEC + 30, arguments);
+                } catch (Exception e) {
+                    CLog.w("Exception: " + e.getMessage());
+                }
+            }
+        }, TIMEOUT_SEC * 1000, device, inputFiles);
+        String logcatOut = AdbUtils.runCommandLine("logcat -d", device);
+        boolean linkerErrorFound = isLinkerErrorPresent(binaryName, logcatOut);
+        if (!linkerErrorFound) {
+            checkCrash(binaryName, errPattern, logcatOut);
+        }
+    }
+}