summaryrefslogtreecommitdiff
path: root/chromium/dbus
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@theqtcompany.com>2014-12-05 15:04:29 +0100
committerAndras Becsi <andras.becsi@theqtcompany.com>2014-12-09 10:49:28 +0100
commitaf6588f8d723931a298c995fa97259bb7f7deb55 (patch)
tree060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/dbus
parent2fff84d821cc7b1c785f6404e0f8091333283e74 (diff)
downloadqtwebengine-chromium-af6588f8d723931a298c995fa97259bb7f7deb55.tar.gz
BASELINE: Update chromium to 40.0.2214.28 and ninja to 1.5.3.
Change-Id: I759465284fd64d59ad120219cbe257f7402c4181 Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/dbus')
-rw-r--r--chromium/dbus/BUILD.gn16
-rw-r--r--chromium/dbus/bus.cc55
-rw-r--r--chromium/dbus/bus.h18
-rw-r--r--chromium/dbus/dbus.gyp4
-rw-r--r--chromium/dbus/dbus_export.h13
-rw-r--r--chromium/dbus/dbus_statistics_unittest.cc4
-rw-r--r--chromium/dbus/end_to_end_async_unittest.cc49
-rw-r--r--chromium/dbus/exported_object.cc14
-rw-r--r--chromium/dbus/message.cc10
-rw-r--r--chromium/dbus/message.h5
-rw-r--r--chromium/dbus/message_unittest.cc37
-rw-r--r--chromium/dbus/mock_object_proxy.h13
-rw-r--r--chromium/dbus/mock_unittest.cc44
-rw-r--r--chromium/dbus/object_manager.cc239
-rw-r--r--chromium/dbus/object_manager.h41
-rw-r--r--chromium/dbus/object_manager_unittest.cc93
-rw-r--r--chromium/dbus/object_proxy.cc51
-rw-r--r--chromium/dbus/object_proxy.h18
-rw-r--r--chromium/dbus/object_proxy_unittest.cc4
-rw-r--r--chromium/dbus/property.cc20
-rw-r--r--chromium/dbus/property.h14
-rw-r--r--chromium/dbus/property_unittest.cc15
-rw-r--r--chromium/dbus/scoped_dbus_error.cc21
-rw-r--r--chromium/dbus/scoped_dbus_error.h17
-rw-r--r--chromium/dbus/signal_sender_verification_unittest.cc64
-rw-r--r--chromium/dbus/test_service.cc23
-rw-r--r--chromium/dbus/test_service.h10
-rw-r--r--chromium/dbus/util.cc14
-rw-r--r--chromium/dbus/util.h28
-rw-r--r--chromium/dbus/util_unittest.cc16
30 files changed, 804 insertions, 166 deletions
diff --git a/chromium/dbus/BUILD.gn b/chromium/dbus/BUILD.gn
index 347bae0fbdf..830bd19406c 100644
--- a/chromium/dbus/BUILD.gn
+++ b/chromium/dbus/BUILD.gn
@@ -25,11 +25,14 @@ component("dbus") {
"object_proxy.h",
"property.cc",
"property.h",
+ "scoped_dbus_error.cc",
"scoped_dbus_error.h",
"string_util.cc",
"string_util.h",
"values_util.cc",
"values_util.h",
+ "util.cc",
+ "util.h",
]
defines = [
@@ -41,18 +44,19 @@ component("dbus") {
"//third_party/protobuf:protobuf_lite",
]
- direct_dependent_configs = [
+ public_configs = [
"//build/config/linux:dbus",
]
}
-proto_library("dbus_test_proto") {
+proto_library("test_proto") {
sources = [ "test_proto.proto" ]
}
# This target contains mocks that can be used to write unit tests without
# issuing actual D-Bus calls.
-source_set("dbus_test_support") {
+source_set("test_support") {
+ testonly = true
sources = [
"mock_bus.cc",
"mock_bus.h",
@@ -90,13 +94,14 @@ test("dbus_unittests") {
"string_util_unittest.cc",
"test_service.cc",
"test_service.h",
+ "util_unittest.cc",
"values_util_unittest.cc",
]
deps = [
":dbus",
- ":dbus_test_proto",
- ":dbus_test_support",
+ ":test_proto",
+ ":test_support",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
@@ -109,6 +114,7 @@ test("dbus_unittests") {
}
executable("dbus_test_server") {
+ testonly = true
sources = [
"test_server.cc",
"test_service.cc",
diff --git a/chromium/dbus/bus.cc b/chromium/dbus/bus.cc
index 28257f8c508..e9e77a5dcd4 100644
--- a/chromium/dbus/bus.cc
+++ b/chromium/dbus/bus.cc
@@ -84,13 +84,13 @@ class Watch : public base::MessagePumpLibevent::Watcher {
private:
// Implement MessagePumpLibevent::Watcher.
- virtual void OnFileCanReadWithoutBlocking(int file_descriptor) OVERRIDE {
+ virtual void OnFileCanReadWithoutBlocking(int file_descriptor) override {
const bool success = dbus_watch_handle(raw_watch_, DBUS_WATCH_READABLE);
CHECK(success) << "Unable to allocate memory";
}
// Implement MessagePumpLibevent::Watcher.
- virtual void OnFileCanWriteWithoutBlocking(int file_descriptor) OVERRIDE {
+ virtual void OnFileCanWriteWithoutBlocking(int file_descriptor) override {
const bool success = dbus_watch_handle(raw_watch_, DBUS_WATCH_WRITABLE);
CHECK(success) << "Unable to allocate memory";
}
@@ -267,7 +267,7 @@ bool Bus::RemoveObjectProxyWithOptions(const std::string& service_name,
if (iter != object_proxy_table_.end()) {
scoped_refptr<ObjectProxy> object_proxy = iter->second;
object_proxy_table_.erase(iter);
- // Object is present. Remove it now and Detach in the DBus thread.
+ // Object is present. Remove it now and Detach on the DBus thread.
GetDBusTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&Bus::RemoveObjectProxyInternal,
@@ -350,17 +350,54 @@ ObjectManager* Bus::GetObjectManager(const std::string& service_name,
return object_manager.get();
}
-void Bus::RemoveObjectManager(const std::string& service_name,
- const ObjectPath& object_path) {
+bool Bus::RemoveObjectManager(const std::string& service_name,
+ const ObjectPath& object_path,
+ const base::Closure& callback) {
AssertOnOriginThread();
+ DCHECK(!callback.is_null());
const ObjectManagerTable::key_type key(service_name + object_path.value());
ObjectManagerTable::iterator iter = object_manager_table_.find(key);
if (iter == object_manager_table_.end())
- return;
+ return false;
+ // ObjectManager is present. Remove it now and CleanUp on the DBus thread.
scoped_refptr<ObjectManager> object_manager = iter->second;
object_manager_table_.erase(iter);
+
+ GetDBusTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&Bus::RemoveObjectManagerInternal,
+ this, object_manager, callback));
+
+ return true;
+}
+
+void Bus::RemoveObjectManagerInternal(
+ scoped_refptr<dbus::ObjectManager> object_manager,
+ const base::Closure& callback) {
+ AssertOnDBusThread();
+ DCHECK(object_manager.get());
+
+ object_manager->CleanUp();
+
+ // The ObjectManager has to be deleted on the origin thread since it was
+ // created there.
+ GetOriginTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&Bus::RemoveObjectManagerInternalHelper,
+ this, object_manager, callback));
+}
+
+void Bus::RemoveObjectManagerInternalHelper(
+ scoped_refptr<dbus::ObjectManager> object_manager,
+ const base::Closure& callback) {
+ AssertOnOriginThread();
+ DCHECK(object_manager.get());
+
+ // Release the object manager and run the callback.
+ object_manager = NULL;
+ callback.Run();
}
void Bus::GetManagedObjects() {
@@ -460,6 +497,12 @@ void Bus::ShutdownAndBlock() {
iter->second->Detach();
}
+ // Clean up the object managers.
+ for (ObjectManagerTable::iterator iter = object_manager_table_.begin();
+ iter != object_manager_table_.end(); ++iter) {
+ iter->second->CleanUp();
+ }
+
// Release object proxies and exported objects here. We should do this
// here rather than in the destructor to avoid memory leaks due to
// cyclic references.
diff --git a/chromium/dbus/bus.h b/chromium/dbus/bus.h
index 647b1b72607..544d31fc169 100644
--- a/chromium/dbus/bus.h
+++ b/chromium/dbus/bus.h
@@ -354,9 +354,15 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
// will return a new object, method calls on any remaining copies of the
// previous object are not permitted.
//
+ // This method will asynchronously clean up any match rules that have been
+ // added for the object manager and invoke |callback| when the operation is
+ // complete. If this method returns false, then |callback| is never called.
+ // The |callback| argument must not be null.
+ //
// Must be called in the origin thread.
- virtual void RemoveObjectManager(const std::string& service_name,
- const ObjectPath& object_path);
+ virtual bool RemoveObjectManager(const std::string& service_name,
+ const ObjectPath& object_path,
+ const base::Closure& callback);
// Instructs all registered object managers to retrieve their set of managed
// objects from their respective remote objects. There is no need to call this
@@ -601,6 +607,14 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
void RemoveObjectProxyInternal(scoped_refptr<dbus::ObjectProxy> object_proxy,
const base::Closure& callback);
+ // Helper functions used for RemoveObjectManager().
+ void RemoveObjectManagerInternal(
+ scoped_refptr<dbus::ObjectManager> object_manager,
+ const base::Closure& callback);
+ void RemoveObjectManagerInternalHelper(
+ scoped_refptr<dbus::ObjectManager> object_manager,
+ const base::Closure& callback);
+
// Helper function used for UnregisterExportedObject().
void UnregisterExportedObjectInternal(
scoped_refptr<dbus::ExportedObject> exported_object);
diff --git a/chromium/dbus/dbus.gyp b/chromium/dbus/dbus.gyp
index 4d90497c936..daac2e26a3e 100644
--- a/chromium/dbus/dbus.gyp
+++ b/chromium/dbus/dbus.gyp
@@ -41,9 +41,12 @@
'object_proxy.h',
'property.cc',
'property.h',
+ 'scoped_dbus_error.cc',
'scoped_dbus_error.h',
'string_util.cc',
'string_util.h',
+ 'util.cc',
+ 'util.h',
'values_util.cc',
'values_util.h',
],
@@ -109,6 +112,7 @@
'string_util_unittest.cc',
'test_service.cc',
'test_service.h',
+ 'util_unittest.cc',
'values_util_unittest.cc',
],
'include_dirs': [
diff --git a/chromium/dbus/dbus_export.h b/chromium/dbus/dbus_export.h
index 0eda41a26fb..7c96d1738f6 100644
--- a/chromium/dbus/dbus_export.h
+++ b/chromium/dbus/dbus_export.h
@@ -10,16 +10,11 @@
// NOTE: We haven't used DBUS_EXPORT because it would conflict with the version
// from /usr/include/dbus-1.0/dbus/dbus-macros.h.
-#if defined(COMPONENT_BUILD)
#if defined(WIN32)
+#error dbus support is not currently expected to work on windows
+#endif // defined(WIN32)
-#if defined(DBUS_IMPLEMENTATION)
-#define CHROME_DBUS_EXPORT __declspec(dllexport)
-#else
-#define CHROME_DBUS_EXPORT __declspec(dllimport)
-#endif // defined(DBUS_IMPLEMENTATION)
-
-#else // !defined(WIN32)
+#if defined(COMPONENT_BUILD)
#if defined(DBUS_IMPLEMENTATION)
#define CHROME_DBUS_EXPORT __attribute__((visibility("default")))
@@ -27,8 +22,6 @@
#define CHROME_DBUS_EXPORT
#endif
-#endif // defined(WIN32)
-
#else // !defined(COMPONENT_BUILD)
#define CHROME_DBUS_EXPORT
diff --git a/chromium/dbus/dbus_statistics_unittest.cc b/chromium/dbus/dbus_statistics_unittest.cc
index 9a2e2a17435..0c0dd034972 100644
--- a/chromium/dbus/dbus_statistics_unittest.cc
+++ b/chromium/dbus/dbus_statistics_unittest.cc
@@ -15,11 +15,11 @@ class DBusStatisticsTest : public testing::Test {
DBusStatisticsTest() {
}
- virtual void SetUp() OVERRIDE {
+ virtual void SetUp() override {
statistics::Initialize();
}
- virtual void TearDown() OVERRIDE {
+ virtual void TearDown() override {
statistics::Shutdown();
}
diff --git a/chromium/dbus/end_to_end_async_unittest.cc b/chromium/dbus/end_to_end_async_unittest.cc
index fb8030bf4cb..15f410eadc0 100644
--- a/chromium/dbus/end_to_end_async_unittest.cc
+++ b/chromium/dbus/end_to_end_async_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread.h"
@@ -77,7 +78,8 @@ class EndToEndAsyncTest : public testing::Test {
base::Bind(&EndToEndAsyncTest::OnConnected,
base::Unretained(this)));
// Wait until the object proxy is connected to the signal.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
// Connect to the "Test2" signal of "org.chromium.TestInterface" from
// the remote object. There was a bug where we were emitting error
@@ -92,7 +94,8 @@ class EndToEndAsyncTest : public testing::Test {
base::Bind(&EndToEndAsyncTest::OnConnected,
base::Unretained(this)));
// Wait until the object proxy is connected to the signal.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
// Create a second object proxy for the root object.
root_object_proxy_ = bus_->GetObjectProxy("org.chromium.TestService",
@@ -109,7 +112,8 @@ class EndToEndAsyncTest : public testing::Test {
base::Bind(&EndToEndAsyncTest::OnConnected,
base::Unretained(this)));
// Wait until the root object proxy is connected to the signal.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop());
+ run_loop_->Run();
}
virtual void TearDown() {
@@ -172,7 +176,8 @@ class EndToEndAsyncTest : public testing::Test {
// Wait for the give number of responses.
void WaitForResponses(size_t num_responses) {
while (response_strings_.size() < num_responses) {
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
}
}
@@ -188,13 +193,14 @@ class EndToEndAsyncTest : public testing::Test {
} else {
response_strings_.push_back(std::string());
}
- message_loop_.Quit();
+ run_loop_->Quit();
};
// Wait for the given number of errors.
void WaitForErrors(size_t num_errors) {
while (error_names_.size() < num_errors) {
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
}
}
@@ -208,7 +214,7 @@ class EndToEndAsyncTest : public testing::Test {
} else {
error_names_.push_back(std::string());
}
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when the "Test" signal is received, in the main thread.
@@ -216,7 +222,7 @@ class EndToEndAsyncTest : public testing::Test {
void OnTestSignal(Signal* signal) {
MessageReader reader(signal);
ASSERT_TRUE(reader.PopString(&test_signal_string_));
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when the "Test" signal is received, in the main thread, by
@@ -225,13 +231,13 @@ class EndToEndAsyncTest : public testing::Test {
void OnRootTestSignal(Signal* signal) {
MessageReader reader(signal);
ASSERT_TRUE(reader.PopString(&root_test_signal_string_));
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when the "Test2" signal is received, in the main thread.
void OnTest2Signal(Signal* signal) {
MessageReader reader(signal);
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when connected to the signal.
@@ -239,22 +245,24 @@ class EndToEndAsyncTest : public testing::Test {
const std::string& signal_name,
bool success) {
ASSERT_TRUE(success);
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when the connection with dbus-daemon is disconnected.
void OnDisconnected() {
- message_loop_.Quit();
+ run_loop_->Quit();
++on_disconnected_call_count_;
}
// Wait for the hey signal to be received.
void WaitForTestSignal() {
// OnTestSignal() will quit the message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
}
base::MessageLoop message_loop_;
+ scoped_ptr<base::RunLoop> run_loop_;
std::vector<std::string> response_strings_;
std::vector<std::string> error_names_;
scoped_ptr<base::Thread> dbus_thread_;
@@ -537,10 +545,11 @@ TEST_F(EndToEndAsyncTest, EmptyResponseCallback) {
timeout_ms,
ObjectProxy::EmptyResponseCallback());
// Post a delayed task to quit the message loop.
+ run_loop_.reset(new base::RunLoop);
message_loop_.PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
+ run_loop_->QuitClosure(),
TestTimeouts::tiny_timeout());
- message_loop_.Run();
+ run_loop_->Run();
// We cannot tell if the empty callback is called, but at least we can
// check if the test does not crash.
}
@@ -584,7 +593,8 @@ TEST_F(EndToEndAsyncTest, DisconnectedSignal) {
base::Bind(&Bus::ClosePrivateConnection,
base::Unretained(bus_.get())));
// OnDisconnected callback quits message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
EXPECT_EQ(1, on_disconnected_call_count_);
}
@@ -608,7 +618,8 @@ class SignalMultipleHandlerTest : public EndToEndAsyncTest {
base::Bind(&SignalMultipleHandlerTest::OnAdditionalConnected,
base::Unretained(this)));
// Wait until the object proxy is connected to the signal.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
}
protected:
@@ -617,7 +628,7 @@ class SignalMultipleHandlerTest : public EndToEndAsyncTest {
void OnAdditionalTestSignal(Signal* signal) {
MessageReader reader(signal);
ASSERT_TRUE(reader.PopString(&additional_test_signal_string_));
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when connected to the signal.
@@ -625,7 +636,7 @@ class SignalMultipleHandlerTest : public EndToEndAsyncTest {
const std::string& signal_name,
bool success) {
ASSERT_TRUE(success);
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Text message from "Test" signal delivered to additional handler.
diff --git a/chromium/dbus/exported_object.cc b/chromium/dbus/exported_object.cc
index 1a4fbb50eb4..107d2e5dd17 100644
--- a/chromium/dbus/exported_object.cc
+++ b/chromium/dbus/exported_object.cc
@@ -15,6 +15,7 @@
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/scoped_dbus_error.h"
+#include "dbus/util.h"
namespace dbus {
@@ -23,15 +24,6 @@ namespace {
// Used for success ratio histograms. 1 for success, 0 for failure.
const int kSuccessRatioHistogramMaxValue = 2;
-// Gets the absolute method name by concatenating the interface name and
-// the method name. Used for building keys for method_table_ in
-// ExportedObject.
-std::string GetAbsoluteMethodName(
- const std::string& interface_name,
- const std::string& method_name) {
- return interface_name + "." + method_name;
-}
-
} // namespace
ExportedObject::ExportedObject(Bus* bus,
@@ -53,7 +45,7 @@ bool ExportedObject::ExportMethodAndBlock(
// Check if the method is already exported.
const std::string absolute_method_name =
- GetAbsoluteMethodName(interface_name, method_name);
+ GetAbsoluteMemberName(interface_name, method_name);
if (method_table_.find(absolute_method_name) != method_table_.end()) {
LOG(ERROR) << absolute_method_name << " is already exported";
return false;
@@ -203,7 +195,7 @@ DBusHandlerResult ExportedObject::HandleMessage(
}
// Check if we know about the method.
- const std::string absolute_method_name = GetAbsoluteMethodName(
+ const std::string absolute_method_name = GetAbsoluteMemberName(
interface, member);
MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
if (iter == method_table_.end()) {
diff --git a/chromium/dbus/message.cc b/chromium/dbus/message.cc
index c9219b7e52b..ddcf85f4f26 100644
--- a/chromium/dbus/message.cc
+++ b/chromium/dbus/message.cc
@@ -935,6 +935,16 @@ Message::DataType MessageReader::GetDataType() {
return static_cast<Message::DataType>(dbus_type);
}
+std::string MessageReader::GetDataSignature() {
+ std::string signature;
+ char* raw_signature = dbus_message_iter_get_signature(&raw_message_iter_);
+ if (raw_signature) {
+ signature = raw_signature;
+ dbus_free(raw_signature);
+ }
+ return signature;
+}
+
bool MessageReader::CheckDataType(int dbus_type) {
const int actual_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
if (actual_type != dbus_type) {
diff --git a/chromium/dbus/message.h b/chromium/dbus/message.h
index db3456acd0c..780e6c5b466 100644
--- a/chromium/dbus/message.h
+++ b/chromium/dbus/message.h
@@ -463,6 +463,11 @@ class CHROME_DBUS_EXPORT MessageReader {
// end of the message.
Message::DataType GetDataType();
+ // Get the DBus signature of the value at the current iterator position.
+ // An empty string will be returned if the iterator points to the end of
+ // the message.
+ std::string GetDataSignature();
+
private:
// Returns true if the data type at the current iterator position
// matches the given D-Bus type, such as DBUS_TYPE_BYTE.
diff --git a/chromium/dbus/message_unittest.cc b/chromium/dbus/message_unittest.cc
index 0c944d9d617..0eaea8395f5 100644
--- a/chromium/dbus/message_unittest.cc
+++ b/chromium/dbus/message_unittest.cc
@@ -24,6 +24,7 @@ TEST(MessageTest, AppendAndPopByte) {
MessageReader reader(message.get());
ASSERT_TRUE(reader.HasMoreData()); // Should have data to read.
ASSERT_EQ(Message::BYTE, reader.GetDataType());
+ ASSERT_EQ("y", reader.GetDataSignature());
bool bool_value = false;
// Should fail as the type is not bool here.
@@ -70,17 +71,29 @@ TEST(MessageTest, AppendAndPopBasicDataTypes) {
MessageReader reader(message.get());
ASSERT_TRUE(reader.HasMoreData());
+ ASSERT_EQ("y", reader.GetDataSignature());
ASSERT_TRUE(reader.PopByte(&byte_value));
+ ASSERT_EQ("b", reader.GetDataSignature());
ASSERT_TRUE(reader.PopBool(&bool_value));
+ ASSERT_EQ("n", reader.GetDataSignature());
ASSERT_TRUE(reader.PopInt16(&int16_value));
+ ASSERT_EQ("q", reader.GetDataSignature());
ASSERT_TRUE(reader.PopUint16(&uint16_value));
+ ASSERT_EQ("i", reader.GetDataSignature());
ASSERT_TRUE(reader.PopInt32(&int32_value));
+ ASSERT_EQ("u", reader.GetDataSignature());
ASSERT_TRUE(reader.PopUint32(&uint32_value));
+ ASSERT_EQ("x", reader.GetDataSignature());
ASSERT_TRUE(reader.PopInt64(&int64_value));
+ ASSERT_EQ("t", reader.GetDataSignature());
ASSERT_TRUE(reader.PopUint64(&uint64_value));
+ ASSERT_EQ("d", reader.GetDataSignature());
ASSERT_TRUE(reader.PopDouble(&double_value));
+ ASSERT_EQ("s", reader.GetDataSignature());
ASSERT_TRUE(reader.PopString(&string_value));
+ ASSERT_EQ("o", reader.GetDataSignature());
ASSERT_TRUE(reader.PopObjectPath(&object_path_value));
+ ASSERT_EQ("", reader.GetDataSignature());
ASSERT_FALSE(reader.HasMoreData());
// 0, 1, 2, 3, 4, 5, 6, 7, 8, "string", "/object/path" should be returned.
@@ -120,6 +133,8 @@ TEST(MessageTest, AppendAndPopFileDescriptor) {
MessageReader reader(message.get());
ASSERT_TRUE(reader.HasMoreData());
+ ASSERT_EQ(Message::UNIX_FD, reader.GetDataType());
+ ASSERT_EQ("h", reader.GetDataSignature());
ASSERT_TRUE(reader.PopFileDescriptor(&fd_value));
ASSERT_FALSE(reader.HasMoreData());
// Descriptor is not valid until explicitly checked.
@@ -171,17 +186,29 @@ TEST(MessageTest, AppendAndPopVariantDataTypes) {
MessageReader reader(message.get());
ASSERT_TRUE(reader.HasMoreData());
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfByte(&byte_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfBool(&bool_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfInt16(&int16_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfUint16(&uint16_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfInt32(&int32_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfUint32(&uint32_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfInt64(&int64_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfUint64(&uint64_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfDouble(&double_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfString(&string_value));
+ ASSERT_EQ("v", reader.GetDataSignature());
ASSERT_TRUE(reader.PopVariantOfObjectPath(&object_path_value));
+ ASSERT_EQ("", reader.GetDataSignature());
ASSERT_FALSE(reader.HasMoreData());
// 0, 1, 2, 3, 4, 5, 6, 7, 8, "string", "/object/path" should be returned.
@@ -210,6 +237,7 @@ TEST(MessageTest, ArrayOfBytes) {
MessageReader reader(message.get());
const uint8* output_bytes = NULL;
size_t length = 0;
+ ASSERT_EQ("ay", reader.GetDataSignature());
ASSERT_TRUE(reader.PopArrayOfBytes(&output_bytes, &length));
ASSERT_FALSE(reader.HasMoreData());
ASSERT_EQ(3U, length);
@@ -227,6 +255,7 @@ TEST(MessageTest, ArrayOfBytes_Empty) {
MessageReader reader(message.get());
const uint8* output_bytes = NULL;
size_t length = 0;
+ ASSERT_EQ("ay", reader.GetDataSignature());
ASSERT_TRUE(reader.PopArrayOfBytes(&output_bytes, &length));
ASSERT_FALSE(reader.HasMoreData());
ASSERT_EQ(0U, length);
@@ -245,6 +274,7 @@ TEST(MessageTest, ArrayOfStrings) {
MessageReader reader(message.get());
std::vector<std::string> output_strings;
+ ASSERT_EQ("as", reader.GetDataSignature());
ASSERT_TRUE(reader.PopArrayOfStrings(&output_strings));
ASSERT_FALSE(reader.HasMoreData());
ASSERT_EQ(4U, output_strings.size());
@@ -265,6 +295,7 @@ TEST(MessageTest, ArrayOfObjectPaths) {
MessageReader reader(message.get());
std::vector<ObjectPath> output_object_paths;
+ ASSERT_EQ("ao", reader.GetDataSignature());
ASSERT_TRUE(reader.PopArrayOfObjectPaths(&output_object_paths));
ASSERT_FALSE(reader.HasMoreData());
ASSERT_EQ(3U, output_object_paths.size());
@@ -283,6 +314,7 @@ TEST(MessageTest, ProtoBuf) {
MessageReader reader(message.get());
TestProto receive_message;
+ ASSERT_EQ("ay", reader.GetDataSignature());
ASSERT_TRUE(reader.PopArrayOfBytesAsProto(&receive_message));
EXPECT_EQ(receive_message.text(), send_message.text());
EXPECT_EQ(receive_message.number(), send_message.number());
@@ -304,6 +336,7 @@ TEST(MessageTest, OpenArrayAndPopArray) {
MessageReader reader(message.get());
ASSERT_EQ(Message::ARRAY, reader.GetDataType());
+ ASSERT_EQ("as", reader.GetDataSignature());
MessageReader array_reader(NULL);
ASSERT_TRUE(reader.PopArray(&array_reader));
ASSERT_FALSE(reader.HasMoreData()); // Should not have more data to read.
@@ -397,11 +430,13 @@ TEST(MessageTest, CreateComplexMessageAndReadIt) {
message->ToString());
MessageReader reader(message.get());
+ ASSERT_EQ("av", reader.GetDataSignature());
MessageReader array_reader(NULL);
ASSERT_TRUE(reader.PopArray(&array_reader));
// The first value in the array.
bool bool_value = false;
+ ASSERT_EQ("v", array_reader.GetDataSignature());
ASSERT_TRUE(array_reader.PopVariantOfBool(&bool_value));
EXPECT_EQ(true, bool_value);
@@ -411,6 +446,7 @@ TEST(MessageTest, CreateComplexMessageAndReadIt) {
ASSERT_TRUE(array_reader.PopVariant(&variant_reader));
{
MessageReader struct_reader(NULL);
+ ASSERT_EQ("(si)", variant_reader.GetDataSignature());
ASSERT_TRUE(variant_reader.PopStruct(&struct_reader));
std::string string_value;
ASSERT_TRUE(struct_reader.PopString(&string_value));
@@ -429,6 +465,7 @@ TEST(MessageTest, CreateComplexMessageAndReadIt) {
ASSERT_TRUE(array_reader.PopVariant(&variant_reader));
{
MessageReader dict_array_reader(NULL);
+ ASSERT_EQ("a{sx}", variant_reader.GetDataSignature());
ASSERT_TRUE(variant_reader.PopArray(&dict_array_reader));
{
MessageReader dict_entry_reader(NULL);
diff --git a/chromium/dbus/mock_object_proxy.h b/chromium/dbus/mock_object_proxy.h
index fcad8607248..7c61b47b428 100644
--- a/chromium/dbus/mock_object_proxy.h
+++ b/chromium/dbus/mock_object_proxy.h
@@ -25,10 +25,21 @@ class MockObjectProxy : public ObjectProxy {
// uncopyable. This is a workaround which defines |MockCallMethodAndBlock| as
// a mock method and makes |CallMethodAndBlock| call the mocked method.
// Use |MockCallMethodAndBlock| for setting/testing expectations.
+ MOCK_METHOD3(MockCallMethodAndBlockWithErrorDetails,
+ Response*(MethodCall* method_call,
+ int timeout_ms,
+ ScopedDBusError* error));
+ virtual scoped_ptr<Response> CallMethodAndBlockWithErrorDetails(
+ MethodCall* method_call,
+ int timeout_ms,
+ ScopedDBusError* error) override {
+ return scoped_ptr<Response>(
+ MockCallMethodAndBlockWithErrorDetails(method_call, timeout_ms, error));
+ }
MOCK_METHOD2(MockCallMethodAndBlock, Response*(MethodCall* method_call,
int timeout_ms));
virtual scoped_ptr<Response> CallMethodAndBlock(MethodCall* method_call,
- int timeout_ms) OVERRIDE {
+ int timeout_ms) override {
return scoped_ptr<Response>(MockCallMethodAndBlock(method_call,
timeout_ms));
}
diff --git a/chromium/dbus/mock_unittest.cc b/chromium/dbus/mock_unittest.cc
index bede2740d40..bfdc5a30c28 100644
--- a/chromium/dbus/mock_unittest.cc
+++ b/chromium/dbus/mock_unittest.cc
@@ -7,11 +7,13 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "dbus/message.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_exported_object.h"
#include "dbus/mock_object_proxy.h"
#include "dbus/object_path.h"
+#include "dbus/scoped_dbus_error.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -43,6 +45,10 @@ class MockTest : public testing::Test {
// CreateMockProxyResponse() to return responses.
EXPECT_CALL(*mock_proxy_.get(), MockCallMethodAndBlock(_, _))
.WillRepeatedly(Invoke(this, &MockTest::CreateMockProxyResponse));
+ EXPECT_CALL(*mock_proxy_.get(),
+ MockCallMethodAndBlockWithErrorDetails(_, _, _))
+ .WillRepeatedly(
+ Invoke(this, &MockTest::CreateMockProxyResponseWithErrorDetails));
// Set an expectation so mock_proxy's CallMethod() will use
// HandleMockProxyResponseWithMessageLoop() to return responses.
@@ -72,12 +78,13 @@ class MockTest : public testing::Test {
MessageReader reader(response);
ASSERT_TRUE(reader.PopString(&response_string_));
}
- message_loop_.Quit();
+ run_loop_->Quit();
};
protected:
std::string response_string_;
base::MessageLoop message_loop_;
+ scoped_ptr<base::RunLoop> run_loop_;
scoped_refptr<MockBus> mock_bus_;
scoped_refptr<MockObjectProxy> mock_proxy_;
@@ -102,6 +109,12 @@ class MockTest : public testing::Test {
return NULL;
}
+ Response* CreateMockProxyResponseWithErrorDetails(
+ MethodCall* method_call, int timeout_ms, ScopedDBusError* error) {
+ dbus_set_error(error->get(), DBUS_ERROR_NOT_SUPPORTED, "Not implemented");
+ return NULL;
+ }
+
// Creates a response and runs the given response callback in the
// message loop with the response. Used to implement for |mock_proxy_|.
void HandleMockProxyResponseWithMessageLoop(
@@ -125,7 +138,7 @@ class MockTest : public testing::Test {
}
};
-// This test demonstrates how to mock a synchronos method call using the
+// This test demonstrates how to mock a synchronous method call using the
// mock classes.
TEST_F(MockTest, CallMethodAndBlock) {
const char kHello[] = "Hello";
@@ -153,7 +166,29 @@ TEST_F(MockTest, CallMethodAndBlock) {
EXPECT_EQ(kHello, text_message);
}
-// This test demonstrates how to mock an asynchronos method call using the
+TEST_F(MockTest, CallMethodAndBlockWithErrorDetails) {
+ // Get an object proxy from the mock bus.
+ ObjectProxy* proxy = mock_bus_->GetObjectProxy(
+ "org.chromium.TestService",
+ ObjectPath("/org/chromium/TestObject"));
+
+ // Create a method call.
+ MethodCall method_call("org.chromium.TestInterface", "Echo");
+
+ ScopedDBusError error;
+ // Call the method.
+ scoped_ptr<Response> response(
+ proxy->CallMethodAndBlockWithErrorDetails(
+ &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT, &error));
+
+ // Check the response.
+ ASSERT_FALSE(response.get());
+ ASSERT_TRUE(error.is_set());
+ EXPECT_STREQ(DBUS_ERROR_NOT_SUPPORTED, error.name());
+ EXPECT_STREQ("Not implemented", error.message());
+}
+
+// This test demonstrates how to mock an asynchronous method call using the
// mock classes.
TEST_F(MockTest, CallMethod) {
const char kHello[] = "hello";
@@ -169,12 +204,13 @@ TEST_F(MockTest, CallMethod) {
writer.AppendString(kHello);
// Call the method.
+ run_loop_.reset(new base::RunLoop);
proxy->CallMethod(&method_call,
ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MockTest::OnResponse,
base::Unretained(this)));
// Run the message loop to let OnResponse be called.
- message_loop_.Run();
+ run_loop_->Run();
EXPECT_EQ(kHello, response_string_);
}
diff --git a/chromium/dbus/object_manager.cc b/chromium/dbus/object_manager.cc
index d8eb569cf72..f754bb693fd 100644
--- a/chromium/dbus/object_manager.cc
+++ b/chromium/dbus/object_manager.cc
@@ -5,11 +5,18 @@
#include "dbus/object_manager.h"
#include "base/bind.h"
+#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
#include "dbus/bus.h"
+#include "dbus/dbus_statistics.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
#include "dbus/property.h"
+#include "dbus/scoped_dbus_error.h"
+#include "dbus/util.h"
namespace dbus {
@@ -26,33 +33,27 @@ ObjectManager::ObjectManager(Bus* bus,
: bus_(bus),
service_name_(service_name),
object_path_(object_path),
+ setup_success_(false),
+ cleanup_called_(false),
weak_ptr_factory_(this) {
DVLOG(1) << "Creating ObjectManager for " << service_name_
<< " " << object_path_.value();
-
DCHECK(bus_);
+ bus_->AssertOnOriginThread();
object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
object_proxy_->SetNameOwnerChangedCallback(
base::Bind(&ObjectManager::NameOwnerChanged,
weak_ptr_factory_.GetWeakPtr()));
- object_proxy_->ConnectToSignal(
- kObjectManagerInterface,
- kObjectManagerInterfacesAdded,
- base::Bind(&ObjectManager::InterfacesAddedReceived,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&ObjectManager::InterfacesAddedConnected,
- weak_ptr_factory_.GetWeakPtr()));
-
- object_proxy_->ConnectToSignal(
- kObjectManagerInterface,
- kObjectManagerInterfacesRemoved,
- base::Bind(&ObjectManager::InterfacesRemovedReceived,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&ObjectManager::InterfacesRemovedConnected,
- weak_ptr_factory_.GetWeakPtr()));
-
- GetManagedObjects();
+ // Set up a match rule and a filter function to handle PropertiesChanged
+ // signals from the service. This is important to avoid any race conditions
+ // that might cause us to miss PropertiesChanged signals once all objects are
+ // initialized via GetManagedObjects.
+ base::PostTaskAndReplyWithResult(
+ bus_->GetDBusTaskRunner(),
+ FROM_HERE,
+ base::Bind(&ObjectManager::SetupMatchRuleAndFilter, this),
+ base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete, this));
}
ObjectManager::~ObjectManager() {
@@ -144,6 +145,205 @@ void ObjectManager::GetManagedObjects() {
weak_ptr_factory_.GetWeakPtr()));
}
+void ObjectManager::CleanUp() {
+ DCHECK(bus_);
+ bus_->AssertOnDBusThread();
+ DCHECK(!cleanup_called_);
+
+ cleanup_called_ = true;
+
+ if (!setup_success_)
+ return;
+
+ if (!bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this))
+ LOG(ERROR) << "Failed to remove filter function";
+
+ ScopedDBusError error;
+ bus_->RemoveMatch(match_rule_, error.get());
+ if (error.is_set())
+ LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
+
+ match_rule_.clear();
+}
+
+void ObjectManager::InitializeObjects() {
+ DCHECK(bus_);
+ DCHECK(object_proxy_);
+ DCHECK(setup_success_);
+
+ // |object_proxy_| is no longer valid if the Bus was shut down before this
+ // call. Don't initiate any other action from the origin thread.
+ if (cleanup_called_)
+ return;
+
+ object_proxy_->ConnectToSignal(
+ kObjectManagerInterface,
+ kObjectManagerInterfacesAdded,
+ base::Bind(&ObjectManager::InterfacesAddedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&ObjectManager::InterfacesAddedConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ object_proxy_->ConnectToSignal(
+ kObjectManagerInterface,
+ kObjectManagerInterfacesRemoved,
+ base::Bind(&ObjectManager::InterfacesRemovedReceived,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&ObjectManager::InterfacesRemovedConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ GetManagedObjects();
+}
+
+bool ObjectManager::SetupMatchRuleAndFilter() {
+ DCHECK(bus_);
+ DCHECK(!setup_success_);
+ bus_->AssertOnDBusThread();
+
+ if (cleanup_called_)
+ return false;
+
+ if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
+ return false;
+
+ service_name_owner_ =
+ bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
+
+ const std::string match_rule =
+ base::StringPrintf(
+ "type='signal', sender='%s', interface='%s', member='%s'",
+ service_name_.c_str(),
+ kPropertiesInterface,
+ kPropertiesChanged);
+
+ if (!bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this)) {
+ LOG(ERROR) << "ObjectManager failed to add filter function";
+ return false;
+ }
+
+ ScopedDBusError error;
+ bus_->AddMatch(match_rule, error.get());
+ if (error.is_set()) {
+ LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
+ << "\". Got " << error.name() << ": " << error.message();
+ bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
+ return false;
+ }
+
+ match_rule_ = match_rule;
+ setup_success_ = true;
+
+ return true;
+}
+
+void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
+ LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
+ << ": Failed to set up match rule.";
+ if (success)
+ InitializeObjects();
+}
+
+// static
+DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
+ DBusMessage* raw_message,
+ void* user_data) {
+ ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
+ return self->HandleMessage(connection, raw_message);
+}
+
+DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
+ DBusMessage* raw_message) {
+ DCHECK(bus_);
+ bus_->AssertOnDBusThread();
+
+ if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ // raw_message will be unrefed on exit of the function. Increment the
+ // reference so we can use it in Signal.
+ dbus_message_ref(raw_message);
+ scoped_ptr<Signal> signal(
+ Signal::FromRawMessage(raw_message));
+
+ const std::string interface = signal->GetInterface();
+ const std::string member = signal->GetMember();
+
+ statistics::AddReceivedSignal(service_name_, interface, member);
+
+ // Only handle the PropertiesChanged signal.
+ const std::string absolute_signal_name =
+ GetAbsoluteMemberName(interface, member);
+ const std::string properties_changed_signal_name =
+ GetAbsoluteMemberName(kPropertiesInterface, kPropertiesChanged);
+ if (absolute_signal_name != properties_changed_signal_name)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ VLOG(1) << "Signal received: " << signal->ToString();
+
+ // Make sure that the signal originated from the correct sender.
+ std::string sender = signal->GetSender();
+ if (service_name_owner_ != sender) {
+ LOG(ERROR) << "Rejecting a message from a wrong sender.";
+ UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ const ObjectPath path = signal->GetPath();
+
+ if (bus_->HasDBusThread()) {
+ // Post a task to run the method in the origin thread. Transfer ownership of
+ // |signal| to NotifyPropertiesChanged, which will handle the clean up.
+ Signal* released_signal = signal.release();
+ bus_->GetOriginTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ObjectManager::NotifyPropertiesChanged,
+ this, path,
+ released_signal));
+ } else {
+ // If the D-Bus thread is not used, just call the callback on the
+ // current thread. Transfer the ownership of |signal| to
+ // NotifyPropertiesChanged.
+ NotifyPropertiesChanged(path, signal.release());
+ }
+
+ // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
+ // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void ObjectManager::NotifyPropertiesChanged(
+ const dbus::ObjectPath object_path,
+ Signal* signal) {
+ DCHECK(bus_);
+ bus_->AssertOnOriginThread();
+
+ NotifyPropertiesChangedHelper(object_path, signal);
+
+ // Delete the message on the D-Bus thread. See comments in HandleMessage.
+ bus_->GetDBusTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&base::DeletePointer<Signal>, signal));
+}
+
+void ObjectManager::NotifyPropertiesChangedHelper(
+ const dbus::ObjectPath object_path,
+ Signal* signal) {
+ DCHECK(bus_);
+ bus_->AssertOnOriginThread();
+
+ MessageReader reader(signal);
+ std::string interface;
+ if (!reader.PopString(&interface)) {
+ LOG(WARNING) << "Property changed signal has wrong parameters: "
+ << "expected interface name: " << signal->ToString();
+ return;
+ }
+
+ PropertySet* properties = GetProperties(object_path, interface);
+ if (properties)
+ properties->ChangedReceived(signal);
+}
+
void ObjectManager::OnGetManagedObjects(Response* response) {
if (response != NULL) {
MessageReader reader(response);
@@ -257,7 +457,6 @@ void ObjectManager::AddInterface(const ObjectPath& object_path,
property_set = object->properties_map[interface_name] =
interface->CreateProperties(object->object_proxy,
object_path, interface_name);
- property_set->ConnectSignals();
} else
property_set = piter->second;
@@ -297,6 +496,8 @@ void ObjectManager::RemoveInterface(const ObjectPath& object_path,
void ObjectManager::NameOwnerChanged(const std::string& old_owner,
const std::string& new_owner) {
+ service_name_owner_ = new_owner;
+
if (!old_owner.empty()) {
ObjectMap::iterator iter = object_map_.begin();
while (iter != object_map_.end()) {
diff --git a/chromium/dbus/object_manager.h b/chromium/dbus/object_manager.h
index 0d3ae5d0616..23a88cdc893 100644
--- a/chromium/dbus/object_manager.h
+++ b/chromium/dbus/object_manager.h
@@ -79,7 +79,7 @@
// Example:
// dbus::PropertySet* CreateProperties(dbus::ObjectProxy* object_proxy,
// const std::string& interface_name)
-// OVERRIDE {
+// override {
// Properties* properties = new Properties(
// object_proxy, interface_name,
// base::Bind(&PropertyChanged,
@@ -223,12 +223,47 @@ public:
// a need to call this manually.
void GetManagedObjects();
+ // Cleans up any match rules and filter functions added by this ObjectManager.
+ // The Bus object will take care of this so you don't have to do it manually.
+ //
+ // BLOCKING CALL.
+ void CleanUp();
+
protected:
virtual ~ObjectManager();
private:
friend class base::RefCountedThreadSafe<ObjectManager>;
+ // Connects the InterfacesAdded and InterfacesRemoved signals and calls
+ // GetManagedObjects. Called from OnSetupMatchRuleAndFilterComplete.
+ void InitializeObjects();
+
+ // Called from the constructor to add a match rule for PropertiesChanged
+ // signals on the DBus thread and set up a corresponding filter function.
+ bool SetupMatchRuleAndFilter();
+
+ // Called on the origin thread once the match rule and filter have been set
+ // up. |success| is false, if an error occurred during set up; it's true
+ // otherwise.
+ void OnSetupMatchRuleAndFilterComplete(bool success);
+
+ // Called by dbus:: when a message is received. This is used to filter
+ // PropertiesChanged signals from the correct sender and relay the event to
+ // the correct PropertySet.
+ static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
+ DBusMessage* raw_message,
+ void* user_data);
+ DBusHandlerResult HandleMessage(DBusConnection* connection,
+ DBusMessage* raw_message);
+
+ // Called when a PropertiesChanged signal is received from the sender.
+ // This method notifies the relevant PropertySet that it should update its
+ // properties based on the received signal. Called from HandleMessage.
+ void NotifyPropertiesChanged(const dbus::ObjectPath object_path,
+ Signal* signal);
+ void NotifyPropertiesChangedHelper(const dbus::ObjectPath object_path,
+ Signal* signal);
// Called by dbus:: in response to the GetManagedObjects() method call.
void OnGetManagedObjects(Response* response);
@@ -281,8 +316,12 @@ public:
Bus* bus_;
std::string service_name_;
+ std::string service_name_owner_;
+ std::string match_rule_;
ObjectPath object_path_;
ObjectProxy* object_proxy_;
+ bool setup_success_;
+ bool cleanup_called_;
// Maps the name of an interface to the implementation class used for
// instantiating PropertySet structures for that interface's properties.
diff --git a/chromium/dbus/object_manager_unittest.cc b/chromium/dbus/object_manager_unittest.cc
index 3e53095b12e..cd02c5e13c1 100644
--- a/chromium/dbus/object_manager_unittest.cc
+++ b/chromium/dbus/object_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "dbus/bus.h"
@@ -27,7 +28,7 @@ class ObjectManagerTest
: public testing::Test,
public ObjectManager::Interface {
public:
- ObjectManagerTest() {
+ ObjectManagerTest() : timeout_expired_(false) {
}
struct Properties : public PropertySet {
@@ -50,7 +51,7 @@ class ObjectManagerTest
virtual PropertySet* CreateProperties(
ObjectProxy* object_proxy,
const ObjectPath& object_path,
- const std::string& interface_name) OVERRIDE {
+ const std::string& interface_name) override {
Properties* properties = new Properties(
object_proxy, interface_name,
base::Bind(&ObjectManagerTest::OnPropertyChanged,
@@ -89,7 +90,6 @@ class ObjectManagerTest
ObjectPath("/org/chromium/TestService"));
object_manager_->RegisterInterface("org.chromium.TestInterface", this);
- object_manager_->GetManagedObjects();
WaitForObject();
}
@@ -105,33 +105,55 @@ class ObjectManagerTest
// Stopping a thread is considered an IO operation, so do this after
// allowing IO.
test_service_->Stop();
+
+ base::RunLoop().RunUntilIdle();
}
void MethodCallback(Response* response) {
method_callback_called_ = true;
- message_loop_.Quit();
+ run_loop_->Quit();
+ }
+
+ // Called from the PropertiesChangedAsObjectsReceived test case. The test will
+ // not run the message loop if it receives the expected PropertiesChanged
+ // signal before the timeout. This method immediately fails the test.
+ void PropertiesChangedTestTimeout() {
+ timeout_expired_ = true;
+ run_loop_->Quit();
+
+ FAIL() << "Never received PropertiesChanged";
}
protected:
// Called when an object is added.
virtual void ObjectAdded(const ObjectPath& object_path,
- const std::string& interface_name) OVERRIDE {
+ const std::string& interface_name) override {
added_objects_.push_back(std::make_pair(object_path, interface_name));
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when an object is removed.
virtual void ObjectRemoved(const ObjectPath& object_path,
- const std::string& interface_name) OVERRIDE {
+ const std::string& interface_name) override {
removed_objects_.push_back(std::make_pair(object_path, interface_name));
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when a property value is updated.
void OnPropertyChanged(const ObjectPath& object_path,
const std::string& name) {
+ // Store the value of the "Name" property if that's the one that
+ // changed.
+ Properties* properties = static_cast<Properties*>(
+ object_manager_->GetProperties(
+ object_path,
+ "org.chromium.TestInterface"));
+ if (name == properties->name.name())
+ last_name_value_ = properties->name.value();
+
+ // Store the updated property.
updated_properties_.push_back(name);
- message_loop_.Quit();
+ run_loop_->Quit();
}
static const size_t kExpectedObjects = 1;
@@ -139,8 +161,10 @@ class ObjectManagerTest
void WaitForObject() {
while (added_objects_.size() < kExpectedObjects ||
- updated_properties_.size() < kExpectedProperties)
- message_loop_.Run();
+ updated_properties_.size() < kExpectedProperties) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
for (size_t i = 0; i < kExpectedObjects; ++i)
added_objects_.erase(added_objects_.begin());
for (size_t i = 0; i < kExpectedProperties; ++i)
@@ -148,14 +172,17 @@ class ObjectManagerTest
}
void WaitForRemoveObject() {
- while (removed_objects_.size() < kExpectedObjects)
- message_loop_.Run();
+ while (removed_objects_.size() < kExpectedObjects) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
for (size_t i = 0; i < kExpectedObjects; ++i)
removed_objects_.erase(removed_objects_.begin());
}
void WaitForMethodCallback() {
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
method_callback_called_ = false;
}
@@ -177,11 +204,15 @@ class ObjectManagerTest
}
base::MessageLoop message_loop_;
+ scoped_ptr<base::RunLoop> run_loop_;
scoped_ptr<base::Thread> dbus_thread_;
scoped_refptr<Bus> bus_;
ObjectManager* object_manager_;
scoped_ptr<TestService> test_service_;
+ std::string last_name_value_;
+ bool timeout_expired_;
+
std::vector<std::pair<ObjectPath, std::string> > added_objects_;
std::vector<std::pair<ObjectPath, std::string> > removed_objects_;
std::vector<std::string> updated_properties_;
@@ -350,4 +381,38 @@ TEST_F(ObjectManagerTest, OwnershipLostAndRegained) {
ASSERT_EQ(1U, object_paths.size());
}
+TEST_F(ObjectManagerTest, PropertiesChangedAsObjectsReceived) {
+ // Remove the existing object manager.
+ object_manager_->UnregisterInterface("org.chromium.TestInterface");
+ run_loop_.reset(new base::RunLoop);
+ EXPECT_TRUE(bus_->RemoveObjectManager(
+ "org.chromium.TestService",
+ ObjectPath("/org/chromium/TestService"),
+ run_loop_->QuitClosure()));
+ run_loop_->Run();
+
+ PerformAction("SetSendImmediatePropertiesChanged",
+ ObjectPath("/org/chromium/TestService"));
+
+ object_manager_ = bus_->GetObjectManager(
+ "org.chromium.TestService",
+ ObjectPath("/org/chromium/TestService"));
+ object_manager_->RegisterInterface("org.chromium.TestInterface", this);
+
+ // The newly created object manager should call GetManagedObjects immediately
+ // after setting up the match rule for PropertiesChanged. We should process
+ // the PropertiesChanged event right after that. If we don't receive it within
+ // 2 seconds, then fail the test.
+ message_loop_.PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ObjectManagerTest::PropertiesChangedTestTimeout,
+ base::Unretained(this)),
+ base::TimeDelta::FromSeconds(2));
+
+ while (last_name_value_ != "ChangedTestServiceName" && !timeout_expired_) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
+}
+
} // namespace dbus
diff --git a/chromium/dbus/object_proxy.cc b/chromium/dbus/object_proxy.cc
index 5167cab7603..59584f2ce34 100644
--- a/chromium/dbus/object_proxy.cc
+++ b/chromium/dbus/object_proxy.cc
@@ -18,12 +18,14 @@
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "dbus/scoped_dbus_error.h"
+#include "dbus/util.h"
namespace dbus {
namespace {
const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
+const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject";
// Used for success ratio histograms. 1 for success, 0 for failure.
const int kSuccessRatioHistogramMaxValue = 2;
@@ -40,15 +42,6 @@ const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
// The NameOwnerChanged member in |kDBusSystemObjectInterface|.
const char kNameOwnerChangedMember[] = "NameOwnerChanged";
-// Gets the absolute signal name by concatenating the interface name and
-// the signal name. Used for building keys for method_table_ in
-// ObjectProxy.
-std::string GetAbsoluteSignalName(
- const std::string& interface_name,
- const std::string& signal_name) {
- return interface_name + "." + signal_name;
-}
-
// An empty function used for ObjectProxy::EmptyResponseCallback().
void EmptyResponseCallbackBody(Response* /*response*/) {
}
@@ -73,8 +66,8 @@ ObjectProxy::~ObjectProxy() {
// Originally we tried to make |method_call| a const reference, but we
// gave up as dbus_connection_send_with_reply_and_block() takes a
// non-const pointer of DBusMessage as the second parameter.
-scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
- int timeout_ms) {
+scoped_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
+ MethodCall* method_call, int timeout_ms, ScopedDBusError* error) {
bus_->AssertOnDBusThread();
if (!bus_->Connect() ||
@@ -84,12 +77,10 @@ scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
DBusMessage* request_message = method_call->raw_message();
- ScopedDBusError error;
-
// Send the message synchronously.
const base::TimeTicks start_time = base::TimeTicks::Now();
DBusMessage* response_message =
- bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get());
+ bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
// Record if the method call is successful, or not. 1 if successful.
UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
response_message ? 1 : 0,
@@ -101,8 +92,8 @@ scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
if (!response_message) {
LogMethodCallFailure(method_call->GetInterface(),
method_call->GetMember(),
- error.is_set() ? error.name() : "unknown error type",
- error.is_set() ? error.message() : "");
+ error->is_set() ? error->name() : "unknown error type",
+ error->is_set() ? error->message() : "");
return scoped_ptr<Response>();
}
// Record time spent for the method call. Don't include failures.
@@ -112,6 +103,12 @@ scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
return Response::FromRawMessage(response_message);
}
+scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
+ int timeout_ms) {
+ ScopedDBusError error;
+ return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
+}
+
void ObjectProxy::CallMethod(MethodCall* method_call,
int timeout_ms,
ResponseCallback callback) {
@@ -420,7 +417,7 @@ bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
return false;
const std::string absolute_signal_name =
- GetAbsoluteSignalName(interface_name, signal_name);
+ GetAbsoluteMemberName(interface_name, signal_name);
// Add a match rule so the signal goes through HandleMessage().
const std::string match_rule =
@@ -487,7 +484,7 @@ DBusHandlerResult ObjectProxy::HandleMessage(
statistics::AddReceivedSignal(service_name_, interface, member);
// Check if we know about the signal.
- const std::string absolute_signal_name = GetAbsoluteSignalName(
+ const std::string absolute_signal_name = GetAbsoluteMemberName(
interface, member);
MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
if (iter == method_table_.end()) {
@@ -561,12 +558,20 @@ void ObjectProxy::LogMethodCallFailure(
const base::StringPiece& method_name,
const base::StringPiece& error_name,
const base::StringPiece& error_message) const {
- if (ignore_service_unknown_errors_ && error_name == kErrorServiceUnknown)
+ if (ignore_service_unknown_errors_ &&
+ (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
return;
- LOG(ERROR) << "Failed to call method: "
- << interface_name << "." << method_name
- << ": object_path= " << object_path_.value()
- << ": " << error_name << ": " << error_message;
+ logging::LogSeverity severity = logging::LOG_ERROR;
+ // "UnknownObject" indicates that an object or service is no longer available,
+ // e.g. a Shill network service has gone out of range. Treat these as warnings
+ // not errors.
+ if (error_name == kErrorObjectUnknown)
+ severity = logging::LOG_WARNING;
+ std::ostringstream msg;
+ msg << "Failed to call method: " << interface_name << "." << method_name
+ << ": object_path= " << object_path_.value()
+ << ": " << error_name << ": " << error_message;
+ logging::LogAtLevel(severity, msg.str());
}
void ObjectProxy::OnCallMethodError(const std::string& interface_name,
diff --git a/chromium/dbus/object_proxy.h b/chromium/dbus/object_proxy.h
index 48c9c03208a..1400328fda0 100644
--- a/chromium/dbus/object_proxy.h
+++ b/chromium/dbus/object_proxy.h
@@ -25,13 +25,14 @@ class Bus;
class ErrorResponse;
class MethodCall;
class Response;
+class ScopedDBusError;
class Signal;
// ObjectProxy is used to communicate with remote objects, mainly for
// calling methods of these objects.
//
// ObjectProxy is a ref counted object, to ensure that |this| of the
-// object is is alive when callbacks referencing |this| are called; the
+// object is alive when callbacks referencing |this| are called; the
// bus always holds at least one of those references so object proxies
// always last as long as the bus that created them.
class CHROME_DBUS_EXPORT ObjectProxy
@@ -46,7 +47,8 @@ class CHROME_DBUS_EXPORT ObjectProxy
// Options to be OR-ed together when calling Bus::GetObjectProxyWithOptions().
// Set the IGNORE_SERVICE_UNKNOWN_ERRORS option to silence logging of
- // org.freedesktop.DBus.Error.ServiceUnknown errors.
+ // org.freedesktop.DBus.Error.ServiceUnknown errors and
+ // org.freedesktop.DBus.Error.ObjectUnknown errors.
enum Options {
DEFAULT_OPTIONS = 0,
IGNORE_SERVICE_UNKNOWN_ERRORS = 1 << 0
@@ -90,6 +92,16 @@ class CHROME_DBUS_EXPORT ObjectProxy
OnConnectedCallback;
// Calls the method of the remote object and blocks until the response
+ // is returned. Returns NULL on error with the error details specified
+ // in the |error| object.
+ //
+ // BLOCKING CALL.
+ virtual scoped_ptr<Response> CallMethodAndBlockWithErrorDetails(
+ MethodCall* method_call,
+ int timeout_ms,
+ ScopedDBusError* error);
+
+ // Calls the method of the remote object and blocks until the response
// is returned. Returns NULL on error.
//
// BLOCKING CALL.
@@ -304,7 +316,7 @@ class CHROME_DBUS_EXPORT ObjectProxy
const bool ignore_service_unknown_errors_;
- // Known name owner of the well-known bus name represnted by |service_name_|.
+ // Known name owner of the well-known bus name represented by |service_name_|.
std::string service_name_owner_;
DISALLOW_COPY_AND_ASSIGN(ObjectProxy);
diff --git a/chromium/dbus/object_proxy_unittest.cc b/chromium/dbus/object_proxy_unittest.cc
index 1cf667c3465..246058ddd5d 100644
--- a/chromium/dbus/object_proxy_unittest.cc
+++ b/chromium/dbus/object_proxy_unittest.cc
@@ -15,7 +15,7 @@ namespace {
class ObjectProxyTest : public testing::Test {
protected:
- virtual void SetUp() OVERRIDE {
+ virtual void SetUp() override {
Bus::Options bus_options;
bus_options.bus_type = Bus::SESSION;
bus_options.connection_type = Bus::PRIVATE;
@@ -25,7 +25,7 @@ class ObjectProxyTest : public testing::Test {
"org.chromium.TestService", ObjectPath("/org/chromium/TestObject"));
}
- virtual void TearDown() OVERRIDE {
+ virtual void TearDown() override {
bus_->ShutdownAndBlock();
}
diff --git a/chromium/dbus/property.cc b/chromium/dbus/property.cc
index 774719f8bf8..9475a0728a6 100644
--- a/chromium/dbus/property.cc
+++ b/chromium/dbus/property.cc
@@ -136,7 +136,7 @@ void PropertySet::GetAll() {
void PropertySet::OnGetAll(Response* response) {
if (!response) {
- LOG(WARNING) << "GetAll request failed.";
+ LOG(WARNING) << "GetAll request failed for: " << interface_;
return;
}
@@ -163,7 +163,8 @@ void PropertySet::Set(PropertyBase* property, SetCallback callback) {
callback));
}
-void PropertySet::OnSet(PropertyBase* property, SetCallback callback,
+void PropertySet::OnSet(PropertyBase* property,
+ SetCallback callback,
Response* response) {
LOG_IF(WARNING, !response) << property->name() << ": Set: failed.";
if (!callback.is_null())
@@ -477,4 +478,19 @@ void Property<std::vector<uint8> >::AppendSetValueToWriter(
writer->CloseContainer(&variant_writer);
}
+template class Property<uint8>;
+template class Property<bool>;
+template class Property<int16>;
+template class Property<uint16>;
+template class Property<int32>;
+template class Property<uint32>;
+template class Property<int64>;
+template class Property<uint64>;
+template class Property<double>;
+template class Property<std::string>;
+template class Property<ObjectPath>;
+template class Property<std::vector<std::string> >;
+template class Property<std::vector<ObjectPath> >;
+template class Property<std::vector<uint8> >;
+
} // namespace dbus
diff --git a/chromium/dbus/property.h b/chromium/dbus/property.h
index f6baffc8a73..a20e0ad466f 100644
--- a/chromium/dbus/property.h
+++ b/chromium/dbus/property.h
@@ -409,67 +409,81 @@ class CHROME_DBUS_EXPORT Property : public PropertyBase {
template <> Property<uint8>::Property();
template <> bool Property<uint8>::PopValueFromReader(MessageReader* reader);
template <> void Property<uint8>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class Property<uint8>;
template <> Property<bool>::Property();
template <> bool Property<bool>::PopValueFromReader(MessageReader* reader);
template <> void Property<bool>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class Property<bool>;
template <> Property<int16>::Property();
template <> bool Property<int16>::PopValueFromReader(MessageReader* reader);
template <> void Property<int16>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class Property<int16>;
template <> Property<uint16>::Property();
template <> bool Property<uint16>::PopValueFromReader(MessageReader* reader);
template <> void Property<uint16>::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<uint16>;
template <> Property<int32>::Property();
template <> bool Property<int32>::PopValueFromReader(MessageReader* reader);
template <> void Property<int32>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class Property<int32>;
template <> Property<uint32>::Property();
template <> bool Property<uint32>::PopValueFromReader(MessageReader* reader);
template <> void Property<uint32>::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<uint32>;
template <> Property<int64>::Property();
template <> bool Property<int64>::PopValueFromReader(MessageReader* reader);
template <> void Property<int64>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class Property<int64>;
template <> Property<uint64>::Property();
template <> bool Property<uint64>::PopValueFromReader(MessageReader* reader);
template <> void Property<uint64>::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<uint64>;
template <> Property<double>::Property();
template <> bool Property<double>::PopValueFromReader(MessageReader* reader);
template <> void Property<double>::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<double>;
template <> bool Property<std::string>::PopValueFromReader(
MessageReader* reader);
template <> void Property<std::string>::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<std::string>;
template <> bool Property<ObjectPath>::PopValueFromReader(
MessageReader* reader);
template <> void Property<ObjectPath>::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<ObjectPath>;
template <> bool Property<std::vector<std::string> >::PopValueFromReader(
MessageReader* reader);
template <> void Property<std::vector<std::string> >::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<std::vector<std::string> >;
template <> bool Property<std::vector<ObjectPath> >::PopValueFromReader(
MessageReader* reader);
template <> void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<std::vector<ObjectPath> >;
template <> bool Property<std::vector<uint8> >::PopValueFromReader(
MessageReader* reader);
template <> void Property<std::vector<uint8> >::AppendSetValueToWriter(
MessageWriter* writer);
+extern template class Property<std::vector<uint8> >;
} // namespace dbus
diff --git a/chromium/dbus/property_unittest.cc b/chromium/dbus/property_unittest.cc
index e078c0044d1..879a9a60665 100644
--- a/chromium/dbus/property_unittest.cc
+++ b/chromium/dbus/property_unittest.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "dbus/bus.h"
@@ -105,20 +106,22 @@ class PropertyTest : public testing::Test {
// waited for.
void PropertyCallback(const std::string& id, bool success) {
last_callback_ = id;
- message_loop_.Quit();
+ run_loop_->Quit();
}
protected:
// Called when a property value is updated.
void OnPropertyChanged(const std::string& name) {
updated_properties_.push_back(name);
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Waits for the given number of updates.
void WaitForUpdates(size_t num_updates) {
- while (updated_properties_.size() < num_updates)
- message_loop_.Run();
+ while (updated_properties_.size() < num_updates) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
for (size_t i = 0; i < num_updates; ++i)
updated_properties_.erase(updated_properties_.begin());
}
@@ -136,11 +139,13 @@ class PropertyTest : public testing::Test {
// other; you can set this to whatever you wish.
void WaitForCallback(const std::string& id) {
while (last_callback_ != id) {
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
}
}
base::MessageLoop message_loop_;
+ scoped_ptr<base::RunLoop> run_loop_;
scoped_ptr<base::Thread> dbus_thread_;
scoped_refptr<Bus> bus_;
ObjectProxy* object_proxy_;
diff --git a/chromium/dbus/scoped_dbus_error.cc b/chromium/dbus/scoped_dbus_error.cc
new file mode 100644
index 00000000000..fa049718ef0
--- /dev/null
+++ b/chromium/dbus/scoped_dbus_error.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium 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 "dbus/scoped_dbus_error.h"
+
+namespace dbus {
+
+ScopedDBusError::ScopedDBusError() {
+ dbus_error_init(&error_);
+}
+
+ScopedDBusError::~ScopedDBusError() {
+ dbus_error_free(&error_);
+}
+
+bool ScopedDBusError::is_set() const {
+ return dbus_error_is_set(&error_);
+}
+
+} // namespace dbus
diff --git a/chromium/dbus/scoped_dbus_error.h b/chromium/dbus/scoped_dbus_error.h
index c15c44397b9..1484dbb81b4 100644
--- a/chromium/dbus/scoped_dbus_error.h
+++ b/chromium/dbus/scoped_dbus_error.h
@@ -7,21 +7,20 @@
#include <dbus/dbus.h>
+#include "dbus/dbus_export.h"
+
namespace dbus {
// Utility class to ensure that DBusError is freed.
-class ScopedDBusError {
+class CHROME_DBUS_EXPORT ScopedDBusError {
public:
- ScopedDBusError() {
- dbus_error_init(&error_);
- }
-
- ~ScopedDBusError() {
- dbus_error_free(&error_);
- }
+ // Do not inline methods that call dbus_error_xxx() functions.
+ // See http://crbug.com/416628
+ ScopedDBusError();
+ ~ScopedDBusError();
DBusError* get() { return &error_; }
- bool is_set() const { return dbus_error_is_set(&error_); }
+ bool is_set() const;
const char* name() { return error_.name; }
const char* message() { return error_.message; }
diff --git a/chromium/dbus/signal_sender_verification_unittest.cc b/chromium/dbus/signal_sender_verification_unittest.cc
index 1d8f6e1d64e..c8589f8b641 100644
--- a/chromium/dbus/signal_sender_verification_unittest.cc
+++ b/chromium/dbus/signal_sender_verification_unittest.cc
@@ -8,6 +8,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/run_loop.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
@@ -65,7 +66,8 @@ class SignalSenderVerificationTest : public testing::Test {
base::Bind(&SignalSenderVerificationTest::OnConnected,
base::Unretained(this)));
// Wait until the object proxy is connected to the signal.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
// Start the test service, using the D-Bus thread.
TestService::Options options;
@@ -85,8 +87,10 @@ class SignalSenderVerificationTest : public testing::Test {
ASSERT_FALSE(test_service2_->has_ownership());
// The name should be owned and known at this point.
- if (!on_name_owner_changed_called_)
- message_loop_.Run();
+ if (!on_name_owner_changed_called_) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
ASSERT_FALSE(latest_name_owner_.empty());
}
@@ -117,7 +121,7 @@ class SignalSenderVerificationTest : public testing::Test {
void OnOwnershipInternal() {
on_ownership_called_ = true;
- message_loop_.Quit();
+ run_loop_->Quit();
}
void OnNameOwnerChanged(bool* called_flag,
@@ -125,7 +129,7 @@ class SignalSenderVerificationTest : public testing::Test {
const std::string& new_owner) {
latest_name_owner_ = new_owner;
*called_flag = true;
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when the "Test" signal is received, in the main thread.
@@ -133,7 +137,7 @@ class SignalSenderVerificationTest : public testing::Test {
void OnTestSignal(Signal* signal) {
MessageReader reader(signal);
ASSERT_TRUE(reader.PopString(&test_signal_string_));
- message_loop_.Quit();
+ run_loop_->Quit();
}
// Called when connected to the signal.
@@ -141,14 +145,15 @@ class SignalSenderVerificationTest : public testing::Test {
const std::string& signal_name,
bool success) {
ASSERT_TRUE(success);
- message_loop_.Quit();
+ run_loop_->Quit();
}
protected:
// Wait for the hey signal to be received.
void WaitForTestSignal() {
// OnTestSignal() will quit the message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
}
// Stopping a thread is considered an IO operation, so we need to fiddle with
@@ -160,6 +165,7 @@ class SignalSenderVerificationTest : public testing::Test {
}
base::MessageLoop message_loop_;
+ scoped_ptr<base::RunLoop> run_loop_;
scoped_ptr<base::Thread> dbus_thread_;
scoped_refptr<Bus> bus_;
ObjectProxy* object_proxy_;
@@ -186,7 +192,8 @@ TEST_F(SignalSenderVerificationTest, TestSignalAccepted) {
ASSERT_EQ(kMessage, test_signal_string_);
}
-TEST_F(SignalSenderVerificationTest, TestSignalRejected) {
+// Disabled, http://crbug.com/407063 .
+TEST_F(SignalSenderVerificationTest, DISABLED_TestSignalRejected) {
// To make sure the histogram instance is created.
UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 0);
base::HistogramBase* reject_signal_histogram =
@@ -223,7 +230,8 @@ TEST_F(SignalSenderVerificationTest, TestOwnerChanged) {
ASSERT_FALSE(latest_name_owner_.empty());
test_service_->ShutdownAndBlock();
// OnNameOwnerChanged will PostTask to quit the message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
// latest_name_owner_ should be empty as the owner is gone.
ASSERT_TRUE(latest_name_owner_.empty());
@@ -235,9 +243,12 @@ TEST_F(SignalSenderVerificationTest, TestOwnerChanged) {
base::Unretained(this), true));
// Both of OnNameOwnerChanged() and OnOwnership() should quit the MessageLoop,
// but there's no expected order of those 2 event.
- message_loop_.Run();
- if (!on_name_owner_changed_called_ || !on_ownership_called_)
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ if (!on_name_owner_changed_called_ || !on_ownership_called_) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
ASSERT_TRUE(on_name_owner_changed_called_);
ASSERT_TRUE(on_ownership_called_);
@@ -258,7 +269,8 @@ TEST_F(SignalSenderVerificationTest, TestOwnerStealing) {
ASSERT_FALSE(latest_name_owner_.empty());
test_service_->ShutdownAndBlock();
// OnNameOwnerChanged will PostTask to quit the message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
// latest_name_owner_ should be empty as the owner is gone.
ASSERT_TRUE(latest_name_owner_.empty());
// Reset the flag as NameOwnerChanged is already received in setup.
@@ -275,7 +287,8 @@ TEST_F(SignalSenderVerificationTest, TestOwnerStealing) {
ASSERT_TRUE(stealable_test_service.has_ownership());
// OnNameOwnerChanged will PostTask to quit the message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
// Send a signal to check that the service is correctly owned.
const char kMessage[] = "hello, world";
@@ -294,9 +307,12 @@ TEST_F(SignalSenderVerificationTest, TestOwnerStealing) {
base::Unretained(this), true));
// Both of OnNameOwnerChanged() and OnOwnership() should quit the MessageLoop,
// but there's no expected order of those 2 event.
- message_loop_.Run();
- if (!on_name_owner_changed_called_ || !on_ownership_called_)
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ if (!on_name_owner_changed_called_ || !on_ownership_called_) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
ASSERT_TRUE(on_name_owner_changed_called_);
ASSERT_TRUE(on_ownership_called_);
@@ -334,7 +350,8 @@ TEST_F(SignalSenderVerificationTest, DISABLED_TestMultipleObjects) {
base::Bind(&SignalSenderVerificationTest::OnConnected,
base::Unretained(this)));
// Wait until the object proxy is connected to the signal.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
// Send the test signal from the exported object.
test_service_->SendTestSignal(kMessage);
@@ -348,7 +365,8 @@ TEST_F(SignalSenderVerificationTest, DISABLED_TestMultipleObjects) {
ASSERT_FALSE(latest_name_owner_.empty());
test_service_->ShutdownAndBlock();
// OnNameOwnerChanged will PostTask to quit the message loop.
- message_loop_.Run();
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
// latest_name_owner_ should be empty as the owner is gone.
ASSERT_TRUE(latest_name_owner_.empty());
@@ -361,8 +379,10 @@ TEST_F(SignalSenderVerificationTest, DISABLED_TestMultipleObjects) {
// Both of OnNameOwnerChanged() and OnOwnership() should quit the MessageLoop,
// but there's no expected order of those 2 event.
while (!on_name_owner_changed_called_ || !second_name_owner_changed_called ||
- !on_ownership_called_)
- message_loop_.Run();
+ !on_ownership_called_) {
+ run_loop_.reset(new base::RunLoop);
+ run_loop_->Run();
+ }
ASSERT_TRUE(on_name_owner_changed_called_);
ASSERT_TRUE(second_name_owner_changed_called);
ASSERT_TRUE(on_ownership_called_);
diff --git a/chromium/dbus/test_service.cc b/chromium/dbus/test_service.cc
index 96fa8bced98..1ec20702467 100644
--- a/chromium/dbus/test_service.cc
+++ b/chromium/dbus/test_service.cc
@@ -24,7 +24,7 @@ void EmptyCallback(bool /* success */) {
namespace dbus {
// Echo, SlowEcho, AsyncEcho, BrokenMethod, GetAll, Get, Set, PerformAction,
-// GetManagedObjects.
+// GetManagedObjects
const int TestService::kNumMethodsToExport = 9;
TestService::Options::Options()
@@ -39,7 +39,11 @@ TestService::TestService(const Options& options)
request_ownership_options_(options.request_ownership_options),
dbus_task_runner_(options.dbus_task_runner),
on_name_obtained_(false, false),
- num_exported_methods_(0) {
+ num_exported_methods_(0),
+ send_immediate_properties_changed_(false),
+ has_ownership_(false),
+ exported_object_(NULL),
+ exported_object_manager_(NULL) {
}
TestService::~TestService() {
@@ -160,6 +164,10 @@ void TestService::ReleaseOwnershipInternal(
callback);
}
+void TestService::SetSendImmediatePropertiesChanged() {
+ send_immediate_properties_changed_ = true;
+}
+
void TestService::OnExported(const std::string& interface_name,
const std::string& method_name,
bool success) {
@@ -471,11 +479,13 @@ void TestService::PerformAction(
return;
}
- if (action == "AddObject")
+ if (action == "AddObject") {
AddObject(object_path);
- else if (action == "RemoveObject")
+ } else if (action == "RemoveObject") {
RemoveObject(object_path);
- else if (action == "ReleaseOwnership") {
+ } else if (action == "SetSendImmediatePropertiesChanged") {
+ SetSendImmediatePropertiesChanged();
+ } if (action == "ReleaseOwnership") {
ReleaseOwnership(base::Bind(&TestService::PerformActionResponse,
base::Unretained(this),
method_call, response_sender));
@@ -556,6 +566,9 @@ void TestService::GetManagedObjects(
writer.CloseContainer(&array_writer);
response_sender.Run(response.Pass());
+
+ if (send_immediate_properties_changed_)
+ SendPropertyChangedSignal("ChangedTestServiceName");
}
void TestService::AddPropertiesToWriter(MessageWriter* writer) {
diff --git a/chromium/dbus/test_service.h b/chromium/dbus/test_service.h
index 523864cafd0..cc7d5211f91 100644
--- a/chromium/dbus/test_service.h
+++ b/chromium/dbus/test_service.h
@@ -106,7 +106,7 @@ class TestService : public base::Thread {
bool success);
// base::Thread override.
- virtual void Run(base::MessageLoop* message_loop) OVERRIDE;
+ virtual void Run(base::MessageLoop* message_loop) override;
//
// Exported methods.
@@ -173,6 +173,10 @@ class TestService : public base::Thread {
// Helper function for ReleaseOwnership().
void ReleaseOwnershipInternal(base::Closure callback);
+ // Configures the test service to send a PropertiesChanged signal for the
+ // "Name" property immediately after a call to GetManagedObjects.
+ void SetSendImmediatePropertiesChanged();
+
// Sends the response on completion of the performed action.
void PerformActionResponse(
MethodCall* method_call,
@@ -197,6 +201,10 @@ class TestService : public base::Thread {
// The number of methods actually exported.
int num_exported_methods_;
+ // True if a PropertiesChanged signal for the "Name" property should be sent
+ // immediately following a call to GetManagedObjects.
+ bool send_immediate_properties_changed_;
+
// True iff this instance has successfully acquired the name ownership.
bool has_ownership_;
diff --git a/chromium/dbus/util.cc b/chromium/dbus/util.cc
new file mode 100644
index 00000000000..26e5c71629f
--- /dev/null
+++ b/chromium/dbus/util.cc
@@ -0,0 +1,14 @@
+// Copyright 2014 The Chromium 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 "dbus/util.h"
+
+namespace dbus {
+
+std::string GetAbsoluteMemberName(const std::string& interface_name,
+ const std::string& member_name) {
+ return interface_name + "." + member_name;
+}
+
+} // namespace dbus
diff --git a/chromium/dbus/util.h b/chromium/dbus/util.h
new file mode 100644
index 00000000000..b983b6fdb86
--- /dev/null
+++ b/chromium/dbus/util.h
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_UTIL_H_
+#define DBUS_UTIL_H_
+
+#include <string>
+
+#include "dbus/dbus_export.h"
+
+namespace dbus {
+
+// Returns the absolute name of a member by concatanating |interface_name| and
+// |member_name|. e.g.:
+// GetAbsoluteMemberName(
+// "org.freedesktop.DBus.Properties",
+// "PropertiesChanged")
+//
+// => "org.freedesktop.DBus.Properties.PropertiesChanged"
+//
+CHROME_DBUS_EXPORT std::string GetAbsoluteMemberName(
+ const std::string& interface_name,
+ const std::string& member_name);
+
+} // namespace dbus
+
+#endif // DBUS_UTIL_H_
diff --git a/chromium/dbus/util_unittest.cc b/chromium/dbus/util_unittest.cc
new file mode 100644
index 00000000000..4bf6efa2aee
--- /dev/null
+++ b/chromium/dbus/util_unittest.cc
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium 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 "dbus/util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace dbus {
+
+TEST(UtilTest, GetAbsoluteMemberName) {
+ EXPECT_EQ("InterfaceName.MemberName",
+ GetAbsoluteMemberName("InterfaceName", "MemberName"));
+ EXPECT_EQ(".", GetAbsoluteMemberName("", ""));
+}
+
+} // namespace dbus