1 #pragma once 2 3 #include <sdbusplus/message.hpp> 4 #include <sdbusplus/bus/match.hpp> 5 #include <vector> 6 #include "data_types.hpp" 7 #include "propertywatch.hpp" 8 9 namespace phosphor 10 { 11 namespace dbus 12 { 13 namespace monitoring 14 { 15 16 static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 17 static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 18 static constexpr auto MAPPER_INTERFACE = 19 "xyz.openbmc_project.ObjectMapper"; 20 21 using MappedPropertyIndex = 22 RefKeyMap<const std::string, 23 RefKeyMap<const std::string, 24 RefVector<const std::string>>>; 25 26 MappedPropertyIndex convert(const PropertyIndex& index); 27 28 template <typename DBusInterfaceType> 29 void PropertyWatch<DBusInterfaceType>::start() 30 { 31 if (alreadyRan) 32 { 33 return; 34 } 35 36 // The index has a flat layout which is not optimal here. Nest 37 // properties in a map of interface names in a map of object paths. 38 auto mapped = convert(index); 39 40 for (const auto& m : mapped) 41 { 42 const auto& path = m.first.get(); 43 const auto& interfaces = m.second; 44 45 // Watch for new interfaces on this path. 46 DBusInterfaceType::addMatch( 47 sdbusplus::bus::match::rules::interfacesAdded(path), 48 [this](auto & msg) 49 // *INDENT-OFF* 50 { 51 this->interfacesAdded(msg); 52 }); 53 // *INDENT-ON* 54 55 // Do a query to populate the cache. Start with a mapper query. 56 // The specific services are queried below. 57 const std::vector<std::string> queryInterfaces; // all interfaces 58 auto mapperResp = 59 DBusInterfaceType::template callMethodAndRead<GetObject>( 60 MAPPER_BUSNAME, 61 MAPPER_PATH, 62 MAPPER_INTERFACE, 63 "GetObject", 64 path, 65 queryInterfaces); 66 67 for (const auto& i : interfaces) 68 { 69 const auto& interface = i.first.get(); 70 71 // Watch for property changes on this interface. 72 DBusInterfaceType::addMatch( 73 sdbusplus::bus::match::rules::propertiesChanged( 74 path, interface), 75 [this](auto & msg) 76 // *INDENT-OFF* 77 { 78 std::string interface; 79 msg.read(interface); 80 auto path = msg.get_path(); 81 this->propertiesChanged(msg, path, interface); 82 }); 83 // *INDENT-ON* 84 85 // The mapper response is a busname:[interfaces] map. Look for 86 // each interface in the index and if found, query the service and 87 // populate the cache entries for the interface. 88 for (const auto& mr : mapperResp) 89 { 90 const auto& busName = mr.first; 91 const auto& mapperInterfaces = mr.second; 92 if (mapperInterfaces.end() == std::find( 93 mapperInterfaces.begin(), 94 mapperInterfaces.end(), 95 interface)) 96 { 97 // This interface isn't being watched. 98 continue; 99 } 100 101 // Delegate type specific property updates to subclasses. 102 updateProperties(busName, path, interface); 103 } 104 } 105 } 106 107 alreadyRan = true; 108 } 109 110 template <typename T, typename DBusInterfaceType> 111 void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties( 112 const std::string& busName, 113 const std::string& path, 114 const std::string& interface) 115 { 116 auto properties = 117 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>( 118 busName.c_str(), 119 path.c_str(), 120 "org.freedesktop.DBus.Properties", 121 "GetAll", 122 interface); 123 propertiesChanged(path, interface, properties); 124 } 125 126 template <typename T, typename DBusInterfaceType> 127 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged( 128 const std::string& path, 129 const std::string& interface, 130 const PropertiesChanged<T>& properties) 131 { 132 // Update the cache for any watched properties. 133 for (const auto& p : properties) 134 { 135 auto key = std::make_tuple(path, interface, p.first); 136 auto item = this->index.find(key); 137 if (item == this->index.end()) 138 { 139 // This property isn't being watched. 140 continue; 141 } 142 143 std::get<2>(item->second).get() = p.second.template get<T>(); 144 } 145 } 146 147 template <typename T, typename DBusInterfaceType> 148 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged( 149 sdbusplus::message::message& msg, 150 const std::string& path, 151 const std::string& interface) 152 { 153 PropertiesChanged<T> properties; 154 msg.read(properties); 155 propertiesChanged(path, interface, properties); 156 } 157 158 template <typename T, typename DBusInterfaceType> 159 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded( 160 const std::string& path, 161 const InterfacesAdded<T>& interfaces) 162 { 163 for (const auto& i : interfaces) 164 { 165 propertiesChanged(path, i.first, i.second); 166 } 167 } 168 169 template <typename T, typename DBusInterfaceType> 170 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded( 171 sdbusplus::message::message& msg) 172 { 173 sdbusplus::message::object_path path; 174 InterfacesAdded<T> interfaces; 175 msg.read(path, interfaces); 176 interfacesAdded(path, interfaces); 177 } 178 179 } // namespace monitoring 180 } // namespace dbus 181 } // namespace phosphor 182