| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "extensions/renderer/dispatcher.h" | 5 #include "extensions/renderer/dispatcher.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 static const int64 kMaxExtensionIdleHandlerDelayMs = 5 * 60 * 1000; | 117 static const int64 kMaxExtensionIdleHandlerDelayMs = 5 * 60 * 1000; |
| 118 static const char kEventDispatchFunction[] = "dispatchEvent"; | 118 static const char kEventDispatchFunction[] = "dispatchEvent"; |
| 119 static const char kOnSuspendEvent[] = "runtime.onSuspend"; | 119 static const char kOnSuspendEvent[] = "runtime.onSuspend"; |
| 120 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled"; | 120 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled"; |
| 121 | 121 |
| 122 // Returns the global value for "chrome" from |context|. If one doesn't exist | 122 // Returns the global value for "chrome" from |context|. If one doesn't exist |
| 123 // creates a new object for it. | 123 // creates a new object for it. |
| 124 // | 124 // |
| 125 // Note that this isn't necessarily an object, since webpages can write, for | 125 // Note that this isn't necessarily an object, since webpages can write, for |
| 126 // example, "window.chrome = true". | 126 // example, "window.chrome = true". |
| 127 v8::Handle<v8::Value> GetOrCreateChrome(ScriptContext* context) { | 127 v8::Local<v8::Value> GetOrCreateChrome(ScriptContext* context) { |
| 128 v8::Handle<v8::String> chrome_string( | 128 v8::Local<v8::String> chrome_string( |
| 129 v8::String::NewFromUtf8(context->isolate(), "chrome")); | 129 v8::String::NewFromUtf8(context->isolate(), "chrome")); |
| 130 v8::Handle<v8::Object> global(context->v8_context()->Global()); | 130 v8::Local<v8::Object> global(context->v8_context()->Global()); |
| 131 v8::Handle<v8::Value> chrome(global->Get(chrome_string)); | 131 v8::Local<v8::Value> chrome(global->Get(chrome_string)); |
| 132 if (chrome->IsUndefined()) { | 132 if (chrome->IsUndefined()) { |
| 133 chrome = v8::Object::New(context->isolate()); | 133 chrome = v8::Object::New(context->isolate()); |
| 134 global->Set(chrome_string, chrome); | 134 global->Set(chrome_string, chrome); |
| 135 } | 135 } |
| 136 return chrome; | 136 return chrome; |
| 137 } | 137 } |
| 138 | 138 |
| 139 // Returns |value| cast to an object if possible, else an empty handle. | 139 // Returns |value| cast to an object if possible, else an empty handle. |
| 140 v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) { | 140 v8::Local<v8::Object> AsObjectOrEmpty(v8::Local<v8::Value> value) { |
| 141 return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>(); | 141 return value->IsObject() ? value.As<v8::Object>() : v8::Local<v8::Object>(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 // Calls a method |method_name| in a module |module_name| belonging to the | 144 // Calls a method |method_name| in a module |module_name| belonging to the |
| 145 // module system from |context|. Intended as a callback target from | 145 // module system from |context|. Intended as a callback target from |
| 146 // ScriptContextSet::ForEach. | 146 // ScriptContextSet::ForEach. |
| 147 void CallModuleMethod(const std::string& module_name, | 147 void CallModuleMethod(const std::string& module_name, |
| 148 const std::string& method_name, | 148 const std::string& method_name, |
| 149 const base::ListValue* args, | 149 const base::ListValue* args, |
| 150 ScriptContext* context) { | 150 ScriptContext* context) { |
| 151 v8::HandleScope handle_scope(context->isolate()); | 151 v8::HandleScope handle_scope(context->isolate()); |
| 152 v8::Context::Scope context_scope(context->v8_context()); | 152 v8::Context::Scope context_scope(context->v8_context()); |
| 153 | 153 |
| 154 scoped_ptr<content::V8ValueConverter> converter( | 154 scoped_ptr<content::V8ValueConverter> converter( |
| 155 content::V8ValueConverter::create()); | 155 content::V8ValueConverter::create()); |
| 156 | 156 |
| 157 std::vector<v8::Handle<v8::Value> > arguments; | 157 std::vector<v8::Local<v8::Value>> arguments; |
| 158 for (base::ListValue::const_iterator it = args->begin(); it != args->end(); | 158 for (base::ListValue::const_iterator it = args->begin(); it != args->end(); |
| 159 ++it) { | 159 ++it) { |
| 160 arguments.push_back(converter->ToV8Value(*it, context->v8_context())); | 160 arguments.push_back(converter->ToV8Value(*it, context->v8_context())); |
| 161 } | 161 } |
| 162 | 162 |
| 163 context->module_system()->CallModuleMethod( | 163 context->module_system()->CallModuleMethod( |
| 164 module_name, method_name, &arguments); | 164 module_name, method_name, &arguments); |
| 165 } | 165 } |
| 166 | 166 |
| 167 // This handles the "chrome." root API object in script contexts. | 167 // This handles the "chrome." root API object in script contexts. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 bool Dispatcher::IsExtensionActive(const std::string& extension_id) const { | 222 bool Dispatcher::IsExtensionActive(const std::string& extension_id) const { |
| 223 bool is_active = | 223 bool is_active = |
| 224 active_extension_ids_.find(extension_id) != active_extension_ids_.end(); | 224 active_extension_ids_.find(extension_id) != active_extension_ids_.end(); |
| 225 if (is_active) | 225 if (is_active) |
| 226 CHECK(extensions_.Contains(extension_id)); | 226 CHECK(extensions_.Contains(extension_id)); |
| 227 return is_active; | 227 return is_active; |
| 228 } | 228 } |
| 229 | 229 |
| 230 void Dispatcher::DidCreateScriptContext( | 230 void Dispatcher::DidCreateScriptContext( |
| 231 blink::WebLocalFrame* frame, | 231 blink::WebLocalFrame* frame, |
| 232 const v8::Handle<v8::Context>& v8_context, | 232 const v8::Local<v8::Context>& v8_context, |
| 233 int extension_group, | 233 int extension_group, |
| 234 int world_id) { | 234 int world_id) { |
| 235 const base::TimeTicks start_time = base::TimeTicks::Now(); | 235 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 236 | 236 |
| 237 ScriptContext* context = script_context_set_->Register( | 237 ScriptContext* context = script_context_set_->Register( |
| 238 frame, v8_context, extension_group, world_id); | 238 frame, v8_context, extension_group, world_id); |
| 239 | 239 |
| 240 // Initialize origin permissions for content scripts, which can't be | 240 // Initialize origin permissions for content scripts, which can't be |
| 241 // initialized in |OnActivateExtension|. | 241 // initialized in |OnActivateExtension|. |
| 242 if (context->context_type() == Feature::CONTENT_SCRIPT_CONTEXT) | 242 if (context->context_type() == Feature::CONTENT_SCRIPT_CONTEXT) |
| 243 InitOriginPermissions(context->extension()); | 243 InitOriginPermissions(context->extension()); |
| 244 | 244 |
| 245 { | 245 { |
| 246 scoped_ptr<ModuleSystem> module_system( | 246 scoped_ptr<ModuleSystem> module_system( |
| 247 new ModuleSystem(context, &source_map_)); | 247 new ModuleSystem(context, &source_map_)); |
| 248 context->set_module_system(module_system.Pass()); | 248 context->set_module_system(module_system.Pass()); |
| 249 } | 249 } |
| 250 ModuleSystem* module_system = context->module_system(); | 250 ModuleSystem* module_system = context->module_system(); |
| 251 | 251 |
| 252 // Enable natives in startup. | 252 // Enable natives in startup. |
| 253 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system); | 253 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system); |
| 254 | 254 |
| 255 RegisterNativeHandlers(module_system, context); | 255 RegisterNativeHandlers(module_system, context); |
| 256 | 256 |
| 257 // chrome.Event is part of the public API (although undocumented). Make it | 257 // chrome.Event is part of the public API (although undocumented). Make it |
| 258 // lazily evalulate to Event from event_bindings.js. For extensions only | 258 // lazily evalulate to Event from event_bindings.js. For extensions only |
| 259 // though, not all webpages! | 259 // though, not all webpages! |
| 260 if (context->extension()) { | 260 if (context->extension()) { |
| 261 v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context)); | 261 v8::Local<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context)); |
| 262 if (!chrome.IsEmpty()) | 262 if (!chrome.IsEmpty()) |
| 263 module_system->SetLazyField(chrome, "Event", kEventBindings, "Event"); | 263 module_system->SetLazyField(chrome, "Event", kEventBindings, "Event"); |
| 264 } | 264 } |
| 265 | 265 |
| 266 UpdateBindingsForContext(context); | 266 UpdateBindingsForContext(context); |
| 267 | 267 |
| 268 bool is_within_platform_app = IsWithinPlatformApp(); | 268 bool is_within_platform_app = IsWithinPlatformApp(); |
| 269 // Inject custom JS into the platform app context. | 269 // Inject custom JS into the platform app context. |
| 270 if (is_within_platform_app) { | 270 if (is_within_platform_app) { |
| 271 module_system->Require("platformApp"); | 271 module_system->Require("platformApp"); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 301 case Feature::WEBUI_CONTEXT: | 301 case Feature::WEBUI_CONTEXT: |
| 302 UMA_HISTOGRAM_TIMES("Extensions.DidCreateScriptContext_WebUI", elapsed); | 302 UMA_HISTOGRAM_TIMES("Extensions.DidCreateScriptContext_WebUI", elapsed); |
| 303 break; | 303 break; |
| 304 } | 304 } |
| 305 | 305 |
| 306 VLOG(1) << "Num tracked contexts: " << script_context_set_->size(); | 306 VLOG(1) << "Num tracked contexts: " << script_context_set_->size(); |
| 307 } | 307 } |
| 308 | 308 |
| 309 void Dispatcher::WillReleaseScriptContext( | 309 void Dispatcher::WillReleaseScriptContext( |
| 310 blink::WebLocalFrame* frame, | 310 blink::WebLocalFrame* frame, |
| 311 const v8::Handle<v8::Context>& v8_context, | 311 const v8::Local<v8::Context>& v8_context, |
| 312 int world_id) { | 312 int world_id) { |
| 313 ScriptContext* context = script_context_set_->GetByV8Context(v8_context); | 313 ScriptContext* context = script_context_set_->GetByV8Context(v8_context); |
| 314 if (!context) | 314 if (!context) |
| 315 return; | 315 return; |
| 316 | 316 |
| 317 context->DispatchOnUnloadEvent(); | 317 context->DispatchOnUnloadEvent(); |
| 318 // TODO(kalman): Make |request_sender| use |context->AddInvalidationObserver|. | 318 // TODO(kalman): Make |request_sender| use |context->AddInvalidationObserver|. |
| 319 // In fact |request_sender_| should really be owned by ScriptContext. | 319 // In fact |request_sender_| should really be owned by ScriptContext. |
| 320 request_sender_->InvalidateSource(context); | 320 request_sender_->InvalidateSource(context); |
| 321 | 321 |
| (...skipping 854 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 RegisterBinding(api_name, context); | 1176 RegisterBinding(api_name, context); |
| 1177 } | 1177 } |
| 1178 break; | 1178 break; |
| 1179 } | 1179 } |
| 1180 } | 1180 } |
| 1181 } | 1181 } |
| 1182 | 1182 |
| 1183 void Dispatcher::RegisterBinding(const std::string& api_name, | 1183 void Dispatcher::RegisterBinding(const std::string& api_name, |
| 1184 ScriptContext* context) { | 1184 ScriptContext* context) { |
| 1185 std::string bind_name; | 1185 std::string bind_name; |
| 1186 v8::Handle<v8::Object> bind_object = | 1186 v8::Local<v8::Object> bind_object = |
| 1187 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); | 1187 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); |
| 1188 | 1188 |
| 1189 // Empty if the bind object failed to be created, probably because the | 1189 // Empty if the bind object failed to be created, probably because the |
| 1190 // extension overrode chrome with a non-object, e.g. window.chrome = true. | 1190 // extension overrode chrome with a non-object, e.g. window.chrome = true. |
| 1191 if (bind_object.IsEmpty()) | 1191 if (bind_object.IsEmpty()) |
| 1192 return; | 1192 return; |
| 1193 | 1193 |
| 1194 v8::Local<v8::String> v8_bind_name = | 1194 v8::Local<v8::String> v8_bind_name = |
| 1195 v8::String::NewFromUtf8(context->isolate(), bind_name.c_str()); | 1195 v8::String::NewFromUtf8(context->isolate(), bind_name.c_str()); |
| 1196 if (bind_object->HasRealNamedProperty(v8_bind_name)) { | 1196 if (bind_object->HasRealNamedProperty(v8_bind_name)) { |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); | 1294 for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); |
| 1295 iter != active_extension_ids_.end(); | 1295 iter != active_extension_ids_.end(); |
| 1296 ++iter) { | 1296 ++iter) { |
| 1297 const Extension* extension = extensions_.GetByID(*iter); | 1297 const Extension* extension = extensions_.GetByID(*iter); |
| 1298 if (extension && extension->is_platform_app()) | 1298 if (extension && extension->is_platform_app()) |
| 1299 return true; | 1299 return true; |
| 1300 } | 1300 } |
| 1301 return false; | 1301 return false; |
| 1302 } | 1302 } |
| 1303 | 1303 |
| 1304 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( | 1304 v8::Local<v8::Object> Dispatcher::GetOrCreateObject( |
| 1305 const v8::Handle<v8::Object>& object, | 1305 const v8::Local<v8::Object>& object, |
| 1306 const std::string& field, | 1306 const std::string& field, |
| 1307 v8::Isolate* isolate) { | 1307 v8::Isolate* isolate) { |
| 1308 v8::Handle<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str()); | 1308 v8::Local<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str()); |
| 1309 // If the object has a callback property, it is assumed it is an unavailable | 1309 // If the object has a callback property, it is assumed it is an unavailable |
| 1310 // API, so it is safe to delete. This is checked before GetOrCreateObject is | 1310 // API, so it is safe to delete. This is checked before GetOrCreateObject is |
| 1311 // called. | 1311 // called. |
| 1312 if (object->HasRealNamedCallbackProperty(key)) { | 1312 if (object->HasRealNamedCallbackProperty(key)) { |
| 1313 object->Delete(key); | 1313 object->Delete(key); |
| 1314 } else if (object->HasRealNamedProperty(key)) { | 1314 } else if (object->HasRealNamedProperty(key)) { |
| 1315 v8::Handle<v8::Value> value = object->Get(key); | 1315 v8::Local<v8::Value> value = object->Get(key); |
| 1316 CHECK(value->IsObject()); | 1316 CHECK(value->IsObject()); |
| 1317 return v8::Handle<v8::Object>::Cast(value); | 1317 return v8::Local<v8::Object>::Cast(value); |
| 1318 } | 1318 } |
| 1319 | 1319 |
| 1320 v8::Handle<v8::Object> new_object = v8::Object::New(isolate); | 1320 v8::Local<v8::Object> new_object = v8::Object::New(isolate); |
| 1321 object->Set(key, new_object); | 1321 object->Set(key, new_object); |
| 1322 return new_object; | 1322 return new_object; |
| 1323 } | 1323 } |
| 1324 | 1324 |
| 1325 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable( | 1325 v8::Local<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable( |
| 1326 const std::string& api_name, | 1326 const std::string& api_name, |
| 1327 std::string* bind_name, | 1327 std::string* bind_name, |
| 1328 ScriptContext* context) { | 1328 ScriptContext* context) { |
| 1329 std::vector<std::string> split; | 1329 std::vector<std::string> split; |
| 1330 base::SplitString(api_name, '.', &split); | 1330 base::SplitString(api_name, '.', &split); |
| 1331 | 1331 |
| 1332 v8::Handle<v8::Object> bind_object; | 1332 v8::Local<v8::Object> bind_object; |
| 1333 | 1333 |
| 1334 // Check if this API has an ancestor. If the API's ancestor is available and | 1334 // Check if this API has an ancestor. If the API's ancestor is available and |
| 1335 // the API is not available, don't install the bindings for this API. If | 1335 // the API is not available, don't install the bindings for this API. If |
| 1336 // the API is available and its ancestor is not, delete the ancestor and | 1336 // the API is available and its ancestor is not, delete the ancestor and |
| 1337 // install the bindings for the API. This is to prevent loading the ancestor | 1337 // install the bindings for the API. This is to prevent loading the ancestor |
| 1338 // API schema if it will not be needed. | 1338 // API schema if it will not be needed. |
| 1339 // | 1339 // |
| 1340 // For example: | 1340 // For example: |
| 1341 // If app is available and app.window is not, just install app. | 1341 // If app is available and app.window is not, just install app. |
| 1342 // If app.window is available and app is not, delete app and install | 1342 // If app.window is available and app is not, delete app and install |
| 1343 // app.window on a new object so app does not have to be loaded. | 1343 // app.window on a new object so app does not have to be loaded. |
| 1344 const FeatureProvider* api_feature_provider = | 1344 const FeatureProvider* api_feature_provider = |
| 1345 FeatureProvider::GetAPIFeatures(); | 1345 FeatureProvider::GetAPIFeatures(); |
| 1346 std::string ancestor_name; | 1346 std::string ancestor_name; |
| 1347 bool only_ancestor_available = false; | 1347 bool only_ancestor_available = false; |
| 1348 | 1348 |
| 1349 for (size_t i = 0; i < split.size() - 1; ++i) { | 1349 for (size_t i = 0; i < split.size() - 1; ++i) { |
| 1350 ancestor_name += (i ? "." : "") + split[i]; | 1350 ancestor_name += (i ? "." : "") + split[i]; |
| 1351 if (api_feature_provider->GetFeature(ancestor_name) && | 1351 if (api_feature_provider->GetFeature(ancestor_name) && |
| 1352 context->GetAvailability(ancestor_name).is_available() && | 1352 context->GetAvailability(ancestor_name).is_available() && |
| 1353 !context->GetAvailability(api_name).is_available()) { | 1353 !context->GetAvailability(api_name).is_available()) { |
| 1354 only_ancestor_available = true; | 1354 only_ancestor_available = true; |
| 1355 break; | 1355 break; |
| 1356 } | 1356 } |
| 1357 | 1357 |
| 1358 if (bind_object.IsEmpty()) { | 1358 if (bind_object.IsEmpty()) { |
| 1359 bind_object = AsObjectOrEmpty(GetOrCreateChrome(context)); | 1359 bind_object = AsObjectOrEmpty(GetOrCreateChrome(context)); |
| 1360 if (bind_object.IsEmpty()) | 1360 if (bind_object.IsEmpty()) |
| 1361 return v8::Handle<v8::Object>(); | 1361 return v8::Local<v8::Object>(); |
| 1362 } | 1362 } |
| 1363 bind_object = GetOrCreateObject(bind_object, split[i], context->isolate()); | 1363 bind_object = GetOrCreateObject(bind_object, split[i], context->isolate()); |
| 1364 } | 1364 } |
| 1365 | 1365 |
| 1366 if (only_ancestor_available) | 1366 if (only_ancestor_available) |
| 1367 return v8::Handle<v8::Object>(); | 1367 return v8::Local<v8::Object>(); |
| 1368 | 1368 |
| 1369 if (bind_name) | 1369 if (bind_name) |
| 1370 *bind_name = split.back(); | 1370 *bind_name = split.back(); |
| 1371 | 1371 |
| 1372 return bind_object.IsEmpty() ? AsObjectOrEmpty(GetOrCreateChrome(context)) | 1372 return bind_object.IsEmpty() ? AsObjectOrEmpty(GetOrCreateChrome(context)) |
| 1373 : bind_object; | 1373 : bind_object; |
| 1374 } | 1374 } |
| 1375 | 1375 |
| 1376 void Dispatcher::RequireGuestViewModules(ScriptContext* context) { | 1376 void Dispatcher::RequireGuestViewModules(ScriptContext* context) { |
| 1377 Feature::Context context_type = context->context_type(); | 1377 Feature::Context context_type = context->context_type(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1411 // The "guestViewDeny" module must always be loaded last. It registers | 1411 // The "guestViewDeny" module must always be loaded last. It registers |
| 1412 // error-providing custom elements for the GuestView types that are not | 1412 // error-providing custom elements for the GuestView types that are not |
| 1413 // available, and thus all of those types must have been checked and loaded | 1413 // available, and thus all of those types must have been checked and loaded |
| 1414 // (or not loaded) beforehand. | 1414 // (or not loaded) beforehand. |
| 1415 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT) { | 1415 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT) { |
| 1416 module_system->Require("guestViewDeny"); | 1416 module_system->Require("guestViewDeny"); |
| 1417 } | 1417 } |
| 1418 } | 1418 } |
| 1419 | 1419 |
| 1420 } // namespace extensions | 1420 } // namespace extensions |
| OLD | NEW |