summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-06 09:59:19 +0000
committerthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-06 09:59:19 +0000
commiteb7ef5f39f4041a06a2eef6e2916b0ab3039238f (patch)
treeaf8e0a815e03c80be555e38a2fd1315cc16eab59
parentae415588b46037ef8fc0ce0a52a1aa86e7762d4c (diff)
downloadchromium_src-eb7ef5f39f4041a06a2eef6e2916b0ab3039238f.zip
chromium_src-eb7ef5f39f4041a06a2eef6e2916b0ab3039238f.tar.gz
chromium_src-eb7ef5f39f4041a06a2eef6e2916b0ab3039238f.tar.bz2
Extensions: Send the tab id to platform apps.
This lets mediaGalleries.addUserSelectedFolder() figure out the tab that triggered the API, so it can display the select dialog in the tab when the platform app has no open windows. BUG=333899 Review URL: https://codereview.chromium.org/145463002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249322 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/api/media_galleries/media_galleries_api.cc15
-rw-r--r--chrome/browser/extensions/api/messaging/message_service.cc38
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc1
-rw-r--r--chrome/common/extensions/extension_messages.h3
-rw-r--r--chrome/renderer/extensions/dispatcher.cc21
-rw-r--r--chrome/renderer/extensions/dispatcher.h5
-rw-r--r--chrome/renderer/extensions/messaging_bindings.cc64
-rw-r--r--chrome/renderer/extensions/request_sender.cc18
-rw-r--r--chrome/renderer/extensions/request_sender.h17
-rw-r--r--extensions/browser/extension_function.cc13
-rw-r--r--extensions/browser/extension_function.h7
11 files changed, 148 insertions, 54 deletions
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
index aeb41d0..bc56c96 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_api.cc
@@ -21,6 +21,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/file_system/file_system_api.h"
#include "chrome/browser/extensions/blob_reader.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/media_galleries/media_file_system_registry.h"
#include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
#include "chrome/browser/media_galleries/media_galleries_histograms.h"
@@ -539,8 +540,16 @@ void MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit() {
const std::string& app_id = GetExtension()->id();
WebContents* contents = GetWebContents(render_view_host(), profile, app_id);
if (!contents) {
- SendResponse(false);
- return;
+ // When the request originated from a background page, but there is no app
+ // window open, check to see if it originated from a tab and display the
+ // dialog in that tab.
+ bool found_tab = extensions::ExtensionTabUtil::GetTabById(
+ source_tab_id(), profile, profile->IsOffTheRecord(),
+ NULL, NULL, &contents, NULL);
+ if (!found_tab || !contents) {
+ SendResponse(false);
+ return;
+ }
}
if (!user_gesture()) {
@@ -691,7 +700,7 @@ bool MediaGalleriesAddScanResultsFunction::RunImpl() {
void MediaGalleriesAddScanResultsFunction::OnPreferencesInit() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
const Extension* extension = GetExtension();
- MediaGalleriesPreferences * preferences =
+ MediaGalleriesPreferences* preferences =
media_file_system_registry()->GetPreferences(GetProfile());
if (MediaGalleriesScanResultDialogController::ScanResultCountForExtension(
preferences, extension) == 0) {
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index 8afd54f..9c54e78 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/extensions/api/messaging/extension_message_port.h"
#include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
#include "chrome/browser/extensions/api/messaging/native_message_port.h"
+#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
@@ -119,14 +120,9 @@ static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
static content::RenderProcessHost* GetExtensionProcess(
Profile* profile, const std::string& extension_id) {
SiteInstance* site_instance =
- ExtensionSystem::Get(profile)->process_manager()->
- GetSiteInstanceForURL(
- Extension::GetBaseURLFromExtensionId(extension_id));
-
- if (!site_instance->HasProcess())
- return NULL;
-
- return site_instance->GetProcess();
+ ExtensionSystem::Get(profile)->process_manager()->GetSiteInstanceForURL(
+ Extension::GetBaseURLFromExtensionId(extension_id));
+ return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
}
} // namespace
@@ -152,12 +148,12 @@ void MessageService::AllocatePortIdPair(int* port1, int* port2) {
// Sanity checks to make sure our channel<->port converters are correct.
DCHECK(IS_OPENER_PORT_ID(port1_id));
- DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
- DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
- DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
- DCHECK(GET_CHANNEL_ID(port1_id) == channel_id);
- DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
- DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
+ DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
+ DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
+ DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
+ DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
+ DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
+ DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
*port1 = port1_id;
*port2 = port2_id;
@@ -300,9 +296,10 @@ void MessageService::OpenChannelToExtension(
GURL source_url_for_tab;
if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
- // Platform apps can be sent messages, but don't have a Tab concept.
- if (!target_extension->is_platform_app())
- source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
+ // Only the tab id is useful to platform apps for internal use. The
+ // unnecessary bits will be stripped out in
+ // MessagingBindings::DispatchOnConnect().
+ source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
source_url_for_tab = source_url;
}
@@ -323,7 +320,9 @@ void MessageService::OpenChannelToExtension(
if (include_tls_channel_id) {
pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
= PendingMessagesQueue();
- property_provider_.GetDomainBoundCert(profile, params->source_url,
+ property_provider_.GetDomainBoundCert(
+ profile,
+ source_url,
base::Bind(&MessageService::GotDomainBoundCert,
weak_factory_.GetWeakPtr(),
base::Passed(make_scoped_ptr(params))));
@@ -551,8 +550,7 @@ void MessageService::CloseChannelImpl(
channels_.erase(channel_iter);
}
-void MessageService::PostMessage(
- int source_port_id, const Message& message) {
+void MessageService::PostMessage(int source_port_id, const Message& message) {
int channel_id = GET_CHANNEL_ID(source_port_id);
MessageChannelMap::iterator iter = channels_.find(channel_id);
if (iter == channels_.end()) {
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 6ac7e78..1de6920 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -509,6 +509,7 @@ ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
function->set_extension(extension);
function->set_profile_id(profile);
function->set_response_callback(callback);
+ function->set_source_tab_id(params.source_tab_id);
return function;
}
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 3a58cf4..e4e5ec4 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -84,6 +84,9 @@ IPC_STRUCT_BEGIN(ExtensionHostMsg_Request_Params)
// extension. Or, they can originate from hosted apps or normal web pages.
IPC_STRUCT_MEMBER(GURL, source_url)
+ // The id of the tab that sent this request, or -1 if there is no source tab.
+ IPC_STRUCT_MEMBER(int, source_tab_id)
+
// Unique request id to match requests and responses.
IPC_STRUCT_MEMBER(int, request_id)
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index c2b7499..270a182 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -587,6 +587,12 @@ void Dispatcher::OnDispatchOnConnect(
const base::DictionaryValue& source_tab,
const ExtensionMsg_ExternalConnectionInfo& info,
const std::string& tls_channel_id) {
+ DCHECK(!ContainsKey(port_to_tab_id_map_, target_port_id));
+ DCHECK_EQ(1, target_port_id % 2); // target renderer ports have odd IDs.
+ int sender_tab_id = -1;
+ source_tab.GetInteger("id", &sender_tab_id);
+ port_to_tab_id_map_[target_port_id] = sender_tab_id;
+
MessagingBindings::DispatchOnConnect(
v8_context_set_.GetAll(),
target_port_id, channel_name, source_tab,
@@ -597,6 +603,14 @@ void Dispatcher::OnDispatchOnConnect(
void Dispatcher::OnDeliverMessage(int target_port_id,
const Message& message) {
+ scoped_ptr<RequestSender::ScopedTabID> scoped_tab_id;
+ std::map<int, int>::const_iterator it =
+ port_to_tab_id_map_.find(target_port_id);
+ if (it != port_to_tab_id_map_.end()) {
+ scoped_tab_id.reset(new RequestSender::ScopedTabID(request_sender(),
+ it->second));
+ }
+
MessagingBindings::DeliverMessage(
v8_context_set_.GetAll(),
target_port_id,
@@ -1665,4 +1679,11 @@ void Dispatcher::InvokeModuleSystemMethod(
}
}
+void Dispatcher::ClearPortData(int port_id) {
+ // Only the target port side has entries in |port_to_tab_id_map_|. If
+ // |port_id| is a source port, std::map::erase() will just silently fail
+ // here as a no-op.
+ port_to_tab_id_map_.erase(port_id);
+}
+
} // namespace extensions
diff --git a/chrome/renderer/extensions/dispatcher.h b/chrome/renderer/extensions/dispatcher.h
index bcdece9..57a52e4 100644
--- a/chrome/renderer/extensions/dispatcher.h
+++ b/chrome/renderer/extensions/dispatcher.h
@@ -143,6 +143,8 @@ class Dispatcher : public content::RenderProcessObserver {
const base::ListValue& args,
bool user_gesture);
+ void ClearPortData(int port_id);
+
private:
friend class ::ChromeRenderViewTest;
FRIEND_TEST_ALL_PREFIXES(RendererPermissionsPolicyDelegateTest,
@@ -309,6 +311,9 @@ class Dispatcher : public content::RenderProcessObserver {
std::string system_font_family_;
std::string system_font_size_;
+ // Mapping of port IDs to tabs. If there is no tab, the value would be -1.
+ std::map<int, int> port_to_tab_id_map_;
+
DISALLOW_COPY_AND_ASSIGN(Dispatcher);
};
diff --git a/chrome/renderer/extensions/messaging_bindings.cc b/chrome/renderer/extensions/messaging_bindings.cc
index a265292..8c3bad9 100644
--- a/chrome/renderer/extensions/messaging_bindings.cc
+++ b/chrome/renderer/extensions/messaging_bindings.cc
@@ -47,6 +47,8 @@
using content::RenderThread;
using content::V8ValueConverter;
+namespace extensions {
+
namespace {
struct ExtensionData {
@@ -57,19 +59,19 @@ struct ExtensionData {
std::map<int, PortData> ports; // port ID -> data
};
-static base::LazyInstance<ExtensionData> g_extension_data =
+base::LazyInstance<ExtensionData> g_extension_data =
LAZY_INSTANCE_INITIALIZER;
-static bool HasPortData(int port_id) {
+bool HasPortData(int port_id) {
return g_extension_data.Get().ports.find(port_id) !=
g_extension_data.Get().ports.end();
}
-static ExtensionData::PortData& GetPortData(int port_id) {
+ExtensionData::PortData& GetPortData(int port_id) {
return g_extension_data.Get().ports[port_id];
}
-static void ClearPortData(int port_id) {
+void ClearPortData(int port_id) {
g_extension_data.Get().ports.erase(port_id);
}
@@ -77,11 +79,10 @@ const char kPortClosedError[] = "Attempting to use a disconnected port object";
const char kReceivingEndDoesntExistError[] =
"Could not establish connection. Receiving end does not exist.";
-class ExtensionImpl : public extensions::ChromeV8Extension {
+class ExtensionImpl : public ChromeV8Extension {
public:
- explicit ExtensionImpl(extensions::Dispatcher* dispatcher,
- extensions::ChromeV8Context* context)
- : extensions::ChromeV8Extension(dispatcher, context) {
+ ExtensionImpl(Dispatcher* dispatcher, ChromeV8Context* context)
+ : ChromeV8Extension(dispatcher, context) {
RouteFunction("CloseChannel",
base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this)));
RouteFunction("PortAddRef",
@@ -97,6 +98,11 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
virtual ~ExtensionImpl() {}
+ void ClearPortDataAndNotifyDispatcher(int port_id) {
+ ClearPortData(port_id);
+ dispatcher()->ClearPortData(port_id);
+ }
+
// Sends a message along the given channel.
void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
content::RenderView* renderview = GetRenderView();
@@ -117,9 +123,8 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
renderview->Send(new ExtensionHostMsg_PostMessage(
renderview->GetRoutingID(), port_id,
- extensions::Message(
- *v8::String::Utf8Value(args[1]),
- blink::WebUserGestureIndicator::isProcessingUserGesture())));
+ Message(*v8::String::Utf8Value(args[1]),
+ blink::WebUserGestureIndicator::isProcessingUserGesture())));
}
// Forcefully disconnects a port.
@@ -140,7 +145,7 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
new ExtensionHostMsg_CloseChannel(port_id, std::string()));
}
- ClearPortData(port_id);
+ ClearPortDataAndNotifyDispatcher(port_id);
}
// A new port has been created for a context. This occurs both when script
@@ -167,7 +172,7 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
// Send via the RenderThread because the RenderView might be closing.
content::RenderThread::Get()->Send(
new ExtensionHostMsg_CloseChannel(port_id, std::string()));
- ClearPortData(port_id);
+ ClearPortDataAndNotifyDispatcher(port_id);
}
}
@@ -210,8 +215,8 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
callback->Call(context->Global(), 0, NULL);
}
- extensions::ScopedPersistent<v8::Object> object_;
- extensions::ScopedPersistent<v8::Function> callback_;
+ ScopedPersistent<v8::Object> object_;
+ ScopedPersistent<v8::Function> callback_;
v8::Isolate* isolate_;
DISALLOW_COPY_AND_ASSIGN(GCCallback);
@@ -232,8 +237,6 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
} // namespace
-namespace extensions {
-
ChromeV8Extension* MessagingBindings::Get(
Dispatcher* dispatcher,
ChromeV8Context* context) {
@@ -272,13 +275,14 @@ void MessagingBindings::DispatchOnConnect(
continue;
v8::Handle<v8::Value> tab = v8::Null(isolate);
- if (!source_tab.empty())
- tab = converter->ToV8Value(&source_tab, (*it)->v8_context());
-
v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate);
- if ((*it)->extension()) {
+ const Extension* extension = (*it)->extension();
+ if (extension) {
+ if (!source_tab.empty() && !extension->is_platform_app())
+ tab = converter->ToV8Value(&source_tab, (*it)->v8_context());
+
ExternallyConnectableInfo* externally_connectable =
- ExternallyConnectableInfo::Get((*it)->extension());
+ ExternallyConnectableInfo::Get(extension);
if (externally_connectable &&
externally_connectable->accepts_tls_channel_id) {
tls_channel_id_value =
@@ -290,23 +294,31 @@ void MessagingBindings::DispatchOnConnect(
}
v8::Handle<v8::Value> arguments[] = {
+ // portId
v8::Integer::New(isolate, target_port_id),
+ // channelName
v8::String::NewFromUtf8(isolate,
channel_name.c_str(),
v8::String::kNormalString,
channel_name.size()),
- tab, v8::String::NewFromUtf8(isolate,
- source_extension_id.c_str(),
- v8::String::kNormalString,
- source_extension_id.size()),
+ // sourceTab
+ tab,
+ // sourceExtensionId
+ v8::String::NewFromUtf8(isolate,
+ source_extension_id.c_str(),
+ v8::String::kNormalString,
+ source_extension_id.size()),
+ // targetExtensionId
v8::String::NewFromUtf8(isolate,
target_extension_id.c_str(),
v8::String::kNormalString,
target_extension_id.size()),
+ // sourceUrl
v8::String::NewFromUtf8(isolate,
source_url_spec.c_str(),
v8::String::kNormalString,
source_url_spec.size()),
+ // tlsChannelId
tls_channel_id_value,
};
diff --git a/chrome/renderer/extensions/request_sender.cc b/chrome/renderer/extensions/request_sender.cc
index a08cca3..c01e0ba 100644
--- a/chrome/renderer/extensions/request_sender.cc
+++ b/chrome/renderer/extensions/request_sender.cc
@@ -26,7 +26,22 @@ struct PendingRequest {
RequestSender::Source* source;
};
-RequestSender::RequestSender(Dispatcher* dispatcher) : dispatcher_(dispatcher) {
+RequestSender::ScopedTabID::ScopedTabID(RequestSender* request_sender,
+ int tab_id)
+ : request_sender_(request_sender),
+ tab_id_(tab_id),
+ previous_tab_id_(request_sender->source_tab_id_) {
+ request_sender_->source_tab_id_ = tab_id;
+}
+
+RequestSender::ScopedTabID::~ScopedTabID() {
+ DCHECK_EQ(tab_id_, request_sender_->source_tab_id_);
+ request_sender_->source_tab_id_ = previous_tab_id_;
+}
+
+RequestSender::RequestSender(Dispatcher* dispatcher)
+ : dispatcher_(dispatcher),
+ source_tab_id_(-1) {
}
RequestSender::~RequestSender() {
@@ -90,6 +105,7 @@ void RequestSender::StartRequest(Source* source,
params.arguments.Swap(value_args);
params.extension_id = context->GetExtensionID();
params.source_url = source_url;
+ params.source_tab_id = source_tab_id_;
params.request_id = request_id;
params.has_callback = has_callback;
params.user_gesture =
diff --git a/chrome/renderer/extensions/request_sender.h b/chrome/renderer/extensions/request_sender.h
index 618a967..1f59ab8 100644
--- a/chrome/renderer/extensions/request_sender.h
+++ b/chrome/renderer/extensions/request_sender.h
@@ -42,6 +42,20 @@ class RequestSender {
const std::string& error) = 0;
};
+ // Helper class to (re)set the |source_tab_id_| below.
+ class ScopedTabID {
+ public:
+ ScopedTabID(RequestSender* request_sender, int tab_id);
+ ~ScopedTabID();
+
+ private:
+ RequestSender* const request_sender_;
+ const int tab_id_;
+ const int previous_tab_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTabID);
+ };
+
explicit RequestSender(Dispatcher* dispatcher);
~RequestSender();
@@ -73,6 +87,7 @@ class RequestSender {
void InvalidateSource(Source* source);
private:
+ friend class ScopedTabID;
typedef std::map<int, linked_ptr<PendingRequest> > PendingRequestMap;
void InsertRequest(int request_id, PendingRequest* pending_request);
@@ -81,6 +96,8 @@ class RequestSender {
Dispatcher* dispatcher_;
PendingRequestMap pending_requests_;
+ int source_tab_id_; // Id of the tab sending the request, or -1 if no tab.
+
DISALLOW_COPY_AND_ASSIGN(RequestSender);
};
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index be5192d..8c7c752 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -37,7 +37,7 @@ class UIThreadExtensionFunction::RenderHostTracker
public:
explicit RenderHostTracker(UIThreadExtensionFunction* function)
: content::WebContentsObserver(
- function->render_view_host() ?
+ function->render_view_host() ?
WebContents::FromRenderViewHost(function->render_view_host()) :
WebContents::FromRenderFrameHost(
function->render_frame_host())),
@@ -77,7 +77,9 @@ ExtensionFunction::ExtensionFunction()
include_incognito_(false),
user_gesture_(false),
bad_message_(false),
- histogram_value_(extensions::functions::UNKNOWN) {}
+ histogram_value_(extensions::functions::UNKNOWN),
+ source_tab_id_(-1) {
+}
ExtensionFunction::~ExtensionFunction() {
}
@@ -157,8 +159,11 @@ void ExtensionFunction::SendResponseImpl(bool success) {
}
UIThreadExtensionFunction::UIThreadExtensionFunction()
- : render_view_host_(NULL), render_frame_host_(NULL), context_(NULL),
- delegate_(NULL) {}
+ : render_view_host_(NULL),
+ render_frame_host_(NULL),
+ context_(NULL),
+ delegate_(NULL) {
+}
UIThreadExtensionFunction::~UIThreadExtensionFunction() {
if (dispatcher() && render_view_host())
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 49d370e..099dff1 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -192,6 +192,9 @@ class ExtensionFunction
response_callback_ = callback;
}
+ void set_source_tab_id(int source_tab_id) { source_tab_id_ = source_tab_id; }
+ int source_tab_id() const { return source_tab_id_; }
+
protected:
friend struct ExtensionFunctionDeleteTraits;
@@ -264,6 +267,10 @@ class ExtensionFunction
// The callback to run once the function has done execution.
ResponseCallback response_callback_;
+ // The ID of the tab triggered this function call, or -1 if there is no tab.
+ int source_tab_id_;
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ExtensionFunction);
};