Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(387)

Side by Side Diff: content/common/service_manager/embedded_service_runner.cc

Issue 2476063002: Service Manager: Rework Service and ServiceContext lifetime (Closed)
Patch Set: . Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 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 "content/common/service_manager/embedded_service_runner.h" 5 #include "content/common/service_manager/embedded_service_runner.h"
6 6
7 #include <map>
8 #include <memory>
9 #include <utility>
7 #include <vector> 10 #include <vector>
8 11
9 #include "base/bind.h" 12 #include "base/bind.h"
10 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
11 #include "base/memory/ref_counted.h" 15 #include "base/memory/ref_counted.h"
12 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
13 #include "base/threading/thread.h" 17 #include "base/threading/thread.h"
14 #include "base/threading/thread_checker.h" 18 #include "base/threading/thread_checker.h"
15 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
16 #include "services/service_manager/public/cpp/service_context.h" 20 #include "services/service_manager/public/cpp/service_context.h"
17 21
18 namespace content { 22 namespace content {
19 23
20 class EmbeddedServiceRunner::Instance 24 class EmbeddedServiceRunner::InstanceManager
21 : public base::RefCountedThreadSafe<Instance> { 25 : public base::RefCountedThreadSafe<InstanceManager> {
22 public: 26 public:
23 Instance(const base::StringPiece& name, 27 InstanceManager(const base::StringPiece& name,
24 const ServiceInfo& info, 28 const ServiceInfo& info,
25 const base::Closure& quit_closure) 29 const base::Closure& quit_closure)
26 : name_(name.as_string()), 30 : name_(name.as_string()),
27 factory_callback_(info.factory), 31 factory_callback_(info.factory),
28 use_own_thread_(!info.task_runner && info.use_own_thread), 32 use_own_thread_(!info.task_runner && info.use_own_thread),
29 service_owns_context_(info.service_owns_context),
30 quit_closure_(quit_closure), 33 quit_closure_(quit_closure),
31 quit_task_runner_(base::ThreadTaskRunnerHandle::Get()), 34 quit_task_runner_(base::ThreadTaskRunnerHandle::Get()),
32 task_runner_(info.task_runner) { 35 service_task_runner_(info.task_runner) {
33 if (!use_own_thread_ && !task_runner_) 36 if (!use_own_thread_ && !service_task_runner_)
34 task_runner_ = base::ThreadTaskRunnerHandle::Get(); 37 service_task_runner_ = base::ThreadTaskRunnerHandle::Get();
35 } 38 }
36 39
37 void BindServiceRequest(service_manager::mojom::ServiceRequest request) { 40 void BindServiceRequest(service_manager::mojom::ServiceRequest request) {
38 DCHECK(runner_thread_checker_.CalledOnValidThread()); 41 DCHECK(runner_thread_checker_.CalledOnValidThread());
39 42
40 if (use_own_thread_ && !thread_) { 43 if (use_own_thread_ && !thread_) {
41 // Start a new thread if necessary. 44 // Start a new thread if necessary.
42 thread_.reset(new base::Thread(name_)); 45 thread_.reset(new base::Thread(name_));
43 thread_->Start(); 46 thread_->Start();
44 task_runner_ = thread_->task_runner(); 47 service_task_runner_ = thread_->task_runner();
45 } 48 }
46 49
47 DCHECK(task_runner_); 50 DCHECK(service_task_runner_);
48 task_runner_->PostTask( 51 service_task_runner_->PostTask(
49 FROM_HERE, 52 FROM_HERE,
50 base::Bind(&Instance::BindServiceRequestOnApplicationThread, this, 53 base::Bind(&InstanceManager::BindServiceRequestOnServiceThread,
51 base::Passed(&request))); 54 this, base::Passed(&request)));
52 } 55 }
53 56
54 void ShutDown() { 57 void ShutDown() {
55 DCHECK(runner_thread_checker_.CalledOnValidThread()); 58 DCHECK(runner_thread_checker_.CalledOnValidThread());
56 if (!task_runner_) 59 if (!service_task_runner_)
57 return; 60 return;
58 // Any extant ServiceContexts must be destroyed on the application thread. 61 // Any extant ServiceContexts must be destroyed on the application thread.
59 if (task_runner_->BelongsToCurrentThread()) { 62 if (service_task_runner_->BelongsToCurrentThread()) {
60 Quit(); 63 QuitOnServiceThread();
61 } else { 64 } else {
62 task_runner_->PostTask(FROM_HERE, 65 service_task_runner_->PostTask(
63 base::Bind(&Instance::Quit, this)); 66 FROM_HERE, base::Bind(&InstanceManager::QuitOnServiceThread, this));
64 } 67 }
65 } 68 }
66 69
67 private: 70 private:
68 friend class base::RefCountedThreadSafe<Instance>; 71 friend class base::RefCountedThreadSafe<InstanceManager>;
69 72
70 ~Instance() { 73 ~InstanceManager() {
71 // If this instance had its own thread, it MUST be explicitly destroyed by 74 // If this instance had its own thread, it MUST be explicitly destroyed by
72 // QuitOnRunnerThread() by the time this destructor is run. 75 // QuitOnRunnerThread() by the time this destructor is run.
73 DCHECK(!thread_); 76 DCHECK(!thread_);
74 } 77 }
75 78
76 void BindServiceRequestOnApplicationThread( 79 void BindServiceRequestOnServiceThread(
77 service_manager::mojom::ServiceRequest request) { 80 service_manager::mojom::ServiceRequest request) {
78 DCHECK(task_runner_->BelongsToCurrentThread()); 81 DCHECK(service_task_runner_->BelongsToCurrentThread());
79 82
80 if (!service_) { 83 int instance_id = next_instance_id_++;
81 service_ = factory_callback_.Run( 84 base::Closure quit_closure =
82 base::Bind(&Instance::Quit, base::Unretained(this))); 85 base::Bind(&InstanceManager::OnInstanceLost, this, instance_id);
83 }
84 86
85 std::unique_ptr<service_manager::ServiceContext> new_connection = 87 // TODO(rockot): Get rid of the quit closure argument to the factory
88 // function. Services should request termination via their ServiceContext
89 // once we have that working.
90 std::unique_ptr<service_manager::ServiceContext> context =
86 base::MakeUnique<service_manager::ServiceContext>( 91 base::MakeUnique<service_manager::ServiceContext>(
87 service_.get(), std::move(request)); 92 factory_callback_.Run(quit_closure), std::move(request));
88 if (service_owns_context_) { 93
89 service_->set_context(std::move(new_connection)); 94 service_manager::ServiceContext* raw_context = context.get();
90 } else { 95 context->SetConnectionLostClosure(quit_closure);
91 service_manager::ServiceContext* new_connection_ptr = 96 contexts_.insert(std::make_pair(raw_context, std::move(context)));
92 new_connection.get(); 97 id_to_context_map_.insert(std::make_pair(instance_id, raw_context));
93 service_manager_connections_.push_back(std::move(new_connection));
94 new_connection_ptr->SetConnectionLostClosure(
95 base::Bind(&Instance::OnStop, base::Unretained(this),
96 new_connection_ptr));
97 }
98 } 98 }
99 99
100 void OnStop(service_manager::ServiceContext* connection) { 100 void OnInstanceLost(int instance_id) {
101 DCHECK(task_runner_->BelongsToCurrentThread()); 101 DCHECK(service_task_runner_->BelongsToCurrentThread());
102 102
103 for (auto it = service_manager_connections_.begin(); 103 auto id_iter = id_to_context_map_.find(instance_id);
104 it != service_manager_connections_.end(); ++it) { 104 CHECK(id_iter != id_to_context_map_.end());
105 if (it->get() == connection) { 105
106 service_manager_connections_.erase(it); 106 auto context_iter = contexts_.find(id_iter->second);
107 break; 107 CHECK(context_iter != contexts_.end());
108 } 108 contexts_.erase(context_iter);
109 } 109 id_to_context_map_.erase(id_iter);
110
111 // If we've lost the last instance, run the quit closure.
112 if (contexts_.empty())
113 QuitOnServiceThread();
110 } 114 }
111 115
112 void Quit() { 116 void QuitOnServiceThread() {
113 DCHECK(task_runner_->BelongsToCurrentThread()); 117 DCHECK(service_task_runner_->BelongsToCurrentThread());
114 118
115 service_manager_connections_.clear(); 119 contexts_.clear();
116 service_.reset();
117 if (quit_task_runner_->BelongsToCurrentThread()) { 120 if (quit_task_runner_->BelongsToCurrentThread()) {
118 QuitOnRunnerThread(); 121 QuitOnRunnerThread();
119 } else { 122 } else {
120 quit_task_runner_->PostTask( 123 quit_task_runner_->PostTask(
121 FROM_HERE, base::Bind(&Instance::QuitOnRunnerThread, this)); 124 FROM_HERE, base::Bind(&InstanceManager::QuitOnRunnerThread, this));
122 } 125 }
123 } 126 }
124 127
125 void QuitOnRunnerThread() { 128 void QuitOnRunnerThread() {
126 DCHECK(runner_thread_checker_.CalledOnValidThread()); 129 DCHECK(runner_thread_checker_.CalledOnValidThread());
127 if (thread_) { 130 if (thread_) {
128 thread_.reset(); 131 thread_.reset();
129 task_runner_ = nullptr; 132 service_task_runner_ = nullptr;
130 } 133 }
131 quit_closure_.Run(); 134 quit_closure_.Run();
132 } 135 }
133 136
134 const std::string name_; 137 const std::string name_;
135 const ServiceInfo::ServiceFactory factory_callback_; 138 const ServiceInfo::ServiceFactory factory_callback_;
136 const bool use_own_thread_; 139 const bool use_own_thread_;
137 const bool service_owns_context_;
138 const base::Closure quit_closure_; 140 const base::Closure quit_closure_;
139 const scoped_refptr<base::SingleThreadTaskRunner> quit_task_runner_; 141 const scoped_refptr<base::SingleThreadTaskRunner> quit_task_runner_;
140 142
141 // Thread checker used to ensure certain operations happen only on the 143 // Thread checker used to ensure certain operations happen only on the
142 // runner's (i.e. our owner's) thread. 144 // runner's (i.e. our owner's) thread.
143 base::ThreadChecker runner_thread_checker_; 145 base::ThreadChecker runner_thread_checker_;
144 146
145 // These fields must only be accessed from the runner's thread. 147 // These fields must only be accessed from the runner's thread.
146 std::unique_ptr<base::Thread> thread_; 148 std::unique_ptr<base::Thread> thread_;
147 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 149 scoped_refptr<base::SingleThreadTaskRunner> service_task_runner_;
148 150
149 // These fields must only be accessed from the application thread, except in 151 // These fields must only be accessed from the service thread, except in
150 // the destructor which may run on either the runner thread or the application 152 // the destructor which may run on either the runner thread or the service
151 // thread. 153 // thread.
152 std::unique_ptr<service_manager::Service> service_;
153 std::vector<std::unique_ptr<service_manager::ServiceContext>>
154 service_manager_connections_;
155 154
156 DISALLOW_COPY_AND_ASSIGN(Instance); 155 // A map which owns all existing Service instances for this service.
156 using ServiceContextMap =
157 std::map<service_manager::ServiceContext*,
158 std::unique_ptr<service_manager::ServiceContext>>;
159 ServiceContextMap contexts_;
160
161 int next_instance_id_ = 0;
162
163 // A mapping from instance ID to (not owned) ServiceContext.
164 //
165 // TODO(rockot): Remove this once we get rid of the quit closure argument to
166 // service factory functions.
167 std::map<int, service_manager::ServiceContext*> id_to_context_map_;
168
169 DISALLOW_COPY_AND_ASSIGN(InstanceManager);
157 }; 170 };
158 171
159 EmbeddedServiceRunner::EmbeddedServiceRunner(const base::StringPiece& name, 172 EmbeddedServiceRunner::EmbeddedServiceRunner(const base::StringPiece& name,
160 const ServiceInfo& info) 173 const ServiceInfo& info)
161 : weak_factory_(this) { 174 : weak_factory_(this) {
162 instance_ = new Instance(name, info, 175 instance_manager_ = new InstanceManager(
163 base::Bind(&EmbeddedServiceRunner::OnQuit, 176 name, info, base::Bind(&EmbeddedServiceRunner::OnQuit,
164 weak_factory_.GetWeakPtr())); 177 weak_factory_.GetWeakPtr()));
165 } 178 }
166 179
167 EmbeddedServiceRunner::~EmbeddedServiceRunner() { 180 EmbeddedServiceRunner::~EmbeddedServiceRunner() {
168 instance_->ShutDown(); 181 instance_manager_->ShutDown();
169 } 182 }
170 183
171 void EmbeddedServiceRunner::BindServiceRequest( 184 void EmbeddedServiceRunner::BindServiceRequest(
172 service_manager::mojom::ServiceRequest request) { 185 service_manager::mojom::ServiceRequest request) {
173 instance_->BindServiceRequest(std::move(request)); 186 instance_manager_->BindServiceRequest(std::move(request));
174 } 187 }
175 188
176 void EmbeddedServiceRunner::SetQuitClosure( 189 void EmbeddedServiceRunner::SetQuitClosure(
177 const base::Closure& quit_closure) { 190 const base::Closure& quit_closure) {
178 quit_closure_ = quit_closure; 191 quit_closure_ = quit_closure;
179 } 192 }
180 193
181 void EmbeddedServiceRunner::OnQuit() { 194 void EmbeddedServiceRunner::OnQuit() {
182 if (!quit_closure_.is_null()) 195 if (!quit_closure_.is_null())
183 quit_closure_.Run(); 196 quit_closure_.Run();
184 } 197 }
185 198
186 } // namespace content 199 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698