1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "GarageModeServerSideHandler.h"
18
19 #include <chrono>
20 #include <condition_variable>
21 #include <fstream>
22 #include <thread>
23
24 #include <errno.h>
25 #include <sys/inotify.h>
26
27 #include <android-base/logging.h>
28 #include <utils/SystemClock.h>
29
30 #include "Utils.h"
31 #include "vhal_v2_0/VehicleUtils.h"
32
33 namespace android::hardware::automotive::vehicle::V2_0::impl {
34
35 using std::chrono::duration_cast;
36 using std::chrono::steady_clock;
37 using std::literals::chrono_literals::operator""s;
38
39 class GarageModeServerSideHandlerImpl : public GarageModeServerSideHandler {
40 public:
GarageModeServerSideHandlerImpl(IVehicleServer * vehicleServer,VehiclePropValuePool * vehicleObjectPool,const std::string & powerStateMarkerFilePath)41 GarageModeServerSideHandlerImpl(IVehicleServer* vehicleServer,
42 VehiclePropValuePool* vehicleObjectPool,
43 const std::string& powerStateMarkerFilePath)
44 : mVehicleServer(vehicleServer),
45 mValueObjectPool(vehicleObjectPool),
46 mPowerStateMarkerPath(powerStateMarkerFilePath) {
47 mThreads.emplace_back(std::bind(&GarageModeServerSideHandlerImpl::PowerStateWatcher, this));
48 mThreads.emplace_back(
49 std::bind(&GarageModeServerSideHandlerImpl::HeartbeatTimeoutWatcher, this));
50 }
51
~GarageModeServerSideHandlerImpl()52 ~GarageModeServerSideHandlerImpl() {
53 mShuttingDownFlag.store(true);
54 mHeartbeatCV.notify_all();
55 for (auto& thread : mThreads) {
56 if (thread.joinable()) {
57 thread.join();
58 }
59 }
60 }
61
62 void HandleHeartbeat() override;
63
64 private:
65 void HeartbeatTimeoutWatcher();
66
67 void PowerStateWatcher();
68
69 void HandleNewPowerState();
70
71 recyclable_ptr<VehiclePropValue> CreateApPowerStateReq(VehicleApPowerStateReq state,
72 int32_t param);
73
74 IVehicleServer* const mVehicleServer;
75 VehiclePropValuePool* const mValueObjectPool;
76
77 // TODO(chenhaosjtuacm): use std::filesystem when toolchain >= gcc8 is available
78 const std::string mPowerStateMarkerPath;
79
80 std::atomic<bool> mSystemShuttingDownPrepareFlag{false};
81 std::atomic<bool> mShuttingDownFlag{false};
82 std::atomic<steady_clock::time_point> mLastHeartbeatTime{};
83 std::vector<std::thread> mThreads;
84 std::condition_variable mHeartbeatCV;
85 std::mutex mHeartbeatMutex;
86 };
87
HandleHeartbeat()88 void GarageModeServerSideHandlerImpl::HandleHeartbeat() {
89 LOG(DEBUG) << __func__ << ": received heartbeat from the client";
90 mLastHeartbeatTime.store(steady_clock::now());
91 }
92
HeartbeatTimeoutWatcher()93 void GarageModeServerSideHandlerImpl::HeartbeatTimeoutWatcher() {
94 constexpr auto kHeartbeatTimeout = duration_cast<steady_clock::duration>(5s);
95 constexpr auto kHeartbeatCheckPeriod = 1s;
96 while (!mShuttingDownFlag.load()) {
97 if (!mSystemShuttingDownPrepareFlag.load()) {
98 std::unique_lock<std::mutex> heartbeatLock(mHeartbeatMutex);
99 mHeartbeatCV.wait(heartbeatLock, [this]() {
100 return mSystemShuttingDownPrepareFlag.load() || mShuttingDownFlag.load();
101 });
102
103 // Reset mLastHeartbeatTime everytime after entering shutdown state
104 HandleHeartbeat();
105 }
106 auto timeSinceLastHeartbeat = steady_clock::now() - mLastHeartbeatTime.load();
107 if (timeSinceLastHeartbeat > kHeartbeatTimeout) {
108 LOG(ERROR) << __func__ << ": heartbeat timeout!";
109 // TODO(chenhaosjtuacm): Shutdown AGL
110 break;
111 }
112 std::this_thread::sleep_for(kHeartbeatCheckPeriod);
113 }
114 }
115
PowerStateWatcher()116 void GarageModeServerSideHandlerImpl::PowerStateWatcher() {
117 constexpr auto kFileStatusCheckPeriod = 1s;
118
119 bool log_marker_file_not_exists_message_once = false;
120 bool log_marker_file_no_access_message_once = false;
121 auto call_once = [](bool* once_flag, auto&& func) {
122 if (!*once_flag) {
123 *once_flag = true;
124 func();
125 }
126 };
127
128 while (access(mPowerStateMarkerPath.c_str(), F_OK | R_OK) < 0) {
129 if (errno == ENOENT) {
130 call_once(&log_marker_file_not_exists_message_once, [this]() {
131 LOG(ERROR) << __func__ << ": marker file " << mPowerStateMarkerPath
132 << " has not been created yet.";
133 });
134 } else {
135 call_once(&log_marker_file_no_access_message_once, [this]() {
136 LOG(ERROR) << __func__ << ": no read access to marker file "
137 << mPowerStateMarkerPath;
138 });
139 }
140 std::this_thread::sleep_for(kFileStatusCheckPeriod);
141 }
142
143 int inotifyFd = inotify_init();
144 if (inotifyFd < 0) {
145 LOG(ERROR) << __func__ << ": failed to open inotify instance: " << strerror(errno);
146 return;
147 }
148
149 int watchDescriptor = inotify_add_watch(inotifyFd, mPowerStateMarkerPath.c_str(), IN_MODIFY);
150 if (watchDescriptor < 0) {
151 LOG(ERROR) << __func__ << ": failed to watch file " << mPowerStateMarkerPath << " : "
152 << strerror(errno);
153 return;
154 }
155
156 alignas(alignof(struct inotify_event)) char inotifyEventBuffer[4096] = {0};
157 [[maybe_unused]] struct inotify_event& inotifyEvent =
158 *reinterpret_cast<struct inotify_event*>(inotifyEventBuffer);
159
160 HandleNewPowerState();
161 while (!mShuttingDownFlag.load()) {
162 if (!WaitForReadWithTimeout(inotifyFd, kFileStatusCheckPeriod)) {
163 continue;
164 }
165
166 auto eventReadLen = read(inotifyFd, inotifyEventBuffer, sizeof(inotifyEventBuffer));
167 if (eventReadLen < 0) {
168 LOG(ERROR) << __func__ << "failed to read the inotify event: " << strerror(errno);
169 return;
170 }
171 if (eventReadLen < static_cast<ssize_t>(sizeof(struct inotify_event))) {
172 LOG(ERROR) << __func__ << ": failed to read the full event, min event size: "
173 << sizeof(struct inotify_event) << ", read size: " << eventReadLen;
174 return;
175 }
176 HandleNewPowerState();
177 }
178 }
179
HandleNewPowerState()180 void GarageModeServerSideHandlerImpl::HandleNewPowerState() {
181 std::ifstream markerFileStream(mPowerStateMarkerPath);
182 std::string powerStateString;
183
184 markerFileStream >> powerStateString;
185 LOG(INFO) << __func__ << ": set power state to " << powerStateString;
186
187 if (powerStateString == "shutdown") {
188 mVehicleServer->onPropertyValueFromCar(
189 *CreateApPowerStateReq(VehicleApPowerStateReq::SHUTDOWN_PREPARE,
190 toInt(VehicleApPowerStateShutdownParam::CAN_SLEEP)),
191 true);
192 mSystemShuttingDownPrepareFlag.store(true);
193 mHeartbeatCV.notify_all();
194 } else if (powerStateString == "on") {
195 if (mSystemShuttingDownPrepareFlag.load()) {
196 mVehicleServer->onPropertyValueFromCar(
197 *CreateApPowerStateReq(VehicleApPowerStateReq::CANCEL_SHUTDOWN, 0), true);
198 mSystemShuttingDownPrepareFlag.store(false);
199 } else {
200 LOG(INFO) << __func__ << ": not in the shutdown state, nothing changed";
201 }
202 } else {
203 LOG(ERROR) << __func__ << ": unknown power state: " << powerStateString;
204 }
205 }
206
CreateApPowerStateReq(VehicleApPowerStateReq state,int32_t param)207 recyclable_ptr<VehiclePropValue> GarageModeServerSideHandlerImpl::CreateApPowerStateReq(
208 VehicleApPowerStateReq state, int32_t param) {
209 auto req = mValueObjectPool->obtain(VehiclePropertyType::INT32_VEC, 2);
210 req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
211 req->areaId = 0;
212 req->timestamp = elapsedRealtimeNano();
213 req->status = VehiclePropertyStatus::AVAILABLE;
214 req->value.int32Values[0] = toInt(state);
215 req->value.int32Values[1] = param;
216 return req;
217 }
218
makeGarageModeServerSideHandler(IVehicleServer * vehicleServer,VehiclePropValuePool * valueObjectPool,const std::string & powerStateMarkerFilePath)219 std::unique_ptr<GarageModeServerSideHandler> makeGarageModeServerSideHandler(
220 IVehicleServer* vehicleServer, VehiclePropValuePool* valueObjectPool,
221 const std::string& powerStateMarkerFilePath) {
222 return std::make_unique<GarageModeServerSideHandlerImpl>(vehicleServer, valueObjectPool,
223 powerStateMarkerFilePath);
224 }
225
226 } // namespace android::hardware::automotive::vehicle::V2_0::impl
227