1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
// Copyright 2014 The Chromium Authors
// 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 <utility>
#include "base/functional/bind.h"
#include "content/public/renderer/v8_value_converter.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"
#include "v8/include/v8-container.h"
#include "v8/include/v8-function-callback.h"
#include "v8/include/v8-isolate.h"
#include "v8/include/v8-primitive.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() = default;
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 v8::LocalVector<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::List 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.Append(
base::Value::FromUniquePtrValue(std::move(converted_arg)));
}
ipc_sender->SendActivityLogIPC(script_context->GetExtensionID(),
IPCMessageSender::ActivityLogCallType::APICALL,
call_name, std::move(value_args),
/*extra=*/std::string());
}
void APIActivityLogger::LogEvent(IPCMessageSender* ipc_sender,
ScriptContext* script_context,
const std::string& event_name,
base::Value::List arguments) {
if (!IsLoggingEnabled())
return;
ipc_sender->SendActivityLogIPC(script_context->GetExtensionID(),
IPCMessageSender::ActivityLogCallType::EVENT,
event_name, std::move(arguments),
/*extra=*/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::List 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.Append(
base::Value::FromUniquePtrValue(std::move(converted_arg)));
}
}
ipc_sender_->SendActivityLogIPC(extension_id, call_type, call_name,
std::move(arguments), extra);
}
} // namespace extensions
|