Implement ScheduleTask API using grpc.
Implement the ScheduleTask APIs in reference remote access
HAL by using grpc to communicate with an external grpc server.
Test: atest RemoteAccessServiceUnitTest
Bug: 297271235
Change-Id: I2d363aa244c842cea5be0c35f4f3a7961eb3cc0b
diff --git a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
index 292c80e..9224ebc 100644
--- a/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
+++ b/automotive/remoteaccess/hal/default/fuzzer/fuzzer.cpp
@@ -55,6 +55,31 @@
return Status::OK;
}
+ Status ScheduleTask(ClientContext* context, const ScheduleTaskRequest& request,
+ ScheduleTaskResponse* response) {
+ return Status::OK;
+ }
+
+ Status UnscheduleTask(ClientContext* context, const UnscheduleTaskRequest& request,
+ UnscheduleTaskResponse* response) {
+ return Status::OK;
+ }
+
+ Status UnscheduleAllTasks(ClientContext* context, const UnscheduleAllTasksRequest& request,
+ UnscheduleAllTasksResponse* response) {
+ return Status::OK;
+ }
+
+ Status IsTaskScheduled(ClientContext* context, const IsTaskScheduledRequest& request,
+ IsTaskScheduledResponse* response) {
+ return Status::OK;
+ }
+
+ Status GetAllScheduledTasks(ClientContext* context, const GetAllScheduledTasksRequest& request,
+ GetAllScheduledTasksResponse* response) {
+ return Status::OK;
+ }
+
// Async methods which we do not care.
ClientAsyncReaderInterface<GetRemoteTasksResponse>* AsyncGetRemoteTasksRaw(
[[maybe_unused]] ClientContext* context,
@@ -83,6 +108,76 @@
[[maybe_unused]] CompletionQueue* c) {
return nullptr;
}
+
+ ClientAsyncResponseReaderInterface<ScheduleTaskResponse>* AsyncScheduleTaskRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const ScheduleTaskRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<ScheduleTaskResponse>* PrepareAsyncScheduleTaskRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const ScheduleTaskRequest& request,
+ [[maybe_unused]] CompletionQueue* c) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>* AsyncUnscheduleTaskRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const UnscheduleTaskRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>* PrepareAsyncUnscheduleTaskRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const UnscheduleTaskRequest& request,
+ [[maybe_unused]] CompletionQueue* c) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>* AsyncUnscheduleAllTasksRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const UnscheduleAllTasksRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*
+ PrepareAsyncUnscheduleAllTasksRaw([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const UnscheduleAllTasksRequest& request,
+ [[maybe_unused]] CompletionQueue* c) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>* AsyncIsTaskScheduledRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const IsTaskScheduledRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>* PrepareAsyncIsTaskScheduledRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const IsTaskScheduledRequest& request,
+ [[maybe_unused]] CompletionQueue* c) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>* AsyncGetAllScheduledTasksRaw(
+ [[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetAllScheduledTasksRequest& request,
+ [[maybe_unused]] CompletionQueue* cq) {
+ return nullptr;
+ }
+
+ ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>*
+ PrepareAsyncGetAllScheduledTasksRaw([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const GetAllScheduledTasksRequest& request,
+ [[maybe_unused]] CompletionQueue* c) {
+ return nullptr;
+ }
};
} // namespace remoteaccess
diff --git a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
index 4fe0d01..e061016 100644
--- a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
+++ b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
@@ -18,6 +18,12 @@
package android.hardware.automotive.remoteaccess;
+enum ErrorCode {
+ OK = 0;
+ UNSPECIFIED = 1;
+ INVALID_ARG = 2;
+}
+
/**
* Service provided by a wakeup client running on TCU.
*/
@@ -50,6 +56,50 @@
* to wake up AP.
*/
rpc NotifyWakeupRequired(NotifyWakeupRequiredRequest) returns (NotifyWakeupRequiredResponse) {}
+
+ /**
+ * Schedules a task to be executed later even when the vehicle is off.
+ *
+ * <p>This sends a scheduled task message to a device external to Android so that the device
+ * can wake up Android and deliver the task through {@link IRemoteTaskCallback}.
+ *
+ * <p>Note that the scheduled task execution is on a best-effort basis. Multiple situations
+ * might cause the task not to execute successfully:
+ *
+ * <ul>
+ * <li>The vehicle is low on battery and the other device decides not to wake up Android.
+ * <li>User turns off vehicle while the task is executing.
+ * <li>The task logic itself fails.
+ *
+ * <p>Must return a response with error code: {@code INVALID_ARG} if a pending schedule with the
+ * same {@code scheduleId} for this client exists.
+ */
+ rpc ScheduleTask(ScheduleTaskRequest) returns (ScheduleTaskResponse) {}
+
+ /**
+ * Unschedules a scheduled task.
+ *
+ * <p>Does nothing if a pending schedule with {@code clientId} and {@code scheduleId} does not
+ * exist.
+ */
+ rpc UnscheduleTask(UnscheduleTaskRequest) returns (UnscheduleTaskResponse) {}
+
+ /**
+ * Unschedules all scheduled tasks for the client.
+ */
+ rpc UnscheduleAllTasks(UnscheduleAllTasksRequest) returns (UnscheduleAllTasksResponse) {}
+
+ /**
+ * Returns whether the specified task is scheduled.
+ */
+ rpc IsTaskScheduled(IsTaskScheduledRequest) returns (IsTaskScheduledResponse) {}
+
+ /**
+ * Gets all pending scheduled tasks for the client.
+ *
+ * <p>The finished scheduled tasks will not be included.
+ */
+ rpc GetAllScheduledTasks(GetAllScheduledTasksRequest) returns (GetAllScheduledTasksResponse) {}
}
message GetRemoteTasksRequest {}
@@ -64,3 +114,50 @@
}
message NotifyWakeupRequiredResponse {}
+
+message ScheduleTaskRequest {
+ GrpcScheduleInfo scheduleInfo = 1;
+}
+
+message ScheduleTaskResponse {
+ ErrorCode errorCode = 1;
+}
+
+message GrpcScheduleInfo {
+ string clientId = 1;
+ string scheduleId = 2;
+ bytes data = 3;
+ int32 count = 4;
+ int64 startTimeInEpochSeconds = 5;
+ int64 periodicInSeconds = 6;
+}
+
+message UnscheduleTaskRequest {
+ string clientId = 1;
+ string scheduleId = 2;
+}
+
+message UnscheduleTaskResponse {}
+
+message UnscheduleAllTasksRequest {
+ string clientId = 1;
+}
+
+message UnscheduleAllTasksResponse {}
+
+message IsTaskScheduledRequest {
+ string clientId = 1;
+ string scheduleId = 2;
+}
+
+message IsTaskScheduledResponse {
+ bool isTaskScheduled = 1;
+}
+
+message GetAllScheduledTasksRequest {
+ string clientId = 1;
+}
+
+message GetAllScheduledTasksResponse {
+ repeated GrpcScheduleInfo allScheduledTasks = 1;
+}
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 7721bf4..0944d86 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -314,38 +314,106 @@
return ScopedAStatus::ok();
}
-ScopedAStatus RemoteAccessService::isTaskScheduleSupported([[maybe_unused]] bool* out) {
- // TODO(b/297271235): implement this.
+ScopedAStatus RemoteAccessService::isTaskScheduleSupported(bool* out) {
+ *out = true;
return ScopedAStatus::ok();
}
-ScopedAStatus RemoteAccessService::scheduleTask([[maybe_unused]] const ScheduleInfo& scheduleInfo) {
- // TODO(b/297271235): implement this.
+ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
+ ClientContext context;
+ ScheduleTaskRequest request = {};
+ ScheduleTaskResponse response = {};
+ request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
+ request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
+ request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
+ scheduleInfo.taskData.size());
+ request.mutable_scheduleinfo()->set_count(scheduleInfo.count);
+ request.mutable_scheduleinfo()->set_starttimeinepochseconds(
+ scheduleInfo.startTimeInEpochSeconds);
+ request.mutable_scheduleinfo()->set_periodicinseconds(scheduleInfo.periodicInSeconds);
+ Status status = mGrpcStub->ScheduleTask(&context, request, &response);
+ if (!status.ok()) {
+ return rpcStatusToScopedAStatus(status, "Failed to call ScheduleTask");
+ }
+ int errorCode = response.errorcode();
+ switch (errorCode) {
+ case ErrorCode::OK:
+ return ScopedAStatus::ok();
+ case ErrorCode::INVALID_ARG:
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ default:
+ // Should not happen.
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ -1, ("Got unknown error code: " + ErrorCode_Name(errorCode) +
+ " from remote access HAL")
+ .c_str());
+ }
+}
+
+ScopedAStatus RemoteAccessService::unscheduleTask(const std::string& clientId,
+ const std::string& scheduleId) {
+ ClientContext context;
+ UnscheduleTaskRequest request = {};
+ UnscheduleTaskResponse response = {};
+ request.set_clientid(clientId);
+ request.set_scheduleid(scheduleId);
+ Status status = mGrpcStub->UnscheduleTask(&context, request, &response);
+ if (!status.ok()) {
+ return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleTask");
+ }
return ScopedAStatus::ok();
}
-ScopedAStatus RemoteAccessService::unscheduleTask([[maybe_unused]] const std::string& clientId,
- [[maybe_unused]] const std::string& scheduleId) {
- // TODO(b/297271235): implement this.
+ScopedAStatus RemoteAccessService::unscheduleAllTasks(const std::string& clientId) {
+ ClientContext context;
+ UnscheduleAllTasksRequest request = {};
+ UnscheduleAllTasksResponse response = {};
+ request.set_clientid(clientId);
+ Status status = mGrpcStub->UnscheduleAllTasks(&context, request, &response);
+ if (!status.ok()) {
+ return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleAllTasks");
+ }
return ScopedAStatus::ok();
}
-ScopedAStatus RemoteAccessService::unscheduleAllTasks(
- [[maybe_unused]] const std::string& clientId) {
- // TODO(b/297271235): implement this.
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemoteAccessService::isTaskScheduled([[maybe_unused]] const std::string& clientId,
- [[maybe_unused]] const std::string& scheduleId,
- [[maybe_unused]] bool* out) {
- // TODO(b/297271235): implement this.
+ScopedAStatus RemoteAccessService::isTaskScheduled(const std::string& clientId,
+ const std::string& scheduleId, bool* out) {
+ ClientContext context;
+ IsTaskScheduledRequest request = {};
+ IsTaskScheduledResponse response = {};
+ request.set_clientid(clientId);
+ request.set_scheduleid(scheduleId);
+ Status status = mGrpcStub->IsTaskScheduled(&context, request, &response);
+ if (!status.ok()) {
+ return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
+ }
+ *out = response.istaskscheduled();
return ScopedAStatus::ok();
}
ScopedAStatus RemoteAccessService::getAllScheduledTasks(const std::string& clientId,
std::vector<ScheduleInfo>* out) {
- // TODO(b/297271235): implement this.
+ ClientContext context;
+ GetAllScheduledTasksRequest request = {};
+ GetAllScheduledTasksResponse response = {};
+ request.set_clientid(clientId);
+ Status status = mGrpcStub->GetAllScheduledTasks(&context, request, &response);
+ if (!status.ok()) {
+ return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
+ }
+ out->clear();
+ for (int i = 0; i < response.allscheduledtasks_size(); i++) {
+ const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
+ ScheduleInfo scheduleInfo = {
+ .clientId = rpcScheduleInfo.clientid(),
+ .scheduleId = rpcScheduleInfo.scheduleid(),
+ .taskData = stringToBytes(rpcScheduleInfo.data()),
+ .count = rpcScheduleInfo.count(),
+ .startTimeInEpochSeconds = rpcScheduleInfo.starttimeinepochseconds(),
+ .periodicInSeconds = rpcScheduleInfo.periodicinseconds(),
+ };
+ out->push_back(std::move(scheduleInfo));
+ }
return ScopedAStatus::ok();
}
diff --git a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
index c5afd63..c0038c2 100644
--- a/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
+++ b/automotive/remoteaccess/hal/default/test/RemoteAccessServiceUnitTest.cpp
@@ -21,6 +21,7 @@
#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
#include <aidl/android/hardware/automotive/vehicle/VehiclePropValue.h>
+#include <android/binder_status.h>
#include <gmock/gmock.h>
#include <grpcpp/test/mock_stream.h>
#include <gtest/gtest.h>
@@ -46,6 +47,7 @@
using ::aidl::android::hardware::automotive::remoteaccess::ApState;
using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::grpc::ClientAsyncReaderInterface;
@@ -63,6 +65,12 @@
using ::testing::SetArgPointee;
constexpr char kTestVin[] = "test_VIN";
+const std::string kTestClientId = "test client id";
+const std::string kTestScheduleId = "test schedule id";
+const std::vector<uint8_t> kTestData = {0xde, 0xad, 0xbe, 0xef};
+constexpr int32_t kTestCount = 1234;
+constexpr int64_t kTestStartTimeInEpochSeconds = 2345;
+constexpr int64_t kTestPeriodicInSeconds = 123;
} // namespace
@@ -73,6 +81,21 @@
MOCK_METHOD(Status, NotifyWakeupRequired,
(ClientContext * context, const NotifyWakeupRequiredRequest& request,
NotifyWakeupRequiredResponse* response));
+ MOCK_METHOD(Status, ScheduleTask,
+ (ClientContext * context, const ScheduleTaskRequest& request,
+ ScheduleTaskResponse* response));
+ MOCK_METHOD(Status, UnscheduleTask,
+ (ClientContext * context, const UnscheduleTaskRequest& request,
+ UnscheduleTaskResponse* response));
+ MOCK_METHOD(Status, UnscheduleAllTasks,
+ (ClientContext * context, const UnscheduleAllTasksRequest& request,
+ UnscheduleAllTasksResponse* response));
+ MOCK_METHOD(Status, IsTaskScheduled,
+ (ClientContext * context, const IsTaskScheduledRequest& request,
+ IsTaskScheduledResponse* response));
+ MOCK_METHOD(Status, GetAllScheduledTasks,
+ (ClientContext * context, const GetAllScheduledTasksRequest& request,
+ GetAllScheduledTasksResponse* response));
// Async methods which we do not care.
MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
(ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
@@ -88,6 +111,42 @@
PrepareAsyncNotifyWakeupRequiredRaw,
(ClientContext * context, const NotifyWakeupRequiredRequest& request,
CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<ScheduleTaskResponse>*, AsyncScheduleTaskRaw,
+ (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<ScheduleTaskResponse>*,
+ PrepareAsyncScheduleTaskRaw,
+ (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>*, AsyncUnscheduleTaskRaw,
+ (ClientContext * context, const UnscheduleTaskRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>*,
+ PrepareAsyncUnscheduleTaskRaw,
+ (ClientContext * context, const UnscheduleTaskRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*,
+ AsyncUnscheduleAllTasksRaw,
+ (ClientContext * context, const UnscheduleAllTasksRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*,
+ PrepareAsyncUnscheduleAllTasksRaw,
+ (ClientContext * context, const UnscheduleAllTasksRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>*,
+ AsyncIsTaskScheduledRaw,
+ (ClientContext * context, const IsTaskScheduledRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>*,
+ PrepareAsyncIsTaskScheduledRaw,
+ (ClientContext * context, const IsTaskScheduledRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>*,
+ AsyncGetAllScheduledTasksRaw,
+ (ClientContext * context, const GetAllScheduledTasksRequest& request,
+ CompletionQueue* cq));
+ MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllScheduledTasksResponse>*,
+ PrepareAsyncGetAllScheduledTasksRaw,
+ (ClientContext * context, const GetAllScheduledTasksRequest& request,
+ CompletionQueue* cq));
};
class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
@@ -367,6 +426,174 @@
ASSERT_EQ(vehicleId, kTestVin);
}
+TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduleSupported) {
+ bool out = false;
+ ScopedAStatus status = getService()->isTaskScheduleSupported(&out);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(out);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask) {
+ ScheduleTaskRequest grpcRequest = {};
+ EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
+ .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+ const ScheduleTaskRequest& request,
+ [[maybe_unused]] ScheduleTaskResponse* response) {
+ grpcRequest = request;
+ return Status();
+ });
+ ScheduleInfo scheduleInfo = {
+ .clientId = kTestClientId,
+ .scheduleId = kTestScheduleId,
+ .taskData = kTestData,
+ .count = kTestCount,
+ .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+ .periodicInSeconds = kTestPeriodicInSeconds,
+ };
+
+ ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(grpcRequest.scheduleinfo().clientid(), kTestClientId);
+ EXPECT_EQ(grpcRequest.scheduleinfo().scheduleid(), kTestScheduleId);
+ EXPECT_EQ(grpcRequest.scheduleinfo().data(), std::string(kTestData.begin(), kTestData.end()));
+ EXPECT_EQ(grpcRequest.scheduleinfo().count(), kTestCount);
+ EXPECT_EQ(grpcRequest.scheduleinfo().starttimeinepochseconds(), kTestStartTimeInEpochSeconds);
+ EXPECT_EQ(grpcRequest.scheduleinfo().periodicinseconds(), kTestPeriodicInSeconds);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidArg) {
+ EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
+ .WillOnce([]([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const ScheduleTaskRequest& request,
+ ScheduleTaskResponse* response) {
+ response->set_errorcode(ErrorCode::INVALID_ARG);
+ return Status();
+ });
+ ScheduleInfo scheduleInfo = {
+ .clientId = kTestClientId,
+ .scheduleId = kTestScheduleId,
+ .taskData = kTestData,
+ .count = kTestCount,
+ .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+ .periodicInSeconds = kTestPeriodicInSeconds,
+ };
+
+ ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_UnspecifiedError) {
+ EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
+ .WillOnce([]([[maybe_unused]] ClientContext* context,
+ [[maybe_unused]] const ScheduleTaskRequest& request,
+ ScheduleTaskResponse* response) {
+ response->set_errorcode(ErrorCode::UNSPECIFIED);
+ return Status();
+ });
+ ScheduleInfo scheduleInfo = {
+ .clientId = kTestClientId,
+ .scheduleId = kTestScheduleId,
+ .taskData = kTestData,
+ .count = kTestCount,
+ .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
+ .periodicInSeconds = kTestPeriodicInSeconds,
+ };
+
+ ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
+
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleTask) {
+ UnscheduleTaskRequest grpcRequest = {};
+ EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleTask)
+ .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+ const UnscheduleTaskRequest& request,
+ [[maybe_unused]] UnscheduleTaskResponse* response) {
+ grpcRequest = request;
+ return Status();
+ });
+
+ ScopedAStatus status = getService()->unscheduleTask(kTestClientId, kTestScheduleId);
+
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+ EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleAllTasks) {
+ UnscheduleAllTasksRequest grpcRequest = {};
+ EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleAllTasks)
+ .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+ const UnscheduleAllTasksRequest& request,
+ [[maybe_unused]] UnscheduleAllTasksResponse* response) {
+ grpcRequest = request;
+ return Status();
+ });
+
+ ScopedAStatus status = getService()->unscheduleAllTasks(kTestClientId);
+
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduled) {
+ bool isTaskScheduled = false;
+ IsTaskScheduledRequest grpcRequest = {};
+ EXPECT_CALL(*getGrpcWakeupClientStub(), IsTaskScheduled)
+ .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+ const IsTaskScheduledRequest& request,
+ IsTaskScheduledResponse* response) {
+ grpcRequest = request;
+ response->set_istaskscheduled(true);
+ return Status();
+ });
+
+ ScopedAStatus status =
+ getService()->isTaskScheduled(kTestClientId, kTestScheduleId, &isTaskScheduled);
+
+ ASSERT_TRUE(status.isOk());
+ EXPECT_TRUE(isTaskScheduled);
+ EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+ EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
+}
+
+TEST_F(RemoteAccessServiceUnitTest, testGetAllScheduledTasks) {
+ std::vector<ScheduleInfo> result;
+ GetAllScheduledTasksRequest grpcRequest = {};
+ EXPECT_CALL(*getGrpcWakeupClientStub(), GetAllScheduledTasks)
+ .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
+ const GetAllScheduledTasksRequest& request,
+ GetAllScheduledTasksResponse* response) {
+ grpcRequest = request;
+ GrpcScheduleInfo* newInfo = response->add_allscheduledtasks();
+ newInfo->set_clientid(kTestClientId);
+ newInfo->set_scheduleid(kTestScheduleId);
+ newInfo->set_data(kTestData.data(), kTestData.size());
+ newInfo->set_count(kTestCount);
+ newInfo->set_starttimeinepochseconds(kTestStartTimeInEpochSeconds);
+ newInfo->set_periodicinseconds(kTestPeriodicInSeconds);
+ return Status();
+ });
+
+ ScopedAStatus status = getService()->getAllScheduledTasks(kTestClientId, &result);
+
+ ASSERT_TRUE(status.isOk());
+ EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
+ ASSERT_EQ(result.size(), 1u);
+ ASSERT_EQ(result[0].clientId, kTestClientId);
+ ASSERT_EQ(result[0].scheduleId, kTestScheduleId);
+ ASSERT_EQ(result[0].taskData, kTestData);
+ ASSERT_EQ(result[0].count, kTestCount);
+ ASSERT_EQ(result[0].startTimeInEpochSeconds, kTestStartTimeInEpochSeconds);
+ ASSERT_EQ(result[0].periodicInSeconds, kTestPeriodicInSeconds);
+}
+
} // namespace remoteaccess
} // namespace automotive
} // namespace hardware