1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_ 6 #define CONTENT_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_ 7 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/macros.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/optional.h" 14 #include "content/common/content_export.h" 15 #include "content/public/browser/browser_message_filter.h" 16 #include "content/public/browser/browser_task_traits.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "ipc/ipc_channel_proxy.h" 19 #include "mojo/public/cpp/bindings/associated_receiver_set.h" 20 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" 21 22 namespace content { 23 24 // A helper interface which owns an associated interface receiver on the IO 25 // thread. Subclassess of BrowserMessageFilter may use this to simplify 26 // the transition to Mojo interfaces. 27 // 28 // In general the correct pattern for using this is as follows: 29 // 30 // class FooMessageFilter : public BrowserMessageFilter, 31 // public BrowserAssociatedInterface<mojom::Foo>, 32 // public mojom::Foo { 33 // public: 34 // FooMessageFilter() 35 // : BrowserMessageFilter(FooMsgStart), 36 // BrowserAssociatedInterface<mojom::Foo>(this, this) {} 37 // 38 // // BrowserMessageFilter implementation: 39 // bool OnMessageReceived(const IPC::Message& message) override { 40 // // ... 41 // return true; 42 // } 43 // 44 // // mojom::Foo implementation: 45 // void DoStuff() override { /* ... */ } 46 // }; 47 // 48 // The remote side of an IPC channel can request the |mojom::Foo| associated 49 // interface and use it would use any other associated remote proxy. Messages 50 // received for |mojom::Foo| on the local side of the channel will retain FIFO 51 // with respect to classical IPC messages received via OnMessageReceived(). 52 // 53 // See BrowserAssociatedInterfaceTest.Basic for a simple working example usage. 54 template <typename Interface> 55 class BrowserAssociatedInterface { 56 public: 57 // |filter| and |impl| must live at least as long as this object. BrowserAssociatedInterface(BrowserMessageFilter * filter,Interface * impl)58 BrowserAssociatedInterface(BrowserMessageFilter* filter, Interface* impl) 59 : internal_state_(new InternalState(impl)) { 60 filter->AddAssociatedInterface( 61 Interface::Name_, 62 base::BindRepeating(&InternalState::BindReceiver, internal_state_), 63 base::BindOnce(&InternalState::ClearReceivers, internal_state_)); 64 } 65 ~BrowserAssociatedInterface()66 ~BrowserAssociatedInterface() { internal_state_->ClearReceivers(); } 67 68 private: 69 friend class TestDriverMessageFilter; 70 71 class InternalState : public base::RefCountedThreadSafe<InternalState> { 72 public: InternalState(Interface * impl)73 explicit InternalState(Interface* impl) 74 : impl_(impl), receivers_(base::in_place) {} 75 ClearReceivers()76 void ClearReceivers() { 77 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 78 GetIOThreadTaskRunner({})->PostTask( 79 FROM_HERE, base::BindOnce(&InternalState::ClearReceivers, this)); 80 return; 81 } 82 receivers_.reset(); 83 } 84 BindReceiver(mojo::ScopedInterfaceEndpointHandle handle)85 void BindReceiver(mojo::ScopedInterfaceEndpointHandle handle) { 86 DCHECK_CURRENTLY_ON(BrowserThread::IO); 87 // If this interface has already been shut down we drop the receiver. 88 if (!receivers_) 89 return; 90 receivers_->Add( 91 impl_, mojo::PendingAssociatedReceiver<Interface>(std::move(handle))); 92 } 93 94 private: 95 friend class base::RefCountedThreadSafe<InternalState>; 96 friend class TestDriverMessageFilter; 97 ~InternalState()98 ~InternalState() {} 99 100 Interface* impl_; 101 base::Optional<mojo::AssociatedReceiverSet<Interface>> receivers_; 102 103 DISALLOW_COPY_AND_ASSIGN(InternalState); 104 }; 105 106 scoped_refptr<InternalState> internal_state_; 107 108 DISALLOW_COPY_AND_ASSIGN(BrowserAssociatedInterface); 109 }; 110 111 } // namespace content 112 113 #endif // CONTENT_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_ 114