Commit b19fcfe2 authored by lazyboy's avatar lazyboy Committed by Commit bot

Remove some UI->FILE->UI thread hops in ExecuteCodeFunction.

There are 3 types of tasks in ExecuteCodeFunction that require FILE thread:
a) Reading the file content (for non-component extension files)
b) Retrieving the file GURL of the script file from base::FilePath
c) content l10n (if the script is CSS)

This CL does all of these in on UI->FILE hop and doesn't require
additional FILE thread hop.
Previously, the most common case, i.e. chrome.tabs.executeScript()
with {file:...}, would require UI->FILE->UI->FILE->UI. With this CL
this become UI->FILE->UI.

This CL accomplishes this with adding an optional callback to FileReader,
to specify additional tasks to be run on FILE thread.

So the thread hop changes are:
Component extension's executeScript() with file:... url would stay same.
*All* other means of executing script file:... url, e.g.
chrome.tabs.executeScript(,{file:..}) would require two (UI->FILE->UI) less
thread hops, whee!

BUG=622464
Test=None, internal only change.

Review-Url: https://codereview.chromium.org/2301713002
Cr-Commit-Position: refs/heads/master@{#419023}
parent 2db76b7d
...@@ -90,9 +90,11 @@ class ContentScriptLoader { ...@@ -90,9 +90,11 @@ class ContentScriptLoader {
extensions::ExtensionResource resource = resources_.front(); extensions::ExtensionResource resource = resources_.front();
resources_.pop(); resources_.pop();
scoped_refptr<FileReader> reader( scoped_refptr<FileReader> reader(new FileReader(
new FileReader(resource, base::Bind(&ContentScriptLoader::OnFileLoaded, resource,
base::Unretained(this)))); FileReader::OptionalFileThreadTaskCallback(), // null callback.
base::Bind(&ContentScriptLoader::OnFileLoaded,
base::Unretained(this))));
reader->Start(); reader->Start();
} }
......
...@@ -42,62 +42,49 @@ ExecuteCodeFunction::ExecuteCodeFunction() { ...@@ -42,62 +42,49 @@ ExecuteCodeFunction::ExecuteCodeFunction() {
ExecuteCodeFunction::~ExecuteCodeFunction() { ExecuteCodeFunction::~ExecuteCodeFunction() {
} }
void ExecuteCodeFunction::DidLoadFile(bool success, void ExecuteCodeFunction::GetFileURLAndMaybeLocalizeOnFileThread(
std::unique_ptr<std::string> data) { const std::string& extension_id,
if (!success || !details_->file) { const base::FilePath& extension_path,
DidLoadAndLocalizeFile(resource_.relative_path().AsUTF8Unsafe(), success, const std::string& extension_default_locale,
std::move(data)); bool might_require_localization,
std::string* data) {
DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
if (!might_require_localization)
return; return;
}
ScriptExecutor::ScriptType script_type = bool needs_message_substituion =
ShouldInsertCSS() ? ScriptExecutor::CSS : ScriptExecutor::JAVASCRIPT; data->find(extensions::MessageBundle::kMessageBegin) != std::string::npos;
if (!needs_message_substituion)
return;
std::string extension_id; std::unique_ptr<SubstitutionMap> localization_messages(
base::FilePath extension_path; file_util::LoadMessageBundleSubstitutionMap(extension_path, extension_id,
std::string extension_default_locale; extension_default_locale));
if (extension()) {
extension_id = extension()->id();
extension_path = extension()->path();
extension()->manifest()->GetString(manifest_keys::kDefaultLocale,
&extension_default_locale);
}
content::BrowserThread::PostTask( std::string error;
content::BrowserThread::FILE, FROM_HERE, MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
base::Bind(&ExecuteCodeFunction::GetFileURLAndLocalizeCSS, this, data, &error);
script_type, base::Passed(std::move(data)), extension_id,
extension_path, extension_default_locale));
} }
void ExecuteCodeFunction::GetFileURLAndLocalizeCSS( void ExecuteCodeFunction::GetFileURLAndLocalizeComponentResourceOnFileThread(
ScriptExecutor::ScriptType script_type,
std::unique_ptr<std::string> data, std::unique_ptr<std::string> data,
const std::string& extension_id, const std::string& extension_id,
const base::FilePath& extension_path, const base::FilePath& extension_path,
const std::string& extension_default_locale) { const std::string& extension_default_locale,
// Check if the file is CSS and needs localization. bool might_require_localization) {
if ((script_type == ScriptExecutor::CSS) && !extension_id.empty() && DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
(data->find(MessageBundle::kMessageBegin) != std::string::npos)) { GetFileURLAndMaybeLocalizeOnFileThread(
std::unique_ptr<SubstitutionMap> localization_messages( extension_id, extension_path, extension_default_locale,
file_util::LoadMessageBundleSubstitutionMap( might_require_localization, data.get());
extension_path, extension_id, extension_default_locale));
bool success = true;
// We need to do message replacement on the data, so it has to be mutable.
std::string error;
MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages,
data.get(), &error);
}
file_url_ = net::FilePathToFileURL(resource_.GetFilePath());
// Call back DidLoadAndLocalizeFile on the UI thread. The success parameter
// is always true, because if loading had failed, we wouldn't have had
// anything to localize.
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, content::BrowserThread::UI, FROM_HERE,
base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this, base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
resource_.relative_path().AsUTF8Unsafe(), true, resource_.relative_path().AsUTF8Unsafe(), success,
base::Passed(std::move(data)))); base::Passed(std::move(data))));
} }
...@@ -207,6 +194,15 @@ bool ExecuteCodeFunction::LoadFile(const std::string& file) { ...@@ -207,6 +194,15 @@ bool ExecuteCodeFunction::LoadFile(const std::string& file) {
return false; return false;
} }
const std::string& extension_id = extension()->id();
base::FilePath extension_path = extension()->path();
std::string extension_default_locale;
extension()->manifest()->GetString(manifest_keys::kDefaultLocale,
&extension_default_locale);
// TODO(lazyboy): |extension_id| should not be empty(), turn this into a
// DCHECK.
bool might_require_localization = ShouldInsertCSS() && !extension_id.empty();
int resource_id; int resource_id;
const ComponentExtensionResourceManager* const ComponentExtensionResourceManager*
component_extension_resource_manager = component_extension_resource_manager =
...@@ -219,11 +215,25 @@ bool ExecuteCodeFunction::LoadFile(const std::string& file) { ...@@ -219,11 +215,25 @@ bool ExecuteCodeFunction::LoadFile(const std::string& file) {
&resource_id)) { &resource_id)) {
base::StringPiece resource = base::StringPiece resource =
ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
DidLoadFile(true, base::WrapUnique( std::unique_ptr<std::string> data(
new std::string(resource.data(), resource.size()))); new std::string(resource.data(), resource.size()));
content::BrowserThread::PostTask(
content::BrowserThread::FILE, FROM_HERE,
base::Bind(&ExecuteCodeFunction::
GetFileURLAndLocalizeComponentResourceOnFileThread,
this, base::Passed(std::move(data)), extension_id,
extension_path, extension_default_locale,
might_require_localization));
} else { } else {
FileReader::OptionalFileThreadTaskCallback get_file_and_l10n_callback =
base::Bind(&ExecuteCodeFunction::GetFileURLAndMaybeLocalizeOnFileThread,
this, extension_id, extension_path, extension_default_locale,
might_require_localization);
scoped_refptr<FileReader> file_reader(new FileReader( scoped_refptr<FileReader> file_reader(new FileReader(
resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this))); resource_, get_file_and_l10n_callback,
base::Bind(&ExecuteCodeFunction::DidLoadAndLocalizeFile, this,
resource_.relative_path().AsUTF8Unsafe())));
file_reader->Start(); file_reader->Start();
} }
......
...@@ -52,17 +52,27 @@ class ExecuteCodeFunction : public AsyncExtensionFunction { ...@@ -52,17 +52,27 @@ class ExecuteCodeFunction : public AsyncExtensionFunction {
std::unique_ptr<api::extension_types::InjectDetails> details_; std::unique_ptr<api::extension_types::InjectDetails> details_;
private: private:
// Called when contents from the file whose path is specified in JSON // Retrieves the file url for the given |extension_path| and optionally
// arguments has been loaded. // localizes |data|.
void DidLoadFile(bool success, std::unique_ptr<std::string> data); // Localization depends on whether |might_require_localization| was specified.
// Only CSS file content needs to be localized.
// Runs on FILE thread. Loads message bundles for the extension and void GetFileURLAndMaybeLocalizeOnFileThread(
// localizes the CSS data. Calls back DidLoadAndLocalizeFile on the UI thread. const std::string& extension_id,
void GetFileURLAndLocalizeCSS(ScriptExecutor::ScriptType script_type, const base::FilePath& extension_path,
std::unique_ptr<std::string> data, const std::string& extension_default_locale,
const std::string& extension_id, bool might_require_localization,
const base::FilePath& extension_path, std::string* data);
const std::string& extension_default_locale);
// Retrieves the file url for the given |extension_path| and optionally
// localizes |data|.
// Similar to GetFileURLAndMaybeLocalizeOnFileThread, but only applies to
// component extension resource.
void GetFileURLAndLocalizeComponentResourceOnFileThread(
std::unique_ptr<std::string> data,
const std::string& extension_id,
const base::FilePath& extension_path,
const std::string& extension_default_locale,
bool might_require_localization);
// Run in UI thread. Code string contains the code to be executed. Returns // Run in UI thread. Code string contains the code to be executed. Returns
// true on success. If true is returned, this does an AddRef. // true on success. If true is returned, this does an AddRef.
......
...@@ -5,16 +5,20 @@ ...@@ -5,16 +5,20 @@
#include "extensions/browser/file_reader.h" #include "extensions/browser/file_reader.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
using content::BrowserThread; using content::BrowserThread;
FileReader::FileReader(const extensions::ExtensionResource& resource, FileReader::FileReader(
const Callback& callback) const extensions::ExtensionResource& resource,
const OptionalFileThreadTaskCallback& optional_file_thread_task_callback,
const DoneCallback& done_callback)
: resource_(resource), : resource_(resource),
callback_(callback), optional_file_thread_task_callback_(optional_file_thread_task_callback),
done_callback_(done_callback),
origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
void FileReader::Start() { void FileReader::Start() {
...@@ -28,6 +32,17 @@ FileReader::~FileReader() {} ...@@ -28,6 +32,17 @@ FileReader::~FileReader() {}
void FileReader::ReadFileOnBackgroundThread() { void FileReader::ReadFileOnBackgroundThread() {
std::unique_ptr<std::string> data(new std::string()); std::unique_ptr<std::string> data(new std::string());
bool success = base::ReadFileToString(resource_.GetFilePath(), data.get()); bool success = base::ReadFileToString(resource_.GetFilePath(), data.get());
if (!optional_file_thread_task_callback_.is_null()) {
if (success) {
base::ResetAndReturn(&optional_file_thread_task_callback_)
.Run(data.get());
} else {
optional_file_thread_task_callback_.Reset();
}
}
origin_task_runner_->PostTask( origin_task_runner_->PostTask(
FROM_HERE, base::Bind(callback_, success, base::Passed(std::move(data)))); FROM_HERE, base::Bind(base::ResetAndReturn(&done_callback_), success,
base::Passed(std::move(data))));
} }
...@@ -19,10 +19,15 @@ ...@@ -19,10 +19,15 @@
class FileReader : public base::RefCountedThreadSafe<FileReader> { class FileReader : public base::RefCountedThreadSafe<FileReader> {
public: public:
// Reports success or failure and the data of the file upon success. // Reports success or failure and the data of the file upon success.
typedef base::Callback<void(bool, std::unique_ptr<std::string>)> Callback; using DoneCallback = base::Callback<void(bool, std::unique_ptr<std::string>)>;
// Lets the caller accomplish tasks on the file data, after the file content
// has been read.
// If the file reading doesn't succeed, this will be ignored.
using OptionalFileThreadTaskCallback = base::Callback<void(std::string*)>;
FileReader(const extensions::ExtensionResource& resource, FileReader(const extensions::ExtensionResource& resource,
const Callback& callback); const OptionalFileThreadTaskCallback& file_thread_task_callback,
const DoneCallback& done_callback);
// Called to start reading the file on a background thread. Upon completion, // Called to start reading the file on a background thread. Upon completion,
// the callback will be notified of the results. // the callback will be notified of the results.
...@@ -36,7 +41,8 @@ class FileReader : public base::RefCountedThreadSafe<FileReader> { ...@@ -36,7 +41,8 @@ class FileReader : public base::RefCountedThreadSafe<FileReader> {
void ReadFileOnBackgroundThread(); void ReadFileOnBackgroundThread();
extensions::ExtensionResource resource_; extensions::ExtensionResource resource_;
Callback callback_; OptionalFileThreadTaskCallback optional_file_thread_task_callback_;
DoneCallback done_callback_;
const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
}; };
......
...@@ -35,7 +35,7 @@ class Receiver { ...@@ -35,7 +35,7 @@ class Receiver {
Receiver() : succeeded_(false) { Receiver() : succeeded_(false) {
} }
FileReader::Callback NewCallback() { FileReader::DoneCallback NewCallback() {
return base::Bind(&Receiver::DidReadFile, base::Unretained(this)); return base::Bind(&Receiver::DidReadFile, base::Unretained(this));
} }
...@@ -67,7 +67,8 @@ void RunBasicTest(const char* filename) { ...@@ -67,7 +67,8 @@ void RunBasicTest(const char* filename) {
Receiver receiver; Receiver receiver;
scoped_refptr<FileReader> file_reader( scoped_refptr<FileReader> file_reader(
new FileReader(resource, receiver.NewCallback())); new FileReader(resource, FileReader::OptionalFileThreadTaskCallback(),
receiver.NewCallback()));
file_reader->Start(); file_reader->Start();
base::RunLoop().Run(); base::RunLoop().Run();
...@@ -95,7 +96,8 @@ TEST_F(FileReaderTest, NonExistantFile) { ...@@ -95,7 +96,8 @@ TEST_F(FileReaderTest, NonExistantFile) {
Receiver receiver; Receiver receiver;
scoped_refptr<FileReader> file_reader( scoped_refptr<FileReader> file_reader(
new FileReader(resource, receiver.NewCallback())); new FileReader(resource, FileReader::OptionalFileThreadTaskCallback(),
receiver.NewCallback()));
file_reader->Start(); file_reader->Start();
base::RunLoop().Run(); base::RunLoop().Run();
......
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