Merge "Add fuzzer for local prebuild graph runner" into rvc-qpr-dev
diff --git a/computepipe/runner/graph/LocalPrebuiltGraph.cpp b/computepipe/runner/graph/LocalPrebuiltGraph.cpp
index ae4cc8c..821e549 100644
--- a/computepipe/runner/graph/LocalPrebuiltGraph.cpp
+++ b/computepipe/runner/graph/LocalPrebuiltGraph.cpp
@@ -179,7 +179,7 @@
         const std::string& prebuilt_library,
         std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
     std::unique_lock<std::mutex> lock(LocalPrebuiltGraph::mCreationMutex);
-    if (mPrebuiltGraphInstance != nullptr) {
+    if (mPrebuiltGraphInstance == nullptr) {
         mPrebuiltGraphInstance = new LocalPrebuiltGraph();
     }
     if (mPrebuiltGraphInstance->mGraphState.load() != PrebuiltGraphState::UNINITIALIZED) {
diff --git a/computepipe/tests/fuzz/Android.bp b/computepipe/tests/fuzz/Android.bp
index 97f3435..6c54b64 100644
--- a/computepipe/tests/fuzz/Android.bp
+++ b/computepipe/tests/fuzz/Android.bp
@@ -80,3 +80,25 @@
         "libprotobuf-mutator",
     ],
 }
+
+cc_fuzz {
+    name: "local_prebuild_graph_fuzzer",
+    defaults: ["libcomputepipefuzz-defaults"],
+    cppflags:[
+        "-fexceptions",
+        "-Wno-unused-variable",
+    ],
+    static_libs: [
+        "computepipe_prebuilt_graph",
+    ],
+    shared_libs: [
+        "libstubgraphimpl",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/computepipe/runner/graph",
+    ],
+    srcs: [
+        "LocalPrebuildGraphFuzzer.cpp",
+    ],
+}
diff --git a/computepipe/tests/fuzz/Common.h b/computepipe/tests/fuzz/Common.h
new file mode 100644
index 0000000..ffaf015
--- /dev/null
+++ b/computepipe/tests/fuzz/Common.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CPP_COMPUTEPIPE_TESTS_FUZZ_COMMON_H_
+#define CPP_COMPUTEPIPE_TESTS_FUZZ_COMMON_H_
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace runner {
+namespace test {
+
+const int kMaxFuzzerConsumedBytes = 12;
+
+#define RUNNER_COMP_BASE_ENUM                                                   \
+    HANDLE_CONFIG_PHASE,                  /* verify handleConfigPhase */        \
+            HANDLE_EXECUTION_PHASE,       /* verify handleExecutionPhase */     \
+            HANDLE_STOP_IMMEDIATE_PHASE,  /* verify handleStopImmediatePhase */ \
+            HANDLE_STOP_WITH_FLUSH_PHASE, /* verify handleStopWithFlushPhase */ \
+            HANDLE_RESET_PHASE,           /* verify handleResetPhase */         \
+            API_SUM
+
+}  // namespace test
+}  // namespace runner
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_COMPUTEPIPE_TESTS_FUZZ_COMMON_H_
diff --git a/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp b/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
new file mode 100644
index 0000000..cd35918
--- /dev/null
+++ b/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 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.
+ */
+
+#include <android-base/logging.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gmock/gmock.h>
+#include "ClientConfig.pb.h"
+#include "Common.h"
+#include "LocalPrebuiltGraph.h"
+#include "PrebuiltEngineInterface.h"
+
+using ::android::automotive::computepipe::runner::ClientConfig;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+namespace {
+
+enum LOCAL_PREBUILD_GRAPH_FUZZ_FUNCS {
+    GET_GRAPH_TYPE,
+    GET_GRAPH_STATE,
+    GET_STATUS,
+    GET_ERROR_MESSAGE,
+    GET_SUPPORTED_GRAPH_CONFIGS,
+    SET_INPUT_STREAM_DATA,
+    SET_INPUT_STREAM_PIXEL_DATA,
+    START_GRAPH_PROFILING,
+    STOP_GRAPH_PROFILING,
+    RUNNER_COMP_BASE_ENUM
+};
+
+// Barebones implementation of the PrebuiltEngineInterface. This implementation should suffice for
+// basic cases. More complicated use cases might need their own implementation of it.
+typedef std::function<void(int, int64_t, const runner::InputFrame&)> PixelCallback;
+typedef std::function<void(int, int64_t, std::string&&)> SerializedStreamCallback;
+typedef std::function<void(Status, std::string&&)> GraphTerminationCallback;
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+private:
+    PixelCallback mPixelCallbackFn;
+    SerializedStreamCallback mSerializedStreamCallbackFn;
+    GraphTerminationCallback mGraphTerminationCallbackFn;
+
+public:
+    virtual ~PrebuiltEngineInterfaceImpl() = default;
+
+    void DispatchPixelData(int streamId, int64_t timestamp,
+                           const runner::InputFrame& frame) override {
+        mPixelCallbackFn(streamId, timestamp, frame);
+    }
+
+    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+        mSerializedStreamCallbackFn(streamId, timestamp, std::move(data));
+    }
+
+    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+        mGraphTerminationCallbackFn(status, std::move(msg));
+    }
+
+    void SetPixelCallback(PixelCallback callback) { mPixelCallbackFn = callback; }
+
+    void SetSerializedStreamCallback(SerializedStreamCallback callback) {
+        mSerializedStreamCallbackFn = callback;
+    }
+
+    void SetGraphTerminationCallback(GraphTerminationCallback callback) {
+        mGraphTerminationCallbackFn = callback;
+    }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    // Initialization goes here
+    bool graphHasTerminated = false;
+    int numOutputStreamCallbacksReceived[4] = {0, 0, 0, 0};
+
+    PrebuiltEngineInterfaceImpl callback;
+    callback.SetGraphTerminationCallback(
+            [&graphHasTerminated](Status, std::string) { graphHasTerminated = true; });
+
+    // Add multiple pixel stream callback functions to see if all of them register.
+    callback.SetPixelCallback([&numOutputStreamCallbacksReceived](int streamIndex, int64_t,
+                                                                  const runner::InputFrame&) {
+        ASSERT_TRUE(streamIndex == 0 || streamIndex == 1);
+        numOutputStreamCallbacksReceived[streamIndex]++;
+    });
+
+    // Add multiple stream callback functions to see if all of them register.
+    callback.SetSerializedStreamCallback(
+            [&numOutputStreamCallbacksReceived](int streamIndex, int64_t, std::string&&) {
+                ASSERT_TRUE(streamIndex == 2 || streamIndex == 3);
+                numOutputStreamCallbacksReceived[streamIndex]++;
+            });
+
+    std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+            std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+                    std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+    PrebuiltGraph* graph = GetLocalGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+
+    // Fuzz goes here
+    FuzzedDataProvider fdp(data, size);
+    while (fdp.remaining_bytes() > runner::test::kMaxFuzzerConsumedBytes) {
+        switch (fdp.ConsumeIntegralInRange<uint32_t>(0, API_SUM - 1)) {
+            case GET_GRAPH_TYPE: {
+                graph->GetGraphType();
+                break;
+            }
+            case GET_GRAPH_STATE: {
+                graph->GetGraphState();
+                break;
+            }
+            case GET_STATUS: {
+                graph->GetStatus();
+                break;
+            }
+            case GET_ERROR_MESSAGE: {
+                graph->GetErrorMessage();
+                break;
+            }
+            case GET_SUPPORTED_GRAPH_CONFIGS: {
+                graph->GetSupportedGraphConfigs();
+                break;
+            }
+            case SET_INPUT_STREAM_DATA: {
+                graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/"");
+                break;
+            }
+            case SET_INPUT_STREAM_PIXEL_DATA: {
+                runner::InputFrame inputFrame(0, 0, PixelFormat::RGB, 0, nullptr);
+                graph->SetInputStreamPixelData(/*streamIndex =*/1, /*timestamp =*/0,
+                                               /*inputFrame =*/inputFrame);
+                break;
+            }
+            case START_GRAPH_PROFILING: {
+                graph->StartGraphProfiling();
+                break;
+            }
+            case STOP_GRAPH_PROFILING: {
+                graph->StopGraphProfiling();
+                break;
+            }
+            case HANDLE_CONFIG_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleConfigPhase(e);
+                break;
+            }
+            case HANDLE_EXECUTION_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleExecutionPhase(e);
+                break;
+            }
+            case HANDLE_STOP_IMMEDIATE_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleStopImmediatePhase(e);
+                break;
+            }
+            case HANDLE_STOP_WITH_FLUSH_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleStopWithFlushPhase(e);
+                break;
+            }
+            case HANDLE_RESET_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleResetPhase(e);
+                break;
+            }
+            default:
+                LOG(ERROR) << "Unexpected option aborting...";
+                break;
+        }
+    }
+    return 0;
+}
+
+}  // namespace
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp b/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp
index 3e98e2a..44a0471 100644
--- a/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp
+++ b/computepipe/tests/fuzz/PixelMemHandleFuzzer.cpp
@@ -32,7 +32,7 @@
 namespace stream_manager {
 namespace {
 
-InputFrame convertToInputFrame(const fuzz::proto::Frame frame) {
+InputFrame convertToInputFrame(const fuzz::proto::Frame& frame) {
     uint32_t height = frame.height();
     uint32_t width = frame.width();
     uint32_t stride = frame.stride();