1 /**
2 * Copyright © 2024 IBM Corporation
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 "dbus_interfaces_finder.hpp"
18
19 #include <algorithm>
20 #include <exception>
21 #include <map>
22 #include <utility>
23
24 namespace phosphor::power::util
25 {
26
DBusInterfacesFinder(sdbusplus::bus_t & bus,const std::string & service,const std::vector<std::string> & interfaces,Callback callback)27 DBusInterfacesFinder::DBusInterfacesFinder(
28 sdbusplus::bus_t& bus, const std::string& service,
29 const std::vector<std::string>& interfaces, Callback callback) :
30 bus{bus}, service{service}, interfaces{interfaces},
31 callback{std::move(callback)},
32 match{bus,
33 sdbusplus::bus::match::rules::interfacesAdded() +
34 sdbusplus::bus::match::rules::sender(service),
35 std::bind(&DBusInterfacesFinder::interfacesAddedCallback, this,
36 std::placeholders::_1)}
37 {
38 findInterfaces();
39 }
40
interfacesAddedCallback(sdbusplus::message_t & message)41 void DBusInterfacesFinder::interfacesAddedCallback(
42 sdbusplus::message_t& message)
43 {
44 // Exit if message is invalid
45 if (!message)
46 {
47 return;
48 }
49
50 try
51 {
52 // Read the D-Bus message
53 sdbusplus::message::object_path path;
54 std::map<std::string, std::map<std::string, util::DbusVariant>>
55 interfaces;
56 message.read(path, interfaces);
57
58 // Call callback for interfaces that we are looking for
59 for (const auto& [interface, properties] : interfaces)
60 {
61 if (std::ranges::contains(this->interfaces, interface))
62 {
63 callback(path, interface, properties);
64 }
65 }
66 }
67 catch (const std::exception&)
68 {
69 // Error trying to read InterfacesAdded message. One possible cause
70 // could be a property whose value is an unexpected data type.
71 }
72 }
73
findInterfaces()74 void DBusInterfacesFinder::findInterfaces()
75 {
76 try
77 {
78 // Use ObjectMapper to find interface instances that already exist
79 auto objects = util::getSubTree(bus, "/", interfaces, 0);
80
81 // Search for matching interfaces in returned objects
82 for (const auto& [path, services] : objects)
83 {
84 for (const auto& [service, interfaces] : services)
85 {
86 if (service == this->service)
87 {
88 for (const auto& interface : interfaces)
89 {
90 if (std::ranges::contains(this->interfaces, interface))
91 {
92 auto properties = util::getAllProperties(
93 bus, path, interface, service);
94 callback(path, interface, properties);
95 }
96 }
97 }
98 }
99 }
100 }
101 catch (const std::exception&)
102 {
103 // Interface instances might not be available yet
104 }
105 }
106
107 } // namespace phosphor::power::util
108