mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 10:05:19 +00:00
Add a test wakeupclient service implementation.
The test implementation will send out a remote task to remote access HAL every 5s. Test: Manually test on gcar_emu. adb root adb remount adb reboot adb root adb remount m -j TestWakeupClientServer cd out/target/product/emulator_car64_x86_64 adb push ./vendor/bin/TestWakeupClientServer /vendor/bin adb shell In the shell: su /vendor/bin/TestWakeupClientServer Check adb logcat, verify tasks are received. Bug: 246841306 Change-Id: Idaf198662f7004e3a9e77d75caeffc00cda49218
This commit is contained in:
@@ -37,6 +37,7 @@ cc_binary {
|
||||
],
|
||||
cflags: [
|
||||
"-Wno-unused-parameter",
|
||||
"-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -104,14 +104,19 @@ void RemoteAccessService::runTaskLoop() {
|
||||
}
|
||||
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()) {
|
||||
7
automotive/remoteaccess/test_grpc_server/README.md
Normal file
7
automotive/remoteaccess/test_grpc_server/README.md
Normal file
@@ -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.
|
||||
34
automotive/remoteaccess/test_grpc_server/impl/Android.bp
Normal file
34
automotive/remoteaccess/test_grpc_server/impl/Android.bp
Normal file
@@ -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\"",
|
||||
],
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
48
automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
Normal file
48
automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user