1 // Copyright 2014 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.
5 #include "extensions/browser/mojo/stash_backend.h"
8 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
9 #include "third_party/mojo/src/mojo/public/cpp/environment/async_waiter.h"
11 namespace extensions
{
14 // An implementation of StashService that forwards calls to a StashBackend.
15 class StashServiceImpl
: public StashService
{
17 StashServiceImpl(mojo::InterfaceRequest
<StashService
> request
,
18 base::WeakPtr
<StashBackend
> backend
);
19 ~StashServiceImpl() override
;
21 // StashService overrides.
22 void AddToStash(mojo::Array
<StashedObjectPtr
> stash
) override
;
24 const mojo::Callback
<void(mojo::Array
<StashedObjectPtr
> stash
)>& callback
)
28 mojo::StrongBinding
<StashService
> binding_
;
29 base::WeakPtr
<StashBackend
> backend_
;
31 DISALLOW_COPY_AND_ASSIGN(StashServiceImpl
);
34 StashServiceImpl::StashServiceImpl(mojo::InterfaceRequest
<StashService
> request
,
35 base::WeakPtr
<StashBackend
> backend
)
36 : binding_(this, request
.Pass()), backend_(backend
) {
39 StashServiceImpl::~StashServiceImpl() {
42 void StashServiceImpl::AddToStash(
43 mojo::Array
<StashedObjectPtr
> stashed_objects
) {
46 backend_
->AddToStash(stashed_objects
.Pass());
49 void StashServiceImpl::RetrieveStash(
50 const mojo::Callback
<void(mojo::Array
<StashedObjectPtr
>)>& callback
) {
52 callback
.Run(mojo::Array
<StashedObjectPtr
>(0));
55 callback
.Run(backend_
->RetrieveStash());
60 // A stash entry for a stashed object. This handles notifications if a handle
61 // within the stashed object is readable.
62 class StashBackend::StashEntry
{
64 // Construct a StashEntry for |stashed_object|. If |on_handle_readable| is
65 // non-null, it will be invoked when any handle on |stashed_object| is
67 StashEntry(StashedObjectPtr stashed_object
,
68 const base::Closure
& on_handle_readable
);
71 // Returns the stashed object.
72 StashedObjectPtr
Release();
74 // Cancels notifications for handles becoming readable.
75 void CancelHandleNotifications();
78 // Invoked when a handle within |stashed_object_| is readable.
79 void OnHandleReady(MojoResult result
);
81 // The waiters that are waiting for handles to be readable.
82 ScopedVector
<mojo::AsyncWaiter
> waiters_
;
84 StashedObjectPtr stashed_object_
;
86 // If non-null, a callback to call when a handle contained within
87 // |stashed_object_| is readable.
88 const base::Closure on_handle_readable_
;
91 StashBackend::StashBackend(const base::Closure
& on_handle_readable
)
92 : on_handle_readable_(on_handle_readable
),
97 StashBackend::~StashBackend() {
100 void StashBackend::AddToStash(mojo::Array
<StashedObjectPtr
> stashed_objects
) {
101 for (size_t i
= 0; i
< stashed_objects
.size(); i
++) {
102 stashed_objects_
.push_back(
103 new StashEntry(stashed_objects
[i
].Pass(),
104 has_notified_
? base::Closure()
105 : base::Bind(&StashBackend::OnHandleReady
,
106 weak_factory_
.GetWeakPtr())));
110 mojo::Array
<StashedObjectPtr
> StashBackend::RetrieveStash() {
111 has_notified_
= false;
112 mojo::Array
<StashedObjectPtr
> result(0);
113 for (auto& entry
: stashed_objects_
) {
114 result
.push_back(entry
->Release());
116 stashed_objects_
.clear();
117 return result
.Pass();
120 void StashBackend::BindToRequest(mojo::InterfaceRequest
<StashService
> request
) {
121 new StashServiceImpl(request
.Pass(), weak_factory_
.GetWeakPtr());
124 void StashBackend::OnHandleReady() {
125 DCHECK(!has_notified_
);
126 has_notified_
= true;
127 for (auto& entry
: stashed_objects_
) {
128 entry
->CancelHandleNotifications();
130 if (!on_handle_readable_
.is_null())
131 on_handle_readable_
.Run();
134 StashBackend::StashEntry::StashEntry(StashedObjectPtr stashed_object
,
135 const base::Closure
& on_handle_readable
)
136 : stashed_object_(stashed_object
.Pass()),
137 on_handle_readable_(on_handle_readable
) {
138 if (on_handle_readable_
.is_null() || !stashed_object_
->monitor_handles
)
141 for (size_t i
= 0; i
< stashed_object_
->stashed_handles
.size(); i
++) {
142 waiters_
.push_back(new mojo::AsyncWaiter(
143 stashed_object_
->stashed_handles
[i
].get(), MOJO_HANDLE_SIGNAL_READABLE
,
144 base::Bind(&StashBackend::StashEntry::OnHandleReady
,
145 base::Unretained(this))));
149 StashBackend::StashEntry::~StashEntry() {
152 StashedObjectPtr
StashBackend::StashEntry::Release() {
154 return stashed_object_
.Pass();
157 void StashBackend::StashEntry::CancelHandleNotifications() {
161 void StashBackend::StashEntry::OnHandleReady(MojoResult result
) {
162 if (result
!= MOJO_RESULT_OK
)
164 on_handle_readable_
.Run();
167 } // namespace extensions