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