diff --git a/automotive/remoteaccess/impl/default/client/Android.bp b/automotive/remoteaccess/hal/default/Android.bp similarity index 97% rename from automotive/remoteaccess/impl/default/client/Android.bp rename to automotive/remoteaccess/hal/default/Android.bp index 6327637941..25bda3e7a6 100644 --- a/automotive/remoteaccess/impl/default/client/Android.bp +++ b/automotive/remoteaccess/hal/default/Android.bp @@ -37,6 +37,7 @@ cc_binary { ], cflags: [ "-Wno-unused-parameter", + "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"", ], } diff --git a/automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h similarity index 100% rename from automotive/remoteaccess/impl/default/client/include/RemoteAccessService.h rename to automotive/remoteaccess/hal/default/include/RemoteAccessService.h 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 743189854b..8720c2f5c6 100644 --- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessImpl.cpp +++ b/automotive/remoteaccess/hal/default/src/RemoteAccessImpl.cpp @@ -20,27 +20,35 @@ #include #include +#include +#include #include +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/impl/default/client/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp similarity index 95% rename from automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp rename to automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp index 6b97840999..6c297e3cd3 100644 --- a/automotive/remoteaccess/impl/default/client/src/RemoteAccessService.cpp +++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp @@ -104,14 +104,19 @@ void RemoteAccessService::runTaskLoop() { } GetRemoteTasksResponse response; while (reader->Read(&response)) { + ALOGI("Receiving one task from remote task client"); + std::shared_ptr callback; { std::lock_guard 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()) { diff --git a/automotive/remoteaccess/impl/default/test/Android.bp b/automotive/remoteaccess/hal/default/test/Android.bp similarity index 100% rename from automotive/remoteaccess/impl/default/test/Android.bp rename to automotive/remoteaccess/hal/default/test/Android.bp 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/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md new file mode 100644 index 0000000000..deea764078 --- /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/test_grpc_server/impl/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp new file mode 100644 index 0000000000..5332c9241f --- /dev/null +++ b/automotive/remoteaccess/test_grpc_server/impl/Android.bp @@ -0,0 +1,34 @@ +// 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. + +cc_binary { + name: "TestWakeupClientServer", + vendor: true, + srcs: ["src/*.cpp"], + local_include_dirs: ["include"], + shared_libs: [ + "libbase", + "liblog", + "libutils", + "libgrpc++", + "libprotobuf-cpp-full", + ], + whole_static_libs: [ + "wakeup_client_protos", + ], + cflags: [ + "-Wno-unused-parameter", + "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"", + ], +} 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 0000000000..4c440b8c00 --- /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 +#include +#include +#include +#include +#include +#include + +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 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 maybePopOne(); + void waitForTask(); + void stopWait(); + + private: + std::mutex mLock; + std::queue 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* 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 0000000000..1eb87e285e --- /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 +#include +#include +#include + +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(DATA), sizeof(DATA))); + std::string clientIdStr = StringPrintf("%d", clientId); + response.set_clientid(clientIdStr); + return response; +} + +std::optional TaskQueue::maybePopOne() { + std::lock_guard 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 lockGuard(mLock); + mTasks.push(task); + mTasksNotEmptyCv.notify_all(); +} + +void TaskQueue::waitForTask() { + std::unique_lock lock(mLock); + mTasksNotEmptyCv.wait(lock, [this] { + ScopedLockAssertion lockAssertion(mLock); + return mTasks.size() > 0 || mStopped; + }); +} + +void TaskQueue::stopWait() { + std::lock_guard lockGuard(mLock); + mStopped = true; + mTasksNotEmptyCv.notify_all(); +} + +TestWakeupClientServiceImpl::TestWakeupClientServiceImpl() { + mThread = std::thread([this] { fakeTaskGenerateLoop(); }); +} + +TestWakeupClientServiceImpl::~TestWakeupClientServiceImpl() { + { + std::lock_guard 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* 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 0000000000..bb03e703a6 --- /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 + +#include "TestWakeupClientServiceImpl.h" + +#include +#include +#include +#include +#include + +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 service = + std::make_unique(); + + ServerBuilder builder; + builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials()); + builder.RegisterService(service.get()); + std::unique_ptr 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; +}