Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Unified Diff: chrome/renderer/extensions/dispatcher.cc

Issue 11571014: Lazy load chrome.* APIs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressed comments Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/extensions/dispatcher.cc
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index 94a90d6dd15e027f56171962a0c3e7041b9f7f32..7f3e6b7bf79794cb29022ca0066b7185951a2a67 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -8,12 +8,14 @@
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_piece.h"
+#include "base/string_split.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/api/extension_api.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
+#include "chrome/common/extensions/features/feature.h"
#include "chrome/common/extensions/manifest.h"
#include "chrome/common/extensions/permissions/permission_set.h"
#include "chrome/common/url_constants.h"
@@ -23,6 +25,7 @@
#include "chrome/renderer/extensions/app_bindings.h"
#include "chrome/renderer/extensions/app_runtime_custom_bindings.h"
#include "chrome/renderer/extensions/app_window_custom_bindings.h"
+#include "chrome/renderer/extensions/binding_generating_native_handler.h"
#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "chrome/renderer/extensions/chrome_v8_extension.h"
#include "chrome/renderer/extensions/content_watcher.h"
@@ -38,7 +41,7 @@
#include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
#include "chrome/renderer/extensions/miscellaneous_bindings.h"
#include "chrome/renderer/extensions/module_system.h"
-#include "chrome/renderer/extensions/native_handler.h"
+#include "chrome/renderer/extensions/object_backed_native_handler.h"
#include "chrome/renderer/extensions/page_actions_custom_bindings.h"
#include "chrome/renderer/extensions/page_capture_custom_bindings.h"
#include "chrome/renderer/extensions/request_sender.h"
@@ -89,10 +92,69 @@ static const char kEventDispatchFunction[] = "Event.dispatchEvent";
static const char kOnUnloadEvent[] = "runtime.onSuspend";
static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
-class ChromeHiddenNativeHandler : public NativeHandler {
+static v8::Handle<v8::Object> GetOrCreateChrome(
+ v8::Handle<v8::Context> context) {
+ v8::Handle<v8::String> chrome_string(v8::String::New("chrome"));
+ v8::Handle<v8::Object> global(context->Global());
+ v8::Handle<v8::Value> chrome(global->Get(chrome_string));
+ if (chrome.IsEmpty() || chrome->IsUndefined()) {
+ v8::Handle<v8::Object> chrome_object(v8::Object::New());
+ global->Set(chrome_string, chrome_object);
+ return chrome_object;
+ }
+ CHECK(chrome->IsObject());
+ return chrome->ToObject();
+}
+
+class SchemaRegistryNativeHandler : public ObjectBackedNativeHandler {
+ public:
+ SchemaRegistryNativeHandler(V8SchemaRegistry* registry, v8::Isolate* isolate)
+ : ObjectBackedNativeHandler(isolate),
+ registry_(registry) {
+ RouteFunction("GetSchema",
+ base::Bind(&SchemaRegistryNativeHandler::GetSchema,
+ base::Unretained(this)));
+ }
+
+ private:
+ v8::Handle<v8::Value> GetSchema(const v8::Arguments& args) {
+ return registry_->GetSchema(*v8::String::AsciiValue(args[0]));
+ }
+
+ V8SchemaRegistry* registry_;
+};
+
+class V8ContextNativeHandler : public ObjectBackedNativeHandler {
+ public:
+ V8ContextNativeHandler(ChromeV8Context* context, v8::Isolate* isolate)
+ : ObjectBackedNativeHandler(isolate),
+ context_(context) {
+ RouteFunction("GetAvailability",
+ base::Bind(&V8ContextNativeHandler::GetAvailability,
+ base::Unretained(this)));
+ }
+
+ private:
+ v8::Handle<v8::Value> GetAvailability(const v8::Arguments& args) {
+ CHECK_EQ(args.Length(), 1);
+ std::string api_name = *v8::String::AsciiValue(args[0]->ToString());
+ Feature::Availability availability = context_->GetAvailability(api_name);
+
+ v8::Handle<v8::Object> ret = v8::Object::New();
+ ret->Set(v8::String::New("is_available"),
+ v8::Boolean::New(availability.is_available()));
+ ret->Set(v8::String::New("message"),
+ v8::String::New(availability.message().c_str()));
+ return ret;
+ }
+
+ ChromeV8Context* context_;
+};
+
+class ChromeHiddenNativeHandler : public ObjectBackedNativeHandler {
public:
explicit ChromeHiddenNativeHandler(v8::Isolate* isolate)
- : NativeHandler(isolate) {
+ : ObjectBackedNativeHandler(isolate) {
RouteFunction("GetChromeHidden",
base::Bind(&ChromeHiddenNativeHandler::GetChromeHidden,
base::Unretained(this)));
@@ -103,10 +165,23 @@ class ChromeHiddenNativeHandler : public NativeHandler {
}
};
-class PrintNativeHandler : public NativeHandler {
+class ChromeNativeHandler : public ObjectBackedNativeHandler {
+ public:
+ explicit ChromeNativeHandler(v8::Isolate* isolate)
+ : ObjectBackedNativeHandler(isolate) {
+ RouteFunction("GetChrome",
+ base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this)));
+ }
+
+ v8::Handle<v8::Value> GetChrome(const v8::Arguments& args) {
+ return GetOrCreateChrome(v8::Context::GetCurrent());
+ }
+};
+
+class PrintNativeHandler : public ObjectBackedNativeHandler {
public:
explicit PrintNativeHandler(v8::Isolate* isolate)
- : NativeHandler(isolate) {
+ : ObjectBackedNativeHandler(isolate) {
RouteFunction("Print",
base::Bind(&PrintNativeHandler::Print,
base::Unretained(this)));
@@ -238,13 +313,15 @@ class ProcessInfoNativeHandler : public ChromeV8Extension {
bool send_request_disabled_;
};
-class LoggingNativeHandler : public NativeHandler {
+class LoggingNativeHandler : public ObjectBackedNativeHandler {
public:
- explicit LoggingNativeHandler(v8::Isolate* isolate)
- : NativeHandler(isolate) {
+ explicit LoggingNativeHandler(v8::Isolate* isolate, ChromeV8Context* context)
+ : ObjectBackedNativeHandler(isolate),
+ context_(context) {
RouteFunction("DCHECK",
- base::Bind(&LoggingNativeHandler::Dcheck,
- base::Unretained(this)));
+ base::Bind(&LoggingNativeHandler::Dcheck, base::Unretained(this)));
+ RouteFunction("Error",
+ base::Bind(&LoggingNativeHandler::Error, base::Unretained(this)));
}
v8::Handle<v8::Value> Dcheck(const v8::Arguments& args) {
@@ -274,6 +351,15 @@ class LoggingNativeHandler : public NativeHandler {
return v8::Undefined();
}
+ v8::Handle<v8::Value> Error(const v8::Arguments& args) {
+ CHECK_EQ(args.Length(), 1);
+ std::string message = *v8::String::AsciiValue(args[0]->ToString());
+ ExtensionHelper::Get(context_->GetRenderView())->AddMessageToRootConsole(
+ content::CONSOLE_MESSAGE_LEVEL_ERROR,
+ message);
+ return v8::Undefined();
not at google - send to devlin 2013/02/15 22:26:17 I just tested, and console.error works from the on
cduvall 2013/02/19 23:58:49 Hmm I don't know why I thought it didn't, I though
+ }
+
private:
std::string ToStringOrDefault(const v8::Handle<v8::String>& v8_string,
const std::string& dflt) {
@@ -282,6 +368,8 @@ class LoggingNativeHandler : public NativeHandler {
std::string ascii_value = *v8::String::AsciiValue(v8_string);
return ascii_value.empty() ? dflt : ascii_value;
}
+
+ ChromeV8Context* context_;
};
void InstallAppBindings(ModuleSystem* module_system,
@@ -302,20 +390,6 @@ void InstallWebstoreBindings(ModuleSystem* module_system,
"chromeHiddenWebstore");
}
-static v8::Handle<v8::Object> GetOrCreateChrome(
- v8::Handle<v8::Context> context) {
- v8::Handle<v8::String> chrome_string(v8::String::New("chrome"));
- v8::Handle<v8::Object> global(context->Global());
- v8::Handle<v8::Value> chrome(global->Get(chrome_string));
- if (chrome.IsEmpty() || chrome->IsUndefined()) {
- v8::Handle<v8::Object> chrome_object(v8::Object::New());
- global->Set(chrome_string, chrome_object);
- return chrome_object;
- }
- CHECK(chrome->IsObject());
- return chrome->ToObject();
-}
-
} // namespace
Dispatcher::Dispatcher()
@@ -560,6 +634,67 @@ bool Dispatcher::AllowScriptExtension(WebFrame* frame,
return true;
}
+v8::Handle<v8::Object> Dispatcher::GetOrCreateObject(
+ v8::Handle<v8::Object> object,
+ const std::string& field) {
+ v8::Handle<v8::String> key = v8::String::New(field.c_str());
+ // This little dance is for APIs that may be unavailable but have available
+ // children. For example, chrome.app can be unavailable, while
+ // chrome.app.runtime is available. The lazy getter for chrome.app must be
+ // deleted, so that there isn't an error when accessing chrome.app.runtime.
+ if (object->Has(key)) {
+ v8::Handle<v8::Object> existing =
+ v8::Handle<v8::Object>::Cast(object->Get(key));
+ if (!existing.IsEmpty() && !existing->IsUndefined())
+ return existing;
+ else
+ object->Delete(key);
+ }
+
+ v8::Handle<v8::Object> new_object = v8::Object::New();
+ object->Set(key, new_object);
+ return new_object;
+}
+
+void Dispatcher::RegisterSchemaGeneratedBindings(
+ ModuleSystem* module_system,
+ ChromeV8Context* context,
+ v8::Handle<v8::Context> v8_context) {
+ std::set<std::string> apis =
+ ExtensionAPI::GetSharedInstance()->GetAllAPINames();
+ for (std::set<std::string>::iterator it = apis.begin();
+ it != apis.end(); ++it) {
+ const std::string& api_name = *it;
+
+ std::vector<std::string> split;
+ base::SplitString(api_name, '.', &split);
+
+ v8::Handle<v8::Object> bind_object = GetOrCreateChrome(v8_context);
+ for (size_t i = 0; i < split.size() - 1; ++i)
+ bind_object = GetOrCreateObject(bind_object, split[i]);
+
+ if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
+ InstallBindings(module_system, v8_context, api_name);
+ } else if (!source_map_.Contains(api_name)) {
+ module_system->RegisterNativeHandler(
+ api_name,
+ scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
+ module_system,
+ api_name,
+ "binding")));
+ module_system->SetNativeLazyField(bind_object,
+ split.back(),
+ api_name,
+ "binding");
+ } else {
+ module_system->SetLazyField(bind_object,
+ split.back(),
+ api_name,
+ "binding");
+ }
+ }
+}
+
void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
ChromeV8Context* context) {
module_system->RegisterNativeHandler("event_bindings",
@@ -624,10 +759,8 @@ void Dispatcher::PopulateSourceMap() {
source_map_.RegisterSource("event_bindings", IDR_EVENT_BINDINGS_JS);
source_map_.RegisterSource("miscellaneous_bindings",
IDR_MISCELLANEOUS_BINDINGS_JS);
- source_map_.RegisterSource("schema_generated_bindings",
- IDR_SCHEMA_GENERATED_BINDINGS_JS);
source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
- source_map_.RegisterSource("apitest", IDR_EXTENSION_APITEST_JS);
+ source_map_.RegisterSource("test", IDR_EXTENSION_APITEST_JS);
// Libraries.
source_map_.RegisterSource("contentWatcher", IDR_CONTENT_WATCHER_JS);
@@ -691,10 +824,11 @@ void Dispatcher::PopulateSourceMap() {
source_map_.RegisterSource("webRequestInternal",
IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
+ source_map_.RegisterSource("binding", IDR_BINDING_JS);
// Platform app sources that are not API-specific..
source_map_.RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS);
- source_map_.RegisterSource("webview", IDR_WEB_VIEW_JS);
+ source_map_.RegisterSource("web_view", IDR_WEB_VIEW_JS);
source_map_.RegisterSource("denyWebview", IDR_WEB_VIEW_DENY_JS);
source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
source_map_.RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS);
@@ -768,6 +902,8 @@ void Dispatcher::DidCreateScriptContext(
RegisterNativeHandlers(module_system.get(), context);
v8::Isolate* isolate = v8_context->GetIsolate();
+ module_system->RegisterNativeHandler("chrome",
+ scoped_ptr<NativeHandler>(new ChromeNativeHandler(isolate)));
module_system->RegisterNativeHandler("chrome_hidden",
scoped_ptr<NativeHandler>(new ChromeHiddenNativeHandler(isolate)));
module_system->RegisterNativeHandler("print",
@@ -775,7 +911,12 @@ void Dispatcher::DidCreateScriptContext(
module_system->RegisterNativeHandler("lazy_background_page",
scoped_ptr<NativeHandler>(new LazyBackgroundPageNativeHandler(this)));
module_system->RegisterNativeHandler("logging",
- scoped_ptr<NativeHandler>(new LoggingNativeHandler(isolate)));
+ scoped_ptr<NativeHandler>(new LoggingNativeHandler(isolate, context)));
+ module_system->RegisterNativeHandler("schema_registry",
+ scoped_ptr<NativeHandler>(
+ new SchemaRegistryNativeHandler(v8_schema_registry(), isolate)));
+ module_system->RegisterNativeHandler("v8_context",
+ scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, isolate)));
int manifest_version = extension ? extension->manifest_version() : 1;
bool send_request_disabled =
@@ -799,27 +940,26 @@ void Dispatcher::DidCreateScriptContext(
InstallBindings(module_system.get(), v8_context, "app");
InstallBindings(module_system.get(), v8_context, "webstore");
break;
-
case Feature::BLESSED_EXTENSION_CONTEXT:
case Feature::UNBLESSED_EXTENSION_CONTEXT:
case Feature::CONTENT_SCRIPT_CONTEXT: {
- module_system->Require("miscellaneous_bindings");
- module_system->Require("schema_generated_bindings");
- module_system->Require("apitest");
+ if (extension && !extension->is_platform_app())
+ module_system->Require("miscellaneous_bindings");
// TODO(kalman): move this code back out of the switch and execute it
// regardless of |context_type|. ExtensionAPI knows how to return the
// correct APIs, however, until it doesn't have a 2MB overhead we can't
// load it in every process.
- const std::set<std::string>& apis = context->GetAvailableExtensionAPIs();
- for (std::set<std::string>::const_iterator i = apis.begin();
- i != apis.end(); ++i) {
- InstallBindings(module_system.get(), v8_context, *i);
- }
-
+ RegisterSchemaGeneratedBindings(module_system.get(),
+ context,
+ v8_context);
break;
}
}
+ // TODO(cduvall): Hack for loading chromeHidden.JSON before an extension can
+ // trash the global JSON object (event.js).
+ // This is for ExtensionApiTest.Messaging.
+ module_system->Require("event_bindings");
not at google - send to devlin 2013/02/15 22:26:17 ah, good point. I just wrote https://codereview.c
cduvall 2013/02/19 23:58:49 Done. I'll change it to include json once your cha
// Inject custom JS into the platform app context.
if (IsWithinPlatformApp(frame))
@@ -827,7 +967,7 @@ void Dispatcher::DidCreateScriptContext(
if (context_type == Feature::BLESSED_EXTENSION_CONTEXT) {
bool has_permission = extension->HasAPIPermission(APIPermission::kWebView);
- module_system->Require(has_permission ? "webview" : "denyWebview");
+ module_system->Require(has_permission ? "web_view" : "denyWebview");
}
context->set_module_system(module_system.Pass());

Powered by Google App Engine
This is Rietveld 408576698