blob: 71f9134a4acd1a4bc34def9fba78cc4cd723c0e7 [file] [log] [blame]
Andrew Geisslere426b582020-05-28 12:40:55 -05001#include "config.h"
2
3#include "chassis_state_manager.hpp"
4
5#include "xyz/openbmc_project/Common/error.hpp"
6#include "xyz/openbmc_project/State/Shutdown/Power/error.hpp"
7
Matt Spinlerbbbc0162020-11-11 14:43:50 -06008#include <fmt/format.h>
9
Andrew Geisslere426b582020-05-28 12:40:55 -050010#include <cereal/archives/json.hpp>
11#include <phosphor-logging/elog-errors.hpp>
12#include <phosphor-logging/log.hpp>
Andrew Geissler0029a5d2017-01-24 14:48:35 -060013#include <sdbusplus/bus.hpp>
William A. Kennington III09568ff2018-05-11 00:03:12 -070014#include <sdbusplus/exception.hpp>
William A. Kennington IIId998f822018-10-17 23:17:57 -070015#include <sdeventplus/event.hpp>
16#include <sdeventplus/exception.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050017
Andrew Geisslerf2b22e82021-03-12 14:47:03 -060018#include <filesystem>
Andrew Geisslere426b582020-05-28 12:40:55 -050019#include <fstream>
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -050020
Andrew Geisslera90a31a2016-12-13 16:16:28 -060021namespace phosphor
22{
23namespace state
24{
25namespace manager
26{
27
28// When you see server:: you know we're referencing our base class
29namespace server = sdbusplus::xyz::openbmc_project::State::server;
30
31using namespace phosphor::logging;
William A. Kennington IIId998f822018-10-17 23:17:57 -070032using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Aatir Manzur27115ae2019-07-23 16:25:38 -050033using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Blackout;
Josh D. King6838ea92017-04-11 13:39:18 -050034constexpr auto CHASSIS_STATE_POWEROFF_TGT = "obmc-chassis-poweroff@0.target";
Andrew Geissler58a18012018-01-19 19:36:05 -080035constexpr auto CHASSIS_STATE_HARD_POWEROFF_TGT =
36 "obmc-chassis-hard-poweroff@0.target";
Josh D. King6838ea92017-04-11 13:39:18 -050037constexpr auto CHASSIS_STATE_POWERON_TGT = "obmc-chassis-poweron@0.target";
Andrew Geissler0029a5d2017-01-24 14:48:35 -060038
Josh D. King697474c2017-03-02 11:15:55 -060039constexpr auto ACTIVE_STATE = "active";
40constexpr auto ACTIVATING_STATE = "activating";
41
Andrew Geisslerce80f242017-01-24 13:25:33 -060042/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080043const std::map<server::Chassis::Transition, std::string> SYSTEMD_TARGET_TABLE =
44 {
Andrew Geissler8cf2f9a2017-07-21 11:58:04 -050045 // Use the hard off target to ensure we shutdown immediately
46 {server::Chassis::Transition::Off, CHASSIS_STATE_HARD_POWEROFF_TGT},
Andrew Geissler58a18012018-01-19 19:36:05 -080047 {server::Chassis::Transition::On, CHASSIS_STATE_POWERON_TGT}};
Andrew Geisslerce80f242017-01-24 13:25:33 -060048
Andrew Geissler58a18012018-01-19 19:36:05 -080049constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
50constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Andrew Geisslerce80f242017-01-24 13:25:33 -060051constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
52
Josh D. King697474c2017-03-02 11:15:55 -060053constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
54constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
55
Andrew Geisslerf2b22e82021-03-12 14:47:03 -060056constexpr auto CHASSIS_ON_FILE = "/run/openbmc/chassis@%d-on";
57
Andrew Geissler0029a5d2017-01-24 14:48:35 -060058void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060059{
Andrew Geissler3a30b052019-05-14 15:54:37 -050060 try
61 {
62 auto method = this->bus.new_method_call(
63 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "Subscribe");
Andrew Geissler5b950272019-05-24 12:27:51 -050064 this->bus.call(method);
Andrew Geissler3a30b052019-05-14 15:54:37 -050065 }
Patrick Williams0a675212021-09-02 09:49:43 -050066 catch (const sdbusplus::exception::exception& ex)
Andrew Geissler3a30b052019-05-14 15:54:37 -050067 {
68 log<level::ERR>("Failed to subscribe to systemd signals",
69 entry("ERR=%s", ex.what()));
70 elog<InternalFailure>();
71 }
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060072
Andrew Geissler0029a5d2017-01-24 14:48:35 -060073 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060074}
75
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060076// TODO - Will be rewritten once sdbusplus client bindings are in place
77// and persistent storage design is in place and sdbusplus
78// has read property function
79void Chassis::determineInitialState()
80{
Patrick Williams2975e262020-05-13 18:01:09 -050081 std::variant<int> pgood = -1;
Andrew Geissler58a18012018-01-19 19:36:05 -080082 auto method = this->bus.new_method_call(
83 "org.openbmc.control.Power", "/org/openbmc/control/power0",
84 "org.freedesktop.DBus.Properties", "Get");
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060085
86 method.append("org.openbmc.control.Power", "pgood");
William A. Kennington III09568ff2018-05-11 00:03:12 -070087 try
88 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070089 auto reply = this->bus.call(method);
Anthony Wilson32c532e2018-10-25 21:56:07 -050090 reply.read(pgood);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070091
Patrick Williams37413dc2020-05-13 11:29:54 -050092 if (std::get<int>(pgood) == 1)
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070093 {
94 log<level::INFO>("Initial Chassis State will be On",
95 entry("CHASSIS_CURRENT_POWER_STATE=%s",
96 convertForMessage(PowerState::On).c_str()));
97 server::Chassis::currentPowerState(PowerState::On);
98 server::Chassis::requestedPowerTransition(Transition::On);
99 return;
100 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500101 else
102 {
103 // The system is off. If we think it should be on then
104 // we probably lost AC while up, so set a new state
105 // change time.
106 uint64_t lastTime;
107 PowerState lastState;
108
109 if (deserializeStateChangeTime(lastTime, lastState))
110 {
111 if (lastState == PowerState::On)
112 {
Aatir Manzur27115ae2019-07-23 16:25:38 -0500113 report<Blackout>();
Matt Spinler9eab9862018-07-11 14:13:52 -0500114 setStateChangeTime();
115 }
116 }
117 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700118 }
Patrick Williams0a675212021-09-02 09:49:43 -0500119 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700120 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700121 // It's acceptable for the pgood state service to not be available
122 // since it will notify us of the pgood state when it comes up.
123 if (e.name() != nullptr &&
124 strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
125 {
126 goto fail;
127 }
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600128
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700129 // Only log for unexpected error types.
130 log<level::ERR>("Error performing call to get pgood",
131 entry("ERROR=%s", e.what()));
132 goto fail;
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600133 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700134
135fail:
136 log<level::INFO>("Initial Chassis State will be Off",
137 entry("CHASSIS_CURRENT_POWER_STATE=%s",
138 convertForMessage(PowerState::Off).c_str()));
139 server::Chassis::currentPowerState(PowerState::Off);
140 server::Chassis::requestedPowerTransition(Transition::Off);
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600141
142 return;
143}
144
Andrew Geisslerce80f242017-01-24 13:25:33 -0600145void Chassis::executeTransition(Transition tranReq)
146{
147 auto sysdTarget = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
148
Andrew Geissler58a18012018-01-19 19:36:05 -0800149 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
150 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geisslerce80f242017-01-24 13:25:33 -0600151
152 method.append(sysdTarget);
153 method.append("replace");
154
155 this->bus.call_noreply(method);
156
157 return;
158}
159
Josh D. King697474c2017-03-02 11:15:55 -0600160bool Chassis::stateActive(const std::string& target)
161{
Patrick Williams2975e262020-05-13 18:01:09 -0500162 std::variant<std::string> currentState;
Josh D. King697474c2017-03-02 11:15:55 -0600163 sdbusplus::message::object_path unitTargetPath;
164
Andrew Geissler58a18012018-01-19 19:36:05 -0800165 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
166 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King697474c2017-03-02 11:15:55 -0600167
168 method.append(target);
Josh D. King697474c2017-03-02 11:15:55 -0600169
William A. Kennington III09568ff2018-05-11 00:03:12 -0700170 try
171 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500172 auto result = this->bus.call(method);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700173 result.read(unitTargetPath);
174 }
Patrick Williams0a675212021-09-02 09:49:43 -0500175 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700176 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500177 log<level::ERR>("Error in GetUnit call", entry("ERROR=%s", e.what()));
William A. Kennington III09568ff2018-05-11 00:03:12 -0700178 return false;
179 }
Josh D. King697474c2017-03-02 11:15:55 -0600180
Andrew Geissler58a18012018-01-19 19:36:05 -0800181 method = this->bus.new_method_call(
182 SYSTEMD_SERVICE,
183 static_cast<const std::string&>(unitTargetPath).c_str(),
184 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King697474c2017-03-02 11:15:55 -0600185
186 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
Josh D. King697474c2017-03-02 11:15:55 -0600187
Anthony Wilson32c532e2018-10-25 21:56:07 -0500188 try
Josh D. King697474c2017-03-02 11:15:55 -0600189 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500190 auto result = this->bus.call(method);
191 result.read(currentState);
192 }
Patrick Williams0a675212021-09-02 09:49:43 -0500193 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500194 {
195 log<level::ERR>("Error in ActiveState Get",
196 entry("ERROR=%s", e.what()));
Josh D. King697474c2017-03-02 11:15:55 -0600197 return false;
198 }
199
Patrick Williams37413dc2020-05-13 11:29:54 -0500200 const auto& currentStateStr = std::get<std::string>(currentState);
William A. Kennington III7a0689a2018-11-12 17:19:33 -0800201 return currentStateStr == ACTIVE_STATE ||
202 currentStateStr == ACTIVATING_STATE;
Josh D. King697474c2017-03-02 11:15:55 -0600203}
204
Patrick Williams8f8ba392017-05-05 15:47:39 -0500205int Chassis::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600206{
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600207 sdbusplus::message::object_path newStateObjPath;
208 std::string newStateUnit{};
209 std::string newStateResult{};
210
Andrew Geissler58a18012018-01-19 19:36:05 -0800211 // Read the msg and populate each variable
William A. Kennington III09568ff2018-05-11 00:03:12 -0700212 try
213 {
Andrew Geissler9b8af4f2019-09-12 14:19:14 -0500214 // newStateID is a throwaway that is needed in order to read the
215 // parameters that are useful out of the dbus message
216 uint32_t newStateID{};
William A. Kennington III09568ff2018-05-11 00:03:12 -0700217 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
218 }
Patrick Williams0a675212021-09-02 09:49:43 -0500219 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700220 {
221 log<level::ERR>("Error in state change - bad encoding",
222 entry("ERROR=%s", e.what()),
223 entry("REPLY_SIG=%s", msg.get_signature()));
224 return 0;
225 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600226
Andrew Geissler58a18012018-01-19 19:36:05 -0800227 if ((newStateUnit == CHASSIS_STATE_POWEROFF_TGT) &&
228 (newStateResult == "done") && (!stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600229 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930230 log<level::INFO>("Received signal that power OFF is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600231 this->currentPowerState(server::Chassis::PowerState::Off);
Matt Spinler9eab9862018-07-11 14:13:52 -0500232 this->setStateChangeTime();
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600233 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800234 else if ((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
235 (newStateResult == "done") &&
236 (stateActive(CHASSIS_STATE_POWERON_TGT)))
237 {
238 log<level::INFO>("Received signal that power ON is complete");
239 this->currentPowerState(server::Chassis::PowerState::On);
Matt Spinler9eab9862018-07-11 14:13:52 -0500240 this->setStateChangeTime();
Andrew Geisslerf2b22e82021-03-12 14:47:03 -0600241
242 // Remove temporary file which is utilized for scenarios where the
243 // BMC is rebooted while the chassis power is still on.
244 // This file is used to indicate to chassis related systemd services
245 // that the chassis is already on and they should skip running.
246 // Once the chassis state is back to on we can clear this file.
247 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
248 size++; // null
249 std::unique_ptr<char[]> chassisFile(new char[size]);
250 std::snprintf(chassisFile.get(), size, CHASSIS_ON_FILE, 0);
251 if (std::filesystem::exists(chassisFile.get()))
252 {
253 std::filesystem::remove(chassisFile.get());
254 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800255 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600256
257 return 0;
258}
259
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600260Chassis::Transition Chassis::requestedPowerTransition(Transition value)
261{
262
Matt Spinlerbbbc0162020-11-11 14:43:50 -0600263 log<level::INFO>(fmt::format("Change to Chassis Requested Power State: {}",
264 convertForMessage(value))
265 .c_str());
Andrew Geisslerce80f242017-01-24 13:25:33 -0600266 executeTransition(value);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600267 return server::Chassis::requestedPowerTransition(value);
268}
269
270Chassis::PowerState Chassis::currentPowerState(PowerState value)
271{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500272 PowerState chassisPowerState;
Matt Spinlerbbbc0162020-11-11 14:43:50 -0600273 log<level::INFO>(fmt::format("Change to Chassis Power State: {}",
274 convertForMessage(value))
275 .c_str());
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500276
277 chassisPowerState = server::Chassis::currentPowerState(value);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500278 pohTimer.setEnabled(chassisPowerState == PowerState::On);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500279 return chassisPowerState;
280}
281
Patrick Williams45a1ed72021-04-30 21:02:43 -0500282uint32_t Chassis::pohCounter(uint32_t value)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500283{
Patrick Williams45a1ed72021-04-30 21:02:43 -0500284 if (value != pohCounter())
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500285 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500286 ChassisInherit::pohCounter(value);
Matt Spinler81957842018-07-11 10:37:12 -0500287 serializePOH();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500288 }
Patrick Williams45a1ed72021-04-30 21:02:43 -0500289 return pohCounter();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500290}
291
Patrick Williams45a1ed72021-04-30 21:02:43 -0500292void Chassis::pohCallback()
William A. Kennington IIId998f822018-10-17 23:17:57 -0700293{
294 if (ChassisInherit::currentPowerState() == PowerState::On)
295 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500296 pohCounter(pohCounter() + 1);
William A. Kennington IIId998f822018-10-17 23:17:57 -0700297 }
298}
299
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500300void Chassis::restorePOHCounter()
301{
302 uint32_t counter;
Matt Spinler81957842018-07-11 10:37:12 -0500303 if (!deserializePOH(POH_COUNTER_PERSIST_PATH, counter))
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500304 {
305 // set to default value
Patrick Williams45a1ed72021-04-30 21:02:43 -0500306 pohCounter(0);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500307 }
308 else
309 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500310 pohCounter(counter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500311 }
312}
313
Matt Spinler81957842018-07-11 10:37:12 -0500314fs::path Chassis::serializePOH(const fs::path& path)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500315{
316 std::ofstream os(path.c_str(), std::ios::binary);
317 cereal::JSONOutputArchive oarchive(os);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500318 oarchive(pohCounter());
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500319 return path;
320}
321
Patrick Williams45a1ed72021-04-30 21:02:43 -0500322bool Chassis::deserializePOH(const fs::path& path, uint32_t& pohCounter)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500323{
324 try
325 {
326 if (fs::exists(path))
327 {
328 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
329 cereal::JSONInputArchive iarchive(is);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500330 iarchive(pohCounter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500331 return true;
332 }
333 return false;
334 }
335 catch (cereal::Exception& e)
336 {
337 log<level::ERR>(e.what());
338 fs::remove(path);
339 return false;
340 }
341 catch (const fs::filesystem_error& e)
342 {
343 return false;
344 }
345
346 return false;
347}
348
349void Chassis::startPOHCounter()
350{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500351 auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
352 fs::create_directories(dir);
353
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500354 try
355 {
William A. Kennington IIId998f822018-10-17 23:17:57 -0700356 auto event = sdeventplus::Event::get_default();
357 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
358 event.loop();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500359 }
William A. Kennington IIId998f822018-10-17 23:17:57 -0700360 catch (const sdeventplus::SdEventError& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500361 {
William A. Kennington IIId998f822018-10-17 23:17:57 -0700362 log<level::ERR>("Error occurred during the sdeventplus loop",
363 entry("ERROR=%s", e.what()));
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500364 phosphor::logging::commit<InternalFailure>();
365 }
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600366}
367
Matt Spinler9eab9862018-07-11 14:13:52 -0500368void Chassis::serializeStateChangeTime()
369{
370 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
371 std::ofstream os(path.c_str(), std::ios::binary);
372 cereal::JSONOutputArchive oarchive(os);
373
374 oarchive(ChassisInherit::lastStateChangeTime(),
375 ChassisInherit::currentPowerState());
376}
377
378bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
379{
380 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
381
382 try
383 {
384 if (fs::exists(path))
385 {
386 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
387 cereal::JSONInputArchive iarchive(is);
388 iarchive(time, state);
389 return true;
390 }
391 }
392 catch (std::exception& e)
393 {
394 log<level::ERR>(e.what());
395 fs::remove(path);
396 }
397
398 return false;
399}
400
401void Chassis::restoreChassisStateChangeTime()
402{
403 uint64_t time;
404 PowerState state;
405
406 if (!deserializeStateChangeTime(time, state))
407 {
408 ChassisInherit::lastStateChangeTime(0);
409 }
410 else
411 {
412 ChassisInherit::lastStateChangeTime(time);
413 }
414}
415
416void Chassis::setStateChangeTime()
417{
418 using namespace std::chrono;
419 uint64_t lastTime;
420 PowerState lastState;
421
422 auto now =
423 duration_cast<milliseconds>(system_clock::now().time_since_epoch())
424 .count();
425
426 // If power is on when the BMC is rebooted, this function will get called
427 // because sysStateChange() runs. Since the power state didn't change
428 // in this case, neither should the state change time, so check that
429 // the power state actually did change here.
430 if (deserializeStateChangeTime(lastTime, lastState))
431 {
432 if (lastState == ChassisInherit::currentPowerState())
433 {
434 return;
435 }
436 }
437
438 ChassisInherit::lastStateChangeTime(now);
439 serializeStateChangeTime();
440}
441
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600442} // namespace manager
443} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700444} // namespace phosphor