OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/mojo/stash_backend.h" | 5 #include "extensions/browser/mojo/stash_backend.h" |
6 | 6 |
| 7 #include "base/bind.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" |
| 10 |
7 namespace extensions { | 11 namespace extensions { |
| 12 namespace { |
8 | 13 |
9 // An implementation of StashService that forwards calls to a StashBackend. | 14 // An implementation of StashService that forwards calls to a StashBackend. |
10 class StashServiceImpl : public mojo::InterfaceImpl<StashService> { | 15 class StashServiceImpl : public StashService { |
11 public: | 16 public: |
12 explicit StashServiceImpl(base::WeakPtr<StashBackend> backend); | 17 StashServiceImpl(mojo::InterfaceRequest<StashService> request, |
| 18 base::WeakPtr<StashBackend> backend); |
13 ~StashServiceImpl() override; | 19 ~StashServiceImpl() override; |
14 | 20 |
15 // mojo::InterfaceImpl<StashService> overrides. | 21 // StashService overrides. |
16 void AddToStash(mojo::Array<StashedObjectPtr> stash) override; | 22 void AddToStash(mojo::Array<StashedObjectPtr> stash) override; |
17 void RetrieveStash( | 23 void RetrieveStash( |
18 const mojo::Callback<void(mojo::Array<StashedObjectPtr> stash)>& callback) | 24 const mojo::Callback<void(mojo::Array<StashedObjectPtr> stash)>& callback) |
19 override; | 25 override; |
20 | 26 |
21 private: | 27 private: |
| 28 mojo::StrongBinding<StashService> binding_; |
22 base::WeakPtr<StashBackend> backend_; | 29 base::WeakPtr<StashBackend> backend_; |
23 | 30 |
24 DISALLOW_COPY_AND_ASSIGN(StashServiceImpl); | 31 DISALLOW_COPY_AND_ASSIGN(StashServiceImpl); |
25 }; | 32 }; |
26 | 33 |
27 StashBackend::StashBackend() : weak_factory_(this) { | 34 StashServiceImpl::StashServiceImpl(mojo::InterfaceRequest<StashService> request, |
| 35 base::WeakPtr<StashBackend> backend) |
| 36 : binding_(this, request.Pass()), backend_(backend) { |
| 37 } |
| 38 |
| 39 StashServiceImpl::~StashServiceImpl() { |
| 40 } |
| 41 |
| 42 void StashServiceImpl::AddToStash( |
| 43 mojo::Array<StashedObjectPtr> stashed_objects) { |
| 44 if (!backend_) |
| 45 return; |
| 46 backend_->AddToStash(stashed_objects.Pass()); |
| 47 } |
| 48 |
| 49 void StashServiceImpl::RetrieveStash( |
| 50 const mojo::Callback<void(mojo::Array<StashedObjectPtr>)>& callback) { |
| 51 if (!backend_) { |
| 52 callback.Run(mojo::Array<StashedObjectPtr>(0)); |
| 53 return; |
| 54 } |
| 55 callback.Run(backend_->RetrieveStash()); |
| 56 } |
| 57 |
| 58 } // namespace |
| 59 |
| 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 { |
| 63 public: |
| 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 |
| 66 // readable. |
| 67 StashEntry(StashedObjectPtr stashed_object, |
| 68 const base::Closure& on_handle_readable); |
| 69 ~StashEntry(); |
| 70 |
| 71 // Returns the stashed object. |
| 72 StashedObjectPtr Release(); |
| 73 |
| 74 // Cancels notifications for handles becoming readable. |
| 75 void CancelHandleNotifications(); |
| 76 |
| 77 private: |
| 78 // Invoked when a handle within |stashed_object_| is readable. |
| 79 void OnHandleReady(MojoResult result); |
| 80 |
| 81 // The waiters that are waiting for handles to be readable. |
| 82 ScopedVector<mojo::AsyncWaiter> waiters_; |
| 83 |
| 84 StashedObjectPtr stashed_object_; |
| 85 |
| 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_; |
| 89 }; |
| 90 |
| 91 StashBackend::StashBackend(const base::Closure& on_handle_readable) |
| 92 : on_handle_readable_(on_handle_readable), |
| 93 has_notified_(false), |
| 94 weak_factory_(this) { |
28 } | 95 } |
29 | 96 |
30 StashBackend::~StashBackend() { | 97 StashBackend::~StashBackend() { |
31 } | 98 } |
32 | 99 |
33 void StashBackend::AddToStash(mojo::Array<StashedObjectPtr> stashed_objects) { | 100 void StashBackend::AddToStash(mojo::Array<StashedObjectPtr> stashed_objects) { |
34 for (size_t i = 0; i < stashed_objects.size(); i++) { | 101 for (size_t i = 0; i < stashed_objects.size(); i++) { |
35 stashed_objects_.push_back(stashed_objects[i].Pass()); | 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()))); |
36 } | 107 } |
37 } | 108 } |
38 | 109 |
39 mojo::Array<StashedObjectPtr> StashBackend::RetrieveStash() { | 110 mojo::Array<StashedObjectPtr> StashBackend::RetrieveStash() { |
40 if (stashed_objects_.is_null()) | 111 has_notified_ = false; |
41 stashed_objects_.resize(0); | 112 mojo::Array<StashedObjectPtr> result(0); |
42 return stashed_objects_.Pass(); | 113 for (auto& entry : stashed_objects_) { |
| 114 result.push_back(entry->Release()); |
| 115 } |
| 116 stashed_objects_.clear(); |
| 117 return result.Pass(); |
43 } | 118 } |
44 | 119 |
45 void StashBackend::BindToRequest(mojo::InterfaceRequest<StashService> request) { | 120 void StashBackend::BindToRequest(mojo::InterfaceRequest<StashService> request) { |
46 mojo::BindToRequest(new StashServiceImpl(weak_factory_.GetWeakPtr()), | 121 new StashServiceImpl(request.Pass(), weak_factory_.GetWeakPtr()); |
47 &request); | |
48 } | 122 } |
49 | 123 |
50 StashServiceImpl::StashServiceImpl(base::WeakPtr<StashBackend> backend) | 124 void StashBackend::OnHandleReady() { |
51 : backend_(backend) { | 125 DCHECK(!has_notified_); |
| 126 has_notified_ = true; |
| 127 for (auto& entry : stashed_objects_) { |
| 128 entry->CancelHandleNotifications(); |
| 129 } |
| 130 if (!on_handle_readable_.is_null()) |
| 131 on_handle_readable_.Run(); |
52 } | 132 } |
53 | 133 |
54 StashServiceImpl::~StashServiceImpl() { | 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) |
| 139 return; |
| 140 |
| 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)))); |
| 146 } |
55 } | 147 } |
56 | 148 |
57 void StashServiceImpl::AddToStash( | 149 StashBackend::StashEntry::~StashEntry() { |
58 mojo::Array<StashedObjectPtr> stashed_objects) { | |
59 if (!backend_) | |
60 return; | |
61 backend_->AddToStash(stashed_objects.Pass()); | |
62 } | 150 } |
63 | 151 |
64 void StashServiceImpl::RetrieveStash( | 152 StashedObjectPtr StashBackend::StashEntry::Release() { |
65 const mojo::Callback<void(mojo::Array<StashedObjectPtr>)>& callback) { | 153 waiters_.clear(); |
66 if (!backend_) { | 154 return stashed_object_.Pass(); |
67 callback.Run(mojo::Array<StashedObjectPtr>(0)); | 155 } |
| 156 |
| 157 void StashBackend::StashEntry::CancelHandleNotifications() { |
| 158 waiters_.clear(); |
| 159 } |
| 160 |
| 161 void StashBackend::StashEntry::OnHandleReady(MojoResult result) { |
| 162 if (result != MOJO_RESULT_OK) |
68 return; | 163 return; |
69 } | 164 on_handle_readable_.Run(); |
70 callback.Run(backend_->RetrieveStash()); | |
71 } | 165 } |
72 | 166 |
73 } // namespace extensions | 167 } // namespace extensions |
OLD | NEW |