aboutsummaryrefslogtreecommitdiffstats
path: root/brillo/dbus/exported_property_set.cc
blob: 018843e9594b1d13585f0e3e895335f73b8f5a0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <brillo/dbus/exported_property_set.h>

#include <base/bind.h>
#include <dbus/bus.h>
#include <dbus/property.h>  // For kPropertyInterface

#include <brillo/dbus/async_event_sequencer.h>
#include <brillo/dbus/dbus_object.h>
#include <brillo/errors/error_codes.h>

using brillo::dbus_utils::AsyncEventSequencer;

namespace brillo {

namespace dbus_utils {

ExportedPropertySet::ExportedPropertySet(dbus::Bus* bus)
    : bus_(bus), weak_ptr_factory_(this) {
}

void ExportedPropertySet::OnPropertiesInterfaceExported(
    DBusInterface* prop_interface) {
  signal_properties_changed_ =
      prop_interface->RegisterSignalOfType<SignalPropertiesChanged>(
          dbus::kPropertiesChanged);
}

ExportedPropertySet::PropertyWriter ExportedPropertySet::GetPropertyWriter(
    const std::string& interface_name) {
  return base::Bind(&ExportedPropertySet::WritePropertiesToDict,
                    weak_ptr_factory_.GetWeakPtr(),
                    interface_name);
}

void ExportedPropertySet::RegisterProperty(
    const std::string& interface_name,
    const std::string& property_name,
    ExportedPropertyBase* exported_property) {
  bus_->AssertOnOriginThread();
  auto& prop_map = properties_[interface_name];
  auto res = prop_map.insert(std::make_pair(property_name, exported_property));
  CHECK(res.second) << "Property '" << property_name << "' already exists";
  // Technically, the property set exists longer than the properties themselves,
  // so we could use Unretained here rather than a weak pointer.
  ExportedPropertyBase::OnUpdateCallback cb =
      base::Bind(&ExportedPropertySet::HandlePropertyUpdated,
                 weak_ptr_factory_.GetWeakPtr(),
                 interface_name,
                 property_name);
  exported_property->SetUpdateCallback(cb);
}

void ExportedPropertySet::UnregisterProperty(const std::string& interface_name,
                                             const std::string& property_name) {
  bus_->AssertOnOriginThread();
  auto& prop_map = properties_[interface_name];
  auto prop_iter = prop_map.find(property_name);
  CHECK(prop_iter != prop_map.end())
      << "Property '" << property_name << "' doesn't exist";
  prop_iter->second->ClearUpdateCallback();
  prop_map.erase(prop_iter);
}

VariantDictionary ExportedPropertySet::HandleGetAll(
    const std::string& interface_name) {
  bus_->AssertOnOriginThread();
  return GetInterfaceProperties(interface_name);
}

VariantDictionary ExportedPropertySet::GetInterfaceProperties(
    const std::string& interface_name) const {
  VariantDictionary properties;
  auto property_map_itr = properties_.find(interface_name);
  if (property_map_itr != properties_.end()) {
    for (const auto& kv : property_map_itr->second)
      properties.insert(std::make_pair(kv.first, kv.second->GetValue()));
  }
  return properties;
}

void ExportedPropertySet::WritePropertiesToDict(
    const std::string& interface_name,
    VariantDictionary* dict) {
  *dict = GetInterfaceProperties(interface_name);
}

bool ExportedPropertySet::HandleGet(brillo::ErrorPtr* error,
                                    const std::string& interface_name,
                                    const std::string& property_name,
                                    brillo::Any* result) {
  bus_->AssertOnOriginThread();
  auto property_map_itr = properties_.find(interface_name);
  if (property_map_itr == properties_.end()) {
    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
                         DBUS_ERROR_UNKNOWN_INTERFACE,
                         "No such interface on object.");
    return false;
  }
  LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
  auto property_itr = property_map_itr->second.find(property_name);
  if (property_itr == property_map_itr->second.end()) {
    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
                         DBUS_ERROR_UNKNOWN_PROPERTY,
                         "No such property on interface.");
    return false;
  }
  *result = property_itr->second->GetValue();
  return true;
}

bool ExportedPropertySet::HandleSet(brillo::ErrorPtr* error,
                                    const std::string& interface_name,
                                    const std::string& property_name,
                                    const brillo::Any& value) {
  bus_->AssertOnOriginThread();
  auto property_map_itr = properties_.find(interface_name);
  if (property_map_itr == properties_.end()) {
    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
                         DBUS_ERROR_UNKNOWN_INTERFACE,
                         "No such interface on object.");
    return false;
  }
  LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
  auto property_itr = property_map_itr->second.find(property_name);
  if (property_itr == property_map_itr->second.end()) {
    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
                         DBUS_ERROR_UNKNOWN_PROPERTY,
                         "No such property on interface.");
    return false;
  }

  return property_itr->second->SetValue(error, value);
}

void ExportedPropertySet::HandlePropertyUpdated(
    const std::string& interface_name,
    const std::string& property_name,
    const ExportedPropertyBase* exported_property) {
  bus_->AssertOnOriginThread();
  // Send signal only if the object has been exported successfully.
  // This could happen when a property value is changed (which triggers
  // the notification) before D-Bus interface is completely exported/claimed.
  auto signal = signal_properties_changed_.lock();
  if (!signal)
    return;
  VariantDictionary changed_properties{
      {property_name, exported_property->GetValue()}};
  // The interface specification tells us to include this list of properties
  // which have changed, but for whom no value is conveyed.  Currently, we
  // don't do anything interesting here.
  std::vector<std::string> invalidated_properties;  // empty.
  signal->Send(interface_name, changed_properties, invalidated_properties);
}

void ExportedPropertyBase::NotifyPropertyChanged() {
  // These is a brief period after the construction of an ExportedProperty
  // when this callback is not initialized because the property has not
  // been registered with the parent ExportedPropertySet.  During this period
  // users should be initializing values via SetValue, and no notifications
  // should be triggered by the ExportedPropertySet.
  if (!on_update_callback_.is_null()) {
    on_update_callback_.Run(this);
  }
}

void ExportedPropertyBase::SetUpdateCallback(const OnUpdateCallback& cb) {
  on_update_callback_ = cb;
}

void ExportedPropertyBase::ClearUpdateCallback() {
  on_update_callback_.Reset();
}

void ExportedPropertyBase::SetAccessMode(
    ExportedPropertyBase::Access access_mode) {
  access_mode_ = access_mode;
}

ExportedPropertyBase::Access ExportedPropertyBase::GetAccessMode() const {
  return access_mode_;
}

}  // namespace dbus_utils

}  // namespace brillo