Merge changes I551bf9ab,Idaf19866 am: 6a242f300c

Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/interfaces/+/19959265

Change-Id: I9438c49414e66d12a8ca97088973305dd0c3b0d5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/automotive/remoteaccess/impl/default/client/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
similarity index 94%
rename from automotive/remoteaccess/impl/default/client/Android.bp
rename to automotive/remoteaccess/hal/default/Android.bp
index 6327637..2502079 100644
--- a/automotive/remoteaccess/impl/default/client/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -29,6 +29,7 @@
         "RemoteAccessService",
     ],
     shared_libs: [
+        "libbase",
         "libbinder_ndk",
         "liblog",
         "libutils",
@@ -37,6 +38,7 @@
     ],
     cflags: [
         "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
     ],
 }
 
@@ -55,6 +57,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libcutils",
         "liblog",
         "libutils",
         "libgrpc++",
diff --git a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
similarity index 74%
rename from automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
rename to automotive/remoteaccess/hal/default/include/RemoteAccessService.h
index 806440a..207c093 100644
--- a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -18,8 +18,11 @@
 
 #include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
 #include <aidl/android/hardware/automotive/remoteaccess/BnRemoteAccess.h>
+#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
 #include <aidl/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.h>
 #include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+#include <utils/SystemClock.h>
 #include <wakeup_client.grpc.pb.h>
 
 #include <string>
@@ -30,6 +33,27 @@
 namespace automotive {
 namespace remoteaccess {
 
+// A IRemoteTaskCallback implementation for debug purpose.
+class DebugRemoteTaskCallback final
+    : public aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback {
+  public:
+    DebugRemoteTaskCallback() { mStartTimeMillis = android::uptimeMillis(); };
+
+    ndk::ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
+                                             const std::vector<uint8_t>& data) override;
+    std::string printTasks();
+
+  private:
+    struct TaskData {
+        std::string clientId;
+        std::vector<uint8_t> data;
+    };
+
+    std::mutex mLock;
+    int64_t mStartTimeMillis;
+    std::vector<TaskData> mTasks;
+};
+
 class RemoteAccessService
     : public aidl::android::hardware::automotive::remoteaccess::BnRemoteAccess {
   public:
@@ -51,10 +75,14 @@
     ndk::ScopedAStatus notifyApStateChange(
             const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
 
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
   private:
     // For testing.
     friend class RemoteAccessServiceUnitTest;
 
+    static bool checkDumpPermission();
+
     WakeupClient::StubInterface* mGrpcStub;
     std::thread mThread;
     std::mutex mLock;
@@ -69,12 +97,14 @@
     bool mTaskLoopRunning GUARDED_BY(mStartStopTaskLoopLock);
     // Default wait time before retry connecting to remote access client is 10s.
     size_t mRetryWaitInMs = 10'000;
+    std::shared_ptr<DebugRemoteTaskCallback> mDebugCallback;
 
     void runTaskLoop();
     void maybeStartTaskLoop();
     void maybeStopTaskLoop();
 
     void setRetryWaitInMs(size_t retryWaitInMs) { mRetryWaitInMs = retryWaitInMs; }
+    void dumpHelp(int fd);
 };
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/impl/default/proto/Android.bp b/automotive/remoteaccess/hal/default/proto/Android.bp
similarity index 100%
rename from automotive/remoteaccess/impl/default/proto/Android.bp
rename to automotive/remoteaccess/hal/default/proto/Android.bp
diff --git a/automotive/remoteaccess/impl/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
similarity index 100%
rename from automotive/remoteaccess/impl/default/proto/wakeup_client.proto
rename to automotive/remoteaccess/hal/default/proto/wakeup_client.proto
diff --git a/automotive/remoteaccess/impl/default/client/remoteaccess-default-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
similarity index 100%
rename from automotive/remoteaccess/impl/default/client/remoteaccess-default-service.rc
rename to automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
diff --git a/automotive/remoteaccess/impl/default/client/remoteaccess-default-service.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
similarity index 100%
rename from automotive/remoteaccess/impl/default/client/remoteaccess-default-service.xml
rename to automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
diff --git a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
similarity index 70%
rename from automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
rename to automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
index 7431898..8720c2f 100644
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp
@@ -20,27 +20,35 @@
 
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <grpcpp/create_channel.h>
+#include <stdlib.h>
 #include <utils/Log.h>
 
+constexpr char SERVICE_NAME[] = "android.hardware.automotive.remoteaccess.IRemoteAccess/default";
+
 int main(int /* argc */, char* /* argv */[]) {
     ALOGI("Registering RemoteAccessService as service...");
 
-    // TODO(b/241483300): Create GrpcClientStub here.
+#ifndef GRPC_SERVICE_ADDRESS
+    ALOGE("GRPC_SERVICE_ADDRESS is not defined, exiting");
+    exit(1);
+#endif
+    auto channel = grpc::CreateChannel(GRPC_SERVICE_ADDRESS, grpc::InsecureChannelCredentials());
+    auto clientStub = android::hardware::automotive::remoteaccess::WakeupClient::NewStub(channel);
     auto service = ndk::SharedRefBase::make<
-            android::hardware::automotive::remoteaccess::RemoteAccessService>(nullptr);
+            android::hardware::automotive::remoteaccess::RemoteAccessService>(clientStub.get());
 
-    binder_exception_t err = AServiceManager_addService(
-            service->asBinder().get(), "android.hardware.automotive.remote.IRemoteAccess/default");
+    binder_exception_t err = AServiceManager_addService(service->asBinder().get(), SERVICE_NAME);
     if (err != EX_NONE) {
         ALOGE("failed to register android.hardware.automotive.remote.IRemoteAccess service, "
               "exception: %d",
               err);
-        return 1;
+        exit(1);
     }
 
     if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
         ALOGE("%s", "failed to set thread pool max thread count");
-        return 1;
+        exit(1);
     }
     ABinderProcess_startThreadPool();
 
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
new file mode 100644
index 0000000..cc8b50c
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -0,0 +1,314 @@
+/*
+ * 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 <android-base/stringprintf.h>
+#include <android/binder_status.h>
+#include <grpc++/grpc++.h>
+#include <private/android_filesystem_config.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 ::android::base::ScopedLockAssertion;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::grpc::ClientContext;
+using ::grpc::ClientReaderInterface;
+using ::grpc::Status;
+using ::grpc::StatusCode;
+using ::ndk::ScopedAStatus;
+
+const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
+constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
+constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
+constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
+constexpr char COMMAND_SHOW_TASK[] = "--show-task";
+
+std::vector<uint8_t> stringToBytes(const std::string& s) {
+    const char* data = s.data();
+    return std::vector<uint8_t>(data, data + s.size());
+}
+
+ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
+}
+
+std::string printBytes(const std::vector<uint8_t>& bytes) {
+    std::string s;
+    for (size_t i = 0; i < bytes.size(); i++) {
+        StringAppendF(&s, "%02x", bytes[i]);
+    }
+    return s;
+}
+
+bool checkBoolFlag(const char* flag) {
+    return !strcmp(flag, "1") || !strcmp(flag, "0");
+}
+
+}  // namespace
+
+RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
+    : mGrpcStub(grpcStub){};
+
+RemoteAccessService::~RemoteAccessService() {
+    maybeStopTaskLoop();
+}
+
+void RemoteAccessService::maybeStartTaskLoop() {
+    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
+    if (mTaskLoopRunning) {
+        return;
+    }
+
+    mThread = std::thread([this]() { runTaskLoop(); });
+
+    mTaskLoopRunning = true;
+}
+
+void RemoteAccessService::maybeStopTaskLoop() {
+    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
+    if (!mTaskLoopRunning) {
+        return;
+    }
+
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        // Try to stop the reading stream.
+        if (mGetRemoteTasksContext) {
+            mGetRemoteTasksContext->TryCancel();
+            mGetRemoteTasksContext.reset();
+        }
+        mTaskWaitStopped = true;
+        mCv.notify_all();
+    }
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+
+    mTaskLoopRunning = false;
+}
+
+void RemoteAccessService::runTaskLoop() {
+    GetRemoteTasksRequest request = {};
+    std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
+    while (true) {
+        {
+            std::lock_guard<std::mutex> lockGuard(mLock);
+            mGetRemoteTasksContext.reset(new ClientContext());
+            reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
+        }
+        GetRemoteTasksResponse response;
+        while (reader->Read(&response)) {
+            ALOGI("Receiving one task from remote task client");
+
+            std::shared_ptr<IRemoteTaskCallback> callback;
+            {
+                std::lock_guard<std::mutex> lockGuard(mLock);
+                callback = mRemoteTaskCallback;
+            }
+            if (callback == nullptr) {
+                ALOGD("No callback registered, task ignored");
+                continue;
+            }
+            ALOGD("Calling onRemoteTaskRequested callback for client ID: %s",
+                  response.clientid().c_str());
+            ScopedAStatus callbackStatus = callback->onRemoteTaskRequested(
+                    response.clientid(), stringToBytes(response.data()));
+            if (!callbackStatus.isOk()) {
+                ALOGE("Failed to call onRemoteTaskRequested callback, status: %d, message: %s",
+                      callbackStatus.getStatus(), callbackStatus.getMessage());
+            }
+        }
+        Status status = reader->Finish();
+
+        ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
+              status.error_code(), status.error_message().c_str());
+        // The long lasting connection should not return. But if the server returns, retry after
+        // 10s.
+        {
+            std::unique_lock lk(mLock);
+            if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
+                    ScopedLockAssertion lockAssertion(mLock);
+                    return mTaskWaitStopped;
+                })) {
+                // If the stopped flag is set, we are quitting, exit the loop.
+                break;
+            }
+        }
+    }
+}
+
+ScopedAStatus RemoteAccessService::getDeviceId(std::string* deviceId) {
+    // TODO(b/241483300): Call VHAL to get VIN.
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
+    *wakeupServiceName = WAKEUP_SERVICE_NAME;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
+        const std::shared_ptr<IRemoteTaskCallback>& callback) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mRemoteTaskCallback = callback;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mRemoteTaskCallback.reset();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
+    ClientContext context;
+    NotifyWakeupRequiredRequest request = {};
+    request.set_iswakeuprequired(newState.isWakeupRequired);
+    NotifyWakeupRequiredResponse response = {};
+    Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
+    if (!status.ok()) {
+        return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
+    }
+
+    if (newState.isReadyForRemoteTask) {
+        maybeStartTaskLoop();
+    } else {
+        maybeStopTaskLoop();
+    }
+    return ScopedAStatus::ok();
+}
+
+bool RemoteAccessService::checkDumpPermission() {
+    uid_t uid = AIBinder_getCallingUid();
+    return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
+}
+
+void RemoteAccessService::dumpHelp(int fd) {
+    dprintf(fd, "%s",
+            (std::string("RemoteAccess HAL debug interface, Usage: \n") + COMMAND_SET_AP_STATE +
+             " [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired)  Set the new AP state\n" +
+             COMMAND_START_DEBUG_CALLBACK +
+             " Start a debug callback that will record the received tasks\n" +
+             COMMAND_STOP_DEBUG_CALLBACK + " Stop the debug callback\n" + COMMAND_SHOW_TASK +
+             " Show tasks received by debug callback\n")
+                    .c_str());
+}
+
+binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
+    if (!checkDumpPermission()) {
+        dprintf(fd, "Caller must be root, system or shell\n");
+        return STATUS_PERMISSION_DENIED;
+    }
+
+    if (numArgs == 0) {
+        dumpHelp(fd);
+        return STATUS_OK;
+    }
+
+    if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
+        if (numArgs < 3) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        ApState apState = {};
+        const char* remoteTaskFlag = args[1];
+        if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        if (!checkBoolFlag(args[1])) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        if (!strcmp(args[1], "1")) {
+            apState.isReadyForRemoteTask = true;
+        }
+        if (!checkBoolFlag(args[2])) {
+            dumpHelp(fd);
+            return STATUS_OK;
+        }
+        if (!strcmp(args[2], "1")) {
+            apState.isWakeupRequired = true;
+        }
+        auto status = notifyApStateChange(apState);
+        if (!status.isOk()) {
+            dprintf(fd, "Failed to set AP state, code: %d, error: %s\n", status.getStatus(),
+                    status.getMessage());
+        } else {
+            dprintf(fd, "successfully set the new AP state\n");
+        }
+    } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
+        mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
+        setRemoteTaskCallback(mDebugCallback);
+        dprintf(fd, "Debug callback registered\n");
+    } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
+        if (mDebugCallback) {
+            mDebugCallback.reset();
+        }
+        clearRemoteTaskCallback();
+        dprintf(fd, "Debug callback unregistered\n");
+    } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
+        if (mDebugCallback) {
+            dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
+        } else {
+            dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
+                    COMMAND_START_DEBUG_CALLBACK);
+        }
+    } else {
+        dumpHelp(fd);
+    }
+
+    return STATUS_OK;
+}
+
+ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
+                                                             const std::vector<uint8_t>& data) {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mTasks.push_back({
+            .clientId = clientId,
+            .data = data,
+    });
+    return ScopedAStatus::ok();
+}
+
+std::string DebugRemoteTaskCallback::printTasks() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
+                                 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
+    for (size_t i = 0; i < mTasks.size(); i++) {
+        StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
+                      printBytes(mTasks[i].data).c_str());
+    }
+    return s;
+}
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/impl/default/test/Android.bp b/automotive/remoteaccess/hal/default/test/Android.bp
similarity index 98%
rename from automotive/remoteaccess/impl/default/test/Android.bp
rename to automotive/remoteaccess/hal/default/test/Android.bp
index e92440f..bf7d0b6 100644
--- a/automotive/remoteaccess/impl/default/test/Android.bp
+++ b/automotive/remoteaccess/hal/default/test/Android.bp
@@ -24,6 +24,7 @@
         "RemoteAccessService",
     ],
     shared_libs: [
+        "libbase",
         "libbinder_ndk",
         "liblog",
         "libutils",
diff --git a/automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
similarity index 100%
rename from automotive/remoteaccess/impl/default/test/RemoteAccessServiceUnitTest.cpp
rename to automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
diff --git a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp b/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
deleted file mode 100644
index 6b97840..0000000
--- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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 <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 ::android::base::ScopedLockAssertion;
-using ::grpc::ClientContext;
-using ::grpc::ClientReaderInterface;
-using ::grpc::Status;
-using ::grpc::StatusCode;
-using ::ndk::ScopedAStatus;
-
-const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
-
-std::vector<uint8_t> stringToBytes(const std::string& s) {
-    const char* data = s.data();
-    return std::vector<uint8_t>(data, data + s.size());
-}
-
-ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
-    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
-            status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
-}
-
-}  // namespace
-
-RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
-    : mGrpcStub(grpcStub){};
-
-RemoteAccessService::~RemoteAccessService() {
-    maybeStopTaskLoop();
-}
-
-void RemoteAccessService::maybeStartTaskLoop() {
-    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
-    if (mTaskLoopRunning) {
-        return;
-    }
-
-    mThread = std::thread([this]() { runTaskLoop(); });
-
-    mTaskLoopRunning = true;
-}
-
-void RemoteAccessService::maybeStopTaskLoop() {
-    std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
-    if (!mTaskLoopRunning) {
-        return;
-    }
-
-    {
-        std::lock_guard<std::mutex> lockGuard(mLock);
-        // Try to stop the reading stream.
-        if (mGetRemoteTasksContext) {
-            mGetRemoteTasksContext->TryCancel();
-            mGetRemoteTasksContext.reset();
-        }
-        mTaskWaitStopped = true;
-        mCv.notify_all();
-    }
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-
-    mTaskLoopRunning = false;
-}
-
-void RemoteAccessService::runTaskLoop() {
-    GetRemoteTasksRequest request = {};
-    std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
-    while (true) {
-        {
-            std::lock_guard<std::mutex> lockGuard(mLock);
-            mGetRemoteTasksContext.reset(new ClientContext());
-            reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
-        }
-        GetRemoteTasksResponse response;
-        while (reader->Read(&response)) {
-            std::shared_ptr<IRemoteTaskCallback> callback;
-            {
-                std::lock_guard<std::mutex> lockGuard(mLock);
-                callback = mRemoteTaskCallback;
-            }
-            if (callback == nullptr) {
-                continue;
-            }
-            ScopedAStatus callbackStatus = callback->onRemoteTaskRequested(
-                    response.clientid(), stringToBytes(response.data()));
-            if (!callbackStatus.isOk()) {
-                ALOGE("Failed to call onRemoteTaskRequested callback, status: %d, message: %s",
-                      callbackStatus.getStatus(), callbackStatus.getMessage());
-            }
-        }
-        Status status = reader->Finish();
-
-        ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
-              status.error_code(), status.error_message().c_str());
-        // The long lasting connection should not return. But if the server returns, retry after
-        // 10s.
-        {
-            std::unique_lock lk(mLock);
-            if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
-                    ScopedLockAssertion lockAssertion(mLock);
-                    return mTaskWaitStopped;
-                })) {
-                // If the stopped flag is set, we are quitting, exit the loop.
-                break;
-            }
-        }
-    }
-}
-
-ScopedAStatus RemoteAccessService::getDeviceId(std::string* deviceId) {
-    // TODO(b/241483300): Call VHAL to get VIN.
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
-    *wakeupServiceName = WAKEUP_SERVICE_NAME;
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
-        [[maybe_unused]] const std::shared_ptr<IRemoteTaskCallback>& callback) {
-    std::lock_guard<std::mutex> lockGuard(mLock);
-    mRemoteTaskCallback = callback;
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
-    std::lock_guard<std::mutex> lockGuard(mLock);
-    mRemoteTaskCallback.reset();
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
-    ClientContext context;
-    NotifyWakeupRequiredRequest request = {};
-    request.set_iswakeuprequired(newState.isWakeupRequired);
-    NotifyWakeupRequiredResponse response = {};
-    Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
-    if (!status.ok()) {
-        return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
-    }
-
-    if (newState.isReadyForRemoteTask) {
-        maybeStartTaskLoop();
-    } else {
-        maybeStopTaskLoop();
-    }
-    return ScopedAStatus::ok();
-}
-
-}  // namespace remoteaccess
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
new file mode 100644
index 0000000..deea764
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -0,0 +1,7 @@
+# Test GRPC Server.
+
+A test GRPC server that implements wakeup_client.proto. This test server acts
+as a reference implementation for a remote wakeup client running on TCU. This
+reference server also implements wakeup_client_debug.proto which is the
+debugging interface. It is recommended that the actual implementation also
+implements this test interface for easier end-to-end testing.
diff --git a/automotive/remoteaccess/impl/default/test/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
similarity index 68%
copy from automotive/remoteaccess/impl/default/test/Android.bp
copy to automotive/remoteaccess/test_grpc_server/impl/Android.bp
index e92440f..5332c92 100644
--- a/automotive/remoteaccess/impl/default/test/Android.bp
+++ b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
@@ -12,32 +12,23 @@
 // 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",
+cc_binary {
+    name: "TestWakeupClientServer",
     vendor: true,
-    srcs: ["*.cpp"],
-    whole_static_libs: [
-        "RemoteAccessService",
-    ],
+    srcs: ["src/*.cpp"],
+    local_include_dirs: ["include"],
     shared_libs: [
-        "libbinder_ndk",
+        "libbase",
         "liblog",
         "libutils",
         "libgrpc++",
         "libprotobuf-cpp-full",
     ],
-    // libgrpc++.so is installed as root, require root to access it.
-    require_root: true,
-    static_libs: [
-        "libgtest",
-        "libgmock",
+    whole_static_libs: [
+        "wakeup_client_protos",
     ],
     cflags: [
         "-Wno-unused-parameter",
+        "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
     ],
-    test_suites: ["device-tests"],
 }
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
new file mode 100644
index 0000000..4c440b8
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <wakeup_client.grpc.pb.h>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+// A class to generate fake task for testing. Not required for real implementation. In real
+// implementation, the task should come from remote task server. This class is thread-safe.
+class FakeTaskGenerator final {
+  public:
+    GetRemoteTasksResponse generateTask();
+
+  private:
+    // Simulates the client ID for each task.
+    std::atomic<int> mCurrentClientId = 0;
+    constexpr static uint8_t DATA[] = {0xde, 0xad, 0xbe, 0xef};
+};
+
+// TaskQueue is thread-safe.
+class TaskQueue final {
+  public:
+    void add(const GetRemoteTasksResponse& response);
+    std::optional<GetRemoteTasksResponse> maybePopOne();
+    void waitForTask();
+    void stopWait();
+
+  private:
+    std::mutex mLock;
+    std::queue<GetRemoteTasksResponse> mTasks GUARDED_BY(mLock);
+    // A variable to notify mTasks is not empty.
+    std::condition_variable mTasksNotEmptyCv;
+    bool mStopped GUARDED_BY(mLock);
+};
+
+class TestWakeupClientServiceImpl final : public WakeupClient::Service {
+  public:
+    TestWakeupClientServiceImpl();
+
+    ~TestWakeupClientServiceImpl();
+
+    grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
+                                grpc::ServerWriter<GetRemoteTasksResponse>* writer) override;
+
+    grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
+                                      const NotifyWakeupRequiredRequest* request,
+                                      NotifyWakeupRequiredResponse* response) override;
+
+  private:
+    // This is a thread for communicating with remote wakeup server (via network) and receive tasks
+    // from it.
+    std::thread mThread;
+    // A variable to notify server is stopping.
+    std::condition_variable mServerStoppedCv;
+    std::mutex mLock;
+    bool mServerStopped GUARDED_BY(mLock);
+
+    // Thread-safe. For test impl only.
+    FakeTaskGenerator mFakeTaskGenerator;
+    // Thread-sfae.
+    TaskQueue mTaskQueue;
+
+    void fakeTaskGenerateLoop();
+};
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
new file mode 100644
index 0000000..1eb87e2
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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 "TestWakeupClientServiceImpl.h"
+
+#include <android-base/stringprintf.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace remoteaccess {
+
+namespace {
+
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringPrintf;
+using ::grpc::ServerContext;
+using ::grpc::ServerWriter;
+using ::grpc::Status;
+
+constexpr int kTaskIntervalInSec = 5;
+
+}  // namespace
+
+GetRemoteTasksResponse FakeTaskGenerator::generateTask() {
+    int clientId = mCurrentClientId++;
+    GetRemoteTasksResponse response;
+    response.set_data(std::string(reinterpret_cast<const char*>(DATA), sizeof(DATA)));
+    std::string clientIdStr = StringPrintf("%d", clientId);
+    response.set_clientid(clientIdStr);
+    return response;
+}
+
+std::optional<GetRemoteTasksResponse> TaskQueue::maybePopOne() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    if (mTasks.size() == 0) {
+        return std::nullopt;
+    }
+    GetRemoteTasksResponse response = mTasks.front();
+    mTasks.pop();
+    return std::move(response);
+}
+void TaskQueue::add(const GetRemoteTasksResponse& task) {
+    // TODO (b/246841306): add timeout to tasks.
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mTasks.push(task);
+    mTasksNotEmptyCv.notify_all();
+}
+
+void TaskQueue::waitForTask() {
+    std::unique_lock<std::mutex> lock(mLock);
+    mTasksNotEmptyCv.wait(lock, [this] {
+        ScopedLockAssertion lockAssertion(mLock);
+        return mTasks.size() > 0 || mStopped;
+    });
+}
+
+void TaskQueue::stopWait() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+    mStopped = true;
+    mTasksNotEmptyCv.notify_all();
+}
+
+TestWakeupClientServiceImpl::TestWakeupClientServiceImpl() {
+    mThread = std::thread([this] { fakeTaskGenerateLoop(); });
+}
+
+TestWakeupClientServiceImpl::~TestWakeupClientServiceImpl() {
+    {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mServerStopped = true;
+        mServerStoppedCv.notify_all();
+    }
+    mTaskQueue.stopWait();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() {
+    // In actual implementation, this should communicate with the remote server and receives tasks
+    // from it. Here we simulate receiving one remote task every {kTaskIntervalInSec}s.
+    while (true) {
+        mTaskQueue.add(mFakeTaskGenerator.generateTask());
+        ALOGI("Sleeping for %d seconds until next task", kTaskIntervalInSec);
+
+        std::unique_lock lk(mLock);
+        if (mServerStoppedCv.wait_for(lk, std::chrono::seconds(kTaskIntervalInSec), [this] {
+                ScopedLockAssertion lockAssertion(mLock);
+                return mServerStopped;
+            })) {
+            // If the stopped flag is set, we are quitting, exit the loop.
+            return;
+        }
+    }
+}
+
+Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context,
+                                                   const GetRemoteTasksRequest* request,
+                                                   ServerWriter<GetRemoteTasksResponse>* writer) {
+    ALOGD("GetRemoteTasks called");
+    while (true) {
+        mTaskQueue.waitForTask();
+
+        while (true) {
+            auto maybeTask = mTaskQueue.maybePopOne();
+            if (!maybeTask.has_value()) {
+                // No task left, loop again and wait for another task(s).
+                break;
+            }
+            // Loop through all the task in the queue but obtain lock for each element so we don't
+            // hold lock while writing the response.
+            const GetRemoteTasksResponse& response = maybeTask.value();
+            if (!writer->Write(response)) {
+                // Broken stream, maybe the client is shutting down.
+                ALOGW("Failed to deliver remote task to remote access HAL");
+                // The task failed to be sent, add it back to the queue. The order might change, but
+                // it is okay.
+                mTaskQueue.add(response);
+                return Status::CANCELLED;
+            }
+        }
+    }
+    return Status::OK;
+}
+
+Status TestWakeupClientServiceImpl::NotifyWakeupRequired(ServerContext* context,
+                                                         const NotifyWakeupRequiredRequest* request,
+                                                         NotifyWakeupRequiredResponse* response) {
+    return Status::OK;
+}
+
+}  // namespace remoteaccess
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
new file mode 100644
index 0000000..bb03e70
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 <string>
+
+#include "TestWakeupClientServiceImpl.h"
+
+#include <grpc/grpc.h>
+#include <grpcpp/security/server_credentials.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <utils/Log.h>
+
+using ::android::hardware::automotive::remoteaccess::TestWakeupClientServiceImpl;
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+using ::grpc::ServerWriter;
+
+void RunServer() {
+    std::string serverAddress(GRPC_SERVICE_ADDRESS);
+    std::shared_ptr<TestWakeupClientServiceImpl> service =
+            std::make_unique<TestWakeupClientServiceImpl>();
+
+    ServerBuilder builder;
+    builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials());
+    builder.RegisterService(service.get());
+    std::unique_ptr<Server> server(builder.BuildAndStart());
+    ALOGI("Test Remote Access GRPC Server listening on %s", serverAddress.c_str());
+    server->Wait();
+}
+
+int main(int argc, char** argv) {
+    RunServer();
+    return 0;
+}