Implement the GrpcWakeupClient.

Implement a remoteaccess HAL implementation that talks with
the wake up client using grpc.

Test: local build.
Bug: 241483300
Change-Id: I02a51f41427fa2854930d2076ca3a49791488fd9
diff --git a/automotive/remoteaccess/impl/default/client/Android.bp b/automotive/remoteaccess/impl/default/client/Android.bp
index 38c79af..6327637 100644
--- a/automotive/remoteaccess/impl/default/client/Android.bp
+++ b/automotive/remoteaccess/impl/default/client/Android.bp
@@ -32,6 +32,11 @@
         "libbinder_ndk",
         "liblog",
         "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
     ],
 }
 
@@ -45,10 +50,17 @@
     ],
     whole_static_libs: [
         "android.hardware.automotive.remoteaccess-V1-ndk",
+        "wakeup_client_protos",
     ],
     shared_libs: [
+        "libbase",
         "libbinder_ndk",
         "liblog",
         "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
     ],
 }
diff --git a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h b/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
index c54aefe..f060b6c 100644
--- a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
+++ b/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
@@ -19,8 +19,10 @@
 #include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
 #include <aidl/android/hardware/automotive/remoteaccess/BnRemoteAccess.h>
 #include <aidl/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.h>
+#include <wakeup_client.grpc.pb.h>
 
 #include <string>
+#include <thread>
 
 namespace android {
 namespace hardware {
@@ -30,9 +32,11 @@
 class RemoteAccessService
     : public aidl::android::hardware::automotive::remoteaccess::BnRemoteAccess {
   public:
+    RemoteAccessService(WakeupClient::StubInterface* grpcStub);
+
     ndk::ScopedAStatus getDeviceId(std::string* deviceId) override;
 
-    ndk::ScopedAStatus getWakeupServiceName(std::string* wakeupServerName) override;
+    ndk::ScopedAStatus getWakeupServiceName(std::string* wakeupServiceName) override;
 
     ndk::ScopedAStatus setRemoteTaskCallback(
             const std::shared_ptr<
@@ -43,6 +47,14 @@
 
     ndk::ScopedAStatus notifyApStateChange(
             const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
+
+  private:
+    WakeupClient::StubInterface* mGrpcStub;
+    std::shared_ptr<aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback>
+            mRemoteTaskCallback;
+    std::thread mThread;
+
+    void taskLoop();
 };
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
index 91a6419..7431898 100644
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
+++ b/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
@@ -25,8 +25,9 @@
 int main(int /* argc */, char* /* argv */[]) {
     ALOGI("Registering RemoteAccessService as service...");
 
+    // TODO(b/241483300): Create GrpcClientStub here.
     auto service = ndk::SharedRefBase::make<
-            android::hardware::automotive::remoteaccess::RemoteAccessService>();
+            android::hardware::automotive::remoteaccess::RemoteAccessService>(nullptr);
 
     binder_exception_t err = AServiceManager_addService(
             service->asBinder().get(), "android.hardware.automotive.remote.IRemoteAccess/default");
diff --git a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp b/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
index e24293f..f567113 100644
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
@@ -16,30 +16,58 @@
 
 #include "RemoteAccessService.h"
 
+#include <android/binder_status.h>
+#include <grpc++/grpc++.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <thread>
+
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace remoteaccess {
 
+namespace {
+
 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
 using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
+using ::grpc::ClientContext;
+using ::grpc::ClientReader;
+using ::grpc::Status;
+using ::grpc::StatusCode;
 using ::ndk::ScopedAStatus;
 
-ScopedAStatus RemoteAccessService::getDeviceId([[maybe_unused]] std::string* deviceId) {
+const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
+
+}  // namespace
+
+RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
+    : mGrpcStub(grpcStub) {
+    // mThread = std::thread([this]() { taskLoop(); });
+}
+
+void RemoteAccessService::taskLoop() {
+    // TODO(b/241483300): handle remote tasks.
+}
+
+ScopedAStatus RemoteAccessService::getDeviceId(std::string* deviceId) {
+    // TODO(b/241483300): Call VHAL to get VIN.
     return ScopedAStatus::ok();
 }
 
-ScopedAStatus RemoteAccessService::getWakeupServiceName(
-        [[maybe_unused]] std::string* wakeupServiceName) {
+ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
+    *wakeupServiceName = WAKEUP_SERVICE_NAME;
     return ScopedAStatus::ok();
 }
 
 ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
         [[maybe_unused]] const std::shared_ptr<IRemoteTaskCallback>& callback) {
+    mRemoteTaskCallback = callback;
     return ScopedAStatus::ok();
 }
 
 ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
+    mRemoteTaskCallback.reset();
     return ScopedAStatus::ok();
 }
 
diff --git a/automotive/remoteaccess/impl/default/proto/Android.bp b/automotive/remoteaccess/impl/default/proto/Android.bp
index c882f55..d3c75a6 100644
--- a/automotive/remoteaccess/impl/default/proto/Android.bp
+++ b/automotive/remoteaccess/impl/default/proto/Android.bp
@@ -24,7 +24,9 @@
     ],
     out: [
         "wakeup_client.pb.h",
+        "wakeup_client.grpc.pb.h",
     ],
+    vendor: true,
 }
 
 genrule {
@@ -39,7 +41,9 @@
     ],
     out: [
         "wakeup_client.pb.cc",
+        "wakeup_client.grpc.pb.cc",
     ],
+    vendor: true,
 }
 
 cc_library_static {
diff --git a/automotive/remoteaccess/impl/default/test/Android.bp b/automotive/remoteaccess/impl/default/test/Android.bp
new file mode 100644
index 0000000..e92440f
--- /dev/null
+++ b/automotive/remoteaccess/impl/default/test/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "RemoteAccessServiceUnitTest",
+    vendor: true,
+    srcs: ["*.cpp"],
+    whole_static_libs: [
+        "RemoteAccessService",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    // libgrpc++.so is installed as root, require root to access it.
+    require_root: true,
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
new file mode 100644
index 0000000..de25927
--- /dev/null
+++ b/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 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 "RemoteAccessService.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wakeup_client.grpc.pb.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+using ::grpc::ClientAsyncReaderInterface;
+using ::grpc::ClientAsyncResponseReaderInterface;
+using ::grpc::ClientContext;
+using ::grpc::ClientReader;
+using ::grpc::ClientReaderInterface;
+using ::grpc::CompletionQueue;
+using ::grpc::Status;
+
+using ::ndk::ScopedAStatus;
+
+class MockGrpcClientStub : public WakeupClient::StubInterface {
+  public:
+    MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
+                (ClientContext * context, const GetRemoteTasksRequest& request));
+    MOCK_METHOD(Status, NotifyWakeupRequired,
+                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+                 NotifyWakeupRequiredResponse* response));
+    // Async methods which we do not care.
+    MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
+                (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
+                 void* tag));
+    MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
+                (ClientContext * context, const GetRemoteTasksRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
+                AsyncNotifyWakeupRequiredRaw,
+                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+                 CompletionQueue* cq));
+    MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
+                PrepareAsyncNotifyWakeupRequiredRaw,
+                (ClientContext * context, const NotifyWakeupRequiredRequest& request,
+                 CompletionQueue* cq));
+};
+
+class RemoteAccessServiceUnitTest : public ::testing::Test {
+  public:
+    RemoteAccessServiceUnitTest() {
+        mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
+        mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
+    }
+
+    MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
+
+    RemoteAccessService* getService() { return mService.get(); }
+
+  private:
+    std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
+    std::shared_ptr<RemoteAccessService> mService;
+};
+
+TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
+    std::string serviceName;
+
+    ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
+
+    EXPECT_TRUE(status.isOk());
+    EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
+}
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android