Check OperatingSystemStatus to determine POST done.

updateBiosDone property in service xyz.openbmc_project.Host.Misc.Manager
is used to determine the POST done. But this service has Intel specific
dependencies. So if this service is not available, we can use property
OperatingSystemState in xyz.openbmc_project.State.OperatingSystem
service. According to x86-power-control repo, OperatingSystemState
should return one of "CBoot", "PXEBoot", "DiagBoot", "CDROMBoot",
"ROMBoot", "BootComplete" or "Standby" once the POST is asserted. Only
"Inactive" indicates that POST is not done.

Tested:
Tested this on the BMC and verified that the host state  changes to
postComplete

Signed-off-by: kasunath <kasunath@google.com>
Change-Id: Ia9c6edf2305ef83587e187d1cd508e0024c052a5
diff --git a/src/cpuinfo_utils.cpp b/src/cpuinfo_utils.cpp
index 96e8e6f..e30a275 100644
--- a/src/cpuinfo_utils.cpp
+++ b/src/cpuinfo_utils.cpp
@@ -18,6 +18,7 @@
 #include <boost/algorithm/string/predicate.hpp>
 #include <sdbusplus/asio/property.hpp>
 #include <xyz/openbmc_project/State/Host/server.hpp>
+#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
 
 #include <iostream>
 #include <type_traits>
@@ -29,9 +30,11 @@
 
 using namespace sdbusplus::xyz::openbmc_project;
 using PowerState = State::server::Host::HostState;
+using OsState = State::OperatingSystem::server::Status::OSStatus;
 
 HostState hostState = HostState::off;
 static PowerState powerState = PowerState::Off;
+static OsState osState = OsState::Inactive;
 static bool biosDone = false;
 
 static std::shared_ptr<sdbusplus::asio::connection> dbusConn;
@@ -46,8 +49,16 @@
         // since the two signals come from different services and there is no
         // tight guarantee about their relationship.
         biosDone = false;
+        // Setting osState to inactive for the same reason as above.
+        osState = OsState::Inactive;
     }
-    else if (!biosDone)
+    // Both biosDone and OsState tell us about the POST done status. At least
+    // one of them should indicate that the POST is done.
+    // According to openbmc_project/State/OperatingSystem/Status.interface.yaml
+    // Only "Inactive" indicates that the POST is not done. All the other
+    // statuses (CBoot, PXEBoot, DiagBoot, CDROMBoot, ROMBoot, BootComplete,
+    // Standby) indicate that the POST is done.
+    else if ((!biosDone) && (osState == OsState::Inactive))
     {
         hostState = HostState::postInProgress;
     }
@@ -70,6 +81,37 @@
     updateHostState();
 }
 
+void updateOsState(const std::string& newState)
+{
+    // newState might not contain the full path. It might just contain the enum
+    // string (By the time I am writing this, its not returning the full path).
+    // Full string:
+    // "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby". Just
+    // the string for enum: "Standby". If the newState doesn't contain the full
+    // string, convertOSStatusFromString will fail. Prepend the full path if
+    // needed.
+    std::string full_path = newState;
+    if (newState.find("xyz.") == std::string::npos)
+    {
+        full_path =
+            "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus." +
+            newState;
+    }
+
+    try
+    {
+        osState =
+            State::OperatingSystem::server::Status::convertOSStatusFromString(
+                full_path);
+    }
+    catch (const sdbusplus::exception::InvalidEnumString& ex)
+    {
+        std::cerr << "Invalid OperatingSystem Status: " << full_path << "\n";
+        osState = OsState::Inactive;
+    }
+    updateHostState();
+}
+
 /**
  * Register a handler to be called whenever the given property is changed. Also
  * call the handler once immediately (asynchronously) with the current property
@@ -233,6 +275,15 @@
                         "/xyz/openbmc_project/misc/platform_state",
                         "xyz.openbmc_project.State.Host.Misc", "CoreBiosDone",
                         updateBiosDone);
+    // xyz.openbmc_project.Host.Misc.Manager has Intel specific dependencies.
+    // If it is not available, then we can use the OperatingSystemState in
+    // xyz.openbmc_project.State.OperatingSystem. According to x86-power-control
+    // repo, OperatingSystemState should return "standby" once the POST is
+    // asserted.
+    subscribeToProperty("xyz.openbmc_project.State.OperatingSystem",
+                        "/xyz/openbmc_project/state/os",
+                        "xyz.openbmc_project.State.OperatingSystem.Status",
+                        "OperatingSystemState", updateOsState);
 
     initialized = true;
 }