OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 #include "content/browser/in_process_webkit/indexed_db_key_utility_client.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/lazy_instance.h" | |
9 #include "base/synchronization/waitable_event.h" | |
10 #include "content/browser/utility_process_host_impl.h" | |
11 #include "content/common/indexed_db/indexed_db_key.h" | |
12 #include "content/common/indexed_db/indexed_db_key_path.h" | |
13 #include "content/common/indexed_db/indexed_db_messages.h" | |
14 #include "content/common/utility_messages.h" | |
15 #include "content/public/browser/utility_process_host_client.h" | |
16 #include "content/public/common/serialized_script_value.h" | |
17 | |
18 using content::BrowserThread; | |
19 using content::IndexedDBKey; | |
20 using content::IndexedDBKeyPath; | |
21 using content::UtilityProcessHostClient; | |
22 using content::SerializedScriptValue; | |
23 | |
24 // This class is used to obtain IndexedDBKeys from SerializedScriptValues | |
25 // given an IDBKeyPath. It uses UtilityProcess to do this inside a sandbox | |
26 // (a V8 lock is required there). At this level, all methods are synchronous | |
27 // as required by the caller. The public API is used on WEBKIT thread, | |
28 // but internally it moves around to UI and IO as needed. | |
29 class KeyUtilityClientImpl | |
30 : public base::RefCountedThreadSafe<KeyUtilityClientImpl> { | |
31 public: | |
32 KeyUtilityClientImpl(); | |
33 | |
34 // Starts the UtilityProcess. Must be called before any other method. | |
35 void StartUtilityProcess(); | |
36 | |
37 // Stops the UtilityProcess. No further keys can be created after this. | |
38 void Shutdown(); | |
39 | |
40 // Synchronously obtain the |keys| from |values| for the given |key_path|. | |
41 void CreateIDBKeysFromSerializedValuesAndKeyPath( | |
42 const std::vector<SerializedScriptValue>& values, | |
43 const IndexedDBKeyPath& key_path, | |
44 std::vector<IndexedDBKey>* keys); | |
45 | |
46 // Synchronously inject |key| into |value| using the given |key_path|, | |
47 // returning the new value. | |
48 SerializedScriptValue InjectIDBKeyIntoSerializedValue( | |
49 const IndexedDBKey& key, | |
50 const SerializedScriptValue& value, | |
51 const IndexedDBKeyPath& key_path); | |
52 | |
53 private: | |
54 class Client : public UtilityProcessHostClient { | |
55 public: | |
56 explicit Client(KeyUtilityClientImpl* parent); | |
57 | |
58 // UtilityProcessHostClient | |
59 virtual void OnProcessCrashed(int exit_code); | |
60 virtual bool OnMessageReceived(const IPC::Message& message); | |
61 | |
62 // IPC message handlers | |
63 void OnIDBKeysFromValuesAndKeyPathSucceeded( | |
64 int id, const std::vector<IndexedDBKey>& keys); | |
65 void OnIDBKeysFromValuesAndKeyPathFailed(int id); | |
66 void OnInjectIDBKeyFinished(const SerializedScriptValue& value); | |
67 | |
68 private: | |
69 virtual ~Client() {} | |
70 | |
71 KeyUtilityClientImpl* parent_; | |
72 | |
73 DISALLOW_COPY_AND_ASSIGN(Client); | |
74 }; | |
75 | |
76 friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>; | |
77 ~KeyUtilityClientImpl(); | |
78 | |
79 void GetRDHAndStartUtilityProcess(); | |
80 void StartUtilityProcessInternal(); | |
81 void EndUtilityProcessInternal(); | |
82 void CallStartIDBKeyFromValueAndKeyPathFromIOThread( | |
83 const std::vector<SerializedScriptValue>& values, | |
84 const IndexedDBKeyPath& key_path); | |
85 void CallStartInjectIDBKeyFromIOThread( | |
86 const IndexedDBKey& key, | |
87 const SerializedScriptValue& value, | |
88 const IndexedDBKeyPath& key_path); | |
89 | |
90 void SetKeys(const std::vector<IndexedDBKey>& keys); | |
91 void FinishCreatingKeys(); | |
92 void SetValueAfterInjection(const SerializedScriptValue& value); | |
93 void FinishInjectingKey(); | |
94 | |
95 base::WaitableEvent waitable_event_; | |
96 | |
97 // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e., | |
98 // these members are only set / read when the other thread is blocked. | |
99 enum State { | |
100 STATE_UNINITIALIZED, | |
101 STATE_INITIALIZED, | |
102 STATE_CREATING_KEYS, | |
103 STATE_INJECTING_KEY, | |
104 STATE_SHUTDOWN, | |
105 }; | |
106 State state_; | |
107 std::vector<IndexedDBKey> keys_; | |
108 SerializedScriptValue value_after_injection_; | |
109 | |
110 // Used in the IO thread. | |
111 base::WeakPtr<content::UtilityProcessHost> utility_process_host_; | |
112 scoped_refptr<Client> client_; | |
113 | |
114 DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl); | |
115 }; | |
116 | |
117 // IndexedDBKeyUtilityClient definitions. | |
118 | |
119 static base::LazyInstance<IndexedDBKeyUtilityClient> client_instance = | |
120 LAZY_INSTANCE_INITIALIZER; | |
121 | |
122 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient() | |
123 : is_shutdown_(false) { | |
124 // Note that creating the impl_ object is deferred until it is first needed, | |
125 // as this class can be constructed even though it never gets used. | |
126 } | |
127 | |
128 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { | |
129 DCHECK(!impl_ || is_shutdown_); | |
130 } | |
131 | |
132 // static | |
133 void IndexedDBKeyUtilityClient::Shutdown() { | |
134 IndexedDBKeyUtilityClient* instance = client_instance.Pointer(); | |
135 if (!instance->impl_) | |
136 return; | |
137 | |
138 instance->is_shutdown_ = true; | |
139 instance->impl_->Shutdown(); | |
140 } | |
141 | |
142 // static | |
143 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath( | |
144 const std::vector<SerializedScriptValue>& values, | |
145 const IndexedDBKeyPath& key_path, | |
146 std::vector<IndexedDBKey>* keys) { | |
147 IndexedDBKeyUtilityClient* instance = client_instance.Pointer(); | |
148 | |
149 if (instance->is_shutdown_) { | |
150 keys->clear(); | |
151 return; | |
152 } | |
153 | |
154 if (!instance->impl_) { | |
155 instance->impl_ = new KeyUtilityClientImpl(); | |
156 instance->impl_->StartUtilityProcess(); | |
157 } | |
158 | |
159 instance->impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path, | |
160 keys); | |
161 } | |
162 | |
163 // static | |
164 SerializedScriptValue | |
165 IndexedDBKeyUtilityClient::InjectIDBKeyIntoSerializedValue( | |
166 const IndexedDBKey& key, const SerializedScriptValue& value, | |
167 const IndexedDBKeyPath& key_path) { | |
168 IndexedDBKeyUtilityClient* instance = client_instance.Pointer(); | |
169 | |
170 if (instance->is_shutdown_) | |
171 return SerializedScriptValue(); | |
172 | |
173 if (!instance->impl_) { | |
174 instance->impl_ = new KeyUtilityClientImpl(); | |
175 instance->impl_->StartUtilityProcess(); | |
176 } | |
177 | |
178 return instance->impl_->InjectIDBKeyIntoSerializedValue(key, value, key_path); | |
179 } | |
180 | |
181 | |
182 | |
183 // KeyUtilityClientImpl definitions. | |
184 | |
185 void KeyUtilityClientImpl::Shutdown() { | |
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
187 | |
188 if (utility_process_host_) { | |
189 utility_process_host_->EndBatchMode(); | |
190 utility_process_host_.reset(); | |
191 } | |
192 client_ = NULL; | |
193 state_ = STATE_SHUTDOWN; | |
194 } | |
195 | |
196 KeyUtilityClientImpl::KeyUtilityClientImpl() | |
197 : waitable_event_(false, false), | |
198 state_(STATE_UNINITIALIZED) { | |
199 } | |
200 | |
201 KeyUtilityClientImpl::~KeyUtilityClientImpl() { | |
202 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN); | |
203 DCHECK(!utility_process_host_); | |
204 DCHECK(!client_.get()); | |
205 } | |
206 | |
207 void KeyUtilityClientImpl::StartUtilityProcess() { | |
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
209 DCHECK(state_ == STATE_UNINITIALIZED); | |
210 | |
211 GetRDHAndStartUtilityProcess(); | |
212 waitable_event_.Wait(); | |
213 | |
214 DCHECK(state_ == STATE_INITIALIZED); | |
215 } | |
216 | |
217 void KeyUtilityClientImpl::CreateIDBKeysFromSerializedValuesAndKeyPath( | |
218 const std::vector<SerializedScriptValue>& values, | |
219 const IndexedDBKeyPath& key_path, | |
220 std::vector<IndexedDBKey>* keys) { | |
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
222 if (state_ == STATE_SHUTDOWN) { | |
223 keys->clear(); | |
224 return; | |
225 } | |
226 | |
227 DCHECK(state_ == STATE_INITIALIZED); | |
228 | |
229 state_ = STATE_CREATING_KEYS; | |
230 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path); | |
231 waitable_event_.Wait(); | |
232 DCHECK(state_ == STATE_INITIALIZED); | |
233 | |
234 *keys = keys_; | |
235 } | |
236 | |
237 SerializedScriptValue KeyUtilityClientImpl::InjectIDBKeyIntoSerializedValue( | |
238 const IndexedDBKey& key, | |
239 const SerializedScriptValue& value, | |
240 const IndexedDBKeyPath& key_path) { | |
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
242 if (state_ == STATE_SHUTDOWN) | |
243 return SerializedScriptValue(); | |
244 | |
245 DCHECK(state_ == STATE_INITIALIZED); | |
246 | |
247 state_ = STATE_INJECTING_KEY; | |
248 CallStartInjectIDBKeyFromIOThread(key, value, key_path); | |
249 | |
250 waitable_event_.Wait(); | |
251 DCHECK(state_ == STATE_INITIALIZED); | |
252 | |
253 return value_after_injection_; | |
254 } | |
255 | |
256 | |
257 void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() { | |
258 // In order to start the UtilityProcess, we need to grab | |
259 // a pointer to the ResourceDispatcherHost. This can only | |
260 // be done on the UI thread. See the comment at the top of | |
261 // browser_process.h | |
262 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
263 BrowserThread::PostTask( | |
264 BrowserThread::UI, FROM_HERE, | |
265 base::Bind(&KeyUtilityClientImpl::GetRDHAndStartUtilityProcess, this)); | |
266 return; | |
267 } | |
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
269 StartUtilityProcessInternal(); | |
270 } | |
271 | |
272 void KeyUtilityClientImpl::StartUtilityProcessInternal() { | |
273 // The ResourceDispatcherHost can only be used on the IO thread. | |
274 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
276 BrowserThread::PostTask( | |
277 BrowserThread::IO, FROM_HERE, | |
278 base::Bind(&KeyUtilityClientImpl::StartUtilityProcessInternal, this)); | |
279 return; | |
280 } | |
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
282 DCHECK(state_ == STATE_UNINITIALIZED); | |
283 | |
284 client_ = new KeyUtilityClientImpl::Client(this); | |
285 utility_process_host_ = (new UtilityProcessHostImpl( | |
286 client_.get(), BrowserThread::IO))->AsWeakPtr(); | |
287 utility_process_host_->EnableZygote(); | |
288 utility_process_host_->StartBatchMode(); | |
289 state_ = STATE_INITIALIZED; | |
290 waitable_event_.Signal(); | |
291 } | |
292 | |
293 void KeyUtilityClientImpl::EndUtilityProcessInternal() { | |
294 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
295 BrowserThread::PostTask( | |
296 BrowserThread::IO, FROM_HERE, | |
297 base::Bind(&KeyUtilityClientImpl::EndUtilityProcessInternal, this)); | |
298 return; | |
299 } | |
300 | |
301 if (utility_process_host_) { | |
302 utility_process_host_->EndBatchMode(); | |
303 utility_process_host_.reset(); | |
304 } | |
305 client_ = NULL; | |
306 state_ = STATE_SHUTDOWN; | |
307 waitable_event_.Signal(); | |
308 } | |
309 | |
310 void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread( | |
311 const std::vector<SerializedScriptValue>& values, | |
312 const IndexedDBKeyPath& key_path) { | |
313 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
314 BrowserThread::PostTask( | |
315 BrowserThread::IO, FROM_HERE, | |
316 base::Bind(&KeyUtilityClientImpl:: | |
317 CallStartIDBKeyFromValueAndKeyPathFromIOThread, | |
318 this, values, key_path)); | |
319 return; | |
320 } | |
321 | |
322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
323 if (utility_process_host_) { | |
324 utility_process_host_->Send(new UtilityMsg_IDBKeysFromValuesAndKeyPath( | |
325 0, values, key_path)); | |
326 } | |
327 } | |
328 | |
329 void KeyUtilityClientImpl::CallStartInjectIDBKeyFromIOThread( | |
330 const IndexedDBKey& key, | |
331 const SerializedScriptValue& value, | |
332 const IndexedDBKeyPath& key_path) { | |
333 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
334 BrowserThread::PostTask( | |
335 BrowserThread::IO, FROM_HERE, | |
336 base::Bind(&KeyUtilityClientImpl::CallStartInjectIDBKeyFromIOThread, | |
337 this, key, value, key_path)); | |
338 return; | |
339 } | |
340 | |
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
342 if (utility_process_host_) | |
343 utility_process_host_->Send(new UtilityMsg_InjectIDBKey( | |
344 key, value, key_path)); | |
345 } | |
346 | |
347 void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) { | |
348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
349 keys_ = keys; | |
350 } | |
351 | |
352 void KeyUtilityClientImpl::FinishCreatingKeys() { | |
353 DCHECK(state_ == STATE_CREATING_KEYS); | |
354 state_ = STATE_INITIALIZED; | |
355 waitable_event_.Signal(); | |
356 } | |
357 | |
358 void KeyUtilityClientImpl::SetValueAfterInjection( | |
359 const SerializedScriptValue& value) { | |
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
361 value_after_injection_ = value; | |
362 } | |
363 | |
364 void KeyUtilityClientImpl::FinishInjectingKey() { | |
365 DCHECK(state_ == STATE_INJECTING_KEY); | |
366 state_ = STATE_INITIALIZED; | |
367 waitable_event_.Signal(); | |
368 } | |
369 | |
370 KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent) | |
371 : parent_(parent) { | |
372 } | |
373 | |
374 void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) { | |
375 if (parent_->state_ == STATE_CREATING_KEYS) | |
376 parent_->FinishCreatingKeys(); | |
377 parent_->Shutdown(); | |
378 } | |
379 | |
380 bool KeyUtilityClientImpl::Client::OnMessageReceived( | |
381 const IPC::Message& message) { | |
382 bool handled = true; | |
383 IPC_BEGIN_MESSAGE_MAP(KeyUtilityClientImpl::Client, message) | |
384 IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded, | |
385 OnIDBKeysFromValuesAndKeyPathSucceeded) | |
386 IPC_MESSAGE_HANDLER(UtilityHostMsg_InjectIDBKey_Finished, | |
387 OnInjectIDBKeyFinished) | |
388 IPC_MESSAGE_UNHANDLED(handled = false) | |
389 IPC_END_MESSAGE_MAP() | |
390 return handled; | |
391 } | |
392 | |
393 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded( | |
394 int id, const std::vector<IndexedDBKey>& keys) { | |
395 parent_->SetKeys(keys); | |
396 parent_->FinishCreatingKeys(); | |
397 } | |
398 | |
399 void KeyUtilityClientImpl::Client::OnInjectIDBKeyFinished( | |
400 const SerializedScriptValue& value) { | |
401 parent_->SetValueAfterInjection(value); | |
402 parent_->FinishInjectingKey(); | |
403 } | |
404 | |
405 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed( | |
406 int id) { | |
407 parent_->FinishCreatingKeys(); | |
408 } | |
OLD | NEW |