Add Grpc graph runner fuzzer
Bug: 167296056
Test: Follow go/android-fuzzing to build and test
we will add this fuzzer to go/aae-fuzz-dashboard
Change-Id: I791573af22be885b7cbd40e2b461f392884413c5
Merged-In: I791573af22be885b7cbd40e2b461f392884413c5
diff --git a/computepipe/tests/fuzz/Android.bp b/computepipe/tests/fuzz/Android.bp
index ee95bb1..9e4257f 100644
--- a/computepipe/tests/fuzz/Android.bp
+++ b/computepipe/tests/fuzz/Android.bp
@@ -34,6 +34,7 @@
"-Wall",
"-Werror",
"-Wno-unused-parameter",
+ "-Wno-unused-variable",
],
static_libs: [
"computepipe_runner_component",
@@ -51,6 +52,7 @@
],
header_libs: [
"computepipe_runner_includes",
+ "graph_test_headers",
],
include_dirs: [
"packages/services/Car/computepipe",
@@ -101,7 +103,6 @@
defaults: ["libcomputepipefuzz-defaults"],
cppflags:[
"-fexceptions",
- "-Wno-unused-variable",
],
static_libs: [
"computepipe_prebuilt_graph",
@@ -117,3 +118,27 @@
"LocalPrebuildGraphFuzzer.cpp",
],
}
+
+cc_fuzz {
+ name: "grpc_graph_fuzzer",
+ defaults: ["libcomputepipefuzz-defaults"],
+ cppflags:[
+ "-fexceptions",
+ ],
+ static_libs: [
+ "computepipe_grpc_graph_proto",
+ ],
+ shared_libs: [
+ "computepipe_grpc_graph",
+ "libcomputepipeprotos",
+ "libgrpc++",
+ "libprotobuf-cpp-full",
+ ],
+ include_dirs: [
+ "packages/services/Car/computepipe",
+ "packages/services/Car/computepipe/runner/graph",
+ ],
+ srcs: [
+ "GrpcGraphFuzzer.cpp",
+ ],
+}
diff --git a/computepipe/tests/fuzz/Common.h b/computepipe/tests/fuzz/Common.h
index ffaf015..9934b61 100644
--- a/computepipe/tests/fuzz/Common.h
+++ b/computepipe/tests/fuzz/Common.h
@@ -33,6 +33,19 @@
HANDLE_RESET_PHASE, /* verify handleResetPhase */ \
API_SUM
+#define GRAPH_RUNNER_BASE_ENUM \
+ GET_GRAPH_TYPE, /* verify GetGraphType */ \
+ GET_GRAPH_STATE, /* verify GetGraphState */ \
+ GET_STATUS, /* verify GetStatus */ \
+ GET_ERROR_MESSAGE, /* verify GetErrorMessage */ \
+ GET_SUPPORTED_GRAPH_CONFIGS, /* verify GetSupportedGraphConfigs */ \
+ SET_INPUT_STREAM_DATA, /* verify SetInputStreamData */ \
+ SET_INPUT_STREAM_PIXEL_DATA, /* verify SetInputStreamPixelData */ \
+ START_GRAPH_PROFILING, /* verify StartGraphProfiling */ \
+ STOP_GRAPH_PROFILING /* verify StopGraphProfiling */
+
+const char kAddress[16] = "[::]:10000";
+
} // namespace test
} // namespace runner
} // namespace computepipe
diff --git a/computepipe/tests/fuzz/GrpcGraphFuzzer.cpp b/computepipe/tests/fuzz/GrpcGraphFuzzer.cpp
new file mode 100644
index 0000000..338b3f8
--- /dev/null
+++ b/computepipe/tests/fuzz/GrpcGraphFuzzer.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 "GrpcGraph.h"
+#include "GrpcGraphServerImpl.h"
+
+using ::android::automotive::computepipe::runner::ClientConfig;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+namespace {
+
+enum GRPC_GRAPH_FUZZ_FUNCS {
+ GRAPH_RUNNER_BASE_ENUM,
+ DISPATCH_PIXEL_DATA, /* verify dispatchPixelData */
+ DISPATCH_SERIALIZED_DATA, /* dispatchSerializedData */
+ DISPATCH_GRAPH_TERMINATION_MSG, /* dispatchGraphTerminationMessage */
+ RUNNER_COMP_BASE_ENUM
+};
+
+bool DoInitialization() {
+ // Initialization goes here
+ std::shared_ptr<GrpcGraphServerImpl> server;
+ server = std::make_shared<GrpcGraphServerImpl>(runner::test::kAddress);
+ std::thread t = std::thread([server]() { server->startServer(); });
+ t.detach();
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ static bool initialized = DoInitialization();
+ std::shared_ptr<PrebuiltEngineInterfaceImpl> engine;
+ std::unique_ptr<GrpcGraph> graph = std::make_unique<GrpcGraph>();
+ engine = std::make_shared<PrebuiltEngineInterfaceImpl>();
+ Status status = graph->initialize(runner::test::kAddress, engine);
+ if (status != Status::SUCCESS) {
+ LOG(ERROR) << "Initialization of GrpcGraph failed, aborting...";
+ exit(1);
+ }
+
+ // 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;
+ }
+ case DISPATCH_PIXEL_DATA: {
+ runner::InputFrame inputFrame(0, 0, PixelFormat::RGB, 0, nullptr);
+ graph->dispatchPixelData(/*streamIndex =*/1, /*timestamp =*/0,
+ /*inputFrame =*/inputFrame);
+ break;
+ }
+ case DISPATCH_SERIALIZED_DATA: {
+ graph->dispatchSerializedData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/"");
+ break;
+ }
+ case DISPATCH_GRAPH_TERMINATION_MSG: {
+ uint8_t status = fdp.ConsumeIntegralInRange<uint8_t>(0, Status::STATUS_MAX - 1);
+ graph->dispatchGraphTerminationMessage(static_cast<Status>(status), "");
+ 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/LocalPrebuildGraphFuzzer.cpp b/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
index cd35918..c7398e4 100644
--- a/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
+++ b/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
@@ -20,7 +20,7 @@
#include "ClientConfig.pb.h"
#include "Common.h"
#include "LocalPrebuiltGraph.h"
-#include "PrebuiltEngineInterface.h"
+#include "PrebuiltEngineInterfaceImpl.h"
using ::android::automotive::computepipe::runner::ClientConfig;
@@ -31,56 +31,7 @@
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;
- }
-};
+enum LOCAL_PREBUILD_GRAPH_FUZZ_FUNCS { GRAPH_RUNNER_BASE_ENUM, RUNNER_COMP_BASE_ENUM };
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Initialization goes here
diff --git a/computepipe/tests/runner/graph/Android.bp b/computepipe/tests/runner/graph/Android.bp
index 14271dd..26fe1cf 100644
--- a/computepipe/tests/runner/graph/Android.bp
+++ b/computepipe/tests/runner/graph/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+cc_library_headers {
+ name: "graph_test_headers",
+ export_include_dirs: ["./includes"],
+}
+
cc_test {
name: "computepipe_prebuilt_graph_test",
test_suites: ["device-tests"],
@@ -24,7 +29,7 @@
"computepipe_runner_component",
"libgtest",
"libgmock",
- "libcomputepipeprotos",
+ "libcomputepipeprotos",
],
shared_libs: [
"libstubgraphimpl",
@@ -35,6 +40,7 @@
],
header_libs: [
"computepipe_runner_includes",
+ "graph_test_headers",
],
include_dirs: [
"packages/services/Car/computepipe",
@@ -63,7 +69,7 @@
shared_libs: [
"computepipe_grpc_graph",
"libbase",
- "libcomputepipeprotos",
+ "libcomputepipeprotos",
"libgrpc++",
"libdl",
"liblog",
@@ -71,6 +77,7 @@
],
header_libs: [
"computepipe_runner_includes",
+ "graph_test_headers",
],
include_dirs: [
"packages/services/Car/computepipe",
diff --git a/computepipe/tests/runner/graph/GrpcGraphTest.cpp b/computepipe/tests/runner/graph/GrpcGraphTest.cpp
index 2effb00..8a0ddc9 100644
--- a/computepipe/tests/runner/graph/GrpcGraphTest.cpp
+++ b/computepipe/tests/runner/graph/GrpcGraphTest.cpp
@@ -22,6 +22,7 @@
#include <grpc++/grpc++.h>
#include "ClientConfig.pb.h"
+#include "GrpcGraphServerImpl.h"
#include "GrpcPrebuiltGraphService.grpc.pb.h"
#include "GrpcPrebuiltGraphService.pb.h"
#include "Options.pb.h"
@@ -44,190 +45,6 @@
namespace graph {
namespace {
-constexpr char kGraphName[] = "Stub graph name";
-constexpr char kSetGraphConfigMessage[] = "Stub set config message";
-constexpr char kSetDebugOptionMessage[] = "Stub set debug option message";
-constexpr char kStartGraphMessage[] = "Stub start graph message";
-constexpr char kStopGraphMessage[] = "Stub stop graph message";
-constexpr char kOutputStreamPacket[] = "Stub output stream packet";
-constexpr char kResetGraphMessage[] = "ResetGraphMessage";
-
-// This is a barebones synchronous server implementation. A better implementation would be an
-// asynchronous implementation and it is upto the graph provider to do that. This implementation
-// is very specific to tests being conducted here.
-class GrpcGraphServerImpl : public proto::GrpcGraphService::Service {
-private:
- std::string mServerAddress;
- std::unique_ptr<::grpc::Server> mServer;
- std::mutex mLock;
- std::condition_variable mShutdownCv;
- bool mShutdown = false;
-
-public:
- explicit GrpcGraphServerImpl(std::string address) : mServerAddress(address) {}
-
- virtual ~GrpcGraphServerImpl() {
- if (mServer) {
- mServer->Shutdown();
- std::unique_lock lock(mLock);
- if (!mShutdown) {
- mShutdownCv.wait_for(lock, std::chrono::seconds(10),
- [this]() { return mShutdown; });
- }
- }
- }
-
- void startServer() {
- if (mServer == nullptr) {
- ::grpc::ServerBuilder builder;
- builder.RegisterService(this);
- builder.AddListeningPort(mServerAddress, ::grpc::InsecureServerCredentials());
- mServer = builder.BuildAndStart();
- mServer->Wait();
- std::lock_guard lock(mLock);
- mShutdown = true;
- mShutdownCv.notify_one();
- }
- }
-
- ::grpc::Status GetGraphOptions(::grpc::ServerContext* context,
- const proto::GraphOptionsRequest* request,
- proto::GraphOptionsResponse* response) override {
- proto::Options options;
- options.set_graph_name(kGraphName);
- response->set_serialized_options(options.SerializeAsString());
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetGraphConfig(::grpc::ServerContext* context,
- const proto::SetGraphConfigRequest* request,
- proto::StatusResponse* response) override {
- response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
- response->set_message(kSetGraphConfigMessage);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status SetDebugOption(::grpc::ServerContext* context,
- const proto::SetDebugRequest* request,
- proto::StatusResponse* response) override {
- response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
- response->set_message(kSetDebugOptionMessage);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status StartGraphExecution(::grpc::ServerContext* context,
- const proto::StartGraphExecutionRequest* request,
- proto::StatusResponse* response) override {
- response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
- response->set_message(kStartGraphMessage);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status ObserveOutputStream(
- ::grpc::ServerContext* context, const proto::ObserveOutputStreamRequest* request,
- ::grpc::ServerWriter<proto::OutputStreamResponse>* writer) override {
- // Write as many output packets as stream id. This is just to test different number of
- // packets received with each stream. Also write even numbered stream as a pixel packet
- // and odd numbered stream as a data packet.
- for (int i = 0; i < request->stream_id(); i++) {
- proto::OutputStreamResponse response;
- if (request->stream_id() % 2 == 0) {
- response.mutable_pixel_data()->set_data(kOutputStreamPacket);
- response.mutable_pixel_data()->set_height(1);
- response.mutable_pixel_data()->set_width(sizeof(kOutputStreamPacket));
- response.mutable_pixel_data()->set_step(sizeof(kOutputStreamPacket));
- response.mutable_pixel_data()->set_format(proto::PixelFormat::GRAY);
- EXPECT_TRUE(response.has_pixel_data());
- } else {
- response.set_semantic_data(kOutputStreamPacket);
- EXPECT_TRUE(response.has_semantic_data());
- }
- if (!writer->Write(response)) {
- return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost");
- }
- }
-
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status StopGraphExecution(::grpc::ServerContext* context,
- const proto::StopGraphExecutionRequest* request,
- proto::StatusResponse* response) override {
- response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
- response->set_message(kStopGraphMessage);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status ResetGraph(::grpc::ServerContext* context,
- const proto::ResetGraphRequest* request,
- proto::StatusResponse* response) override {
- response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
- response->set_message(kResetGraphMessage);
- return ::grpc::Status::OK;
- }
-
- ::grpc::Status GetProfilingData(::grpc::ServerContext* context,
- const proto::ProfilingDataRequest* request,
- proto::ProfilingDataResponse* response) {
- response->set_data(kSetGraphConfigMessage);
- return ::grpc::Status::OK;
- }
-};
-
-class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
-private:
- std::map<int, int> mNumPacketsPerStream;
- std::mutex mLock;
- std::condition_variable mCv;
- bool mGraphTerminated = false;
-
-public:
- // Prebuilt to engine interface
- void DispatchPixelData(int streamId, int64_t timestamp,
- const runner::InputFrame& frame) override {
- ASSERT_EQ(streamId % 2, 0);
- std::lock_guard lock(mLock);
- if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
- mNumPacketsPerStream[streamId] = 1;
- } else {
- mNumPacketsPerStream[streamId]++;
- }
- }
-
- void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
- ASSERT_EQ(streamId % 2, 1);
- std::lock_guard lock(mLock);
- if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
- mNumPacketsPerStream[streamId] = 1;
- } else {
- mNumPacketsPerStream[streamId]++;
- }
- }
-
- void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
- std::lock_guard lock(mLock);
- mGraphTerminated = true;
- mCv.notify_one();
- }
-
- bool waitForTermination() {
- std::unique_lock lock(mLock);
- if (!mGraphTerminated) {
- mCv.wait_for(lock, std::chrono::seconds(10), [this] { return mGraphTerminated; });
- }
- return mGraphTerminated;
- }
-
- int numPacketsForStream(int streamId) {
- std::lock_guard lock(mLock);
- auto it = mNumPacketsPerStream.find(streamId);
- if (it == mNumPacketsPerStream.end()) {
- return 0;
- }
- return it->second;
- }
-};
-
class GrpcGraphTest : public ::testing::Test {
private:
std::unique_ptr<GrpcGraphServerImpl> mServer;
diff --git a/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp b/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
index d63ec51..ddc3aee 100644
--- a/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
+++ b/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
@@ -18,6 +18,7 @@
#include "ClientConfig.pb.h"
#include "LocalPrebuiltGraph.h"
#include "PrebuiltEngineInterface.h"
+#include "PrebuiltEngineInterfaceImpl.h"
#include "ProfilingType.pb.h"
#include "RunnerComponent.h"
#include "gmock/gmock-matchers.h"
@@ -36,44 +37,6 @@
namespace graph {
namespace {
-// 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;
- }
-};
-
// The stub graph implementation is a passthrough implementation that does not run
// any graph and returns success for all implementations. The only useful things that
// it does for the tests are
diff --git a/computepipe/tests/runner/graph/includes/GrpcGraphServerImpl.h b/computepipe/tests/runner/graph/includes/GrpcGraphServerImpl.h
new file mode 100644
index 0000000..a168728
--- /dev/null
+++ b/computepipe/tests/runner/graph/includes/GrpcGraphServerImpl.h
@@ -0,0 +1,233 @@
+/*
+ * 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_RUNNER_GRAPH_INCLUDES_GRPCGRAPHSERVERIMPL_H_
+#define CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_GRPCGRAPHSERVERIMPL_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "GrpcPrebuiltGraphService.grpc.pb.h"
+#include "GrpcPrebuiltGraphService.pb.h"
+#include "Options.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+constexpr char kGraphName[] = "Stub graph name";
+constexpr char kSetGraphConfigMessage[] = "Stub set config message";
+constexpr char kSetDebugOptionMessage[] = "Stub set debug option message";
+constexpr char kStartGraphMessage[] = "Stub start graph message";
+constexpr char kStopGraphMessage[] = "Stub stop graph message";
+constexpr char kOutputStreamPacket[] = "Stub output stream packet";
+constexpr char kResetGraphMessage[] = "ResetGraphMessage";
+
+// This is a barebones synchronous server implementation. A better implementation would be an
+// asynchronous implementation and it is upto the graph provider to do that. This implementation
+// is very specific to tests being conducted here.
+class GrpcGraphServerImpl : public proto::GrpcGraphService::Service {
+private:
+ std::string mServerAddress;
+ std::unique_ptr<::grpc::Server> mServer;
+ std::mutex mLock;
+ std::condition_variable mShutdownCv;
+ bool mShutdown = false;
+
+public:
+ explicit GrpcGraphServerImpl(std::string address) : mServerAddress(address) {}
+
+ virtual ~GrpcGraphServerImpl() {
+ if (mServer) {
+ mServer->Shutdown();
+ std::unique_lock lock(mLock);
+ if (!mShutdown) {
+ mShutdownCv.wait_for(lock, std::chrono::seconds(10),
+ [this]() { return mShutdown; });
+ }
+ }
+ }
+
+ void startServer() {
+ if (mServer == nullptr) {
+ ::grpc::ServerBuilder builder;
+ builder.RegisterService(this);
+ builder.AddListeningPort(mServerAddress, ::grpc::InsecureServerCredentials());
+ mServer = builder.BuildAndStart();
+ mServer->Wait();
+ std::lock_guard lock(mLock);
+ mShutdown = true;
+ mShutdownCv.notify_one();
+ }
+ }
+
+ ::grpc::Status GetGraphOptions(::grpc::ServerContext* context,
+ const proto::GraphOptionsRequest* request,
+ proto::GraphOptionsResponse* response) override {
+ proto::Options options;
+ options.set_graph_name(kGraphName);
+ response->set_serialized_options(options.SerializeAsString());
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetGraphConfig(::grpc::ServerContext* context,
+ const proto::SetGraphConfigRequest* request,
+ proto::StatusResponse* response) override {
+ response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+ response->set_message(kSetGraphConfigMessage);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetDebugOption(::grpc::ServerContext* context,
+ const proto::SetDebugRequest* request,
+ proto::StatusResponse* response) override {
+ response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+ response->set_message(kSetDebugOptionMessage);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StartGraphExecution(::grpc::ServerContext* context,
+ const proto::StartGraphExecutionRequest* request,
+ proto::StatusResponse* response) override {
+ response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+ response->set_message(kStartGraphMessage);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status ObserveOutputStream(
+ ::grpc::ServerContext* context, const proto::ObserveOutputStreamRequest* request,
+ ::grpc::ServerWriter<proto::OutputStreamResponse>* writer) override {
+ // Write as many output packets as stream id. This is just to test different number of
+ // packets received with each stream. Also write even numbered stream as a pixel packet
+ // and odd numbered stream as a data packet.
+ for (int i = 0; i < request->stream_id(); i++) {
+ proto::OutputStreamResponse response;
+ if (request->stream_id() % 2 == 0) {
+ response.mutable_pixel_data()->set_data(kOutputStreamPacket);
+ response.mutable_pixel_data()->set_height(1);
+ response.mutable_pixel_data()->set_width(sizeof(kOutputStreamPacket));
+ response.mutable_pixel_data()->set_step(sizeof(kOutputStreamPacket));
+ response.mutable_pixel_data()->set_format(proto::PixelFormat::GRAY);
+ EXPECT_TRUE(response.has_pixel_data());
+ } else {
+ response.set_semantic_data(kOutputStreamPacket);
+ EXPECT_TRUE(response.has_semantic_data());
+ }
+ if (!writer->Write(response)) {
+ return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost");
+ }
+ }
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StopGraphExecution(::grpc::ServerContext* context,
+ const proto::StopGraphExecutionRequest* request,
+ proto::StatusResponse* response) override {
+ response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+ response->set_message(kStopGraphMessage);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status ResetGraph(::grpc::ServerContext* context,
+ const proto::ResetGraphRequest* request,
+ proto::StatusResponse* response) override {
+ response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+ response->set_message(kResetGraphMessage);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status GetProfilingData(::grpc::ServerContext* context,
+ const proto::ProfilingDataRequest* request,
+ proto::ProfilingDataResponse* response) {
+ response->set_data(kSetGraphConfigMessage);
+ return ::grpc::Status::OK;
+ }
+};
+
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+private:
+ std::map<int, int> mNumPacketsPerStream;
+ std::mutex mLock;
+ std::condition_variable mCv;
+ bool mGraphTerminated = false;
+
+public:
+ // Prebuilt to engine interface
+ void DispatchPixelData(int streamId, int64_t timestamp,
+ const runner::InputFrame& frame) override {
+ ASSERT_EQ(streamId % 2, 0);
+ std::lock_guard lock(mLock);
+ if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
+ mNumPacketsPerStream[streamId] = 1;
+ } else {
+ mNumPacketsPerStream[streamId]++;
+ }
+ }
+
+ void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+ ASSERT_EQ(streamId % 2, 1);
+ std::lock_guard lock(mLock);
+ if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
+ mNumPacketsPerStream[streamId] = 1;
+ } else {
+ mNumPacketsPerStream[streamId]++;
+ }
+ }
+
+ void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+ std::lock_guard lock(mLock);
+ mGraphTerminated = true;
+ mCv.notify_one();
+ }
+
+ bool waitForTermination() {
+ std::unique_lock lock(mLock);
+ if (!mGraphTerminated) {
+ mCv.wait_for(lock, std::chrono::seconds(10), [this] { return mGraphTerminated; });
+ }
+ return mGraphTerminated;
+ }
+
+ int numPacketsForStream(int streamId) {
+ std::lock_guard lock(mLock);
+ auto it = mNumPacketsPerStream.find(streamId);
+ if (it == mNumPacketsPerStream.end()) {
+ return 0;
+ }
+ return it->second;
+ }
+};
+
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_GRPCGRAPHSERVERIMPL_H_
diff --git a/computepipe/tests/runner/graph/includes/PrebuiltEngineInterfaceImpl.h b/computepipe/tests/runner/graph/includes/PrebuiltEngineInterfaceImpl.h
new file mode 100644
index 0000000..70326ab
--- /dev/null
+++ b/computepipe/tests/runner/graph/includes/PrebuiltEngineInterfaceImpl.h
@@ -0,0 +1,80 @@
+/*
+ * 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_RUNNER_GRAPH_INCLUDES_PREBUILTENGINEINTERFACEIMPL_H_
+#define CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_PREBUILTENGINEINTERFACEIMPL_H_
+
+#include <string>
+
+#include "ClientConfig.pb.h"
+#include "LocalPrebuiltGraph.h"
+#include "PrebuiltEngineInterface.h"
+#include "ProfilingType.pb.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+// 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;
+ }
+};
+
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_PREBUILTENGINEINTERFACEIMPL_H_