OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/child/blob_storage/blob_transport_controller.h" | 5 #include "content/child/blob_storage/blob_transport_controller.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <memory> | 8 #include <memory> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
14 #include "base/callback.h" | 14 #include "base/callback.h" |
15 #include "base/files/file.h" | 15 #include "base/files/file.h" |
16 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
17 #include "base/location.h" | 17 #include "base/location.h" |
18 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
19 #include "base/memory/scoped_vector.h" | 19 #include "base/memory/scoped_vector.h" |
20 #include "base/memory/shared_memory.h" | 20 #include "base/memory/shared_memory.h" |
21 #include "base/metrics/histogram_macros.h" | 21 #include "base/metrics/histogram_macros.h" |
22 #include "base/numerics/safe_conversions.h" | 22 #include "base/numerics/safe_conversions.h" |
23 #include "base/optional.h" | |
24 #include "base/single_thread_task_runner.h" | 23 #include "base/single_thread_task_runner.h" |
25 #include "base/stl_util.h" | 24 #include "base/stl_util.h" |
26 #include "base/task_runner.h" | 25 #include "base/task_runner.h" |
27 #include "base/task_runner_util.h" | 26 #include "base/task_runner_util.h" |
28 #include "base/threading/thread_task_runner_handle.h" | 27 #include "base/threading/thread_task_runner_handle.h" |
29 #include "base/time/time.h" | 28 #include "base/time/time.h" |
30 #include "content/child/blob_storage/blob_consolidation.h" | 29 #include "content/child/blob_storage/blob_consolidation.h" |
31 #include "content/child/child_process.h" | 30 #include "content/child/child_process.h" |
32 #include "content/child/thread_safe_sender.h" | 31 #include "content/child/thread_safe_sender.h" |
33 #include "content/common/fileapi/webblob_messages.h" | 32 #include "content/common/fileapi/webblob_messages.h" |
34 #include "ipc/ipc_message.h" | 33 #include "ipc/ipc_message.h" |
35 #include "ipc/ipc_sender.h" | 34 #include "ipc/ipc_sender.h" |
36 #include "storage/common/blob_storage/blob_item_bytes_request.h" | 35 #include "storage/common/blob_storage/blob_item_bytes_request.h" |
37 #include "storage/common/blob_storage/blob_item_bytes_response.h" | 36 #include "storage/common/blob_storage/blob_item_bytes_response.h" |
38 #include "storage/common/data_element.h" | 37 #include "storage/common/data_element.h" |
39 #include "third_party/WebKit/public/platform/Platform.h" | 38 #include "third_party/WebKit/public/platform/Platform.h" |
40 | 39 |
41 using base::File; | 40 using base::File; |
42 using base::SharedMemory; | 41 using base::SharedMemory; |
43 using base::SharedMemoryHandle; | 42 using base::SharedMemoryHandle; |
44 using storage::BlobItemBytesRequest; | 43 using storage::BlobItemBytesRequest; |
45 using storage::BlobItemBytesResponse; | 44 using storage::BlobItemBytesResponse; |
46 using storage::IPCBlobItemRequestStrategy; | 45 using storage::IPCBlobItemRequestStrategy; |
47 using storage::DataElement; | 46 using storage::DataElement; |
48 using storage::kBlobStorageIPCThresholdBytes; | |
49 | 47 |
50 using storage::BlobItemBytesResponse; | 48 using storage::BlobItemBytesResponse; |
51 using storage::BlobItemBytesRequest; | 49 using storage::BlobItemBytesRequest; |
52 using storage::IPCBlobCreationCancelCode; | 50 using storage::BlobStatus; |
53 | 51 |
54 namespace content { | 52 namespace content { |
55 using ConsolidatedItem = BlobConsolidation::ConsolidatedItem; | 53 using ConsolidatedItem = BlobConsolidation::ConsolidatedItem; |
56 using ReadStatus = BlobConsolidation::ReadStatus; | 54 using ReadStatus = BlobConsolidation::ReadStatus; |
57 | 55 |
58 namespace { | 56 namespace { |
59 static base::LazyInstance<BlobTransportController>::Leaky g_controller = | 57 static base::LazyInstance<BlobTransportController>::Leaky g_controller = |
60 LAZY_INSTANCE_INITIALIZER; | 58 LAZY_INSTANCE_INITIALIZER; |
61 | 59 |
62 // This keeps the process alive while blobs are being transferred. | 60 // This keeps the process alive while blobs are being transferred. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 BlobConsolidation::ReadStatus status = consolidation->VisitMemory( | 106 BlobConsolidation::ReadStatus status = consolidation->VisitMemory( |
109 request.renderer_item_index, request.renderer_item_offset, request.size, | 107 request.renderer_item_index, request.renderer_item_offset, request.size, |
110 base::Bind(&WriteSingleChunk, file)); | 108 base::Bind(&WriteSingleChunk, file)); |
111 if (status != BlobConsolidation::ReadStatus::OK) | 109 if (status != BlobConsolidation::ReadStatus::OK) |
112 return base::nullopt; | 110 return base::nullopt; |
113 File::Info info; | 111 File::Info info; |
114 file->GetInfo(&info); | 112 file->GetInfo(&info); |
115 return base::make_optional(info.last_modified); | 113 return base::make_optional(info.last_modified); |
116 } | 114 } |
117 | 115 |
118 // This returns either the responses, or if they're empty, an error code. | 116 base::Optional<std::vector<BlobItemBytesResponse>> WriteDiskRequests( |
119 std::pair<std::vector<storage::BlobItemBytesResponse>, | |
120 IPCBlobCreationCancelCode> | |
121 WriteDiskRequests( | |
122 scoped_refptr<BlobConsolidation> consolidation, | 117 scoped_refptr<BlobConsolidation> consolidation, |
123 std::unique_ptr<std::vector<BlobItemBytesRequest>> requests, | 118 std::unique_ptr<std::vector<BlobItemBytesRequest>> requests, |
124 const std::vector<IPC::PlatformFileForTransit>& file_handles) { | 119 const std::vector<IPC::PlatformFileForTransit>& file_handles) { |
125 std::vector<BlobItemBytesResponse> responses; | 120 std::vector<BlobItemBytesResponse> responses; |
126 std::vector<base::Time> last_modified_times; | 121 std::vector<base::Time> last_modified_times; |
127 last_modified_times.resize(file_handles.size()); | 122 last_modified_times.resize(file_handles.size()); |
128 // We grab ownership of the file handles here. When this vector is destroyed | 123 // We grab ownership of the file handles here. When this vector is destroyed |
129 // it will close the files. | 124 // it will close the files. |
130 std::vector<File> files; | 125 std::vector<File> files; |
131 files.reserve(file_handles.size()); | 126 files.reserve(file_handles.size()); |
132 for (const auto& file_handle : file_handles) { | 127 for (const auto& file_handle : file_handles) { |
133 files.emplace_back(IPC::PlatformFileForTransitToFile(file_handle)); | 128 files.emplace_back(IPC::PlatformFileForTransitToFile(file_handle)); |
134 } | 129 } |
135 for (const auto& request : *requests) { | 130 for (const auto& request : *requests) { |
136 base::Optional<base::Time> last_modified = WriteSingleRequestToDisk( | 131 base::Optional<base::Time> last_modified = WriteSingleRequestToDisk( |
137 consolidation.get(), request, &files[request.handle_index]); | 132 consolidation.get(), request, &files[request.handle_index]); |
138 if (!last_modified) { | 133 if (!last_modified) { |
139 return std::make_pair(std::vector<storage::BlobItemBytesResponse>(), | 134 return base::nullopt; |
140 IPCBlobCreationCancelCode::FILE_WRITE_FAILED); | |
141 } | 135 } |
142 last_modified_times[request.handle_index] = last_modified.value(); | 136 last_modified_times[request.handle_index] = last_modified.value(); |
143 } | 137 } |
144 for (const auto& request : *requests) { | 138 for (const auto& request : *requests) { |
145 responses.push_back(BlobItemBytesResponse(request.request_number)); | 139 responses.push_back(BlobItemBytesResponse(request.request_number)); |
146 responses.back().time_file_modified = | 140 responses.back().time_file_modified = |
147 last_modified_times[request.handle_index]; | 141 last_modified_times[request.handle_index]; |
148 } | 142 } |
149 | 143 |
150 return std::make_pair(responses, IPCBlobCreationCancelCode::UNKNOWN); | 144 return responses; |
151 } | 145 } |
152 | 146 |
153 } // namespace | 147 } // namespace |
154 | 148 |
155 BlobTransportController* BlobTransportController::GetInstance() { | 149 BlobTransportController* BlobTransportController::GetInstance() { |
156 return g_controller.Pointer(); | 150 return g_controller.Pointer(); |
157 } | 151 } |
158 | 152 |
159 // static | 153 // static |
160 void BlobTransportController::InitiateBlobTransfer( | 154 void BlobTransportController::InitiateBlobTransfer( |
161 const std::string& uuid, | 155 const std::string& uuid, |
162 const std::string& content_type, | 156 const std::string& content_type, |
163 scoped_refptr<BlobConsolidation> consolidation, | 157 scoped_refptr<BlobConsolidation> consolidation, |
164 scoped_refptr<ThreadSafeSender> sender, | 158 scoped_refptr<ThreadSafeSender> sender, |
165 base::SingleThreadTaskRunner* io_runner, | 159 base::SingleThreadTaskRunner* io_runner, |
166 scoped_refptr<base::SingleThreadTaskRunner> main_runner) { | 160 scoped_refptr<base::SingleThreadTaskRunner> main_runner) { |
167 if (main_runner->BelongsToCurrentThread()) { | 161 if (main_runner->BelongsToCurrentThread()) { |
168 IncChildProcessRefCount(); | 162 IncChildProcessRefCount(); |
169 } else { | 163 } else { |
170 main_runner->PostTask(FROM_HERE, base::Bind(&IncChildProcessRefCount)); | 164 main_runner->PostTask(FROM_HERE, base::Bind(&IncChildProcessRefCount)); |
171 } | 165 } |
172 | 166 |
| 167 storage::BlobStorageLimits quotas; |
173 std::vector<storage::DataElement> descriptions; | 168 std::vector<storage::DataElement> descriptions; |
174 std::set<std::string> referenced_blobs = consolidation->referenced_blobs(); | |
175 BlobTransportController::GetDescriptions( | 169 BlobTransportController::GetDescriptions( |
176 consolidation.get(), kBlobStorageIPCThresholdBytes, &descriptions); | 170 consolidation.get(), quotas.max_ipc_memory_size, &descriptions); |
177 // I post the task first to make sure that we store our consolidation before | 171 // I post the task first to make sure that we store our consolidation before |
178 // we get a request back from the browser. | 172 // we get a request back from the browser. |
179 io_runner->PostTask( | 173 io_runner->PostTask( |
180 FROM_HERE, | 174 FROM_HERE, |
181 base::Bind(&BlobTransportController::StoreBlobDataForRequests, | 175 base::Bind(&BlobTransportController::StoreBlobDataForRequests, |
182 base::Unretained(BlobTransportController::GetInstance()), uuid, | 176 base::Unretained(BlobTransportController::GetInstance()), uuid, |
183 base::Passed(std::move(consolidation)), | 177 base::Passed(std::move(consolidation)), |
184 base::Passed(std::move(main_runner)))); | 178 base::Passed(std::move(main_runner)))); |
185 // TODO(dmurph): Merge register and start messages. | 179 sender->Send( |
186 sender->Send(new BlobStorageMsg_RegisterBlobUUID(uuid, content_type, "", | 180 new BlobStorageMsg_RegisterBlob(uuid, content_type, "", descriptions)); |
187 referenced_blobs)); | |
188 sender->Send(new BlobStorageMsg_StartBuildingBlob(uuid, descriptions)); | |
189 } | 181 } |
190 | 182 |
191 void BlobTransportController::OnMemoryRequest( | 183 void BlobTransportController::OnMemoryRequest( |
192 const std::string& uuid, | 184 const std::string& uuid, |
193 const std::vector<storage::BlobItemBytesRequest>& requests, | 185 const std::vector<storage::BlobItemBytesRequest>& requests, |
194 std::vector<base::SharedMemoryHandle>* memory_handles, | 186 std::vector<base::SharedMemoryHandle>* memory_handles, |
195 const std::vector<IPC::PlatformFileForTransit>& file_handles, | 187 const std::vector<IPC::PlatformFileForTransit>& file_handles, |
196 base::TaskRunner* file_runner, | 188 base::TaskRunner* file_runner, |
197 IPC::Sender* sender) { | 189 IPC::Sender* sender) { |
198 std::vector<BlobItemBytesResponse> responses; | 190 std::vector<BlobItemBytesResponse> responses; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 base::Bind(&WriteDiskRequests, make_scoped_refptr(consolidation), | 289 base::Bind(&WriteDiskRequests, make_scoped_refptr(consolidation), |
298 base::Passed(&file_requests), file_handles), | 290 base::Passed(&file_requests), file_handles), |
299 base::Bind(&BlobTransportController::OnFileWriteComplete, | 291 base::Bind(&BlobTransportController::OnFileWriteComplete, |
300 weak_factory_.GetWeakPtr(), sender, uuid)); | 292 weak_factory_.GetWeakPtr(), sender, uuid)); |
301 } | 293 } |
302 | 294 |
303 if (!responses.empty()) | 295 if (!responses.empty()) |
304 sender->Send(new BlobStorageMsg_MemoryItemResponse(uuid, responses)); | 296 sender->Send(new BlobStorageMsg_MemoryItemResponse(uuid, responses)); |
305 } | 297 } |
306 | 298 |
307 void BlobTransportController::OnCancel( | 299 void BlobTransportController::OnBlobFinalStatus(const std::string& uuid, |
308 const std::string& uuid, | 300 storage::BlobStatus code) { |
309 storage::IPCBlobCreationCancelCode code) { | 301 DVLOG_IF(1, storage::BlobStatusIsError(code)) |
310 DVLOG(1) << "Received blob cancel for blob " << uuid | 302 << "Received blob error for blob " << uuid |
311 << " with code: " << static_cast<int>(code); | 303 << " with code: " << static_cast<int>(code); |
| 304 DCHECK(!BlobStatusIsPending(code)); |
312 ReleaseBlobConsolidation(uuid); | 305 ReleaseBlobConsolidation(uuid); |
313 } | 306 } |
314 | 307 |
315 void BlobTransportController::OnDone(const std::string& uuid) { | |
316 ReleaseBlobConsolidation(uuid); | |
317 } | |
318 | |
319 void BlobTransportController::CancelAllBlobTransfers() { | 308 void BlobTransportController::CancelAllBlobTransfers() { |
320 weak_factory_.InvalidateWeakPtrs(); | 309 weak_factory_.InvalidateWeakPtrs(); |
321 if (!blob_storage_.empty() && main_thread_runner_) { | 310 if (!blob_storage_.empty() && main_thread_runner_) { |
322 main_thread_runner_->PostTask( | 311 main_thread_runner_->PostTask( |
323 FROM_HERE, | 312 FROM_HERE, |
324 base::Bind(&DecChildProcessRefCountTimes, blob_storage_.size())); | 313 base::Bind(&DecChildProcessRefCountTimes, blob_storage_.size())); |
325 } | 314 } |
326 main_thread_runner_ = nullptr; | 315 main_thread_runner_ = nullptr; |
327 blob_storage_.clear(); | 316 blob_storage_.clear(); |
328 } | 317 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 } | 370 } |
382 } | 371 } |
383 | 372 |
384 BlobTransportController::BlobTransportController() : weak_factory_(this) {} | 373 BlobTransportController::BlobTransportController() : weak_factory_(this) {} |
385 | 374 |
386 BlobTransportController::~BlobTransportController() {} | 375 BlobTransportController::~BlobTransportController() {} |
387 | 376 |
388 void BlobTransportController::OnFileWriteComplete( | 377 void BlobTransportController::OnFileWriteComplete( |
389 IPC::Sender* sender, | 378 IPC::Sender* sender, |
390 const std::string& uuid, | 379 const std::string& uuid, |
391 const std::pair<std::vector<BlobItemBytesResponse>, | 380 const base::Optional<std::vector<storage::BlobItemBytesResponse>>& result) { |
392 IPCBlobCreationCancelCode>& result) { | |
393 if (blob_storage_.find(uuid) == blob_storage_.end()) | 381 if (blob_storage_.find(uuid) == blob_storage_.end()) |
394 return; | 382 return; |
395 if (!result.first.empty()) { | 383 if (!result) { |
396 sender->Send(new BlobStorageMsg_MemoryItemResponse(uuid, result.first)); | 384 sender->Send(new BlobStorageMsg_SendBlobStatus( |
| 385 uuid, BlobStatus::ERR_FILE_WRITE_FAILED)); |
| 386 ReleaseBlobConsolidation(uuid); |
397 return; | 387 return; |
398 } | 388 } |
399 sender->Send(new BlobStorageMsg_CancelBuildingBlob(uuid, result.second)); | 389 sender->Send(new BlobStorageMsg_MemoryItemResponse(uuid, result.value())); |
400 ReleaseBlobConsolidation(uuid); | |
401 } | 390 } |
402 | 391 |
403 void BlobTransportController::StoreBlobDataForRequests( | 392 void BlobTransportController::StoreBlobDataForRequests( |
404 const std::string& uuid, | 393 const std::string& uuid, |
405 scoped_refptr<BlobConsolidation> consolidation, | 394 scoped_refptr<BlobConsolidation> consolidation, |
406 scoped_refptr<base::SingleThreadTaskRunner> main_runner) { | 395 scoped_refptr<base::SingleThreadTaskRunner> main_runner) { |
407 if (!main_thread_runner_.get()) { | 396 if (!main_thread_runner_.get()) { |
408 main_thread_runner_ = std::move(main_runner); | 397 main_thread_runner_ = std::move(main_runner); |
409 } | 398 } |
410 blob_storage_[uuid] = std::move(consolidation); | 399 blob_storage_[uuid] = std::move(consolidation); |
411 } | 400 } |
412 | 401 |
413 void BlobTransportController::ReleaseBlobConsolidation( | 402 void BlobTransportController::ReleaseBlobConsolidation( |
414 const std::string& uuid) { | 403 const std::string& uuid) { |
415 if (blob_storage_.erase(uuid)) { | 404 if (blob_storage_.erase(uuid)) { |
416 main_thread_runner_->PostTask(FROM_HERE, | 405 main_thread_runner_->PostTask(FROM_HERE, |
417 base::Bind(&DecChildProcessRefCount)); | 406 base::Bind(&DecChildProcessRefCount)); |
418 } | 407 } |
419 } | 408 } |
420 | 409 |
421 } // namespace content | 410 } // namespace content |
OLD | NEW |