summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authorjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-15 10:43:22 +0000
committerjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-15 10:43:22 +0000
commit921777f2b0b5adeb766419ffbf6538d10c819912 (patch)
treec7b81951118217e9956a8d0d5744827336d46043 /chrome/renderer
parent21d90b88fd5b2a054e4825e89d104bfe1aadbdde (diff)
downloadchromium_src-921777f2b0b5adeb766419ffbf6538d10c819912.zip
chromium_src-921777f2b0b5adeb766419ffbf6538d10c819912.tar.gz
chromium_src-921777f2b0b5adeb766419ffbf6538d10c819912.tar.bz2
Make sure ports are closed when they're no longer used.
It appears to be a common pattern that extensions don't invoke the responseCallback, and so the port objects leak. Register a callback that triggers when the responseCallback is finalized to free up these resources. BUG=114738, 93566 TEST=manual Review URL: http://codereview.chromium.org/9693048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126884 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/extensions/miscellaneous_bindings.cc31
-rw-r--r--chrome/renderer/resources/extensions/miscellaneous_bindings.js14
2 files changed, 44 insertions, 1 deletions
diff --git a/chrome/renderer/extensions/miscellaneous_bindings.cc b/chrome/renderer/extensions/miscellaneous_bindings.cc
index 31a8923..8a5f758 100644
--- a/chrome/renderer/extensions/miscellaneous_bindings.cc
+++ b/chrome/renderer/extensions/miscellaneous_bindings.cc
@@ -84,6 +84,8 @@ class ExtensionImpl : public ChromeV8Extension {
return v8::FunctionTemplate::New(PortAddRef);
} else if (name->Equals(v8::String::New("PortRelease"))) {
return v8::FunctionTemplate::New(PortRelease);
+ } else if (name->Equals(v8::String::New("BindToGC"))) {
+ return v8::FunctionTemplate::New(BindToGC);
}
return ChromeV8Extension::GetNativeFunction(name);
}
@@ -149,6 +151,35 @@ class ExtensionImpl : public ChromeV8Extension {
}
return v8::Undefined();
}
+
+ struct GCCallbackArgs {
+ v8::Persistent<v8::Object> object;
+ v8::Persistent<v8::Function> callback;
+ };
+
+ static void GCCallback(v8::Persistent<v8::Value> object, void* parameter) {
+ v8::HandleScope handle_scope;
+ GCCallbackArgs* args = reinterpret_cast<GCCallbackArgs*>(parameter);
+ args->callback->Call(args->callback->CreationContext()->Global(), 0, NULL);
+ args->callback.Dispose();
+ args->object.Dispose();
+ delete args;
+ }
+
+ // Binds a callback to be invoked when the given object is garbage collected.
+ static v8::Handle<v8::Value> BindToGC(const v8::Arguments& args) {
+ if (args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()) {
+ GCCallbackArgs* context = new GCCallbackArgs;
+ context->callback = v8::Persistent<v8::Function>::New(
+ v8::Handle<v8::Function>::Cast(args[1]));
+ context->object = v8::Persistent<v8::Object>::New(
+ v8::Handle<v8::Object>::Cast(args[0]));
+ context->object.MakeWeak(context, GCCallback);
+ } else {
+ NOTREACHED();
+ }
+ return v8::Undefined();
+ }
};
} // namespace
diff --git a/chrome/renderer/resources/extensions/miscellaneous_bindings.js b/chrome/renderer/resources/extensions/miscellaneous_bindings.js
index 6bcfc11..0895e1d 100644
--- a/chrome/renderer/resources/extensions/miscellaneous_bindings.js
+++ b/chrome/renderer/resources/extensions/miscellaneous_bindings.js
@@ -15,6 +15,7 @@ var chrome = chrome || {};
native function PostMessage(portId, msg);
native function GetChromeHidden();
native function Print();
+ native function BindToGC();
var chromeHidden = GetChromeHidden();
var manifestVersion;
@@ -123,7 +124,7 @@ var chrome = chrome || {};
if (requestEvent.hasListeners()) {
var port = chromeHidden.Port.createPort(portId, channelName);
port.onMessage.addListener(function(request) {
- requestEvent.dispatch(request, sender, function(response) {
+ var responseCallback = function(response) {
if (port) {
port.postMessage(response);
port = null;
@@ -141,7 +142,18 @@ var chrome = chrome || {};
chrome.extension.lastError = {"message": errorMsg};
console.error("Could not send response: " + errorMsg);
}
+ };
+ // In case the extension never invokes the responseCallback, and also
+ // doesn't keep a reference to it, we need to clean up the port. Do
+ // so by attaching to the garbage collection of the responseCallback
+ // using some native hackery.
+ BindToGC(responseCallback, function() {
+ if (port) {
+ port.disconnect();
+ port = null;
+ }
});
+ requestEvent.dispatch(request, sender, responseCallback);
});
}
return;