[go: nahoru, domu]

blob: 22b23f3518489ab6744d6e21ce5bfc217c1bbf30 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/renderer/api_activity_logger.h"
#include <stddef.h>
#include <string>
#include "base/bind.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/v8_value_converter.h"
#include "extensions/common/extension_messages.h"
#include "extensions/renderer/activity_log_converter_strategy.h"
#include "extensions/renderer/dispatcher.h"
#include "extensions/renderer/extensions_renderer_client.h"
#include "extensions/renderer/ipc_message_sender.h"
#include "extensions/renderer/script_context.h"
#include "extensions/renderer/worker_script_context_set.h"
#include "extensions/renderer/worker_thread_util.h"
namespace extensions {
namespace {
bool g_log_for_testing = false;
ScriptContext* GetContextByV8Context(v8::Local<v8::Context> context) {
if (worker_thread_util::IsWorkerThread()) {
return Dispatcher::GetWorkerScriptContextSet()->GetContextByV8Context(
context);
}
return ScriptContextSet::GetContextByV8Context(context);
}
} // namespace
APIActivityLogger::APIActivityLogger(IPCMessageSender* ipc_sender,
ScriptContext* context)
: ObjectBackedNativeHandler(context), ipc_sender_(ipc_sender) {}
APIActivityLogger::~APIActivityLogger() {}
void APIActivityLogger::AddRoutes() {
RouteHandlerFunction(
"LogEvent",
base::BindRepeating(&APIActivityLogger::LogForJS, base::Unretained(this),
IPCMessageSender::ActivityLogCallType::EVENT));
RouteHandlerFunction(
"LogAPICall",
base::BindRepeating(&APIActivityLogger::LogForJS, base::Unretained(this),
IPCMessageSender::ActivityLogCallType::APICALL));
}
// static
bool APIActivityLogger::IsLoggingEnabled() {
const Dispatcher* dispatcher =
ExtensionsRendererClient::Get()->GetDispatcher();
return (dispatcher && // dispatcher can be null in unittests.
dispatcher->activity_logging_enabled()) ||
g_log_for_testing;
}
// static
void APIActivityLogger::LogAPICall(
IPCMessageSender* ipc_sender,
v8::Local<v8::Context> context,
const std::string& call_name,
const std::vector<v8::Local<v8::Value>>& arguments) {
if (!IsLoggingEnabled())
return;
ScriptContext* script_context = GetContextByV8Context(context);
if (!script_context)
return;
std::unique_ptr<content::V8ValueConverter> converter =
content::V8ValueConverter::Create();
ActivityLogConverterStrategy strategy;
converter->SetFunctionAllowed(true);
converter->SetStrategy(&strategy);
base::Value::ListStorage value_args;
value_args.reserve(arguments.size());
// TODO(devlin): This doesn't protect against custom properties, so it might
// not perfectly reflect the passed arguments.
for (const auto& arg : arguments) {
std::unique_ptr<base::Value> converted_arg =
converter->FromV8Value(arg, context);
if (!converted_arg)
converted_arg = std::make_unique<base::Value>();
value_args.push_back(
base::Value::FromUniquePtrValue(std::move(converted_arg)));
}
LogInternal(ipc_sender, IPCMessageSender::ActivityLogCallType::APICALL,
script_context->GetExtensionID(), call_name,
std::make_unique<base::ListValue>(std::move(value_args)),
std::string());
}
void APIActivityLogger::LogEvent(IPCMessageSender* ipc_sender,
ScriptContext* script_context,
const std::string& event_name,
std::unique_ptr<base::ListValue> arguments) {
if (!IsLoggingEnabled())
return;
LogInternal(ipc_sender, IPCMessageSender::ActivityLogCallType::EVENT,
script_context->GetExtensionID(), event_name,
std::move(arguments), std::string());
}
void APIActivityLogger::set_log_for_testing(bool log) {
g_log_for_testing = log;
}
void APIActivityLogger::LogForJS(
const IPCMessageSender::ActivityLogCallType call_type,
const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK_GT(args.Length(), 2);
CHECK(args[0]->IsString());
CHECK(args[1]->IsString());
CHECK(args[2]->IsArray());
if (!IsLoggingEnabled())
return;
v8::Isolate* isolate = args.GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
std::string extension_id = *v8::String::Utf8Value(isolate, args[0]);
std::string call_name = *v8::String::Utf8Value(isolate, args[1]);
std::string extra;
if (args.Length() == 4) { // Extras are optional.
CHECK(args[3]->IsString());
extra = *v8::String::Utf8Value(isolate, args[3]);
}
// Get the array of call arguments.
base::Value::ListStorage arguments;
v8::Local<v8::Array> arg_array = v8::Local<v8::Array>::Cast(args[2]);
if (arg_array->Length() > 0) {
arguments.reserve(arg_array->Length());
std::unique_ptr<content::V8ValueConverter> converter =
content::V8ValueConverter::Create();
ActivityLogConverterStrategy strategy;
converter->SetFunctionAllowed(true);
converter->SetStrategy(&strategy);
for (size_t i = 0; i < arg_array->Length(); ++i) {
// TODO(crbug.com/913942): Possibly replace ToLocalChecked here with
// actual error handling.
std::unique_ptr<base::Value> converted_arg = converter->FromV8Value(
arg_array->Get(context, i).ToLocalChecked(), context);
if (!converted_arg)
converted_arg = std::make_unique<base::Value>();
arguments.push_back(
base::Value::FromUniquePtrValue(std::move(converted_arg)));
}
}
LogInternal(ipc_sender_, call_type, extension_id, call_name,
std::make_unique<base::ListValue>(std::move(arguments)), extra);
}
// static
void APIActivityLogger::LogInternal(
IPCMessageSender* ipc_sender,
const IPCMessageSender::ActivityLogCallType call_type,
const std::string& extension_id,
const std::string& call_name,
std::unique_ptr<base::ListValue> arguments,
const std::string& extra) {
DCHECK(IsLoggingEnabled());
ExtensionHostMsg_APIActionOrEvent_Params params;
params.api_call = call_name;
params.arguments.Swap(arguments.get());
params.extra = extra;
ipc_sender->SendActivityLogIPC(extension_id, call_type, params);
}
} // namespace extensions