diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-06-18 14:10:49 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-06-18 13:53:24 +0000 |
commit | 813fbf95af77a531c57a8c497345ad2c61d475b3 (patch) | |
tree | 821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/dbus | |
parent | af6588f8d723931a298c995fa97259bb7f7deb55 (diff) | |
download | qtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz |
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/dbus')
29 files changed, 561 insertions, 233 deletions
diff --git a/chromium/dbus/BUILD.gn b/chromium/dbus/BUILD.gn index 830bd19406c..a133e724b64 100644 --- a/chromium/dbus/BUILD.gn +++ b/chromium/dbus/BUILD.gn @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//testing/test.gni") import("//third_party/protobuf/proto_library.gni") component("dbus") { @@ -29,28 +30,28 @@ component("dbus") { "scoped_dbus_error.h", "string_util.cc", "string_util.h", - "values_util.cc", - "values_util.h", "util.cc", "util.h", + "values_util.cc", + "values_util.h", ] - defines = [ - "DBUS_IMPLEMENTATION", - ] + defines = [ "DBUS_IMPLEMENTATION" ] deps = [ - "//base", "//third_party/protobuf:protobuf_lite", ] - - public_configs = [ - "//build/config/linux:dbus", + public_deps = [ + "//base", ] + + public_configs = [ "//build/config/linux:dbus" ] } proto_library("test_proto") { - sources = [ "test_proto.proto" ] + sources = [ + "test_proto.proto", + ] } # This target contains mocks that can be used to write unit tests without @@ -68,14 +69,14 @@ source_set("test_support") { "mock_object_proxy.h", ] - deps = [ + public_deps = [ ":dbus", + ] + deps = [ "//testing/gmock", ] - configs += [ - "//build/config/linux:dbus", - ] + configs += [ "//build/config/linux:dbus" ] } test("dbus_unittests") { @@ -108,9 +109,7 @@ test("dbus_unittests") { "//third_party/protobuf:protobuf_lite", ] - configs += [ - "//build/config/linux:dbus", - ] + configs += [ "//build/config/linux:dbus" ] } executable("dbus_test_server") { @@ -127,7 +126,5 @@ executable("dbus_test_server") { "//base/test:test_support", ] - configs += [ - "//build/config/linux:dbus", - ] + configs += [ "//build/config/linux:dbus" ] } diff --git a/chromium/dbus/OWNERS b/chromium/dbus/OWNERS index cfe5da564ca..fc425e6db42 100644 --- a/chromium/dbus/OWNERS +++ b/chromium/dbus/OWNERS @@ -1,3 +1,4 @@ +hashimoto@chromium.org keybuk@chromium.org satorux@chromium.org stevenjb@chromium.org diff --git a/chromium/dbus/bus.cc b/chromium/dbus/bus.cc index e9e77a5dcd4..2f1300a25e3 100644 --- a/chromium/dbus/bus.cc +++ b/chromium/dbus/bus.cc @@ -47,9 +47,7 @@ class Watch : public base::MessagePumpLibevent::Watcher { dbus_watch_set_data(raw_watch_, this, NULL); } - virtual ~Watch() { - dbus_watch_set_data(raw_watch_, NULL, NULL); - } + ~Watch() override { dbus_watch_set_data(raw_watch_, NULL, NULL); } // Returns true if the underlying file descriptor is ready to be watched. bool IsReadyToBeWatched() { @@ -84,13 +82,13 @@ class Watch : public base::MessagePumpLibevent::Watcher { private: // Implement MessagePumpLibevent::Watcher. - virtual void OnFileCanReadWithoutBlocking(int file_descriptor) override { + 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 { + void OnFileCanWriteWithoutBlocking(int file_descriptor) override { const bool success = dbus_watch_handle(raw_watch_, DBUS_WATCH_WRITABLE); CHECK(success) << "Unable to allocate memory"; } @@ -197,8 +195,7 @@ Bus::Bus(const Options& options) shutdown_completed_(false), num_pending_watches_(0), num_pending_timeouts_(0), - address_(options.address), - on_disconnected_closure_(options.disconnected_callback) { + address_(options.address) { // This is safe to call multiple times. dbus_threads_init_default(); // The origin message loop is unnecessary if the client uses synchronous @@ -690,7 +687,7 @@ void Bus::Send(DBusMessage* request, uint32* serial) { CHECK(success) << "Unable to allocate memory"; } -bool Bus::AddFilterFunction(DBusHandleMessageFunction filter_function, +void Bus::AddFilterFunction(DBusHandleMessageFunction filter_function, void* user_data) { DCHECK(connection_); AssertOnDBusThread(); @@ -701,17 +698,16 @@ bool Bus::AddFilterFunction(DBusHandleMessageFunction filter_function, filter_functions_added_.end()) { VLOG(1) << "Filter function already exists: " << filter_function << " with associated data: " << user_data; - return false; + return; } const bool success = dbus_connection_add_filter( connection_, filter_function, user_data, NULL); CHECK(success) << "Unable to allocate memory"; filter_functions_added_.insert(filter_data_pair); - return true; } -bool Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function, +void Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function, void* user_data) { DCHECK(connection_); AssertOnDBusThread(); @@ -723,12 +719,11 @@ bool Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function, VLOG(1) << "Requested to remove an unknown filter function: " << filter_function << " with associated data: " << user_data; - return false; + return; } dbus_connection_remove_filter(connection_, filter_function, user_data); filter_functions_added_.erase(filter_data_pair); - return true; } void Bus::AddMatch(const std::string& match_rule, DBusError* error) { @@ -826,8 +821,7 @@ void Bus::ProcessAllIncomingDataIfAny() { return; // It is safe and necessary to call dbus_connection_get_dispatch_status even - // if the connection is lost. Otherwise we will miss "Disconnected" signal. - // (crbug.com/174431) + // if the connection is lost. if (dbus_connection_get_dispatch_status(connection_) == DBUS_DISPATCH_DATA_REMAINS) { while (dbus_connection_dispatch(connection_) == @@ -948,11 +942,8 @@ void Bus::ListenForServiceOwnerChangeInternal( if (!Connect() || !SetUpAsyncOperations()) return; - if (service_owner_changed_listener_map_.empty()) { - bool filter_added = - AddFilterFunction(Bus::OnServiceOwnerChangedFilter, this); - DCHECK(filter_added); - } + if (service_owner_changed_listener_map_.empty()) + AddFilterFunction(Bus::OnServiceOwnerChangedFilter, this); ServiceOwnerChangedListenerMap::iterator it = service_owner_changed_listener_map_.find(service_name); @@ -1026,11 +1017,8 @@ void Bus::UnlistenForServiceOwnerChangeInternal( // And remove |service_owner_changed_listener_map_| entry. service_owner_changed_listener_map_.erase(it); - if (service_owner_changed_listener_map_.empty()) { - bool filter_removed = - RemoveFilterFunction(Bus::OnServiceOwnerChangedFilter, this); - DCHECK(filter_removed); - } + if (service_owner_changed_listener_map_.empty()) + RemoveFilterFunction(Bus::OnServiceOwnerChangedFilter, this); } dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) { @@ -1112,19 +1100,6 @@ void Bus::OnDispatchStatusChanged(DBusConnection* connection, this)); } -void Bus::OnConnectionDisconnected(DBusConnection* connection) { - AssertOnDBusThread(); - - if (!on_disconnected_closure_.is_null()) - GetOriginTaskRunner()->PostTask(FROM_HERE, on_disconnected_closure_); - - if (!connection) - return; - DCHECK(!dbus_connection_get_is_connected(connection)); - - ShutdownAndBlock(); -} - void Bus::OnServiceOwnerChanged(DBusMessage* message) { DCHECK(message); AssertOnDBusThread(); @@ -1215,9 +1190,8 @@ DBusHandlerResult Bus::OnConnectionDisconnectedFilter( if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, kDisconnectedSignal)) { - Bus* self = static_cast<Bus*>(data); - self->OnConnectionDisconnected(connection); - return DBUS_HANDLER_RESULT_HANDLED; + // Abort when the connection is lost. + LOG(FATAL) << "D-Bus connection was disconnected. Aborting."; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } diff --git a/chromium/dbus/bus.h b/chromium/dbus/bus.h index 544d31fc169..f9f0dfd9cf6 100644 --- a/chromium/dbus/bus.h +++ b/chromium/dbus/bus.h @@ -218,12 +218,6 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> { // // Do something. // std::string address; - - // If the connection with dbus-daemon is closed, |disconnected_callback| - // will be called on the origin thread. This is also called when the - // disonnection by ShutdownAndBlock. |disconnected_callback| can be null - // callback - base::Closure disconnected_callback; }; // Creates a Bus object. The actual connection will be established when @@ -471,24 +465,23 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> { virtual void Send(DBusMessage* request, uint32* serial); // Adds the message filter function. |filter_function| will be called - // when incoming messages are received. Returns true on success. + // when incoming messages are received. // // When a new incoming message arrives, filter functions are called in // the order that they were added until the the incoming message is // handled by a filter function. // // The same filter function associated with the same user data cannot be - // added more than once. Returns false for this case. + // added more than once. // // BLOCKING CALL. - virtual bool AddFilterFunction(DBusHandleMessageFunction filter_function, + virtual void AddFilterFunction(DBusHandleMessageFunction filter_function, void* user_data); // Removes the message filter previously added by AddFilterFunction(). - // Returns true on success. // // BLOCKING CALL. - virtual bool RemoveFilterFunction(DBusHandleMessageFunction filter_function, + virtual void RemoveFilterFunction(DBusHandleMessageFunction filter_function, void* user_data); // Adds the match rule. Messages that match the rule will be processed @@ -671,9 +664,6 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> { void OnDispatchStatusChanged(DBusConnection* connection, DBusDispatchStatus status); - // Called when the connection is diconnected. - void OnConnectionDisconnected(DBusConnection* connection); - // Called when a service owner change occurs. void OnServiceOwnerChanged(DBusMessage* message); @@ -761,7 +751,6 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> { int num_pending_timeouts_; std::string address_; - base::Closure on_disconnected_closure_; DISALLOW_COPY_AND_ASSIGN(Bus); }; diff --git a/chromium/dbus/bus_unittest.cc b/chromium/dbus/bus_unittest.cc index d6955698390..22ccddc57cd 100644 --- a/chromium/dbus/bus_unittest.cc +++ b/chromium/dbus/bus_unittest.cc @@ -21,13 +21,6 @@ namespace dbus { namespace { -// Used to test AddFilterFunction(). -DBusHandlerResult DummyHandler(DBusConnection* connection, - DBusMessage* raw_message, - void* user_data) { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - // Test helper for BusTest.ListenForServiceOwnerChange that wraps a // base::RunLoop. At Run() time, the caller pass in the expected number of // quit calls, and at QuitIfConditionIsSatisified() time, only quit the RunLoop @@ -284,27 +277,6 @@ TEST(BusTest, ShutdownAndBlockWithDBusThread) { dbus_thread.Stop(); } -TEST(BusTest, AddFilterFunction) { - Bus::Options options; - scoped_refptr<Bus> bus = new Bus(options); - // Should connect before calling AddFilterFunction(). - bus->Connect(); - - int data1 = 100; - int data2 = 200; - ASSERT_TRUE(bus->AddFilterFunction(&DummyHandler, &data1)); - // Cannot add the same function with the same data. - ASSERT_FALSE(bus->AddFilterFunction(&DummyHandler, &data1)); - // Can add the same function with different data. - ASSERT_TRUE(bus->AddFilterFunction(&DummyHandler, &data2)); - - ASSERT_TRUE(bus->RemoveFilterFunction(&DummyHandler, &data1)); - ASSERT_FALSE(bus->RemoveFilterFunction(&DummyHandler, &data1)); - ASSERT_TRUE(bus->RemoveFilterFunction(&DummyHandler, &data2)); - - bus->ShutdownAndBlock(); -} - TEST(BusTest, DoubleAddAndRemoveMatch) { Bus::Options options; scoped_refptr<Bus> bus = new Bus(options); diff --git a/chromium/dbus/dbus_statistics_unittest.cc b/chromium/dbus/dbus_statistics_unittest.cc index 0c0dd034972..6260a63ebe9 100644 --- a/chromium/dbus/dbus_statistics_unittest.cc +++ b/chromium/dbus/dbus_statistics_unittest.cc @@ -15,13 +15,9 @@ class DBusStatisticsTest : public testing::Test { DBusStatisticsTest() { } - virtual void SetUp() override { - statistics::Initialize(); - } + void SetUp() override { statistics::Initialize(); } - virtual void TearDown() override { - statistics::Shutdown(); - } + void TearDown() override { statistics::Shutdown(); } protected: void AddTestMethodCalls() { diff --git a/chromium/dbus/end_to_end_async_unittest.cc b/chromium/dbus/end_to_end_async_unittest.cc index 15f410eadc0..10516b99971 100644 --- a/chromium/dbus/end_to_end_async_unittest.cc +++ b/chromium/dbus/end_to_end_async_unittest.cc @@ -35,9 +35,7 @@ const int kHugePayloadSize = 64 << 20; // 64 MB // ExportedObject. class EndToEndAsyncTest : public testing::Test { public: - EndToEndAsyncTest() : on_disconnected_call_count_(0) {} - - virtual void SetUp() { + void SetUp() override { // Make the main thread not to allow IO. base::ThreadRestrictions::SetIOAllowed(false); @@ -60,8 +58,6 @@ class EndToEndAsyncTest : public testing::Test { bus_options.bus_type = Bus::SESSION; bus_options.connection_type = Bus::PRIVATE; bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy(); - bus_options.disconnected_callback = - base::Bind(&EndToEndAsyncTest::OnDisconnected, base::Unretained(this)); bus_ = new Bus(bus_options); object_proxy_ = bus_->GetObjectProxy( "org.chromium.TestService", @@ -116,7 +112,7 @@ class EndToEndAsyncTest : public testing::Test { run_loop_->Run(); } - virtual void TearDown() { + void TearDown() override { bus_->ShutdownOnDBusThreadAndBlock(); // Shut down the service. @@ -248,12 +244,6 @@ class EndToEndAsyncTest : public testing::Test { run_loop_->Quit(); } - // Called when the connection with dbus-daemon is disconnected. - void OnDisconnected() { - run_loop_->Quit(); - ++on_disconnected_call_count_; - } - // Wait for the hey signal to be received. void WaitForTestSignal() { // OnTestSignal() will quit the message loop. @@ -274,7 +264,6 @@ class EndToEndAsyncTest : public testing::Test { std::string test_signal_string_; // Text message from "Test" signal delivered to root. std::string root_test_signal_string_; - int on_disconnected_call_count_; }; TEST_F(EndToEndAsyncTest, Echo) { @@ -429,6 +418,33 @@ TEST_F(EndToEndAsyncTest, TimeoutWithErrorCallback) { ASSERT_EQ(DBUS_ERROR_NO_REPLY, error_names_[0]); } +TEST_F(EndToEndAsyncTest, CancelPendingCalls) { + const char* kHello = "hello"; + + // Create the method call. + MethodCall method_call("org.chromium.TestInterface", "Echo"); + MessageWriter writer(&method_call); + writer.AppendString(kHello); + + // Call the method. + const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT; + CallMethod(&method_call, timeout_ms); + + // Remove the object proxy before receiving the result. + // This results in cancelling the pending method call. + bus_->RemoveObjectProxy("org.chromium.TestService", + ObjectPath("/org/chromium/TestObject"), + base::Bind(&base::DoNothing)); + + // We shouldn't receive any responses. Wait for a while just to make sure. + run_loop_.reset(new base::RunLoop); + message_loop_.PostDelayedTask(FROM_HERE, + run_loop_->QuitClosure(), + TestTimeouts::tiny_timeout()); + run_loop_->Run(); + EXPECT_TRUE(response_strings_.empty()); +} + // Tests calling a method that sends its reply asynchronously. TEST_F(EndToEndAsyncTest, AsyncEcho) { const char* kHello = "hello"; @@ -588,22 +604,12 @@ TEST_F(EndToEndAsyncTest, TestHugeSignal) { ASSERT_EQ(kHugeMessage, test_signal_string_); } -TEST_F(EndToEndAsyncTest, DisconnectedSignal) { - bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, - base::Bind(&Bus::ClosePrivateConnection, - base::Unretained(bus_.get()))); - // OnDisconnected callback quits message loop. - run_loop_.reset(new base::RunLoop); - run_loop_->Run(); - EXPECT_EQ(1, on_disconnected_call_count_); -} - class SignalMultipleHandlerTest : public EndToEndAsyncTest { public: SignalMultipleHandlerTest() { } - virtual void SetUp() { + void SetUp() override { // Set up base class. EndToEndAsyncTest::SetUp(); diff --git a/chromium/dbus/end_to_end_sync_unittest.cc b/chromium/dbus/end_to_end_sync_unittest.cc index e3b316ab6f8..1167d96650b 100644 --- a/chromium/dbus/end_to_end_sync_unittest.cc +++ b/chromium/dbus/end_to_end_sync_unittest.cc @@ -21,7 +21,7 @@ class EndToEndSyncTest : public testing::Test { EndToEndSyncTest() { } - virtual void SetUp() { + void SetUp() override { // Start the test service; TestService::Options options; test_service_.reset(new TestService(options)); @@ -40,7 +40,7 @@ class EndToEndSyncTest : public testing::Test { ASSERT_FALSE(client_bus_->HasDBusThread()); } - virtual void TearDown() { + void TearDown() override { test_service_->ShutdownAndBlock(); test_service_->Stop(); client_bus_->ShutdownAndBlock(); diff --git a/chromium/dbus/exported_object.cc b/chromium/dbus/exported_object.cc index 107d2e5dd17..669b871e35b 100644 --- a/chromium/dbus/exported_object.cc +++ b/chromium/dbus/exported_object.cc @@ -91,12 +91,21 @@ void ExportedObject::SendSignal(Signal* signal) { dbus_message_ref(signal_message); const base::TimeTicks start_time = base::TimeTicks::Now(); - bus_->GetDBusTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ExportedObject::SendSignalInternal, - this, - start_time, - signal_message)); + if (bus_->GetDBusTaskRunner()->RunsTasksOnCurrentThread()) { + // The Chrome OS power manager doesn't use a dedicated TaskRunner for + // sending DBus messages. Sending signals asynchronously can cause an + // inversion in the message order if the power manager calls + // ObjectProxy::CallMethodAndBlock() before going back to the top level of + // the MessageLoop: crbug.com/472361. + SendSignalInternal(start_time, signal_message); + } else { + bus_->GetDBusTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ExportedObject::SendSignalInternal, + this, + start_time, + signal_message)); + } } void ExportedObject::Unregister() { diff --git a/chromium/dbus/exported_object.h b/chromium/dbus/exported_object.h index 5f74dc2b1e4..89de096199c 100644 --- a/chromium/dbus/exported_object.h +++ b/chromium/dbus/exported_object.h @@ -92,7 +92,8 @@ class CHROME_DBUS_EXPORT ExportedObject OnExportedCallback on_exported_callback); // Requests to send the signal from this object. The signal will be sent - // asynchronously from the message loop in the D-Bus thread. + // synchronously if this method is called from the message loop in the D-Bus + // thread and asynchronously otherwise. virtual void SendSignal(Signal* signal); // Unregisters the object from the bus. The Bus object will take care of diff --git a/chromium/dbus/file_descriptor.cc b/chromium/dbus/file_descriptor.cc index d2d6a31f1e3..e607fc01356 100644 --- a/chromium/dbus/file_descriptor.cc +++ b/chromium/dbus/file_descriptor.cc @@ -2,12 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/bind.h" #include "base/files/file.h" +#include "base/location.h" #include "base/logging.h" +#include "base/threading/worker_pool.h" #include "dbus/file_descriptor.h" namespace dbus { +void CHROME_DBUS_EXPORT FileDescriptor::Deleter::operator()( + FileDescriptor* fd) { + base::WorkerPool::PostTask( + FROM_HERE, base::Bind(&base::DeletePointer<FileDescriptor>, fd), false); +} + FileDescriptor::~FileDescriptor() { if (owner_) base::File auto_closer(value_); diff --git a/chromium/dbus/file_descriptor.h b/chromium/dbus/file_descriptor.h index 19e0b1ab44b..a01ee6ee011 100644 --- a/chromium/dbus/file_descriptor.h +++ b/chromium/dbus/file_descriptor.h @@ -6,6 +6,7 @@ #define DBUS_FILE_DESCRIPTOR_H_ #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "dbus/dbus_export.h" namespace dbus { @@ -33,6 +34,12 @@ namespace dbus { // with i/o restrictions. class CHROME_DBUS_EXPORT FileDescriptor { public: + // This provides a simple way to pass around file descriptors since they must + // be closed on a thread that is allowed to perform I/O. + struct Deleter { + void CHROME_DBUS_EXPORT operator()(FileDescriptor* fd); + }; + // Permits initialization without a value for passing to // dbus::MessageReader::PopFileDescriptor to fill in and from int values. FileDescriptor() : value_(-1), owner_(false), valid_(false) {} @@ -70,6 +77,9 @@ class CHROME_DBUS_EXPORT FileDescriptor { DISALLOW_COPY_AND_ASSIGN(FileDescriptor); }; +using ScopedFileDescriptor = + scoped_ptr<FileDescriptor, FileDescriptor::Deleter>; + } // namespace dbus #endif // DBUS_FILE_DESCRIPTOR_H_ diff --git a/chromium/dbus/message_unittest.cc b/chromium/dbus/message_unittest.cc index 0eaea8395f5..2c13d08c6b9 100644 --- a/chromium/dbus/message_unittest.cc +++ b/chromium/dbus/message_unittest.cc @@ -4,6 +4,8 @@ #include "dbus/message.h" +#include <stdint.h> + #include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" @@ -400,7 +402,7 @@ TEST(MessageTest, CreateComplexMessageAndReadIt) { MessageWriter dict_entry_writer(NULL); dict_array_writer.OpenDictEntry(&dict_entry_writer); dict_entry_writer.AppendString("foo"); - dict_entry_writer.AppendInt64(GG_INT64_C(1234567890123456789)); + dict_entry_writer.AppendInt64(INT64_C(1234567890123456789)); dict_array_writer.CloseContainer(&dict_entry_writer); } variant_writer.CloseContainer(&dict_array_writer); @@ -475,7 +477,7 @@ TEST(MessageTest, CreateComplexMessageAndReadIt) { EXPECT_EQ("foo", string_value); int64 int64_value = 0; ASSERT_TRUE(dict_entry_reader.PopInt64(&int64_value)); - EXPECT_EQ(GG_INT64_C(1234567890123456789), int64_value); + EXPECT_EQ(INT64_C(1234567890123456789), int64_value); } ASSERT_FALSE(dict_array_reader.HasMoreData()); } diff --git a/chromium/dbus/mock_object_proxy.h b/chromium/dbus/mock_object_proxy.h index 7c61b47b428..66f485ad06f 100644 --- a/chromium/dbus/mock_object_proxy.h +++ b/chromium/dbus/mock_object_proxy.h @@ -29,7 +29,7 @@ class MockObjectProxy : public ObjectProxy { Response*(MethodCall* method_call, int timeout_ms, ScopedDBusError* error)); - virtual scoped_ptr<Response> CallMethodAndBlockWithErrorDetails( + scoped_ptr<Response> CallMethodAndBlockWithErrorDetails( MethodCall* method_call, int timeout_ms, ScopedDBusError* error) override { @@ -38,8 +38,8 @@ class MockObjectProxy : public ObjectProxy { } MOCK_METHOD2(MockCallMethodAndBlock, Response*(MethodCall* method_call, int timeout_ms)); - virtual scoped_ptr<Response> CallMethodAndBlock(MethodCall* method_call, - int timeout_ms) override { + scoped_ptr<Response> CallMethodAndBlock(MethodCall* method_call, + int timeout_ms) override { return scoped_ptr<Response>(MockCallMethodAndBlock(method_call, timeout_ms)); } @@ -58,7 +58,7 @@ class MockObjectProxy : public ObjectProxy { MOCK_METHOD0(Detach, void()); protected: - virtual ~MockObjectProxy(); + ~MockObjectProxy() override; }; } // namespace dbus diff --git a/chromium/dbus/mock_unittest.cc b/chromium/dbus/mock_unittest.cc index bfdc5a30c28..6b2a521127a 100644 --- a/chromium/dbus/mock_unittest.cc +++ b/chromium/dbus/mock_unittest.cc @@ -29,7 +29,7 @@ class MockTest : public testing::Test { MockTest() { } - virtual void SetUp() { + void SetUp() override { // Create a mock bus. Bus::Options options; options.bus_type = Bus::SYSTEM; @@ -66,9 +66,7 @@ class MockTest : public testing::Test { EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return()); } - virtual void TearDown() { - mock_bus_->ShutdownAndBlock(); - } + void TearDown() override { mock_bus_->ShutdownAndBlock(); } // Called when the response is received. void OnResponse(Response* response) { diff --git a/chromium/dbus/object_manager.cc b/chromium/dbus/object_manager.cc index f754bb693fd..851fee44b2e 100644 --- a/chromium/dbus/object_manager.cc +++ b/chromium/dbus/object_manager.cc @@ -155,8 +155,7 @@ void ObjectManager::CleanUp() { if (!setup_success_) return; - if (!bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this)) - LOG(ERROR) << "Failed to remove filter function"; + bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this); ScopedDBusError error; bus_->RemoveMatch(match_rule_, error.get()); @@ -216,10 +215,7 @@ bool ObjectManager::SetupMatchRuleAndFilter() { kPropertiesInterface, kPropertiesChanged); - if (!bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this)) { - LOG(ERROR) << "ObjectManager failed to add filter function"; - return false; - } + bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this); ScopedDBusError error; bus_->AddMatch(match_rule, error.get()); @@ -486,6 +482,7 @@ void ObjectManager::RemoveInterface(const ObjectPath& object_path, interface->ObjectRemoved(object_path, interface_name); } + delete piter->second; object->properties_map.erase(piter); if (object->properties_map.empty()) { diff --git a/chromium/dbus/object_manager_unittest.cc b/chromium/dbus/object_manager_unittest.cc index cd02c5e13c1..76ddb85fa8f 100644 --- a/chromium/dbus/object_manager_unittest.cc +++ b/chromium/dbus/object_manager_unittest.cc @@ -48,10 +48,9 @@ class ObjectManagerTest } }; - virtual PropertySet* CreateProperties( - ObjectProxy* object_proxy, - const ObjectPath& object_path, - const std::string& interface_name) override { + PropertySet* CreateProperties(ObjectProxy* object_proxy, + const ObjectPath& object_path, + const std::string& interface_name) override { Properties* properties = new Properties( object_proxy, interface_name, base::Bind(&ObjectManagerTest::OnPropertyChanged, @@ -59,7 +58,7 @@ class ObjectManagerTest return static_cast<PropertySet*>(properties); } - virtual void SetUp() { + void SetUp() override { // Make the main thread not to allow IO. base::ThreadRestrictions::SetIOAllowed(false); @@ -93,7 +92,7 @@ class ObjectManagerTest WaitForObject(); } - virtual void TearDown() { + void TearDown() override { bus_->ShutdownOnDBusThreadAndBlock(); // Shut down the service. @@ -126,15 +125,15 @@ class ObjectManagerTest protected: // Called when an object is added. - virtual void ObjectAdded(const ObjectPath& object_path, - const std::string& interface_name) override { + void ObjectAdded(const ObjectPath& object_path, + const std::string& interface_name) override { added_objects_.push_back(std::make_pair(object_path, interface_name)); run_loop_->Quit(); } // Called when an object is removed. - virtual void ObjectRemoved(const ObjectPath& object_path, - const std::string& interface_name) override { + void ObjectRemoved(const ObjectPath& object_path, + const std::string& interface_name) override { removed_objects_.push_back(std::make_pair(object_path, interface_name)); run_loop_->Quit(); } diff --git a/chromium/dbus/object_proxy.cc b/chromium/dbus/object_proxy.cc index 59584f2ce34..441dc757bd7 100644 --- a/chromium/dbus/object_proxy.cc +++ b/chromium/dbus/object_proxy.cc @@ -55,12 +55,12 @@ ObjectProxy::ObjectProxy(Bus* bus, : bus_(bus), service_name_(service_name), object_path_(object_path), - filter_added_(false), ignore_service_unknown_errors_( options & IGNORE_SERVICE_UNKNOWN_ERRORS) { } ObjectProxy::~ObjectProxy() { + DCHECK(pending_calls_.empty()); } // Originally we tried to make |method_call| a const reference, but we @@ -169,17 +169,20 @@ void ObjectProxy::ConnectToSignal(const std::string& interface_name, OnConnectedCallback on_connected_callback) { bus_->AssertOnOriginThread(); - base::PostTaskAndReplyWithResult( - bus_->GetDBusTaskRunner(), - FROM_HERE, - base::Bind(&ObjectProxy::ConnectToSignalInternal, - this, - interface_name, - signal_name, - signal_callback), - base::Bind(on_connected_callback, - interface_name, - signal_name)); + if (bus_->HasDBusThread()) { + base::PostTaskAndReplyWithResult( + bus_->GetDBusTaskRunner(), FROM_HERE, + base::Bind(&ObjectProxy::ConnectToSignalInternal, this, interface_name, + signal_name, signal_callback), + base::Bind(on_connected_callback, interface_name, signal_name)); + } else { + // If the bus doesn't have a dedicated dbus thread we need to call + // ConnectToSignalInternal directly otherwise we might miss a signal + // that is currently queued if we do a PostTask. + const bool success = + ConnectToSignalInternal(interface_name, signal_name, signal_callback); + on_connected_callback.Run(interface_name, signal_name, success); + } } void ObjectProxy::SetNameOwnerChangedCallback( @@ -202,22 +205,24 @@ void ObjectProxy::WaitForServiceToBeAvailable( void ObjectProxy::Detach() { bus_->AssertOnDBusThread(); - if (filter_added_) { - if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) { - LOG(ERROR) << "Failed to remove filter function"; - } - } + if (bus_->is_connected()) + bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this); - for (std::set<std::string>::iterator iter = match_rules_.begin(); - iter != match_rules_.end(); ++iter) { + for (const auto& match_rule : match_rules_) { ScopedDBusError error; - bus_->RemoveMatch(*iter, error.get()); + bus_->RemoveMatch(match_rule, error.get()); if (error.is_set()) { // There is nothing we can do to recover, so just print the error. - LOG(ERROR) << "Failed to remove match rule: " << *iter; + LOG(ERROR) << "Failed to remove match rule: " << match_rule; } } match_rules_.clear(); + + for (auto* pending_call : pending_calls_) { + dbus_pending_call_cancel(pending_call); + dbus_pending_call_unref(pending_call); + } + pending_calls_.clear(); } // static @@ -276,9 +281,9 @@ void ObjectProxy::StartAsyncMethodCall(int timeout_ms, pending_call, &ObjectProxy::OnPendingCallIsCompleteThunk, data, - NULL); + &DeleteVoidPointer<OnPendingCallIsCompleteData>); CHECK(success) << "Unable to allocate memory"; - dbus_pending_call_unref(pending_call); + pending_calls_.insert(pending_call); // It's now safe to unref the request message. dbus_message_unref(request_message); @@ -298,6 +303,10 @@ void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, start_time, response_message); bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task); + + // Remove the pending call from the set. + pending_calls_.erase(pending_call); + dbus_pending_call_unref(pending_call); } void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, @@ -368,7 +377,6 @@ void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, data->response_callback, data->error_callback, data->start_time); - delete data; } bool ObjectProxy::ConnectToNameOwnerChangedSignal() { @@ -377,15 +385,8 @@ bool ObjectProxy::ConnectToNameOwnerChangedSignal() { if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) return false; - // We should add the filter only once. Otherwise, HandleMessage() will - // be called more than once. - if (!filter_added_) { - if (bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this)) { - filter_added_ = true; - } else { - LOG(ERROR) << "Failed to add filter function"; - } - } + bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this); + // Add a match_rule listening NameOwnerChanged for the well-known name // |service_name_|. const std::string name_owner_changed_match_rule = diff --git a/chromium/dbus/object_proxy.h b/chromium/dbus/object_proxy.h index 1400328fda0..c0211b1db61 100644 --- a/chromium/dbus/object_proxy.h +++ b/chromium/dbus/object_proxy.h @@ -297,9 +297,6 @@ class CHROME_DBUS_EXPORT ObjectProxy std::string service_name_; ObjectPath object_path_; - // True if the message filter was added. - bool filter_added_; - // The method table where keys are absolute signal names (i.e. interface // name + signal name), and values are lists of the corresponding callbacks. typedef std::map<std::string, std::vector<SignalCallback> > MethodTable; @@ -319,6 +316,8 @@ class CHROME_DBUS_EXPORT ObjectProxy // Known name owner of the well-known bus name represented by |service_name_|. std::string service_name_owner_; + std::set<DBusPendingCall*> pending_calls_; + DISALLOW_COPY_AND_ASSIGN(ObjectProxy); }; diff --git a/chromium/dbus/object_proxy_unittest.cc b/chromium/dbus/object_proxy_unittest.cc index 246058ddd5d..22130b64bc3 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 { + void SetUp() override { Bus::Options bus_options; bus_options.bus_type = Bus::SESSION; bus_options.connection_type = Bus::PRIVATE; @@ -25,9 +25,7 @@ class ObjectProxyTest : public testing::Test { "org.chromium.TestService", ObjectPath("/org/chromium/TestObject")); } - virtual void TearDown() override { - bus_->ShutdownAndBlock(); - } + void TearDown() override { bus_->ShutdownAndBlock(); } base::MessageLoopForIO message_loop_; scoped_refptr<Bus> bus_; diff --git a/chromium/dbus/property.cc b/chromium/dbus/property.cc index 9475a0728a6..66b86c0486d 100644 --- a/chromium/dbus/property.cc +++ b/chromium/dbus/property.cc @@ -21,10 +21,10 @@ namespace dbus { void PropertyBase::Init(PropertySet* property_set, const std::string& name) { DCHECK(!property_set_); property_set_ = property_set; + is_valid_ = false; name_ = name; } - // // PropertySet implementation. // @@ -78,10 +78,10 @@ void PropertySet::ChangedReceived(Signal* signal) { << "expected dictionary: " << signal->ToString(); } - // TODO(keybuk): dbus properties api has invalidated properties array - // on the end, we don't handle this right now because I don't know of - // any service that sends it - or what they expect us to do with it. - // Add later when we need it. + if (!InvalidatePropertiesFromReader(&reader)) { + LOG(WARNING) << "Property changed signal has wrong parameters: " + << "expected array to invalidate: " << signal->ToString(); + } } void PropertySet::ChangedConnected(const std::string& interface_name, @@ -115,8 +115,15 @@ void PropertySet::OnGet(PropertyBase* property, GetCallback callback, } MessageReader reader(response); - if (property->PopValueFromReader(&reader)) + if (property->PopValueFromReader(&reader)) { + property->set_valid(true); NotifyPropertyChanged(property->name()); + } else { + if (property->is_valid()) { + property->set_valid(false); + NotifyPropertyChanged(property->name()); + } + } if (!callback.is_null()) callback.Run(response); @@ -199,13 +206,42 @@ bool PropertySet::UpdatePropertyFromReader(MessageReader* reader) { PropertyBase* property = it->second; if (property->PopValueFromReader(reader)) { + property->set_valid(true); NotifyPropertyChanged(name); return true; } else { + if (property->is_valid()) { + property->set_valid(false); + NotifyPropertyChanged(property->name()); + } return false; } } +bool PropertySet::InvalidatePropertiesFromReader(MessageReader* reader) { + DCHECK(reader); + MessageReader array_reader(NULL); + if (!reader->PopArray(&array_reader)) + return false; + + while (array_reader.HasMoreData()) { + std::string name; + if (!array_reader.PopString(&name)) + return false; + + PropertiesMap::iterator it = properties_map_.find(name); + if (it == properties_map_.end()) + continue; + + PropertyBase* property = it->second; + if (property->is_valid()) { + property->set_valid(false); + NotifyPropertyChanged(property->name()); + } + } + + return true; +} void PropertySet::NotifyPropertyChanged(const std::string& name) { if (!property_changed_callback_.is_null()) @@ -478,6 +514,103 @@ void Property<std::vector<uint8> >::AppendSetValueToWriter( writer->CloseContainer(&variant_writer); } +// +// Property<std::map<std::string, std::string>> specialization. +// + +template <> +bool Property<std::map<std::string, std::string>>::PopValueFromReader( + MessageReader* reader) { + MessageReader variant_reader(NULL); + MessageReader array_reader(NULL); + if (!reader->PopVariant(&variant_reader) || + !variant_reader.PopArray(&array_reader)) + return false; + value_.clear(); + while (array_reader.HasMoreData()) { + dbus::MessageReader dict_entry_reader(NULL); + if (!array_reader.PopDictEntry(&dict_entry_reader)) + return false; + std::string key; + std::string value; + if (!dict_entry_reader.PopString(&key) || + !dict_entry_reader.PopString(&value)) + return false; + value_[key] = value; + } + return true; +} + +template <> +void Property<std::map<std::string, std::string>>::AppendSetValueToWriter( + MessageWriter* writer) { + MessageWriter variant_writer(NULL); + MessageWriter dict_writer(NULL); + writer->OpenVariant("a{ss}", &variant_writer); + variant_writer.OpenArray("{ss}", &dict_writer); + for (const auto& pair : set_value_) { + dbus::MessageWriter entry_writer(NULL); + dict_writer.OpenDictEntry(&entry_writer); + entry_writer.AppendString(pair.first); + entry_writer.AppendString(pair.second); + dict_writer.CloseContainer(&entry_writer); + } + variant_writer.CloseContainer(&dict_writer); + writer->CloseContainer(&variant_writer); +} + +// +// Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>> +// specialization. +// + +template <> +bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: + PopValueFromReader(MessageReader* reader) { + MessageReader variant_reader(NULL); + MessageReader array_reader(NULL); + if (!reader->PopVariant(&variant_reader) || + !variant_reader.PopArray(&array_reader)) + return false; + + value_.clear(); + while (array_reader.HasMoreData()) { + dbus::MessageReader struct_reader(NULL); + if (!array_reader.PopStruct(&struct_reader)) + return false; + + std::pair<std::vector<uint8_t>, uint16_t> entry; + const uint8* bytes = NULL; + size_t length = 0; + if (!struct_reader.PopArrayOfBytes(&bytes, &length)) + return false; + entry.first.assign(bytes, bytes + length); + if (!struct_reader.PopUint16(&entry.second)) + return false; + value_.push_back(entry); + } + return true; +} + +template <> +void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: + AppendSetValueToWriter(MessageWriter* writer) { + MessageWriter variant_writer(NULL); + MessageWriter array_writer(NULL); + writer->OpenVariant("a(ayq)", &variant_writer); + variant_writer.OpenArray("(ayq)", &array_writer); + for (const auto& pair : set_value_) { + dbus::MessageWriter struct_writer(nullptr); + array_writer.OpenStruct(&struct_writer); + struct_writer.AppendArrayOfBytes(std::get<0>(pair).data(), + std::get<0>(pair).size()); + struct_writer.AppendUint16(std::get<1>(pair)); + array_writer.CloseContainer(&struct_writer); + } + variant_writer.CloseContainer(&array_writer); + writer->CloseContainer(&variant_writer); +} + template class Property<uint8>; template class Property<bool>; template class Property<int16>; @@ -492,5 +625,7 @@ template class Property<ObjectPath>; template class Property<std::vector<std::string> >; template class Property<std::vector<ObjectPath> >; template class Property<std::vector<uint8> >; +template class Property<std::map<std::string, std::string>>; +template class Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>; } // namespace dbus diff --git a/chromium/dbus/property.h b/chromium/dbus/property.h index a20e0ad466f..321f4dbd078 100644 --- a/chromium/dbus/property.h +++ b/chromium/dbus/property.h @@ -7,6 +7,8 @@ #include <map> #include <string> +#include <utility> +#include <vector> #include "base/basictypes.h" #include "base/bind.h" @@ -132,7 +134,7 @@ class PropertySet; // used by PropertySet. class PropertyBase { public: - PropertyBase() : property_set_(NULL) {} + PropertyBase() : property_set_(nullptr), is_valid_(false) {} // Initializes the |property_set| and property |name| so that method // calls may be made from this class. This method is called by @@ -154,11 +156,17 @@ class PropertyBase { // } const std::string& name() const { return name_; } + // Returns true if property is valid, false otherwise. + bool is_valid() const { return is_valid_; } + + // Allows to mark Property as valid or invalid. + void set_valid(bool is_valid) { is_valid_ = is_valid; } + // Method used by PropertySet to retrieve the value from a MessageReader, // no knowledge of the contained type is required, this method returns // true if its expected type was found, false if not. // Implementation provided by specialization. - virtual bool PopValueFromReader(MessageReader*) = 0; + virtual bool PopValueFromReader(MessageReader* reader) = 0; // Method used by PropertySet to append the set value to a MessageWriter, // no knowledge of the contained type is required. @@ -179,6 +187,8 @@ class PropertyBase { // no ownership is taken and |property_set_| must outlive this class. PropertySet* property_set_; + bool is_valid_; + // Name of the property. std::string name_; @@ -229,7 +239,7 @@ class CHROME_DBUS_EXPORT PropertySet { // Methods connected by ConnectSignals() and called by dbus:: when // a property is changed. Sub-classes may override if the property // changed signal provides different arguments. - virtual void ChangedReceived(Signal*); + virtual void ChangedReceived(Signal* signal); virtual void ChangedConnected(const std::string& interface_name, const std::string& signal_name, bool success); @@ -300,6 +310,10 @@ class CHROME_DBUS_EXPORT PropertySet { } private: + // Invalidates properties by reading an array of names, from + // |message_reader|. Returns false if message is in incorrect format. + bool InvalidatePropertiesFromReader(MessageReader* reader); + // Pointer to object proxy for making method calls, no ownership is taken // so this must outlive this class. ObjectProxy* object_proxy_; @@ -376,17 +390,17 @@ class CHROME_DBUS_EXPORT Property : public PropertyBase { // Method used by PropertySet to retrieve the value from a MessageReader, // no knowledge of the contained type is required, this method returns // true if its expected type was found, false if not. - virtual bool PopValueFromReader(MessageReader*); + bool PopValueFromReader(MessageReader* reader) override; // Method used by PropertySet to append the set value to a MessageWriter, // no knowledge of the contained type is required. // Implementation provided by specialization. - virtual void AppendSetValueToWriter(MessageWriter* writer); + void AppendSetValueToWriter(MessageWriter* writer) override; // Method used by test and stub implementations of dbus::PropertySet::Set // to replace the property value with the set value without using a // dbus::MessageReader. - virtual void ReplaceValueWithSetValue() { + void ReplaceValueWithSetValue() override { value_ = set_value_; property_set()->NotifyPropertyChanged(name()); } @@ -398,6 +412,10 @@ class CHROME_DBUS_EXPORT Property : public PropertyBase { property_set()->NotifyPropertyChanged(name()); } + // Method used by test and stub implementations to directly set the + // |set_value_| of a property. + void ReplaceSetValueForTesting(const T& value) { set_value_ = value; } + private: // Current cached value of the property. T value_; @@ -485,6 +503,23 @@ template <> void Property<std::vector<uint8> >::AppendSetValueToWriter( MessageWriter* writer); extern template class Property<std::vector<uint8> >; +template <> +bool Property<std::map<std::string, std::string>>::PopValueFromReader( + MessageReader* reader); +template <> +void Property<std::map<std::string, std::string>>::AppendSetValueToWriter( + MessageWriter* writer); +extern template class Property<std::map<std::string, std::string>>; + +template <> +bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: + PopValueFromReader(MessageReader* reader); +template <> +void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: + AppendSetValueToWriter(MessageWriter* writer); +extern template class Property< + std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>; + } // namespace dbus #endif // DBUS_PROPERTY_H_ diff --git a/chromium/dbus/property_unittest.cc b/chromium/dbus/property_unittest.cc index 879a9a60665..5208f848915 100644 --- a/chromium/dbus/property_unittest.cc +++ b/chromium/dbus/property_unittest.cc @@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" #include "dbus/bus.h" @@ -26,8 +27,7 @@ namespace dbus { // Property<>. class PropertyTest : public testing::Test { public: - PropertyTest() { - } + PropertyTest() {} struct Properties : public PropertySet { Property<std::string> name; @@ -49,7 +49,7 @@ class PropertyTest : public testing::Test { } }; - virtual void SetUp() { + void SetUp() override { // Make the main thread not to allow IO. base::ThreadRestrictions::SetIOAllowed(false); @@ -87,7 +87,7 @@ class PropertyTest : public testing::Test { properties_->GetAll(); } - virtual void TearDown() { + void TearDown() override { bus_->ShutdownOnDBusThreadAndBlock(); // Shut down the service. @@ -109,6 +109,10 @@ class PropertyTest : public testing::Test { run_loop_->Quit(); } + // Generic method callback, that might be used together with + // WaitForMethodCallback to test wether method was succesfully called. + void MethodCallback(Response* response) { run_loop_->Quit(); } + protected: // Called when a property value is updated. void OnPropertyChanged(const std::string& name) { @@ -134,6 +138,12 @@ class PropertyTest : public testing::Test { WaitForUpdates(kExpectedSignalUpdates); } + // Waits until MethodCallback is called. + void WaitForMethodCallback() { + run_loop_.reset(new base::RunLoop); + run_loop_->Run(); + } + // Waits for the callback. |id| is the string bound to the callback when // the method call is made that identifies it and distinguishes from any // other; you can set this to whatever you wish. @@ -158,9 +168,14 @@ class PropertyTest : public testing::Test { }; TEST_F(PropertyTest, InitialValues) { + EXPECT_FALSE(properties_->name.is_valid()); + EXPECT_FALSE(properties_->version.is_valid()); + WaitForGetAll(); + EXPECT_TRUE(properties_->name.is_valid()); EXPECT_EQ("TestService", properties_->name.value()); + EXPECT_TRUE(properties_->version.is_valid()); EXPECT_EQ(10, properties_->version.value()); std::vector<std::string> methods = properties_->methods.value(); @@ -277,4 +292,140 @@ TEST_F(PropertyTest, Set) { EXPECT_EQ("NewService", properties_->name.value()); } +TEST_F(PropertyTest, Invalidate) { + WaitForGetAll(); + + EXPECT_TRUE(properties_->name.is_valid()); + + // Invalidate name. + MethodCall method_call("org.chromium.TestInterface", "PerformAction"); + MessageWriter writer(&method_call); + writer.AppendString("InvalidateProperty"); + writer.AppendObjectPath(ObjectPath("/org/chromium/TestService")); + object_proxy_->CallMethod( + &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&PropertyTest::MethodCallback, base::Unretained(this))); + WaitForMethodCallback(); + + // TestService sends a property update. + WaitForUpdates(1); + + EXPECT_FALSE(properties_->name.is_valid()); + + // Set name to something valid. + properties_->name.Set("NewService", + base::Bind(&PropertyTest::PropertyCallback, + base::Unretained(this), "Set")); + WaitForCallback("Set"); + + // TestService sends a property update. + WaitForUpdates(1); + + EXPECT_TRUE(properties_->name.is_valid()); +} + +TEST(PropertyTestStatic, ReadWriteStringMap) { + scoped_ptr<Response> message(Response::CreateEmpty()); + MessageWriter writer(message.get()); + MessageWriter variant_writer(NULL); + MessageWriter variant_array_writer(NULL); + MessageWriter struct_entry_writer(NULL); + + writer.OpenVariant("a{ss}", &variant_writer); + variant_writer.OpenArray("{ss}", &variant_array_writer); + const char* items[] = {"One", "Two", "Three", "Four"}; + for (unsigned i = 0; i < arraysize(items); ++i) { + variant_array_writer.OpenDictEntry(&struct_entry_writer); + struct_entry_writer.AppendString(items[i]); + struct_entry_writer.AppendString(base::UintToString(i + 1)); + variant_array_writer.CloseContainer(&struct_entry_writer); + } + variant_writer.CloseContainer(&variant_array_writer); + writer.CloseContainer(&variant_writer); + + MessageReader reader(message.get()); + Property<std::map<std::string, std::string>> string_map; + EXPECT_TRUE(string_map.PopValueFromReader(&reader)); + ASSERT_EQ(4U, string_map.value().size()); + EXPECT_EQ("1", string_map.value().at("One")); + EXPECT_EQ("2", string_map.value().at("Two")); + EXPECT_EQ("3", string_map.value().at("Three")); + EXPECT_EQ("4", string_map.value().at("Four")); +} + +TEST(PropertyTestStatic, SerializeStringMap) { + std::map<std::string, std::string> test_map; + test_map["Hi"] = "There"; + test_map["Map"] = "Test"; + test_map["Random"] = "Text"; + + scoped_ptr<Response> message(Response::CreateEmpty()); + MessageWriter writer(message.get()); + + Property<std::map<std::string, std::string>> string_map; + string_map.ReplaceSetValueForTesting(test_map); + string_map.AppendSetValueToWriter(&writer); + + MessageReader reader(message.get()); + EXPECT_TRUE(string_map.PopValueFromReader(&reader)); + EXPECT_EQ(test_map, string_map.value()); +} + +TEST(PropertyTestStatic, ReadWriteNetAddressArray) { + scoped_ptr<Response> message(Response::CreateEmpty()); + MessageWriter writer(message.get()); + MessageWriter variant_writer(NULL); + MessageWriter variant_array_writer(NULL); + MessageWriter struct_entry_writer(NULL); + + writer.OpenVariant("a(ayq)", &variant_writer); + variant_writer.OpenArray("(ayq)", &variant_array_writer); + uint8 ip_bytes[] = {0x54, 0x65, 0x73, 0x74, 0x30}; + for (uint16 i = 0; i < 5; ++i) { + variant_array_writer.OpenStruct(&struct_entry_writer); + ip_bytes[4] = 0x30 + i; + struct_entry_writer.AppendArrayOfBytes(ip_bytes, arraysize(ip_bytes)); + struct_entry_writer.AppendUint16(i); + variant_array_writer.CloseContainer(&struct_entry_writer); + } + variant_writer.CloseContainer(&variant_array_writer); + writer.CloseContainer(&variant_writer); + + MessageReader reader(message.get()); + Property<std::vector<std::pair<std::vector<uint8>, uint16>>> ip_list; + EXPECT_TRUE(ip_list.PopValueFromReader(&reader)); + + ASSERT_EQ(5U, ip_list.value().size()); + size_t item_index = 0; + for (auto& item : ip_list.value()) { + ASSERT_EQ(5U, item.first.size()); + ip_bytes[4] = 0x30 + item_index; + EXPECT_EQ(0, memcmp(ip_bytes, item.first.data(), 5U)); + EXPECT_EQ(item_index, item.second); + ++item_index; + } +} + +TEST(PropertyTestStatic, SerializeNetAddressArray) { + std::vector<std::pair<std::vector<uint8>, uint16>> test_list; + + uint8 ip_bytes[] = {0x54, 0x65, 0x73, 0x74, 0x30}; + for (uint16 i = 0; i < 5; ++i) { + ip_bytes[4] = 0x30 + i; + std::vector<uint8> bytes(ip_bytes, ip_bytes + arraysize(ip_bytes)); + test_list.push_back(make_pair(bytes, 16)); + } + + scoped_ptr<Response> message(Response::CreateEmpty()); + MessageWriter writer(message.get()); + + Property<std::vector<std::pair<std::vector<uint8>, uint16>>> ip_list; + ip_list.ReplaceSetValueForTesting(test_list); + ip_list.AppendSetValueToWriter(&writer); + + MessageReader reader(message.get()); + EXPECT_TRUE(ip_list.PopValueFromReader(&reader)); + EXPECT_EQ(test_list, ip_list.value()); +} + } // namespace dbus diff --git a/chromium/dbus/signal_sender_verification_unittest.cc b/chromium/dbus/signal_sender_verification_unittest.cc index c8589f8b641..0f718a4817b 100644 --- a/chromium/dbus/signal_sender_verification_unittest.cc +++ b/chromium/dbus/signal_sender_verification_unittest.cc @@ -28,7 +28,7 @@ class SignalSenderVerificationTest : public testing::Test { on_ownership_called_(false) { } - virtual void SetUp() { + void SetUp() override { base::StatisticsRecorder::Initialize(); // Make the main thread not to allow IO. @@ -94,7 +94,7 @@ class SignalSenderVerificationTest : public testing::Test { ASSERT_FALSE(latest_name_owner_.empty()); } - virtual void TearDown() { + void TearDown() override { bus_->ShutdownOnDBusThreadAndBlock(); // Shut down the service. diff --git a/chromium/dbus/test_server.cc b/chromium/dbus/test_server.cc index 88f751f7eb5..7e4722de9e9 100644 --- a/chromium/dbus/test_server.cc +++ b/chromium/dbus/test_server.cc @@ -10,7 +10,7 @@ int main(int argc, char** argv) { base::AtExitManager exit_manager; - CommandLine::Init(argc, argv); + base::CommandLine::Init(argc, argv); TestTimeouts::Initialize(); base::Thread* dbus_thread = new base::Thread("D-Bus Thread"); diff --git a/chromium/dbus/test_service.cc b/chromium/dbus/test_service.cc index 1ec20702467..2c148697d23 100644 --- a/chromium/dbus/test_service.cc +++ b/chromium/dbus/test_service.cc @@ -4,6 +4,9 @@ #include "dbus/test_service.h" +#include <string> +#include <vector> + #include "base/bind.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" @@ -485,7 +488,7 @@ void TestService::PerformAction( RemoveObject(object_path); } else if (action == "SetSendImmediatePropertiesChanged") { SetSendImmediatePropertiesChanged(); - } if (action == "ReleaseOwnership") { + } else if (action == "ReleaseOwnership") { ReleaseOwnership(base::Bind(&TestService::PerformActionResponse, base::Unretained(this), method_call, response_sender)); @@ -495,6 +498,8 @@ void TestService::PerformAction( base::Unretained(this), method_call, response_sender)); return; + } else if (action == "InvalidateProperty") { + SendPropertyInvalidatedSignal(); } scoped_ptr<Response> response = Response::FromMethodCall(method_call); @@ -702,6 +707,37 @@ void TestService::SendPropertyChangedSignalInternal(const std::string& name) { array_writer.CloseContainer(&dict_entry_writer); writer.CloseContainer(&array_writer); + MessageWriter invalidated_array_writer(NULL); + + writer.OpenArray("s", &invalidated_array_writer); + writer.CloseContainer(&invalidated_array_writer); + + exported_object_->SendSignal(&signal); +} + +void TestService::SendPropertyInvalidatedSignal() { + message_loop()->PostTask( + FROM_HERE, base::Bind(&TestService::SendPropertyInvalidatedSignalInternal, + base::Unretained(this))); +} + +void TestService::SendPropertyInvalidatedSignalInternal() { + Signal signal(kPropertiesInterface, kPropertiesChanged); + MessageWriter writer(&signal); + writer.AppendString("org.chromium.TestInterface"); + + MessageWriter array_writer(NULL); + MessageWriter dict_entry_writer(NULL); + + writer.OpenArray("{sv}", &array_writer); + writer.CloseContainer(&array_writer); + + MessageWriter invalidated_array_writer(NULL); + + writer.OpenArray("s", &invalidated_array_writer); + invalidated_array_writer.AppendString("Name"); + writer.CloseContainer(&invalidated_array_writer); + exported_object_->SendSignal(&signal); } diff --git a/chromium/dbus/test_service.h b/chromium/dbus/test_service.h index cc7d5211f91..de4aa720ac7 100644 --- a/chromium/dbus/test_service.h +++ b/chromium/dbus/test_service.h @@ -46,7 +46,7 @@ class TestService : public base::Thread { static const int kNumMethodsToExport; explicit TestService(const Options& options); - virtual ~TestService(); + ~TestService() override; // Starts the service in a separate thread. // Returns true if the thread is started successfully. @@ -106,7 +106,7 @@ class TestService : public base::Thread { bool success); // base::Thread override. - virtual void Run(base::MessageLoop* message_loop) override; + void Run(base::MessageLoop* message_loop) override; // // Exported methods. @@ -167,6 +167,12 @@ class TestService : public base::Thread { // Helper function for SendPropertyChangedSignal(). void SendPropertyChangedSignalInternal(const std::string& name); + // Sends a property invalidated signal for the name property. + void SendPropertyInvalidatedSignal(); + + // Helper function for SendPropertyInvalidatedSignal(). + void SendPropertyInvalidatedSignalInternal(); + // Helper function for RequestOwnership(). void RequestOwnershipInternal(base::Callback<void(bool)> callback); diff --git a/chromium/dbus/util.h b/chromium/dbus/util.h index b983b6fdb86..b05834ddd6b 100644 --- a/chromium/dbus/util.h +++ b/chromium/dbus/util.h @@ -23,6 +23,13 @@ CHROME_DBUS_EXPORT std::string GetAbsoluteMemberName( const std::string& interface_name, const std::string& member_name); +// Similar to base::DeletePointer, but takes void* as an argument. +// Used as DBusFreeFunction. +template<typename T> +void DeleteVoidPointer(void* memory) { + delete static_cast<T*>(memory); +} + } // namespace dbus #endif // DBUS_UTIL_H_ diff --git a/chromium/dbus/values_util_unittest.cc b/chromium/dbus/values_util_unittest.cc index 336d771400e..27ec2d0c989 100644 --- a/chromium/dbus/values_util_unittest.cc +++ b/chromium/dbus/values_util_unittest.cc @@ -4,9 +4,9 @@ #include "dbus/values_util.h" +#include <cmath> #include <vector> -#include "base/float_util.h" #include "base/json/json_writer.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" @@ -358,7 +358,7 @@ TEST(ValuesUtilTest, PopDoubleToIntDictionary) { const std::vector<int32> values(kValues, kValues + arraysize(kValues)); std::vector<double> keys(values.size()); for (size_t i = 0; i != values.size(); ++i) - keys[i] = sqrt(values[i]); + keys[i] = std::sqrt(values[i]); // Append a dictionary. scoped_ptr<Response> response(Response::CreateEmpty()); |