Index: content/public/browser/browser_associated_interface.h |
diff --git a/content/public/browser/browser_associated_interface.h b/content/public/browser/browser_associated_interface.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca12ff29b446593e88beb777b3ad6a0114c90961 |
--- /dev/null |
+++ b/content/public/browser/browser_associated_interface.h |
@@ -0,0 +1,121 @@ |
+// Copyright 2016 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 CONTENT_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_ |
+#define CONTENT_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_ |
+ |
+#include <memory> |
+#include <string> |
+ |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
+#include "content/common/content_export.h" |
+#include "content/public/browser/browser_message_filter.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "ipc/ipc_channel_proxy.h" |
+#include "mojo/public/cpp/bindings/associated_binding.h" |
+#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" |
+ |
+namespace content { |
+ |
+// A helper interface which owns an associated interface binding on the IO |
+// thread. Subclassess of BrowserMessageFilter may use this to simplify |
+// the transition to Mojo interfaces. |
+// |
+// In general the correct pattern for using this is as follows: |
+// |
+// class FooMessageFilter : public BrowserMessageFilter, |
+// public BrowserAssociatedInterface<mojom::Foo>, |
+// public mojom::Foo { |
+// public: |
+// FooMessageFilter() |
+// : BrowserMessageFilter(FooMsgStart), |
+// BrowserAssociatedInterface<mojom::Foo>(this, this) {} |
+// |
+// // BrowserMessageFilter implementation: |
+// bool OnMessageReceived(const IPC::Message& message) override { |
+// // ... |
+// return true; |
+// } |
+// |
+// // mojom::Foo implementation: |
+// void DoStuff() override { /* ... */ } |
+// }; |
+// |
+// The remote side of an IPC channel can request the |mojom::Foo| associated |
+// interface and use it would use any other associated interface proxy. Messages |
+// received for |mojom::Foo| on the local side of the channel will retain FIFO |
+// with respect to classical IPC messages received via OnMessageReceived(). |
+// |
+// See BrowserAssociatedInterfaceTest.Basic for a simple working example usage. |
+template <typename Interface> |
+class BrowserAssociatedInterface { |
+ public: |
+ // |filter| and |impl| must live at least as long as this object. |
+ BrowserAssociatedInterface(BrowserMessageFilter* filter, Interface* impl) |
+ : internal_state_(new InternalState(impl)) { |
+ internal_state_->Initialize(); |
+ filter->AddAssociatedInterface( |
+ Interface::Name_, |
+ base::Bind(&InternalState::BindRequest, internal_state_)); |
+ } |
+ |
+ ~BrowserAssociatedInterface() { |
+ internal_state_->ShutDown(); |
+ } |
+ |
+ private: |
+ class InternalState : public base::RefCountedThreadSafe<InternalState> { |
+ public: |
+ explicit InternalState(Interface* impl) : impl_(impl) {} |
+ |
+ void Initialize() { |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ base::Bind(&InternalState::Initialize, this)); |
+ return; |
+ } |
+ binding_.reset(new mojo::AssociatedBinding<Interface>(impl_)); |
+ } |
+ |
+ void ShutDown() { |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ base::Bind(&InternalState::ShutDown, this)); |
+ return; |
+ } |
+ binding_.reset(); |
+ } |
+ |
+ void BindRequest(mojo::ScopedInterfaceEndpointHandle handle) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ // If this interface has already been shut down or is already bound, we |
+ // drop the request. |
+ if (!binding_ || binding_->is_bound()) |
+ return; |
+ |
+ binding_->Bind(mojo::MakeAssociatedRequest<Interface>(std::move(handle))); |
+ binding_->set_connection_error_handler( |
+ base::Bind(&InternalState::ShutDown, base::Unretained(this))); |
+ } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<InternalState>; |
+ |
+ ~InternalState() {} |
+ |
+ Interface* impl_; |
+ std::unique_ptr<mojo::AssociatedBinding<Interface>> binding_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(InternalState); |
+ }; |
+ |
+ scoped_refptr<InternalState> internal_state_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BrowserAssociatedInterface); |
+}; |
+ |
+}; |
+ |
+#endif // CONTENT_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_ |