Support Enter Garage Mode in remote access HAL.

Handles task type in reference remote access HAL and passes to
remote access server through GRPC.

Update host-side TestWakeupClientService to handle vehicleInUse
and ApPowerBootupReason VHAL properties.

Update reference VHAL to get the property values rom a remote grpc
server.

Test: atest --host TestWakeupClientServiceImplUnitTest
Manual run TestWakeupClientServerHost verifies that reference
VHAL can get power properties.
Bug: 316233421

Change-Id: I188aa9eed2dedb3b81b4eb6f5685ca33b646b2f5
diff --git a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
index 14ba0a5..8ff6059 100644
--- a/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
+++ b/automotive/remoteaccess/hal/default/proto/wakeup_client.proto
@@ -124,6 +124,11 @@
     ErrorCode errorCode = 1;
 }
 
+enum ScheduleTaskType {
+    CUSTOM = 0;
+    ENTER_GARAGE_MODE = 1;
+}
+
 message GrpcScheduleInfo {
     string clientId = 1;
     string scheduleId = 2;
@@ -131,6 +136,7 @@
     int32 count = 4;
     int64 startTimeInEpochSeconds = 5;
     int64 periodicInSeconds = 6;
+    ScheduleTaskType taskType = 7;
 }
 
 message UnscheduleTaskRequest {
@@ -162,3 +168,25 @@
 message GetAllPendingScheduledTasksResponse {
     repeated GrpcScheduleInfo allScheduledTasks = 1;
 }
+
+/**
+ * Service provided by a power controller unit.
+ */
+service PowerController {
+    rpc IsVehicleInUse(IsVehicleInUseRequest) returns (IsVehicleInUseResponse) {}
+
+    rpc GetApPowerBootupReason(GetApPowerBootupReasonRequest)
+            returns (GetApPowerBootupReasonResponse) {}
+}
+
+message IsVehicleInUseRequest {}
+
+message IsVehicleInUseResponse {
+    bool isVehicleInUse = 1;
+}
+
+message GetApPowerBootupReasonRequest {}
+
+message GetApPowerBootupReasonResponse {
+    int32 bootupReason = 1;
+}
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index dbd5bed..91689b1 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -346,8 +346,8 @@
         return ScopedAStatus::ok();
     }
 
-    // TODO(b/316233421): support ENTER_GARAGE_MODE type.
     out->push_back(TaskType::CUSTOM);
+    out->push_back(TaskType::ENTER_GARAGE_MODE);
     return ScopedAStatus::ok();
 }
 
@@ -380,6 +380,8 @@
     }
 
     request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
+    request.mutable_scheduleinfo()->set_tasktype(
+            static_cast<ScheduleTaskType>(scheduleInfo.taskType));
     request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
     request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
                                              scheduleInfo.taskData.size());
@@ -485,6 +487,7 @@
         const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
         ScheduleInfo scheduleInfo = {
                 .clientId = rpcScheduleInfo.clientid(),
+                .taskType = static_cast<TaskType>(rpcScheduleInfo.tasktype()),
                 .scheduleId = rpcScheduleInfo.scheduleid(),
                 .taskData = stringToBytes(rpcScheduleInfo.data()),
                 .count = rpcScheduleInfo.count(),
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
index 41cc5d0..7424571 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -30,6 +30,11 @@
 namespace automotive {
 namespace remoteaccess {
 
+// The following are the same as VehicleApPowerBootupReason defined in VHAL.
+constexpr int32_t BOOTUP_REASON_USER_POWER_ON = 0;
+constexpr int32_t BOOTUP_REASON_SYSTEM_REMOTE_ACCESS = 2;
+constexpr int32_t BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE = 3;
+
 // 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 {
@@ -98,50 +103,57 @@
 };
 
 // forward-declaration
-class TestWakeupClientServiceImpl;
+class ServiceImpl;
 
 class TaskScheduleMsgHandler final : public android::MessageHandler {
   public:
-    TaskScheduleMsgHandler(TestWakeupClientServiceImpl* mImpl);
+    TaskScheduleMsgHandler(ServiceImpl* impl);
     void handleMessage(const android::Message& message) override;
 
   private:
-    TestWakeupClientServiceImpl* mImpl;
+    ServiceImpl* mImpl;
 };
 
-class TestWakeupClientServiceImpl : public WakeupClient::Service {
+class ServiceImpl {
   public:
-    TestWakeupClientServiceImpl();
+    ServiceImpl();
 
-    ~TestWakeupClientServiceImpl();
+    virtual ~ServiceImpl() = 0;
 
     // Stop the handling for all income requests. Prepare for shutdown.
     void stopServer();
 
     grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
-                                grpc::ServerWriter<GetRemoteTasksResponse>* writer) override;
+                                grpc::ServerWriter<GetRemoteTasksResponse>* writer);
 
     grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
                                       const NotifyWakeupRequiredRequest* request,
-                                      NotifyWakeupRequiredResponse* response) override;
+                                      NotifyWakeupRequiredResponse* response);
 
     grpc::Status ScheduleTask(grpc::ServerContext* context, const ScheduleTaskRequest* request,
-                              ScheduleTaskResponse* response) override;
+                              ScheduleTaskResponse* response);
 
     grpc::Status UnscheduleTask(grpc::ServerContext* context, const UnscheduleTaskRequest* request,
-                                UnscheduleTaskResponse* response) override;
+                                UnscheduleTaskResponse* response);
 
     grpc::Status UnscheduleAllTasks(grpc::ServerContext* context,
                                     const UnscheduleAllTasksRequest* request,
-                                    UnscheduleAllTasksResponse* response) override;
+                                    UnscheduleAllTasksResponse* response);
 
     grpc::Status IsTaskScheduled(grpc::ServerContext* context,
                                  const IsTaskScheduledRequest* request,
-                                 IsTaskScheduledResponse* response) override;
+                                 IsTaskScheduledResponse* response);
 
-    grpc::Status GetAllPendingScheduledTasks(
-            grpc::ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
-            GetAllPendingScheduledTasksResponse* response) override;
+    grpc::Status GetAllPendingScheduledTasks(grpc::ServerContext* context,
+                                             const GetAllPendingScheduledTasksRequest* request,
+                                             GetAllPendingScheduledTasksResponse* response);
+
+    grpc::Status IsVehicleInUse(grpc::ServerContext* context, const IsVehicleInUseRequest* request,
+                                IsVehicleInUseResponse* response);
+
+    grpc::Status GetApPowerBootupReason(grpc::ServerContext* context,
+                                        const GetApPowerBootupReasonRequest* request,
+                                        GetApPowerBootupReasonResponse* response);
 
     /**
      * Starts generating fake tasks for the specific client repeatedly.
@@ -177,7 +189,7 @@
      * This must be implemented by child class and contains device specific logic. E.g. this might
      * be sending QEMU commands for the emulator device.
      */
-    virtual void wakeupApplicationProcessor() = 0;
+    virtual void wakeupApplicationProcessor(int32_t bootupReason) = 0;
 
     /**
      * Cleans up a scheduled task info.
@@ -185,6 +197,16 @@
     void cleanupScheduledTaskLocked(const std::string& clientId, const std::string& scheduleId)
             REQUIRES(mLock);
 
+    /**
+     * Sets whether vehicle is in use.
+     */
+    void setVehicleInUse(bool vehicleInUse);
+
+    /**
+     * Sets the bootup reason.
+     */
+    void setBootupReason(int32_t bootupReason);
+
   private:
     friend class TaskScheduleMsgHandler;
 
@@ -218,6 +240,8 @@
     std::atomic<bool> mServerStopped = false;
     std::unordered_map<std::string, std::unordered_map<std::string, ScheduleInfo>>
             mInfoByScheduleIdByClientId GUARDED_BY(mLock);
+    std::atomic<bool> mVehicleInUse = false;
+    std::atomic<int32_t> mBootupReason = BOOTUP_REASON_USER_POWER_ON;
 
     // Thread-safe. For test impl only.
     FakeTaskGenerator mFakeTaskGenerator;
@@ -232,6 +256,72 @@
     void loop();
 };
 
+class WakeupClientServiceImpl : public WakeupClient::Service {
+  public:
+    WakeupClientServiceImpl(ServiceImpl* impl) { mImpl = impl; }
+
+    grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
+                                grpc::ServerWriter<GetRemoteTasksResponse>* writer) override {
+        return mImpl->GetRemoteTasks(context, request, writer);
+    }
+
+    grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
+                                      const NotifyWakeupRequiredRequest* request,
+                                      NotifyWakeupRequiredResponse* response) override {
+        return mImpl->NotifyWakeupRequired(context, request, response);
+    }
+
+    grpc::Status ScheduleTask(grpc::ServerContext* context, const ScheduleTaskRequest* request,
+                              ScheduleTaskResponse* response) override {
+        return mImpl->ScheduleTask(context, request, response);
+    }
+
+    grpc::Status UnscheduleTask(grpc::ServerContext* context, const UnscheduleTaskRequest* request,
+                                UnscheduleTaskResponse* response) override {
+        return mImpl->UnscheduleTask(context, request, response);
+    }
+
+    grpc::Status UnscheduleAllTasks(grpc::ServerContext* context,
+                                    const UnscheduleAllTasksRequest* request,
+                                    UnscheduleAllTasksResponse* response) override {
+        return mImpl->UnscheduleAllTasks(context, request, response);
+    }
+
+    grpc::Status IsTaskScheduled(grpc::ServerContext* context,
+                                 const IsTaskScheduledRequest* request,
+                                 IsTaskScheduledResponse* response) override {
+        return mImpl->IsTaskScheduled(context, request, response);
+    }
+
+    grpc::Status GetAllPendingScheduledTasks(
+            grpc::ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
+            GetAllPendingScheduledTasksResponse* response) override {
+        return mImpl->GetAllPendingScheduledTasks(context, request, response);
+    }
+
+  private:
+    ServiceImpl* mImpl;
+};
+
+class PowerControllerServiceImpl : public PowerController::Service {
+  public:
+    PowerControllerServiceImpl(ServiceImpl* impl) { mImpl = impl; }
+
+    grpc::Status IsVehicleInUse(grpc::ServerContext* context, const IsVehicleInUseRequest* request,
+                                IsVehicleInUseResponse* response) override {
+        return mImpl->IsVehicleInUse(context, request, response);
+    }
+
+    grpc::Status GetApPowerBootupReason(grpc::ServerContext* context,
+                                        const GetApPowerBootupReasonRequest* request,
+                                        GetApPowerBootupReasonResponse* response) override {
+        return mImpl->GetApPowerBootupReason(context, request, response);
+    }
+
+  private:
+    ServiceImpl* mImpl;
+};
+
 }  // namespace remoteaccess
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
index eed3495..5d33fcb 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -38,7 +38,7 @@
 using ::grpc::Status;
 
 constexpr int64_t kTaskIntervalInMs = 5'000;
-constexpr int64_t kTaskTimeoutInMs = 20'000;
+constexpr int64_t kTaskTimeoutInMs = 60'000;
 
 int64_t msToNs(int64_t ms) {
     return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(ms))
@@ -140,21 +140,21 @@
     }
 }
 
-TestWakeupClientServiceImpl::TestWakeupClientServiceImpl() {
+ServiceImpl::ServiceImpl() {
     mTaskScheduleMsgHandler = android::sp<TaskScheduleMsgHandler>::make(this);
     mLooper = android::sp<Looper>::make(/*opts=*/0);
     mLooperThread = std::thread([this] { loop(); });
     mTaskQueue = std::make_unique<TaskQueue>(mLooper);
 }
 
-TestWakeupClientServiceImpl::~TestWakeupClientServiceImpl() {
+ServiceImpl::~ServiceImpl() {
     if (mServerStopped) {
         return;
     }
     stopServer();
 }
 
-void TestWakeupClientServiceImpl::stopServer() {
+void ServiceImpl::stopServer() {
     mTaskQueue->stopWait();
     stopGeneratingFakeTask();
     // Set the flag so that the loop thread will exit.
@@ -165,7 +165,7 @@
     }
 }
 
-void TestWakeupClientServiceImpl::loop() {
+void ServiceImpl::loop() {
     Looper::setForThread(mLooper);
 
     while (true) {
@@ -176,23 +176,22 @@
     }
 }
 
-void TestWakeupClientServiceImpl::injectTask(const std::string& taskData,
-                                             const std::string& clientId) {
+void ServiceImpl::injectTask(const std::string& taskData, const std::string& clientId) {
     GetRemoteTasksResponse response;
     response.set_data(taskData);
     response.set_clientid(clientId);
     injectTaskResponse(response);
 }
 
-void TestWakeupClientServiceImpl::injectTaskResponse(const GetRemoteTasksResponse& response) {
+void ServiceImpl::injectTaskResponse(const GetRemoteTasksResponse& response) {
     printf("Receive a new task\n");
     mTaskQueue->add(response);
     if (mWakeupRequired) {
-        wakeupApplicationProcessor();
+        wakeupApplicationProcessor(BOOTUP_REASON_SYSTEM_REMOTE_ACCESS);
     }
 }
 
-void TestWakeupClientServiceImpl::startGeneratingFakeTask(const std::string& clientId) {
+void ServiceImpl::startGeneratingFakeTask(const std::string& clientId) {
     std::lock_guard<std::mutex> lockGuard(mLock);
     if (mGeneratingFakeTask) {
         printf("Fake task is already being generated\n");
@@ -203,7 +202,7 @@
     printf("Started generating fake tasks\n");
 }
 
-void TestWakeupClientServiceImpl::stopGeneratingFakeTask() {
+void ServiceImpl::stopGeneratingFakeTask() {
     {
         std::lock_guard<std::mutex> lockGuard(mLock);
         if (!mGeneratingFakeTask) {
@@ -219,7 +218,7 @@
     printf("Stopped generating fake tasks\n");
 }
 
-void TestWakeupClientServiceImpl::fakeTaskGenerateLoop(const std::string& clientId) {
+void ServiceImpl::fakeTaskGenerateLoop(const std::string& clientId) {
     // In actual implementation, this should communicate with the remote server and receives tasks
     // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms.
     while (true) {
@@ -237,9 +236,8 @@
     }
 }
 
-Status TestWakeupClientServiceImpl::GetRemoteTasks(ServerContext* context,
-                                                   const GetRemoteTasksRequest* request,
-                                                   ServerWriter<GetRemoteTasksResponse>* writer) {
+Status ServiceImpl::GetRemoteTasks(ServerContext* context, const GetRemoteTasksRequest* request,
+                                   ServerWriter<GetRemoteTasksResponse>* writer) {
     printf("GetRemoteTasks called\n");
     mRemoteTaskConnectionAlive = true;
     while (true) {
@@ -277,15 +275,15 @@
     return Status::CANCELLED;
 }
 
-Status TestWakeupClientServiceImpl::NotifyWakeupRequired(ServerContext* context,
-                                                         const NotifyWakeupRequiredRequest* request,
-                                                         NotifyWakeupRequiredResponse* response) {
+Status ServiceImpl::NotifyWakeupRequired(ServerContext* context,
+                                         const NotifyWakeupRequiredRequest* request,
+                                         NotifyWakeupRequiredResponse* response) {
     printf("NotifyWakeupRequired called\n");
     if (request->iswakeuprequired() && !mWakeupRequired && !mTaskQueue->isEmpty()) {
         // If wakeup is now required and previously not required, this means we have finished
         // shutting down the device. If there are still pending tasks, try waking up AP again
         // to finish executing those tasks.
-        wakeupApplicationProcessor();
+        wakeupApplicationProcessor(BOOTUP_REASON_SYSTEM_REMOTE_ACCESS);
     }
     mWakeupRequired = request->iswakeuprequired();
     if (mWakeupRequired) {
@@ -296,23 +294,22 @@
     return Status::OK;
 }
 
-void TestWakeupClientServiceImpl::cleanupScheduledTaskLocked(const std::string& clientId,
-                                                             const std::string& scheduleId) {
+void ServiceImpl::cleanupScheduledTaskLocked(const std::string& clientId,
+                                             const std::string& scheduleId) {
     mInfoByScheduleIdByClientId[clientId].erase(scheduleId);
     if (mInfoByScheduleIdByClientId[clientId].size() == 0) {
         mInfoByScheduleIdByClientId.erase(clientId);
     }
 }
 
-TaskScheduleMsgHandler::TaskScheduleMsgHandler(TestWakeupClientServiceImpl* impl) : mImpl(impl) {}
+TaskScheduleMsgHandler::TaskScheduleMsgHandler(ServiceImpl* impl) : mImpl(impl) {}
 
 void TaskScheduleMsgHandler::handleMessage(const android::Message& message) {
     mImpl->handleAddTask(message.what);
 }
 
-Status TestWakeupClientServiceImpl::ScheduleTask(ServerContext* context,
-                                                 const ScheduleTaskRequest* request,
-                                                 ScheduleTaskResponse* response) {
+Status ServiceImpl::ScheduleTask(ServerContext* context, const ScheduleTaskRequest* request,
+                                 ScheduleTaskResponse* response) {
     std::lock_guard<std::mutex> lockGuard(mLock);
 
     const GrpcScheduleInfo& grpcScheduleInfo = request->scheduleinfo();
@@ -359,8 +356,7 @@
     return Status::OK;
 }
 
-bool TestWakeupClientServiceImpl::getScheduleInfoLocked(int scheduleMsgId,
-                                                        ScheduleInfo** outScheduleInfoPtr) {
+bool ServiceImpl::getScheduleInfoLocked(int scheduleMsgId, ScheduleInfo** outScheduleInfoPtr) {
     for (auto& [_, infoByScheduleId] : mInfoByScheduleIdByClientId) {
         for (auto& [_, scheduleInfo] : infoByScheduleId) {
             if (scheduleInfo.scheduleMsgId == scheduleMsgId) {
@@ -372,7 +368,7 @@
     return false;
 }
 
-void TestWakeupClientServiceImpl::handleAddTask(int scheduleMsgId) {
+void ServiceImpl::handleAddTask(int scheduleMsgId) {
     std::lock_guard<std::mutex> lockGuard(mLock);
 
     ScheduleInfo* scheduleInfoPtr;
@@ -385,15 +381,27 @@
     const GrpcScheduleInfo& grpcScheduleInfo = *scheduleInfoPtr->grpcScheduleInfo;
     const std::string scheduleId = grpcScheduleInfo.scheduleid();
     const std::string clientId = grpcScheduleInfo.clientid();
-
-    GetRemoteTasksResponse injectResponse;
-    injectResponse.set_data(grpcScheduleInfo.data().data(), grpcScheduleInfo.data().size());
-    injectResponse.set_clientid(clientId);
-    injectTaskResponse(injectResponse);
     scheduleInfoPtr->currentCount++;
+    ScheduleTaskType taskType = grpcScheduleInfo.tasktype();
+    printf("Sending scheduled tasks for scheduleId: %s, clientId: %s, taskCount: %d, "
+           "taskType: %d\n",
+           scheduleId.c_str(), clientId.c_str(), scheduleInfoPtr->currentCount,
+           static_cast<int>(taskType));
 
-    printf("Sending scheduled tasks for scheduleId: %s, clientId: %s, taskCount: %d\n",
-           scheduleId.c_str(), clientId.c_str(), scheduleInfoPtr->currentCount);
+    if (taskType == ScheduleTaskType::ENTER_GARAGE_MODE) {
+        if (mWakeupRequired) {
+            wakeupApplicationProcessor(BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE);
+        } else {
+            printf("Ignore ENTER_GARAGE_MODE task type because the head unit is already running");
+        }
+    } else if (grpcScheduleInfo.tasktype() == ScheduleTaskType::CUSTOM) {
+        GetRemoteTasksResponse injectResponse;
+        injectResponse.set_data(grpcScheduleInfo.data().data(), grpcScheduleInfo.data().size());
+        injectResponse.set_clientid(clientId);
+        injectTaskResponse(injectResponse);
+    } else {
+        printf("Unknown task type: %d\n", static_cast<int>(taskType));
+    }
 
     if (scheduleInfoPtr->totalCount != 0 &&
         scheduleInfoPtr->currentCount == scheduleInfoPtr->totalCount) {
@@ -407,9 +415,8 @@
                                 android::Message(scheduleMsgId));
 }
 
-Status TestWakeupClientServiceImpl::UnscheduleTask(ServerContext* context,
-                                                   const UnscheduleTaskRequest* request,
-                                                   UnscheduleTaskResponse* response) {
+Status ServiceImpl::UnscheduleTask(ServerContext* context, const UnscheduleTaskRequest* request,
+                                   UnscheduleTaskResponse* response) {
     std::lock_guard<std::mutex> lockGuard(mLock);
 
     const std::string& clientId = request->clientid();
@@ -431,9 +438,9 @@
     return Status::OK;
 }
 
-Status TestWakeupClientServiceImpl::UnscheduleAllTasks(ServerContext* context,
-                                                       const UnscheduleAllTasksRequest* request,
-                                                       UnscheduleAllTasksResponse* response) {
+Status ServiceImpl::UnscheduleAllTasks(ServerContext* context,
+                                       const UnscheduleAllTasksRequest* request,
+                                       UnscheduleAllTasksResponse* response) {
     std::lock_guard<std::mutex> lockGuard(mLock);
 
     const std::string& clientId = request->clientid();
@@ -452,9 +459,8 @@
     return Status::OK;
 }
 
-Status TestWakeupClientServiceImpl::IsTaskScheduled(ServerContext* context,
-                                                    const IsTaskScheduledRequest* request,
-                                                    IsTaskScheduledResponse* response) {
+Status ServiceImpl::IsTaskScheduled(ServerContext* context, const IsTaskScheduledRequest* request,
+                                    IsTaskScheduledResponse* response) {
     std::lock_guard<std::mutex> lockGuard(mLock);
 
     const std::string& clientId = request->clientid();
@@ -475,9 +481,9 @@
     return Status::OK;
 }
 
-Status TestWakeupClientServiceImpl::GetAllPendingScheduledTasks(
-        ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
-        GetAllPendingScheduledTasksResponse* response) {
+Status ServiceImpl::GetAllPendingScheduledTasks(ServerContext* context,
+                                                const GetAllPendingScheduledTasksRequest* request,
+                                                GetAllPendingScheduledTasksResponse* response) {
     const std::string& clientId = request->clientid();
     printf("GetAllPendingScheduledTasks called with client Id: %s\n", clientId.c_str());
     response->clear_allscheduledtasks();
@@ -493,14 +499,35 @@
     return Status::OK;
 }
 
-bool TestWakeupClientServiceImpl::isWakeupRequired() {
+Status ServiceImpl::IsVehicleInUse(ServerContext* context, const IsVehicleInUseRequest* request,
+                                   IsVehicleInUseResponse* response) {
+    response->set_isvehicleinuse(mVehicleInUse);
+    return Status::OK;
+}
+
+Status ServiceImpl::GetApPowerBootupReason(ServerContext* context,
+                                           const GetApPowerBootupReasonRequest* request,
+                                           GetApPowerBootupReasonResponse* response) {
+    response->set_bootupreason(mBootupReason);
+    return Status::OK;
+}
+
+bool ServiceImpl::isWakeupRequired() {
     return mWakeupRequired;
 }
 
-bool TestWakeupClientServiceImpl::isRemoteTaskConnectionAlive() {
+bool ServiceImpl::isRemoteTaskConnectionAlive() {
     return mRemoteTaskConnectionAlive;
 }
 
+void ServiceImpl::setVehicleInUse(bool vehicleInUse) {
+    mVehicleInUse = vehicleInUse;
+}
+
+void ServiceImpl::setBootupReason(int32_t bootupReason) {
+    mBootupReason = bootupReason;
+}
+
 }  // namespace remoteaccess
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
index 5443ad9..63324f3 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
@@ -33,7 +33,12 @@
 #include <grpcpp/server.h>
 #include <grpcpp/server_builder.h>
 
-using ::android::hardware::automotive::remoteaccess::TestWakeupClientServiceImpl;
+using ::android::hardware::automotive::remoteaccess::BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE;
+using ::android::hardware::automotive::remoteaccess::BOOTUP_REASON_SYSTEM_REMOTE_ACCESS;
+using ::android::hardware::automotive::remoteaccess::BOOTUP_REASON_USER_POWER_ON;
+using ::android::hardware::automotive::remoteaccess::PowerControllerServiceImpl;
+using ::android::hardware::automotive::remoteaccess::ServiceImpl;
+using ::android::hardware::automotive::remoteaccess::WakeupClientServiceImpl;
 using ::grpc::Server;
 using ::grpc::ServerBuilder;
 using ::grpc::ServerWriter;
@@ -48,11 +53,13 @@
 
 pid_t emuPid = 0;
 
-void RunServer(const std::string& serviceAddr,
-               std::shared_ptr<TestWakeupClientServiceImpl> service) {
+void RunServer(const std::string& serviceAddr, std::shared_ptr<ServiceImpl> service) {
     ServerBuilder builder;
     builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
-    builder.RegisterService(service.get());
+    WakeupClientServiceImpl wakeupClientService(service.get());
+    builder.RegisterService(&wakeupClientService);
+    PowerControllerServiceImpl powerControllerService(service.get());
+    builder.RegisterService(&powerControllerService);
     std::unique_ptr<Server> server(builder.BuildAndStart());
     printf("Test Remote Access GRPC Server listening on %s\n", serviceAddr.c_str());
     server->Wait();
@@ -81,20 +88,21 @@
     }
 }
 
-bool powerOnEmu() {
+bool powerOnEmu(ServiceImpl* service, int32_t bootupReason) {
     updateEmuStatus();
     if (emuPid != 0) {
         printf("The emulator is already running\n");
         return false;
     }
+    service->setBootupReason(bootupReason);
     emuPid = runCommand(COMMAND_RUN_EMU);
     printf("Emulator started in process: %d\n", emuPid);
     return true;
 }
 
-bool powerOn() {
+bool powerOn(ServiceImpl* service, int32_t bootupReason) {
 #ifdef HOST
-    return powerOnEmu();
+    return powerOnEmu(service, bootupReason);
 #else
     printf("power on is only supported on host\n");
     return false;
@@ -133,21 +141,6 @@
 #endif
 }
 
-void setVehicleInUse(bool vehicleInUse) {
-#ifdef HOST
-    printf("Set vehicleInUse to %d\n", vehicleInUse);
-    int value = 0;
-    if (vehicleInUse) {
-        value = 1;
-    }
-    const char* command = getSetPropCommand(VEHICLE_IN_USE, value);
-    runCommand(command);
-    delete[] command;
-#else
-    printf("set vehicleInUse is only supported on host\n");
-#endif
-}
-
 void help() {
     std::cout << "Remote Access Host Test Utility" << std::endl
               << "help:\t"
@@ -171,8 +164,7 @@
               << "(only supported on host)" << std::endl;
 }
 
-void parseCommand(const std::string& userInput,
-                  std::shared_ptr<TestWakeupClientServiceImpl> service) {
+void parseCommand(const std::string& userInput, std::shared_ptr<ServiceImpl> service) {
     if (userInput == "") {
         // ignore empty line.
     } else if (userInput == "help") {
@@ -199,8 +191,10 @@
         printf("isWakeupRequired: %B, isRemoteTaskConnectionAlive: %B\n",
                service->isWakeupRequired(), service->isRemoteTaskConnectionAlive());
     } else if (userInput == "power on") {
-        powerOn();
+        service->setVehicleInUse(true);
+        powerOn(service.get(), BOOTUP_REASON_USER_POWER_ON);
     } else if (userInput == "power off") {
+        service->setVehicleInUse(false);
         powerOff();
     } else if (userInput.rfind("inject task", 0) == 0) {
         std::stringstream ss;
@@ -226,7 +220,7 @@
         printf("Remote task with client ID: %s, data: %s injected\n", clientId.c_str(),
                taskData.c_str());
     } else if (userInput == "set vehicleInUse") {
-        setVehicleInUse(true);
+        service->setVehicleInUse(true);
     } else {
         printf("Unknown command, see 'help'\n");
     }
@@ -242,14 +236,11 @@
     exit(-1);
 }
 
-class MyTestWakeupClientServiceImpl final : public TestWakeupClientServiceImpl {
+class MyServiceImpl final : public ServiceImpl {
   public:
-    void wakeupApplicationProcessor() override {
+    void wakeupApplicationProcessor(int32_t bootupReason) override {
 #ifdef HOST
-        if (powerOnEmu()) {
-            // If we wake up AP to execute remote task, vehicle in use should be false.
-            setVehicleInUse(false);
-        }
+        powerOnEmu(this, bootupReason);
 #else
         wakeupAp();
 #endif
@@ -262,8 +253,7 @@
         serviceAddr = argv[1];
     }
     // Let the server thread run, we will force kill the server when we exit the program.
-    std::shared_ptr<TestWakeupClientServiceImpl> service =
-            std::make_shared<MyTestWakeupClientServiceImpl>();
+    std::shared_ptr<ServiceImpl> service = std::make_shared<MyServiceImpl>();
     std::thread serverThread([serviceAddr, service] { RunServer(serviceAddr, service); });
 
     // Register the signal handler for SIGTERM and SIGINT so that we can stop the emulator before
diff --git a/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp b/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
index 63458ae..4bc0086 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/test/TestWakeupClientServiceImplUnitTest.cpp
@@ -43,9 +43,9 @@
 constexpr int64_t kTestPeriodicInSeconds = 123;
 const std::string kTestGrpcAddr = "localhost:50051";
 
-class MyTestWakeupClientServiceImpl final : public TestWakeupClientServiceImpl {
+class MyTestWakeupClientServiceImpl final : public ServiceImpl {
   public:
-    void wakeupApplicationProcessor() override {
+    void wakeupApplicationProcessor([[maybe_unused]] int32_t bootupReason) override {
         // Do nothing.
     }
 };
@@ -54,13 +54,14 @@
   public:
     virtual void SetUp() override {
         mServerThread = std::thread([this] {
+            mService = std::make_unique<MyTestWakeupClientServiceImpl>();
+            ServerBuilder builder;
+            builder.AddListeningPort(kTestGrpcAddr, grpc::InsecureServerCredentials());
+            WakeupClientServiceImpl wakeupClientService(mService.get());
+            builder.RegisterService(&wakeupClientService);
+            mServer = builder.BuildAndStart();
             {
                 std::unique_lock<std::mutex> lock(mLock);
-                mService = std::make_unique<MyTestWakeupClientServiceImpl>();
-                ServerBuilder builder;
-                builder.AddListeningPort(kTestGrpcAddr, grpc::InsecureServerCredentials());
-                builder.RegisterService(mService.get());
-                mServer = builder.BuildAndStart();
                 mServerStartCv.notify_one();
             }
             mServer->Wait();
@@ -124,6 +125,7 @@
                               std::chrono::system_clock::now().time_since_epoch())
                               .count();
         request.mutable_scheduleinfo()->set_clientid(kTestClientId);
+        request.mutable_scheduleinfo()->set_tasktype(ScheduleTaskType::CUSTOM);
         request.mutable_scheduleinfo()->set_scheduleid(scheduleId);
         request.mutable_scheduleinfo()->set_data(kTestData.data(), kTestData.size());
         request.mutable_scheduleinfo()->set_count(count);
@@ -156,6 +158,7 @@
     ScheduleTaskResponse response = {};
 
     request.mutable_scheduleinfo()->set_clientid(kTestClientId);
+    request.mutable_scheduleinfo()->set_tasktype(ScheduleTaskType::CUSTOM);
     request.mutable_scheduleinfo()->set_scheduleid(kTestScheduleId);
     request.mutable_scheduleinfo()->set_data(kTestData.data(), kTestData.size());
     request.mutable_scheduleinfo()->set_count(2);
@@ -191,6 +194,7 @@
 
     request.mutable_scheduleinfo()->set_clientid(kTestClientId);
     request.mutable_scheduleinfo()->set_scheduleid(kTestScheduleId);
+    request.mutable_scheduleinfo()->set_tasktype(ScheduleTaskType::CUSTOM);
     request.mutable_scheduleinfo()->set_data(kTestData.data(), kTestData.size());
     request.mutable_scheduleinfo()->set_count(2);
     request.mutable_scheduleinfo()->set_starttimeinepochseconds(getNow() + 1);
@@ -315,6 +319,7 @@
     for (int i = 0; i < 2; i++) {
         EXPECT_EQ(response2.allscheduledtasks(i).clientid(), kTestClientId);
         if (response2.allscheduledtasks(i).scheduleid() == scheduleId1) {
+            EXPECT_EQ(response2.allscheduledtasks(i).tasktype(), ScheduleTaskType::CUSTOM);
             EXPECT_EQ(response2.allscheduledtasks(i).data(),
                       std::string(kTestData.begin(), kTestData.end()));
             EXPECT_EQ(response2.allscheduledtasks(i).count(), count1);
@@ -322,6 +327,7 @@
             EXPECT_EQ(response2.allscheduledtasks(i).periodicinseconds(), periodicInSeconds1);
         } else {
             EXPECT_EQ(response2.allscheduledtasks(i).scheduleid(), scheduleId2);
+            EXPECT_EQ(response2.allscheduledtasks(i).tasktype(), ScheduleTaskType::CUSTOM);
             EXPECT_EQ(response2.allscheduledtasks(i).data(),
                       std::string(kTestData.begin(), kTestData.end()));
             EXPECT_EQ(response2.allscheduledtasks(i).count(), count2);
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 76db891..d987e6f 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -67,6 +67,7 @@
 using ::aidl::android::hardware::automotive::vehicle::LowSpeedCollisionWarningState;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAirbagLocation;
+using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerBootupReason;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
@@ -300,6 +301,8 @@
             std::make_unique<ConstantParser<CrossTrafficMonitoringWarningState>>();
     mConstantParsersByType["LowSpeedAutomaticEmergencyBrakingState"] =
             std::make_unique<ConstantParser<LowSpeedAutomaticEmergencyBrakingState>>();
+    mConstantParsersByType["VehicleApPowerBootupReason"] =
+            std::make_unique<ConstantParser<VehicleApPowerBootupReason>>();
     mConstantParsersByType["Constants"] = std::make_unique<LocalVariableParser>();
 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
     mConstantParsersByType["TestVendorProperty"] =
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 590eff9..1a7cdaf 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -3196,6 +3196,14 @@
             }
         },
         {
+            "property": "VehicleProperty::AP_POWER_BOOTUP_REASON",
+            "defaultValue": {
+                "int32Values": [
+                    "VehicleApPowerBootupReason::USER_POWER_ON"
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::DISPLAY_BRIGHTNESS",
             "defaultValue": {
                 "int32Values": [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index e75f648..80e4087 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -27,11 +27,19 @@
     ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
-    cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
+    cflags: [
+        "-DENABLE_VEHICLE_HAL_TEST_PROPERTIES",
+        // Uncomment this if running on emulator and connecting to a local grpc server
+        // running on host 127.0.0.1:50051 (TestWakeupClientServerHost)
+        // "-DPOWER_GRPC_SERVICE_ADDRESS=\"10.0.2.2:50051\"",
+    ],
     defaults: [
         "VehicleHalDefaults",
         "FakeVehicleHardwareDefaults",
     ],
+    whole_static_libs: [
+        "wakeup_client_protos",
+    ],
 }
 
 cc_defaults {
@@ -54,7 +62,9 @@
         "Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
     ],
     shared_libs: [
+        "libgrpc++",
         "libjsoncpp",
+        "libprotobuf-cpp-full",
     ],
     export_static_lib_headers: ["VehicleHalUtils"],
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 1153217..8d6c883 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -32,6 +32,8 @@
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
+#include <grpc++/grpc++.h>
+#include <wakeup_client.grpc.pb.h>
 
 #include <memory>
 #include <mutex>
@@ -240,6 +242,11 @@
     VhalResult<void> synchronizeHvacTemp(int32_t hvacDualOnAreaId,
                                          std::optional<float> newTempC) const;
     std::optional<int32_t> getSyncedAreaIdIfHvacDualOn(int32_t hvacTemperatureSetAreaId) const;
+    ValueResultType getPowerPropFromExternalService(int32_t propId) const;
+    ValueResultType getVehicleInUse(
+            android::hardware::automotive::remoteaccess::PowerController::Stub* clientStub) const;
+    ValueResultType getApPowerBootupReason(
+            android::hardware::automotive::remoteaccess::PowerController::Stub* clientStub) const;
 
     std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations();
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index bcc765c..c4e7086 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -82,6 +82,12 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehicleUnit;
 
+using ::android::hardware::automotive::remoteaccess::GetApPowerBootupReasonRequest;
+using ::android::hardware::automotive::remoteaccess::GetApPowerBootupReasonResponse;
+using ::android::hardware::automotive::remoteaccess::IsVehicleInUseRequest;
+using ::android::hardware::automotive::remoteaccess::IsVehicleInUseResponse;
+using ::android::hardware::automotive::remoteaccess::PowerController;
+
 using ::android::base::EqualsIgnoreCase;
 using ::android::base::Error;
 using ::android::base::GetIntProperty;
@@ -256,6 +262,11 @@
                 },
         },
 };
+
+// The list of VHAL properties that might be handled by an external power controller.
+const std::unordered_set<int32_t> mPowerPropIds = {toInt(VehicleProperty::VEHICLE_IN_USE),
+                                                   toInt(VehicleProperty::AP_POWER_BOOTUP_REASON)};
+
 }  // namespace
 
 void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config) {
@@ -763,6 +774,13 @@
     int32_t propId = value.prop;
     ValueResultType result;
 
+#ifdef POWER_GRPC_SERVICE_ADDRESS
+    if (mPowerPropIds.find(propId) != mPowerPropIds.end()) {
+        *isSpecialValue = true;
+        return getPowerPropFromExternalService(propId);
+    }
+#endif
+
     if (propId >= STARTING_VENDOR_CODE_PROPERTIES_FOR_TEST &&
         propId < ENDING_VENDOR_CODE_PROPERTIES_FOR_TEST) {
         *isSpecialValue = true;
@@ -844,6 +862,61 @@
     return nullptr;
 }
 
+FakeVehicleHardware::ValueResultType FakeVehicleHardware::getPowerPropFromExternalService(
+        [[maybe_unused]] int32_t propId) const {
+#ifdef POWER_GRPC_SERVICE_ADDRESS
+    auto channel =
+            grpc::CreateChannel(POWER_GRPC_SERVICE_ADDRESS, grpc::InsecureChannelCredentials());
+    auto clientStub = PowerController::NewStub(channel);
+    switch (propId) {
+        case toInt(VehicleProperty::VEHICLE_IN_USE):
+            return getVehicleInUse(clientStub.get());
+        case toInt(VehicleProperty::AP_POWER_BOOTUP_REASON):
+            return getApPowerBootupReason(clientStub.get());
+        default:
+            return StatusError(StatusCode::INTERNAL_ERROR)
+                   << "Unsupported power property ID: " << propId;
+    }
+#else
+    // Must not reach here.
+    return StatusError(StatusCode::INTERNAL_ERROR);
+#endif
+}
+
+FakeVehicleHardware::ValueResultType FakeVehicleHardware::getVehicleInUse(
+        PowerController::Stub* clientStub) const {
+    IsVehicleInUseRequest request = {};
+    IsVehicleInUseResponse response = {};
+    grpc::ClientContext context;
+    auto status = clientStub->IsVehicleInUse(&context, request, &response);
+    if (!status.ok()) {
+        return StatusError(StatusCode::TRY_AGAIN) << "Cannot connect to GRPC service "
+                                                  << ", error: " << status.error_message();
+    }
+    auto result = mValuePool->obtainBoolean(response.isvehicleinuse());
+    result->prop = toInt(VehicleProperty::VEHICLE_IN_USE);
+    result->areaId = 0;
+    result->timestamp = elapsedRealtimeNano();
+    return result;
+}
+
+FakeVehicleHardware::ValueResultType FakeVehicleHardware::getApPowerBootupReason(
+        PowerController::Stub* clientStub) const {
+    GetApPowerBootupReasonRequest request = {};
+    GetApPowerBootupReasonResponse response = {};
+    grpc::ClientContext context;
+    auto status = clientStub->GetApPowerBootupReason(&context, request, &response);
+    if (!status.ok()) {
+        return StatusError(StatusCode::TRY_AGAIN) << "Cannot connect to GRPC service "
+                                                  << ", error: " << status.error_message();
+    }
+    auto result = mValuePool->obtainInt32(response.bootupreason());
+    result->prop = toInt(VehicleProperty::AP_POWER_BOOTUP_REASON);
+    result->areaId = 0;
+    result->timestamp = elapsedRealtimeNano();
+    return result;
+}
+
 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getEchoReverseBytes(
         const VehiclePropValue& value) const {
     auto readResult = mServerSidePropStore->readValue(value);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index b763d2f..ac70b51 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -41,7 +41,9 @@
         "libgmock",
     ],
     shared_libs: [
+        "libgrpc++",
         "libjsoncpp",
+        "libprotobuf-cpp-full",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 90643aa..cab33e1 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -506,6 +506,12 @@
             continue;
         }
 
+        if (propId == toInt(VehicleProperty::VEHICLE_IN_USE) ||
+            propId == toInt(VehicleProperty::AP_POWER_BOOTUP_REASON)) {
+            // These may be controller by an external power control unit.
+            continue;
+        }
+
         if (isGlobalProp(propId)) {
             if (config.initialValue == RawPropValues{}) {
                 addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 0c8ebbd..77facf2 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -65,6 +65,7 @@
 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleAirbagLocation.h>
+#include <aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReq.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleArea.h>