Commit 682c1dbc authored by Marijn Kruisselbrink's avatar Marijn Kruisselbrink Committed by Commit Bot

[NativeFS] Decouple remaining IO thread bound work from the rest of the code.

This refactors the blob interactions to either be behind a PostTask to the IO
thread, or in the case of writes eliminates the direct interaction with the blob
system entirely by reading the blob through its mojo interface instead.

Also migrates one remaining FileSystemContext call to be behind a PostTask to
the IO thread.

This, combined with a previous CL, eliminates all code that required running on
the IO thread, paving the way for moving most of the native file system API
implementation to the UI thread.

Bug: 1011534
Change-Id: I8ef3ce97a77efb42bd12b020e98d7c1430ca3292
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1845914Reviewed-by: default avatarOlivier Yiptong <oyiptong@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705698}
parent 98aac84d
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
#include "base/guid.h" #include "base/guid.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "content/browser/native_file_system/native_file_system_error.h" #include "content/browser/native_file_system/native_file_system_error.h"
#include "content/public/browser/browser_task_traits.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/mime_util.h" #include "net/base/mime_util.h"
#include "storage/browser/blob/blob_data_builder.h" #include "storage/browser/blob/blob_data_builder.h"
...@@ -97,6 +99,42 @@ void NativeFileSystemFileHandleImpl::Transfer( ...@@ -97,6 +99,42 @@ void NativeFileSystemFileHandleImpl::Transfer(
manager()->CreateTransferToken(*this, std::move(token)); manager()->CreateTransferToken(*this, std::move(token));
} }
namespace {
void CreateBlobOnIOThread(
scoped_refptr<storage::FileSystemContext> file_system_context,
const scoped_refptr<ChromeBlobStorageContext>& blob_context,
mojo::PendingReceiver<blink::mojom::Blob> blob_receiver,
const storage::FileSystemURL& url,
const std::string& blob_uuid,
const std::string& content_type,
const base::File::Info& info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto blob_builder = std::make_unique<storage::BlobDataBuilder>(blob_uuid);
// Only append if the file has data.
if (info.size > 0) {
// Use AppendFileSystemFile here, since we're streaming the file directly
// from the file system backend, and the file thus might not actually be
// backed by a file on disk.
blob_builder->AppendFileSystemFile(url.ToGURL(), 0, info.size,
info.last_modified,
std::move(file_system_context));
}
blob_builder->set_content_type(content_type);
std::unique_ptr<BlobDataHandle> blob_handle =
blob_context->context()->AddFinishedBlob(std::move(blob_builder));
// Since the blob we're creating doesn't depend on other blobs, and doesn't
// require blob memory/disk quota, creating the blob can't fail.
DCHECK(!blob_handle->IsBroken());
BlobImpl::Create(std::move(blob_handle), std::move(blob_receiver));
}
} // namespace
void NativeFileSystemFileHandleImpl::DidGetMetaDataForBlob( void NativeFileSystemFileHandleImpl::DidGetMetaDataForBlob(
AsBlobCallback callback, AsBlobCallback callback,
base::File::Error result, base::File::Error result,
...@@ -110,17 +148,7 @@ void NativeFileSystemFileHandleImpl::DidGetMetaDataForBlob( ...@@ -110,17 +148,7 @@ void NativeFileSystemFileHandleImpl::DidGetMetaDataForBlob(
} }
std::string uuid = base::GenerateGUID(); std::string uuid = base::GenerateGUID();
auto blob_builder = std::make_unique<storage::BlobDataBuilder>(uuid); std::string content_type;
// Only append if the file has data.
if (info.size > 0) {
// Use AppendFileSystemFile here, since we're streaming the file directly
// from the file system backend, and the file thus might not actually be
// backed by a file on disk.
blob_builder->AppendFileSystemFile(url().ToGURL(), 0, info.size,
info.last_modified,
file_system_context());
}
base::FilePath::StringType extension = url().path().Extension(); base::FilePath::StringType extension = url().path().Extension();
if (!extension.empty()) { if (!extension.empty()) {
...@@ -130,28 +158,27 @@ void NativeFileSystemFileHandleImpl::DidGetMetaDataForBlob( ...@@ -130,28 +158,27 @@ void NativeFileSystemFileHandleImpl::DidGetMetaDataForBlob(
// however that method can potentially block and thus can't be called from // however that method can potentially block and thus can't be called from
// the IO thread. // the IO thread.
if (net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type)) if (net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type))
blob_builder->set_content_type(mime_type); content_type = std::move(mime_type);
}
std::unique_ptr<BlobDataHandle> blob_handle =
blob_context()->AddFinishedBlob(std::move(blob_builder));
if (blob_handle->IsBroken()) {
std::move(callback).Run(
native_file_system_error::FromStatus(
NativeFileSystemStatus::kOperationFailed, "Failed to create blob."),
nullptr);
return;
} }
// TODO(https://crbug.com/962306): Consider some kind of fallback type when
// the above mime type detection fails.
std::string content_type = blob_handle->content_type();
mojo::PendingRemote<blink::mojom::Blob> blob_remote; mojo::PendingRemote<blink::mojom::Blob> blob_remote;
BlobImpl::Create(std::move(blob_handle), mojo::PendingReceiver<blink::mojom::Blob> blob_receiver =
blob_remote.InitWithNewPipeAndPassReceiver()); blob_remote.InitWithNewPipeAndPassReceiver();
std::move(callback).Run( std::move(callback).Run(
native_file_system_error::Ok(), native_file_system_error::Ok(),
blink::mojom::SerializedBlob::New(uuid, content_type, info.size, blink::mojom::SerializedBlob::New(uuid, content_type, info.size,
std::move(blob_remote))); std::move(blob_remote)));
base::PostTask(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&CreateBlobOnIOThread,
base::WrapRefCounted(file_system_context()),
base::WrapRefCounted(manager()->blob_context()),
std::move(blob_receiver), url(), std::move(uuid),
std::move(content_type), info));
} }
void NativeFileSystemFileHandleImpl::CreateFileWriterImpl( void NativeFileSystemFileHandleImpl::CreateFileWriterImpl(
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "crypto/secure_hash.h" #include "crypto/secure_hash.h"
#include "storage/browser/blob/blob_storage_context.h" #include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/fileapi/file_system_operation_runner.h" #include "storage/browser/fileapi/file_system_operation_runner.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h" #include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom.h" #include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom.h"
...@@ -193,32 +194,31 @@ void NativeFileSystemFileWriterImpl::WriteImpl( ...@@ -193,32 +194,31 @@ void NativeFileSystemFileWriterImpl::WriteImpl(
return; return;
} }
blob_context()->GetBlobDataFromBlobRemote( MojoCreateDataPipeOptions options;
std::move(data), options.struct_size = sizeof(MojoCreateDataPipeOptions);
base::BindOnce(&NativeFileSystemFileWriterImpl::DoWriteBlob, options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
weak_factory_.GetWeakPtr(), std::move(callback), offset)); options.element_num_bytes = 1;
} options.capacity_num_bytes =
blink::BlobUtils::GetDataPipeCapacity(blink::BlobUtils::kUnknownSize);
void NativeFileSystemFileWriterImpl::DoWriteBlob(
WriteCallback callback, mojo::ScopedDataPipeProducerHandle producer_handle;
uint64_t position, mojo::ScopedDataPipeConsumerHandle consumer_handle;
std::unique_ptr<BlobDataHandle> blob) { MojoResult rv =
DCHECK_CURRENTLY_ON(BrowserThread::IO); mojo::CreateDataPipe(&options, &producer_handle, &consumer_handle);
if (rv != MOJO_RESULT_OK) {
if (!blob) {
std::move(callback).Run( std::move(callback).Run(
native_file_system_error::FromStatus( native_file_system_error::FromStatus(
NativeFileSystemStatus::kInvalidArgument, "Blob does not exist"), NativeFileSystemStatus::kOperationFailed,
"Internal read error: failed to create mojo data pipe."),
/*bytes_written=*/0); /*bytes_written=*/0);
return; return;
} }
DoFileSystemOperation( // TODO(mek): We can do this transformation from Blob to DataPipe in the
FROM_HERE, &FileSystemOperationRunner::Write, // renderer, and simplify the mojom exposed interface.
base::BindRepeating(&NativeFileSystemFileWriterImpl::DidWrite, mojo::Remote<blink::mojom::Blob> blob(std::move(data));
weak_factory_.GetWeakPtr(), blob->ReadAll(std::move(producer_handle), mojo::NullRemote());
base::Owned(new WriteState{std::move(callback)})), WriteStreamImpl(offset, std::move(consumer_handle), std::move(callback));
swap_url(), std::move(blob), position);
} }
void NativeFileSystemFileWriterImpl::WriteStreamImpl( void NativeFileSystemFileWriterImpl::WriteStreamImpl(
......
...@@ -76,9 +76,6 @@ class CONTENT_EXPORT NativeFileSystemFileWriterImpl ...@@ -76,9 +76,6 @@ class CONTENT_EXPORT NativeFileSystemFileWriterImpl
void WriteImpl(uint64_t offset, void WriteImpl(uint64_t offset,
mojo::PendingRemote<blink::mojom::Blob> data, mojo::PendingRemote<blink::mojom::Blob> data,
WriteCallback callback); WriteCallback callback);
void DoWriteBlob(WriteCallback callback,
uint64_t position,
std::unique_ptr<storage::BlobDataHandle> blob);
void WriteStreamImpl(uint64_t offset, void WriteStreamImpl(uint64_t offset,
mojo::ScopedDataPipeConsumerHandle stream, mojo::ScopedDataPipeConsumerHandle stream,
WriteStreamCallback callback); WriteStreamCallback callback);
......
...@@ -280,13 +280,17 @@ INSTANTIATE_TEST_SUITE_P(NativeFileSystemFileWriterImplTest, ...@@ -280,13 +280,17 @@ INSTANTIATE_TEST_SUITE_P(NativeFileSystemFileWriterImplTest,
::testing::Bool()); ::testing::Bool());
TEST_F(NativeFileSystemFileWriterImplTest, WriteInvalidBlob) { TEST_F(NativeFileSystemFileWriterImplTest, WriteInvalidBlob) {
// This test primarily verifies behavior of the browser process in the
// presence of a compromised renderer process. The situation this tests for
// normally can't occur. As such it doesn't really matter what status the
// write operation returns, the important part is that nothing crashes.
mojo::PendingRemote<blink::mojom::Blob> blob; mojo::PendingRemote<blink::mojom::Blob> blob;
ignore_result(blob.InitWithNewPipeAndPassReceiver()); ignore_result(blob.InitWithNewPipeAndPassReceiver());
uint64_t bytes_written; uint64_t bytes_written;
NativeFileSystemStatus result = NativeFileSystemStatus result =
WriteBlobSync(0, std::move(blob), &bytes_written); WriteBlobSync(0, std::move(blob), &bytes_written);
EXPECT_EQ(result, NativeFileSystemStatus::kInvalidArgument);
EXPECT_EQ(bytes_written, 0u); EXPECT_EQ(bytes_written, 0u);
result = CloseSync(); result = CloseSync();
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
namespace storage { namespace storage {
class FileSystemContext; class FileSystemContext;
class FileSystemOperationRunner; class FileSystemOperationRunner;
class BlobStorageContext;
} // namespace storage } // namespace storage
namespace content { namespace content {
...@@ -83,9 +82,6 @@ class CONTENT_EXPORT NativeFileSystemHandleBase ...@@ -83,9 +82,6 @@ class CONTENT_EXPORT NativeFileSystemHandleBase
storage::FileSystemContext* file_system_context() { storage::FileSystemContext* file_system_context() {
return manager()->context(); return manager()->context();
} }
storage::BlobStorageContext* blob_context() {
return manager()->blob_context();
}
virtual base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() = 0; virtual base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() = 0;
......
...@@ -37,6 +37,7 @@ using blink::mojom::NativeFileSystemStatus; ...@@ -37,6 +37,7 @@ using blink::mojom::NativeFileSystemStatus;
using PermissionStatus = NativeFileSystemPermissionGrant::PermissionStatus; using PermissionStatus = NativeFileSystemPermissionGrant::PermissionStatus;
using SensitiveDirectoryResult = using SensitiveDirectoryResult =
NativeFileSystemPermissionContext::SensitiveDirectoryResult; NativeFileSystemPermissionContext::SensitiveDirectoryResult;
using storage::FileSystemContext;
namespace { namespace {
...@@ -182,14 +183,29 @@ void NativeFileSystemManagerImpl::BindReceiverFromUIThread( ...@@ -182,14 +183,29 @@ void NativeFileSystemManagerImpl::BindReceiverFromUIThread(
void NativeFileSystemManagerImpl::GetSandboxedFileSystem( void NativeFileSystemManagerImpl::GetSandboxedFileSystem(
GetSandboxedFileSystemCallback callback) { GetSandboxedFileSystemCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
url::Origin origin = receivers_.current_context().origin;
auto response_callback = base::BindOnce(
context()->OpenFileSystem( [](base::WeakPtr<NativeFileSystemManagerImpl> manager,
origin.GetURL(), storage::kFileSystemTypeTemporary, const BindingContext& binding_context,
storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, GetSandboxedFileSystemCallback callback,
base::BindOnce(&NativeFileSystemManagerImpl::DidOpenSandboxedFileSystem, scoped_refptr<base::SequencedTaskRunner> task_runner, const GURL& root,
weak_factory_.GetWeakPtr(), receivers_.current_context(), const std::string& fs_name, base::File::Error result) {
std::move(callback))); task_runner->PostTask(
FROM_HERE,
base::BindOnce(
&NativeFileSystemManagerImpl::DidOpenSandboxedFileSystem,
std::move(manager), binding_context, std::move(callback), root,
fs_name, result));
},
weak_factory_.GetWeakPtr(), receivers_.current_context(),
std::move(callback), base::SequencedTaskRunnerHandle::Get());
GURL origin = receivers_.current_context().origin.GetURL();
base::PostTask(FROM_HERE, {BrowserThread::IO},
base::BindOnce(&FileSystemContext::OpenFileSystem, context(),
origin, storage::kFileSystemTypeTemporary,
storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
std::move(response_callback)));
} }
void NativeFileSystemManagerImpl::ChooseEntries( void NativeFileSystemManagerImpl::ChooseEntries(
......
...@@ -158,9 +158,7 @@ class CONTENT_EXPORT NativeFileSystemManagerImpl ...@@ -158,9 +158,7 @@ class CONTENT_EXPORT NativeFileSystemManagerImpl
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
return context_.get(); return context_.get();
} }
storage::BlobStorageContext* blob_context() { ChromeBlobStorageContext* blob_context() { return blob_context_.get(); }
return blob_context_->context();
}
const base::SequenceBound<storage::FileSystemOperationRunner>& const base::SequenceBound<storage::FileSystemOperationRunner>&
operation_runner(); operation_runner();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment