OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h" | 5 #include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h" |
6 | 6 |
7 #include <vector> | 7 #include "base/lazy_instance.h" |
8 | 8 #include "base/synchronization/waitable_event.h" |
9 #include "chrome/browser/browser_process.h" | 9 #include "chrome/browser/browser_process.h" |
| 10 #include "chrome/browser/utility_process_host.h" |
10 #include "chrome/common/indexed_db_key.h" | 11 #include "chrome/common/indexed_db_key.h" |
11 #include "chrome/common/serialized_script_value.h" | 12 #include "chrome/common/serialized_script_value.h" |
12 | 13 |
| 14 // This class is used to obtain IndexedDBKeys from SerializedScriptValues |
| 15 // given an IDBKeyPath. It uses UtilityProcess to do this inside a sandbox |
| 16 // (a V8 lock is required there). At this level, all methods are synchronous |
| 17 // as required by the caller. The public API is used on WEBKIT thread, |
| 18 // but internally it moves around to UI and IO as needed. |
| 19 class KeyUtilityClientImpl |
| 20 : public base::RefCountedThreadSafe<KeyUtilityClientImpl> { |
| 21 public: |
| 22 KeyUtilityClientImpl(); |
| 23 |
| 24 // Starts the UtilityProcess. Must be called before any other method. |
| 25 void StartUtilityProcess(); |
| 26 |
| 27 // Stops the UtilityProcess. No further keys can be created after this. |
| 28 void Shutdown(); |
| 29 |
| 30 // Synchronously obtain the |keys| from |values| for the given |key_path|. |
| 31 void CreateIDBKeysFromSerializedValuesAndKeyPath( |
| 32 const std::vector<SerializedScriptValue>& values, |
| 33 const string16& key_path, |
| 34 std::vector<IndexedDBKey>* keys); |
| 35 |
| 36 private: |
| 37 class Client : public UtilityProcessHost::Client { |
| 38 public: |
| 39 explicit Client(KeyUtilityClientImpl* parent); |
| 40 |
| 41 // UtilityProcessHost::Client |
| 42 virtual void OnProcessCrashed(int exit_code); |
| 43 virtual void OnIDBKeysFromValuesAndKeyPathSucceeded( |
| 44 int id, const std::vector<IndexedDBKey>& keys); |
| 45 virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id); |
| 46 |
| 47 private: |
| 48 KeyUtilityClientImpl* parent_; |
| 49 |
| 50 DISALLOW_COPY_AND_ASSIGN(Client); |
| 51 }; |
| 52 |
| 53 friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>; |
| 54 ~KeyUtilityClientImpl(); |
| 55 |
| 56 void GetRDHAndStartUtilityProcess(); |
| 57 void StartUtilityProcessInternal(ResourceDispatcherHost* rdh); |
| 58 void EndUtilityProcessInternal(); |
| 59 void CallStartIDBKeyFromValueAndKeyPathFromIOThread( |
| 60 const std::vector<SerializedScriptValue>& values, |
| 61 const string16& key_path); |
| 62 |
| 63 void SetKeys(const std::vector<IndexedDBKey>& keys); |
| 64 void FinishCreatingKeys(); |
| 65 |
| 66 base::WaitableEvent waitable_event_; |
| 67 |
| 68 // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e., |
| 69 // these members are only set / read when the other thread is blocked. |
| 70 enum State { |
| 71 STATE_UNINITIALIZED, |
| 72 STATE_INITIALIZED, |
| 73 STATE_CREATING_KEYS, |
| 74 STATE_SHUTDOWN, |
| 75 }; |
| 76 State state_; |
| 77 std::vector<IndexedDBKey> keys_; |
| 78 |
| 79 // Used in the IO thread. |
| 80 UtilityProcessHost* utility_process_host_; |
| 81 scoped_refptr<Client> client_; |
| 82 |
| 83 DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl); |
| 84 }; |
| 85 |
| 86 // IndexedDBKeyUtilityClient definitions. |
| 87 |
| 88 static base::LazyInstance<IndexedDBKeyUtilityClient> client_instance( |
| 89 base::LINKER_INITIALIZED); |
| 90 |
13 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient() | 91 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient() |
| 92 : is_shutdown_(false) { |
| 93 // Note that creating the impl_ object is deferred until it is first needed, |
| 94 // as this class can be constructed even though it never gets used. |
| 95 } |
| 96 |
| 97 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { |
| 98 DCHECK(!impl_ || is_shutdown_); |
| 99 } |
| 100 |
| 101 // static |
| 102 void IndexedDBKeyUtilityClient::Shutdown() { |
| 103 IndexedDBKeyUtilityClient* instance = client_instance.Pointer(); |
| 104 if (!instance->impl_) |
| 105 return; |
| 106 |
| 107 instance->is_shutdown_ = true; |
| 108 instance->impl_->Shutdown(); |
| 109 } |
| 110 |
| 111 // static |
| 112 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath( |
| 113 const std::vector<SerializedScriptValue>& values, |
| 114 const string16& key_path, |
| 115 std::vector<IndexedDBKey>* keys) { |
| 116 IndexedDBKeyUtilityClient* instance = client_instance.Pointer(); |
| 117 |
| 118 if (instance->is_shutdown_) { |
| 119 keys->clear(); |
| 120 return; |
| 121 } |
| 122 |
| 123 if (!instance->impl_) { |
| 124 instance->impl_ = new KeyUtilityClientImpl(); |
| 125 instance->impl_->StartUtilityProcess(); |
| 126 } |
| 127 |
| 128 instance->impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path, |
| 129 keys); |
| 130 } |
| 131 |
| 132 // KeyUtilityClientImpl definitions. |
| 133 |
| 134 void KeyUtilityClientImpl::Shutdown() { |
| 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 136 |
| 137 utility_process_host_->EndBatchMode(); |
| 138 utility_process_host_ = NULL; |
| 139 client_ = NULL; |
| 140 state_ = STATE_SHUTDOWN; |
| 141 } |
| 142 |
| 143 KeyUtilityClientImpl::KeyUtilityClientImpl() |
14 : waitable_event_(false, false), | 144 : waitable_event_(false, false), |
15 state_(STATE_UNINITIALIZED), | 145 state_(STATE_UNINITIALIZED), |
16 utility_process_host_(NULL) { | 146 utility_process_host_(NULL) { |
17 } | 147 } |
18 | 148 |
19 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { | 149 KeyUtilityClientImpl::~KeyUtilityClientImpl() { |
20 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN); | 150 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN); |
21 DCHECK(!utility_process_host_); | 151 DCHECK(!utility_process_host_); |
22 DCHECK(!client_.get()); | 152 DCHECK(!client_.get()); |
23 } | 153 } |
24 | 154 |
25 void IndexedDBKeyUtilityClient::StartUtilityProcess() { | 155 void KeyUtilityClientImpl::StartUtilityProcess() { |
26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
27 DCHECK(state_ == STATE_UNINITIALIZED); | 157 DCHECK(state_ == STATE_UNINITIALIZED); |
28 | 158 |
29 GetRDHAndStartUtilityProcess(); | 159 GetRDHAndStartUtilityProcess(); |
30 bool ret = waitable_event_.Wait(); | 160 bool ret = waitable_event_.Wait(); |
31 | 161 |
32 DCHECK(ret && state_ == STATE_INITIALIZED); | 162 DCHECK(ret && state_ == STATE_INITIALIZED); |
33 } | 163 } |
34 | 164 |
35 void IndexedDBKeyUtilityClient::EndUtilityProcess() { | 165 void KeyUtilityClientImpl::CreateIDBKeysFromSerializedValuesAndKeyPath( |
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
37 DCHECK(state_ == STATE_INITIALIZED); | |
38 | |
39 EndUtilityProcessInternal(); | |
40 bool ret = waitable_event_.Wait(); | |
41 | |
42 DCHECK(ret && state_ == STATE_SHUTDOWN); | |
43 } | |
44 | |
45 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath( | |
46 const std::vector<SerializedScriptValue>& values, | 166 const std::vector<SerializedScriptValue>& values, |
47 const string16& key_path, | 167 const string16& key_path, |
48 std::vector<IndexedDBKey>* keys) { | 168 std::vector<IndexedDBKey>* keys) { |
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
| 170 if (state_ == STATE_SHUTDOWN) { |
| 171 keys->clear(); |
| 172 return; |
| 173 } |
| 174 |
50 DCHECK(state_ == STATE_INITIALIZED); | 175 DCHECK(state_ == STATE_INITIALIZED); |
51 | 176 |
52 state_ = STATE_CREATING_KEYS; | 177 state_ = STATE_CREATING_KEYS; |
53 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path); | 178 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path); |
54 bool ret = waitable_event_.Wait(); | 179 bool ret = waitable_event_.Wait(); |
55 DCHECK(ret && state_ == STATE_INITIALIZED); | 180 DCHECK(ret && state_ == STATE_INITIALIZED); |
56 | 181 |
57 *keys = keys_; | 182 *keys = keys_; |
58 } | 183 } |
59 | 184 |
60 void IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess() { | 185 void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() { |
61 // In order to start the UtilityProcess, we need to grab | 186 // In order to start the UtilityProcess, we need to grab |
62 // a pointer to the ResourceDispatcherHost. This can only | 187 // a pointer to the ResourceDispatcherHost. This can only |
63 // be done on the UI thread. See the comment at the top of | 188 // be done on the UI thread. See the comment at the top of |
64 // browser_process.h | 189 // browser_process.h |
65 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 190 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
66 BrowserThread::PostTask( | 191 BrowserThread::PostTask( |
67 BrowserThread::UI, FROM_HERE, | 192 BrowserThread::UI, FROM_HERE, |
68 NewRunnableMethod( | 193 NewRunnableMethod( |
69 this, | 194 this, |
70 &IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess)); | 195 &KeyUtilityClientImpl::GetRDHAndStartUtilityProcess)); |
71 return; | 196 return; |
72 } | 197 } |
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
74 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host()); | 199 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host()); |
75 } | 200 } |
76 | 201 |
77 void IndexedDBKeyUtilityClient::StartUtilityProcessInternal( | 202 void KeyUtilityClientImpl::StartUtilityProcessInternal( |
78 ResourceDispatcherHost* rdh) { | 203 ResourceDispatcherHost* rdh) { |
79 DCHECK(rdh); | 204 DCHECK(rdh); |
80 // The ResourceDispatcherHost can only be used on the IO thread. | 205 // The ResourceDispatcherHost can only be used on the IO thread. |
81 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 206 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
83 BrowserThread::PostTask( | 208 BrowserThread::PostTask( |
84 BrowserThread::IO, FROM_HERE, | 209 BrowserThread::IO, FROM_HERE, |
85 NewRunnableMethod( | 210 NewRunnableMethod( |
86 this, | 211 this, |
87 &IndexedDBKeyUtilityClient::StartUtilityProcessInternal, | 212 &KeyUtilityClientImpl::StartUtilityProcessInternal, |
88 rdh)); | 213 rdh)); |
89 return; | 214 return; |
90 } | 215 } |
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
92 DCHECK(state_ == STATE_UNINITIALIZED); | 217 DCHECK(state_ == STATE_UNINITIALIZED); |
93 | 218 |
94 client_ = new IndexedDBKeyUtilityClient::Client(this); | 219 client_ = new KeyUtilityClientImpl::Client(this); |
95 utility_process_host_ = new UtilityProcessHost( | 220 utility_process_host_ = new UtilityProcessHost( |
96 rdh, client_.get(), BrowserThread::IO); | 221 rdh, client_.get(), BrowserThread::IO); |
97 utility_process_host_->StartBatchMode(); | 222 utility_process_host_->StartBatchMode(); |
98 state_ = STATE_INITIALIZED; | 223 state_ = STATE_INITIALIZED; |
99 waitable_event_.Signal(); | 224 waitable_event_.Signal(); |
100 } | 225 } |
101 | 226 |
102 void IndexedDBKeyUtilityClient::EndUtilityProcessInternal() { | 227 void KeyUtilityClientImpl::EndUtilityProcessInternal() { |
103 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 228 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
104 BrowserThread::PostTask( | 229 BrowserThread::PostTask( |
105 BrowserThread::IO, FROM_HERE, | 230 BrowserThread::IO, FROM_HERE, |
106 NewRunnableMethod( | 231 NewRunnableMethod( |
107 this, | 232 this, |
108 &IndexedDBKeyUtilityClient::EndUtilityProcessInternal)); | 233 &KeyUtilityClientImpl::EndUtilityProcessInternal)); |
109 return; | 234 return; |
110 } | 235 } |
111 | 236 |
112 utility_process_host_->EndBatchMode(); | 237 utility_process_host_->EndBatchMode(); |
113 utility_process_host_ = NULL; | 238 utility_process_host_ = NULL; |
114 client_ = NULL; | 239 client_ = NULL; |
115 state_ = STATE_SHUTDOWN; | 240 state_ = STATE_SHUTDOWN; |
116 waitable_event_.Signal(); | 241 waitable_event_.Signal(); |
117 } | 242 } |
118 | 243 |
119 void IndexedDBKeyUtilityClient::CallStartIDBKeyFromValueAndKeyPathFromIOThread( | 244 void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread( |
120 const std::vector<SerializedScriptValue>& values, | 245 const std::vector<SerializedScriptValue>& values, |
121 const string16& key_path) { | 246 const string16& key_path) { |
122 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 247 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
123 BrowserThread::PostTask( | 248 BrowserThread::PostTask( |
124 BrowserThread::IO, FROM_HERE, | 249 BrowserThread::IO, FROM_HERE, |
125 NewRunnableMethod(this, | 250 NewRunnableMethod(this, |
126 &IndexedDBKeyUtilityClient:: | 251 &KeyUtilityClientImpl:: |
127 CallStartIDBKeyFromValueAndKeyPathFromIOThread, | 252 CallStartIDBKeyFromValueAndKeyPathFromIOThread, |
128 values, key_path)); | 253 values, key_path)); |
129 return; | 254 return; |
130 } | 255 } |
131 | 256 |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
133 utility_process_host_->StartIDBKeysFromValuesAndKeyPath( | 258 utility_process_host_->StartIDBKeysFromValuesAndKeyPath( |
134 0, values, key_path); | 259 0, values, key_path); |
135 } | 260 } |
136 | 261 |
137 void IndexedDBKeyUtilityClient::SetKeys(const std::vector<IndexedDBKey>& keys) { | 262 void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) { |
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
139 keys_ = keys; | 264 keys_ = keys; |
140 } | 265 } |
141 | 266 |
142 void IndexedDBKeyUtilityClient::FinishCreatingKeys() { | 267 void KeyUtilityClientImpl::FinishCreatingKeys() { |
143 DCHECK(state_ == STATE_CREATING_KEYS); | 268 DCHECK(state_ == STATE_CREATING_KEYS); |
144 state_ = STATE_INITIALIZED; | 269 state_ = STATE_INITIALIZED; |
145 waitable_event_.Signal(); | 270 waitable_event_.Signal(); |
146 } | 271 } |
147 | 272 |
148 IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent) | 273 KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent) |
149 : parent_(parent) { | 274 : parent_(parent) { |
150 } | 275 } |
151 | 276 |
152 void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) { | 277 void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) { |
153 if (parent_->state_ == STATE_CREATING_KEYS) | 278 if (parent_->state_ == STATE_CREATING_KEYS) |
154 parent_->FinishCreatingKeys(); | 279 parent_->FinishCreatingKeys(); |
155 } | 280 } |
156 | 281 |
157 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathSucceeded( | 282 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded( |
158 int id, const std::vector<IndexedDBKey>& keys) { | 283 int id, const std::vector<IndexedDBKey>& keys) { |
159 parent_->SetKeys(keys); | 284 parent_->SetKeys(keys); |
160 parent_->FinishCreatingKeys(); | 285 parent_->FinishCreatingKeys(); |
161 } | 286 } |
162 | 287 |
163 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathFailed( | 288 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed( |
164 int id) { | 289 int id) { |
165 parent_->FinishCreatingKeys(); | 290 parent_->FinishCreatingKeys(); |
166 } | 291 } |
OLD | NEW |