• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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