summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorplundblad@chromium.org <plundblad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-11 06:24:37 +0000
committerplundblad@chromium.org <plundblad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-11 06:24:37 +0000
commit44beb038b6ed734bae5c4d8101847eb56dc498fe (patch)
tree8f880b1c3bfdeadd0dcbeb59c19b14ddb8de439c
parent21bc6c095c79723f1c2833678f506f19e9b32598 (diff)
downloadchromium_src-44beb038b6ed734bae5c4d8101847eb56dc498fe.zip
chromium_src-44beb038b6ed734bae5c4d8101847eb56dc498fe.tar.gz
chromium_src-44beb038b6ed734bae5c4d8101847eb56dc498fe.tar.bz2
Remove ChromeVox manifest file read from UI thread.
Fixes a DCHECK by making ChromeVox extension load asynchronous. This was broken in r272781 (https://codereview.chromium.org/295123002) when the manifest was moved from the .pak file to its own file on disk. BUG= Review URL: https://codereview.chromium.org/323623002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276277 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/accessibility/accessibility_manager.cc152
-rw-r--r--chrome/browser/chromeos/accessibility/accessibility_manager.h5
-rw-r--r--chrome/browser/extensions/component_loader.cc59
-rw-r--r--chrome/browser/extensions/component_loader.h19
4 files changed, 159 insertions, 76 deletions
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 91a66ae..66bfb63 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -12,6 +12,8 @@
#include "ash/shell.h"
#include "ash/sticky_keys/sticky_keys_controller.h"
#include "ash/system/tray/system_tray_notifier.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram.h"
@@ -157,50 +159,77 @@ class ContentScriptLoader {
std::queue<extensions::ExtensionResource> resources_;
};
-void LoadChromeVoxExtension(Profile* profile,
- RenderViewHost* render_view_host) {
+void InjectChromeVoxContentScript(
+ ExtensionService* extension_service,
+ int render_process_id,
+ int render_view_id,
+ const base::Closure& done_cb);
+
+void LoadChromeVoxExtension(
+ Profile* profile,
+ RenderViewHost* render_view_host,
+ base::Closure done_cb) {
ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile)->extension_service();
- std::string extension_id =
- extension_service->component_loader()->AddChromeVoxExtension();
if (render_view_host) {
- ExtensionService* extension_service =
- extensions::ExtensionSystem::Get(profile)->extension_service();
- const extensions::Extension* extension =
- extension_service->extensions()->GetByID(extension_id);
-
- // Set a flag to tell ChromeVox that it's just been enabled,
- // so that it won't interrupt our speech feedback enabled message.
- ExtensionMsg_ExecuteCode_Params params;
- params.request_id = 0;
- params.extension_id = extension->id();
- params.is_javascript = true;
- params.code = "window.INJECTED_AFTER_LOAD = true;";
- params.run_at = extensions::UserScript::DOCUMENT_IDLE;
- params.all_frames = true;
- params.match_about_blank = false;
- params.in_main_world = false;
- render_view_host->Send(new ExtensionMsg_ExecuteCode(
- render_view_host->GetRoutingID(), params));
-
- // Inject ChromeVox' content scripts.
- ContentScriptLoader* loader = new ContentScriptLoader(
- extension->id(), render_view_host->GetProcess()->GetID(),
- render_view_host->GetRoutingID());
-
- const extensions::UserScriptList& content_scripts =
- extensions::ContentScriptsInfo::GetContentScripts(extension);
- for (size_t i = 0; i < content_scripts.size(); i++) {
- const extensions::UserScript& script = content_scripts[i];
- for (size_t j = 0; j < script.js_scripts().size(); ++j) {
- const extensions::UserScript::File &file = script.js_scripts()[j];
- extensions::ExtensionResource resource = extension->GetResource(
- file.relative_path());
- loader->AppendScript(resource);
- }
+ // Wrap the passed in callback to inject the content script.
+ done_cb = base::Bind(
+ &InjectChromeVoxContentScript,
+ extension_service,
+ render_view_host->GetProcess()->GetID(),
+ render_view_host->GetRoutingID(),
+ done_cb);
+ }
+ extension_service->component_loader()->AddChromeVoxExtension(done_cb);
+}
+
+void InjectChromeVoxContentScript(
+ ExtensionService* extension_service,
+ int render_process_id,
+ int render_view_id,
+ const base::Closure& done_cb) {
+ // Make sure to always run |done_cb|. ChromeVox was loaded even if we end up
+ // not injecting into this particular render view.
+ base::ScopedClosureRunner done_runner(done_cb);
+ RenderViewHost* render_view_host =
+ RenderViewHost::FromID(render_process_id, render_view_id);
+ if (!render_view_host)
+ return;
+ const extensions::Extension* extension =
+ extension_service->extensions()->GetByID(
+ extension_misc::kChromeVoxExtensionId);
+
+ // Set a flag to tell ChromeVox that it's just been enabled,
+ // so that it won't interrupt our speech feedback enabled message.
+ ExtensionMsg_ExecuteCode_Params params;
+ params.request_id = 0;
+ params.extension_id = extension->id();
+ params.is_javascript = true;
+ params.code = "window.INJECTED_AFTER_LOAD = true;";
+ params.run_at = extensions::UserScript::DOCUMENT_IDLE;
+ params.all_frames = true;
+ params.match_about_blank = false;
+ params.in_main_world = false;
+ render_view_host->Send(new ExtensionMsg_ExecuteCode(
+ render_view_host->GetRoutingID(), params));
+
+ // Inject ChromeVox' content scripts.
+ ContentScriptLoader* loader = new ContentScriptLoader(
+ extension->id(), render_view_host->GetProcess()->GetID(),
+ render_view_host->GetRoutingID());
+
+ const extensions::UserScriptList& content_scripts =
+ extensions::ContentScriptsInfo::GetContentScripts(extension);
+ for (size_t i = 0; i < content_scripts.size(); i++) {
+ const extensions::UserScript& script = content_scripts[i];
+ for (size_t j = 0; j < script.js_scripts().size(); ++j) {
+ const extensions::UserScript::File &file = script.js_scripts()[j];
+ extensions::ExtensionResource resource = extension->GetResource(
+ file.relative_path());
+ loader->AppendScript(resource);
}
- loader->Run(); // It cleans itself up when done.
}
+ loader->Run(); // It cleans itself up when done.
}
void UnloadChromeVoxExtension(Profile* profile) {
@@ -523,19 +552,22 @@ void AccessibilityManager::UpdateSpokenFeedbackFromPref() {
}
void AccessibilityManager::LoadChromeVox() {
+ base::Closure done_cb = base::Bind(&AccessibilityManager::PostLoadChromeVox,
+ weak_ptr_factory_.GetWeakPtr(),
+ profile_);
ScreenLocker* screen_locker = ScreenLocker::default_screen_locker();
if (screen_locker && screen_locker->locked()) {
// If on the lock screen, loads ChromeVox only to the lock screen as for
// now. On unlock, it will be loaded to the user screen.
// (see. AccessibilityManager::Observe())
- LoadChromeVoxToLockScreen();
+ LoadChromeVoxToLockScreen(done_cb);
} else {
- LoadChromeVoxToUserScreen();
+ LoadChromeVoxToUserScreen(done_cb);
}
- PostLoadChromeVox(profile_);
}
-void AccessibilityManager::LoadChromeVoxToUserScreen() {
+void AccessibilityManager::LoadChromeVoxToUserScreen(
+ const base::Closure& done_cb) {
if (chrome_vox_loaded_on_user_screen_)
return;
@@ -556,12 +588,15 @@ void AccessibilityManager::LoadChromeVoxToUserScreen() {
chrome_vox_loaded_on_lock_screen_ = true;
}
- LoadChromeVoxExtension(profile_, login_web_ui ?
- login_web_ui->GetWebContents()->GetRenderViewHost() : NULL);
chrome_vox_loaded_on_user_screen_ = true;
+ LoadChromeVoxExtension(
+ profile_, login_web_ui ?
+ login_web_ui->GetWebContents()->GetRenderViewHost() : NULL,
+ done_cb);
}
-void AccessibilityManager::LoadChromeVoxToLockScreen() {
+void AccessibilityManager::LoadChromeVoxToLockScreen(
+ const base::Closure& done_cb) {
if (chrome_vox_loaded_on_lock_screen_)
return;
@@ -570,9 +605,11 @@ void AccessibilityManager::LoadChromeVoxToLockScreen() {
content::WebUI* lock_web_ui = screen_locker->GetAssociatedWebUI();
if (lock_web_ui) {
Profile* profile = Profile::FromWebUI(lock_web_ui);
- LoadChromeVoxExtension(profile,
- lock_web_ui->GetWebContents()->GetRenderViewHost());
chrome_vox_loaded_on_lock_screen_ = true;
+ LoadChromeVoxExtension(
+ profile,
+ lock_web_ui->GetWebContents()->GetRenderViewHost(),
+ done_cb);
}
}
}
@@ -925,7 +962,7 @@ base::TimeDelta AccessibilityManager::PlayShutdownSound() {
}
void AccessibilityManager::InjectChromeVox(RenderViewHost* render_view_host) {
- LoadChromeVoxExtension(profile_, render_view_host);
+ LoadChromeVoxExtension(profile_, render_view_host, base::Closure());
}
scoped_ptr<AccessibilityStatusSubscription>
@@ -1013,16 +1050,13 @@ void AccessibilityManager::Observe(
case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: {
bool is_screen_locked = *content::Details<bool>(details).ptr();
if (spoken_feedback_enabled_) {
- if (is_screen_locked) {
- LoadChromeVoxToLockScreen();
-
- // Status tray gets verbalized by user screen ChromeVox, so we need
- // this as well.
- LoadChromeVoxToUserScreen();
- } else {
- // If spoken feedback was enabled, also enable it on the user screen.
- LoadChromeVoxToUserScreen();
- }
+ if (is_screen_locked)
+ LoadChromeVoxToLockScreen(base::Closure());
+ // If spoken feedback was enabled, make sure it is also enabled on
+ // the user screen.
+ // The status tray gets verbalized by user screen ChromeVox, so we need
+ // to load it on the user screen even if the screen is locked.
+ LoadChromeVoxToUserScreen(base::Closure());
}
break;
}
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 91a4f4c..fa3f336 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -9,6 +9,7 @@
#include "ash/accessibility_delegate.h"
#include "ash/session/session_state_observer.h"
+#include "base/callback_forward.h"
#include "base/callback_list.h"
#include "base/memory/weak_ptr.h"
#include "base/prefs/pref_change_registrar.h"
@@ -195,8 +196,8 @@ class AccessibilityManager
private:
void LoadChromeVox();
- void LoadChromeVoxToUserScreen();
- void LoadChromeVoxToLockScreen();
+ void LoadChromeVoxToUserScreen(const base::Closure& done_cb);
+ void LoadChromeVoxToLockScreen(const base::Closure& done_cb);
void UnloadChromeVox();
void UnloadChromeVoxFromLockScreen();
void PostLoadChromeVox(Profile* profile);
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index cca90da..debe6cf 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -21,6 +21,7 @@
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/plugin_service.h"
@@ -57,6 +58,8 @@
#include "grit/chromium_strings.h"
#endif
+using content::BrowserThread;
+
namespace extensions {
namespace {
@@ -97,6 +100,19 @@ std::string GenerateId(const base::DictionaryValue* manifest,
return id;
}
+#if defined(OS_CHROMEOS)
+scoped_ptr<base::DictionaryValue>
+LoadManifestOnFileThread(
+ const base::FilePath& chromevox_path, const char* manifest_filename) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+ std::string error;
+ scoped_ptr<base::DictionaryValue> manifest(
+ file_util::LoadManifest(chromevox_path, manifest_filename, &error));
+ CHECK(manifest) << error;
+ return manifest.Pass();
+}
+#endif // defined(OS_CHROMEOS)
+
} // namespace
ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
@@ -117,7 +133,8 @@ ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
: profile_prefs_(profile_prefs),
local_state_(local_state),
browser_context_(browser_context),
- extension_service_(extension_service) {}
+ extension_service_(extension_service),
+ weak_factory_(this) {}
ComponentLoader::~ComponentLoader() {
ClearAllRegistered();
@@ -329,24 +346,38 @@ void ComponentLoader::AddNetworkSpeechSynthesisExtension() {
}
#if defined(OS_CHROMEOS)
-std::string ComponentLoader::AddChromeVoxExtension() {
- base::FilePath chromevox_path;
- PathService::Get(chrome::DIR_RESOURCES, &chromevox_path);
- chromevox_path =
- chromevox_path.Append(extension_misc::kChromeVoxExtensionPath);
+void ComponentLoader::AddChromeVoxExtension(
+ const base::Closure& done_cb) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ base::FilePath resources_path;
+ PathService::Get(chrome::DIR_RESOURCES, &resources_path);
+ base::FilePath chromevox_path =
+ resources_path.Append(extension_misc::kChromeVoxExtensionPath);
const CommandLine* command_line = CommandLine::ForCurrentProcess();
const char* manifest_filename =
command_line->HasSwitch(chromeos::switches::kGuestSession) ?
extension_misc::kChromeVoxGuestManifestFilename :
extension_misc::kChromeVoxManifestFilename;
-
- std::string error;
- scoped_ptr<base::DictionaryValue> manifest(
- file_util::LoadManifest(chromevox_path, manifest_filename, &error));
- CHECK(manifest) << error;
-
- return Add(manifest.release(), chromevox_path);
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&LoadManifestOnFileThread, chromevox_path, manifest_filename),
+ base::Bind(&ComponentLoader::AddChromeVoxExtensionWithManifest,
+ weak_factory_.GetWeakPtr(),
+ chromevox_path,
+ done_cb));
+}
+
+void ComponentLoader::AddChromeVoxExtensionWithManifest(
+ const base::FilePath& chromevox_path,
+ const base::Closure& done_cb,
+ scoped_ptr<base::DictionaryValue> manifest) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ std::string extension_id = Add(manifest.release(), chromevox_path);
+ CHECK_EQ(extension_misc::kChromeVoxExtensionId, extension_id);
+ if (!done_cb.is_null())
+ done_cb.Run();
}
std::string ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
@@ -543,7 +574,7 @@ void ComponentLoader::AddDefaultComponentExtensionsWithBackgroundPages(
// Load ChromeVox extension now if spoken feedback is enabled.
if (chromeos::AccessibilityManager::Get() &&
chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
- AddChromeVoxExtension();
+ AddChromeVoxExtension(base::Closure());
}
#endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 735184f..8e09727 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -8,8 +8,10 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
#include "base/values.h"
class ExtensionServiceInterface;
@@ -97,7 +99,10 @@ class ComponentLoader {
void Reload(const std::string& extension_id);
#if defined(OS_CHROMEOS)
- std::string AddChromeVoxExtension();
+ // Calls |done_cb|, if not a null callback, on success.
+ // NOTE: |done_cb| is not called if the component loader is shut down
+ // during loading.
+ void AddChromeVoxExtension(const base::Closure& done_cb);
std::string AddChromeOsSpeechSynthesisExtension();
#endif
@@ -146,6 +151,16 @@ class ComponentLoader {
// Enable HTML5 FileSystem for given component extension in Guest mode.
void EnableFileSystemInGuestMode(const std::string& id);
+#if defined(OS_CHROMEOS)
+ // Used as a reply callback when loading the ChromeVox extension.
+ // Called with a |chromevox_path| and parsed |manifest| and invokes
+ // |done_cb| after adding the extension.
+ void AddChromeVoxExtensionWithManifest(
+ const base::FilePath& chromevox_path,
+ const base::Closure& done_cb,
+ scoped_ptr<base::DictionaryValue> manifest);
+#endif
+
PrefService* profile_prefs_;
PrefService* local_state_;
content::BrowserContext* browser_context_;
@@ -156,6 +171,8 @@ class ComponentLoader {
typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
RegisteredComponentExtensions component_extensions_;
+ base::WeakPtrFactory<ComponentLoader> weak_factory_;
+
FRIEND_TEST_ALL_PREFIXES(TtsApiTest, NetworkSpeechEngine);
FRIEND_TEST_ALL_PREFIXES(TtsApiTest, NoNetworkSpeechEngineWhenOffline);