Loading automotive/remoteaccess/test_grpc_server/README.md +208 −4 Original line number Diff line number Diff line # 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. as a reference implementation for a remote wakeup client running on TCU. The test server does not communicate with any actual network server. It has the following behavior: * It starts a GRPC server on 'DGRPC_SERVICE_ADDRESS' compile flag which is localhost:50051. The GRPC server provides the service according to hardware/interfaces/automotive/remoteaccess/hal/default/proto/wakeup_client.proto. In real implementation, DGRPC_SERVICE_ADDRESS can be specified to any IP address where the TCU can be exposed to Application Processor. The default remote access HAL implementation (hardware/interfaces/automotive/remoteaccess/hal/default/Android.bp) also uses DGRPC_SERVICE_ADDRESS to find this GRPC server, so it must have the same IP address. * It generates a fake task using FakeTaskGenerator every 'kTaskIntervalInMs' ms. In real implementation, it should receive task from the remote server. * Each fake task has an increasing unique client ID. The task data is always what's defined for 'DATA' variable. In real implementation, the client ID and task data should come from the remote server. * The generated tasks are put into a task queue which is a priority queue sorted by task received time. In real implementation, if the server provides a task timestamp, then this queue can be sorted by that task timestamp instead. * When the Application processor is started, the remote access HAL running on Android will call 'GetRemoteTasks' to establish a long-live connection. This connection is used to deliver all task data from remote wakeup client to remote access HAL, which eventually to car service and applications. When the 'GetRemoteTasks' is called, the wakeup client must send all the pending tasks through the 'ServerWriter'. If no task is pending, then it must block and wait for a new task to arrive. If one task data is failed to be sent through the channel, it likely means the other side (Application processor) is shutting down or has closed the channel. The wakeup client must put the task back to the pending queue and wait for a new 'GetRemoteTasks' request to retry sending the task. * When a new task arrives, if 'WakeupRequired' is true, then try to wakeup the Application Processor by sending a specific CAN message. It is possible that the waking up is already in progress. This is okay since Vehicle Processor should ignore wakeup message if a wakeup is already in progress. * When 'WakeupRequired' is updated from false to true, if there are unexpired pending tasks in the task queue, try to wakeup Application Processor. This is to handle the situation when a task arrives while the device is shutting down. During the device shutdown, the channel to deliver the remote tasks to Application Processor is shutdown so the new task will be added to the task queue. 'WakeupRequired' will be set to false to prevent the wakeup message preventing the shutdown. After the shutdown is complete, 'WakeupRequired' will be set to true and this wakeup client must try to wake up the device again to execute the pending tasks. * Every pending task has a timeout: 'KTaskTimeoutInMs'. If the pending task is not delivered to remote access HAL before the timeout (through GetRemoteTasks), the task timed out and a warning message is logged. In real implementation, this kTaskTimeoutInMs has to be set long enough to allow an Android bootup to happen. 20s is a reasonable value. When a task timed out, the wakeup client should also report to remote task server about the task timeout failure. ## How to build the test wakeup client * Under android root: `make -j TestWakeupClientServer` ## How to push the test wakeup client to a TCU which runs Android. * Make the target device writable: `adb root` `adb remount` `adb reboot` `adb root` `adb remount` * Under android root: `cd out/target/product/[product_name]` * `adb push vendor/bin/TestWakeupClientServer /vendor/bin` * `adb shell` * `su` * `/vendor/bin/TestWakeupClientServer` ## How to build and test the test wakeup client using one gcar emulator. In this test setup we will use one google car emulator (gcar_emu_x86_64-userdebug). We assume both the TCU and the remote access HAL runs on the same Android system, and they communicate through local loopback interface. * Under android root, `source build/envsetup.sh` * 'lunch gcar_emu_x86_64-userdebug' * `m -j` * Run the emulator: `aae emulator run` * The android lunch target: gcar_emu_x86_64-userdebug and cf_x86_64_auto-userdebug already contains the default remote access HAL. For other lunch target, you can add the default remote access HAL by adding 'android.hardware.automotive.remoteaccess@V1-default-service' to 'PRODUCT_PACKAGES' variable in mk file, see `device/generic/car/common/car.mk` as example. To verify whether remote access HAL is running, you can use the following command to check: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default` * Make the target device writable: `adb root` `adb remount` `adb reboot` `adb root` `adb remount` * `make -j TestWakeupClientServer` * `cd out/target/product/emulator_car64_x86_64/` * `adb push vendor/bin/TestWakeupClientServer /vendor/bin` * `adb shell` * `su` * `/vendor/bin/TestWakeupClientServer` * Remote access HAL should start by default when the gcar emulator starts. Now the test wake up client should also be running and generating fake tasks. Start a new adb shell session by `adb shell` `su` * Issue the command to start a simple debug callback that will capture all the received tasks at the remote access HAL side: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --start-debug-callback` * Issue the following debug command to remote access HAL to establish the communication channel between it and the test wakeup client. This command also notifies that wakeup is not required: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0` * Wait for a while, issue the following command to show the received fake tasks: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task` You should expect to see some received tasks printed out. * Simulate the Application Processor is shutting down by issuing the following command: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 0` * Wait for a while, issue the following command to show received tasks again: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task` You should expect to see no new tasks received since remote access HAL already closed the communication channel. * Simulate the Application Processor is already shutdown and wake up is required now: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 1` Now you should expect to see the test wakeup client printing out messages that it is trying to wake up application processor. * Simulate the Application Processor is waken up: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0` * A new communication channel should have been established and all pending non-expired tasks should be delivered to the remote access HAL. `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task` * Now you can issue `ctrl c` on the first adb shell to stop the test wakeup client. automotive/remoteaccess/test_grpc_server/impl/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ cc_binary { local_include_dirs: ["include"], shared_libs: [ "libbase", "liblog", "libutils", "libgrpc++", "libprotobuf-cpp-full", Loading automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp +5 −8 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ #include <android-base/stringprintf.h> #include <inttypes.h> #include <utils/Log.h> #include <utils/Looper.h> #include <utils/SystemClock.h> #include <chrono> Loading Loading @@ -133,8 +132,6 @@ void TaskQueue::checkForTestTimeoutLoop() { { std::unique_lock<std::mutex> lock(mLock); if (mStopped) { ALOGW("The TestWakeupClientServiceImpl is stopping, " "exiting checkForTestTimeoutLoop"); return; } } Loading @@ -155,7 +152,7 @@ void TaskQueue::handleTaskTimeout() { break; } // In real implementation, this should report task failure to remote wakeup server. ALOGW("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms", printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms", taskInfo.taskData.clientid().c_str(), taskInfo.timestampInMs, now); mTasks.pop(); } Loading @@ -182,7 +179,7 @@ void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() { // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms. while (true) { mTaskQueue.add(mFakeTaskGenerator.generateTask()); ALOGI("Sleeping for %d seconds until next task", kTaskIntervalInMs); printf("Sleeping for %d seconds until next task\n", kTaskIntervalInMs); std::unique_lock lk(mLock); if (mServerStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] { Loading @@ -198,7 +195,7 @@ void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() { Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context, const GetRemoteTasksRequest* request, ServerWriter<GetRemoteTasksResponse>* writer) { ALOGD("GetRemoteTasks called"); printf("GetRemoteTasks called\n"); while (true) { mTaskQueue.waitForTask(); Loading @@ -213,7 +210,7 @@ Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context, 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"); printf("Failed to deliver remote task to remote access HAL\n"); // The task failed to be sent, add it back to the queue. The order might change, but // it is okay. mTaskQueue.add(response); Loading automotive/remoteaccess/test_grpc_server/impl/src/main.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #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; Loading @@ -38,7 +37,7 @@ void RunServer() { 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()); printf("Test Remote Access GRPC Server listening on %s\n", serverAddress.c_str()); server->Wait(); } Loading Loading
automotive/remoteaccess/test_grpc_server/README.md +208 −4 Original line number Diff line number Diff line # 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. as a reference implementation for a remote wakeup client running on TCU. The test server does not communicate with any actual network server. It has the following behavior: * It starts a GRPC server on 'DGRPC_SERVICE_ADDRESS' compile flag which is localhost:50051. The GRPC server provides the service according to hardware/interfaces/automotive/remoteaccess/hal/default/proto/wakeup_client.proto. In real implementation, DGRPC_SERVICE_ADDRESS can be specified to any IP address where the TCU can be exposed to Application Processor. The default remote access HAL implementation (hardware/interfaces/automotive/remoteaccess/hal/default/Android.bp) also uses DGRPC_SERVICE_ADDRESS to find this GRPC server, so it must have the same IP address. * It generates a fake task using FakeTaskGenerator every 'kTaskIntervalInMs' ms. In real implementation, it should receive task from the remote server. * Each fake task has an increasing unique client ID. The task data is always what's defined for 'DATA' variable. In real implementation, the client ID and task data should come from the remote server. * The generated tasks are put into a task queue which is a priority queue sorted by task received time. In real implementation, if the server provides a task timestamp, then this queue can be sorted by that task timestamp instead. * When the Application processor is started, the remote access HAL running on Android will call 'GetRemoteTasks' to establish a long-live connection. This connection is used to deliver all task data from remote wakeup client to remote access HAL, which eventually to car service and applications. When the 'GetRemoteTasks' is called, the wakeup client must send all the pending tasks through the 'ServerWriter'. If no task is pending, then it must block and wait for a new task to arrive. If one task data is failed to be sent through the channel, it likely means the other side (Application processor) is shutting down or has closed the channel. The wakeup client must put the task back to the pending queue and wait for a new 'GetRemoteTasks' request to retry sending the task. * When a new task arrives, if 'WakeupRequired' is true, then try to wakeup the Application Processor by sending a specific CAN message. It is possible that the waking up is already in progress. This is okay since Vehicle Processor should ignore wakeup message if a wakeup is already in progress. * When 'WakeupRequired' is updated from false to true, if there are unexpired pending tasks in the task queue, try to wakeup Application Processor. This is to handle the situation when a task arrives while the device is shutting down. During the device shutdown, the channel to deliver the remote tasks to Application Processor is shutdown so the new task will be added to the task queue. 'WakeupRequired' will be set to false to prevent the wakeup message preventing the shutdown. After the shutdown is complete, 'WakeupRequired' will be set to true and this wakeup client must try to wake up the device again to execute the pending tasks. * Every pending task has a timeout: 'KTaskTimeoutInMs'. If the pending task is not delivered to remote access HAL before the timeout (through GetRemoteTasks), the task timed out and a warning message is logged. In real implementation, this kTaskTimeoutInMs has to be set long enough to allow an Android bootup to happen. 20s is a reasonable value. When a task timed out, the wakeup client should also report to remote task server about the task timeout failure. ## How to build the test wakeup client * Under android root: `make -j TestWakeupClientServer` ## How to push the test wakeup client to a TCU which runs Android. * Make the target device writable: `adb root` `adb remount` `adb reboot` `adb root` `adb remount` * Under android root: `cd out/target/product/[product_name]` * `adb push vendor/bin/TestWakeupClientServer /vendor/bin` * `adb shell` * `su` * `/vendor/bin/TestWakeupClientServer` ## How to build and test the test wakeup client using one gcar emulator. In this test setup we will use one google car emulator (gcar_emu_x86_64-userdebug). We assume both the TCU and the remote access HAL runs on the same Android system, and they communicate through local loopback interface. * Under android root, `source build/envsetup.sh` * 'lunch gcar_emu_x86_64-userdebug' * `m -j` * Run the emulator: `aae emulator run` * The android lunch target: gcar_emu_x86_64-userdebug and cf_x86_64_auto-userdebug already contains the default remote access HAL. For other lunch target, you can add the default remote access HAL by adding 'android.hardware.automotive.remoteaccess@V1-default-service' to 'PRODUCT_PACKAGES' variable in mk file, see `device/generic/car/common/car.mk` as example. To verify whether remote access HAL is running, you can use the following command to check: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default` * Make the target device writable: `adb root` `adb remount` `adb reboot` `adb root` `adb remount` * `make -j TestWakeupClientServer` * `cd out/target/product/emulator_car64_x86_64/` * `adb push vendor/bin/TestWakeupClientServer /vendor/bin` * `adb shell` * `su` * `/vendor/bin/TestWakeupClientServer` * Remote access HAL should start by default when the gcar emulator starts. Now the test wake up client should also be running and generating fake tasks. Start a new adb shell session by `adb shell` `su` * Issue the command to start a simple debug callback that will capture all the received tasks at the remote access HAL side: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --start-debug-callback` * Issue the following debug command to remote access HAL to establish the communication channel between it and the test wakeup client. This command also notifies that wakeup is not required: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0` * Wait for a while, issue the following command to show the received fake tasks: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task` You should expect to see some received tasks printed out. * Simulate the Application Processor is shutting down by issuing the following command: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 0` * Wait for a while, issue the following command to show received tasks again: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task` You should expect to see no new tasks received since remote access HAL already closed the communication channel. * Simulate the Application Processor is already shutdown and wake up is required now: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 0 1` Now you should expect to see the test wakeup client printing out messages that it is trying to wake up application processor. * Simulate the Application Processor is waken up: `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --set-ap-state 1 0` * A new communication channel should have been established and all pending non-expired tasks should be delivered to the remote access HAL. `dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --show-task` * Now you can issue `ctrl c` on the first adb shell to stop the test wakeup client.
automotive/remoteaccess/test_grpc_server/impl/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ cc_binary { local_include_dirs: ["include"], shared_libs: [ "libbase", "liblog", "libutils", "libgrpc++", "libprotobuf-cpp-full", Loading
automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp +5 −8 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ #include <android-base/stringprintf.h> #include <inttypes.h> #include <utils/Log.h> #include <utils/Looper.h> #include <utils/SystemClock.h> #include <chrono> Loading Loading @@ -133,8 +132,6 @@ void TaskQueue::checkForTestTimeoutLoop() { { std::unique_lock<std::mutex> lock(mLock); if (mStopped) { ALOGW("The TestWakeupClientServiceImpl is stopping, " "exiting checkForTestTimeoutLoop"); return; } } Loading @@ -155,7 +152,7 @@ void TaskQueue::handleTaskTimeout() { break; } // In real implementation, this should report task failure to remote wakeup server. ALOGW("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms", printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms", taskInfo.taskData.clientid().c_str(), taskInfo.timestampInMs, now); mTasks.pop(); } Loading @@ -182,7 +179,7 @@ void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() { // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms. while (true) { mTaskQueue.add(mFakeTaskGenerator.generateTask()); ALOGI("Sleeping for %d seconds until next task", kTaskIntervalInMs); printf("Sleeping for %d seconds until next task\n", kTaskIntervalInMs); std::unique_lock lk(mLock); if (mServerStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] { Loading @@ -198,7 +195,7 @@ void TestWakeupClientServiceImpl::fakeTaskGenerateLoop() { Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context, const GetRemoteTasksRequest* request, ServerWriter<GetRemoteTasksResponse>* writer) { ALOGD("GetRemoteTasks called"); printf("GetRemoteTasks called\n"); while (true) { mTaskQueue.waitForTask(); Loading @@ -213,7 +210,7 @@ Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context, 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"); printf("Failed to deliver remote task to remote access HAL\n"); // The task failed to be sent, add it back to the queue. The order might change, but // it is okay. mTaskQueue.add(response); Loading
automotive/remoteaccess/test_grpc_server/impl/src/main.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #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; Loading @@ -38,7 +37,7 @@ void RunServer() { 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()); printf("Test Remote Access GRPC Server listening on %s\n", serverAddress.c_str()); server->Wait(); } Loading