#ifndef CONTENT_PUBLIC_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_
#define CONTENT_PUBLIC_BROWSER_BROWSER_ASSOCIATED_INTERFACE_H_
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_channel_proxy.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
template <typename Interface>
class BrowserAssociatedInterface : public Interface {
public:
explicit BrowserAssociatedInterface(BrowserMessageFilter* filter)
: internal_state_(new InternalState(this)) {
filter->AddAssociatedInterface(
Interface::Name_,
base::BindRepeating(&InternalState::BindReceiver, internal_state_),
base::BindOnce(&InternalState::ClearReceivers, internal_state_));
}
BrowserAssociatedInterface(const BrowserAssociatedInterface&) = delete;
BrowserAssociatedInterface& operator=(const BrowserAssociatedInterface&) =
delete;
~BrowserAssociatedInterface() { internal_state_->ClearReceivers(); }
private:
friend class TestDriverMessageFilter;
class InternalState : public base::RefCountedThreadSafe<InternalState> {
public:
explicit InternalState(Interface* impl)
: impl_(impl), receivers_(absl::in_place) {}
InternalState(const InternalState&) = delete;
InternalState& operator=(const InternalState&) = delete;
void ClearReceivers() {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&InternalState::ClearReceivers, this));
return;
}
receivers_.reset();
impl_ = nullptr;
}
void BindReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!receivers_)
return;
receivers_->Add(
impl_, mojo::PendingAssociatedReceiver<Interface>(std::move(handle)));
}
private:
friend class base::RefCountedThreadSafe<InternalState>;
friend class TestDriverMessageFilter;
~InternalState() {}
raw_ptr<Interface> impl_;
absl::optional<mojo::AssociatedReceiverSet<Interface>> receivers_;
};
scoped_refptr<InternalState> internal_state_;
};
}
#endif