// 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/console.h" #include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/lazy_instance.h" #include "base/macros.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "extensions/renderer/get_script_context.h" #include "extensions/renderer/script_context.h" #include "extensions/renderer/script_context_set.h" #include "extensions/renderer/v8_helpers.h" #include "extensions/renderer/worker_thread_dispatcher.h" #include "gin/converter.h" #include "gin/per_isolate_data.h" #include "third_party/blink/public/web/web_console_message.h" namespace extensions { namespace console { namespace { // Writes |message| to stack to show up in minidump, then crashes. void CheckWithMinidump(const std::string& message) { DEBUG_ALIAS_FOR_CSTR(minidump, message.c_str(), 1024); CHECK(false) << message; } void BoundLogMethodCallback(const v8::FunctionCallbackInfo& info) { std::string message; for (int i = 0; i < info.Length(); ++i) { if (i > 0) message += " "; message += *v8::String::Utf8Value(info.GetIsolate(), info[i]); } ScriptContext* script_context = GetScriptContextFromV8Context(info.GetIsolate()->GetCurrentContext()); // TODO(devlin): Consider (D)CHECK(script_context) const auto level = static_cast( info.Data().As()->Value()); AddMessage(script_context, level, message); } gin::WrapperInfo kWrapperInfo = {gin::kEmbedderNativeGin}; } // namespace void Fatal(ScriptContext* context, const std::string& message) { AddMessage(context, blink::mojom::ConsoleMessageLevel::kError, message); CheckWithMinidump(message); } void AddMessage(ScriptContext* script_context, blink::mojom::ConsoleMessageLevel level, const std::string& message) { if (!script_context) { LOG(WARNING) << "Could not log \"" << message << "\": no ScriptContext found"; return; } if (!script_context->is_valid()) { LOG(WARNING) << "Could not log \"" << message << "\": ScriptContext invalidated."; return; } blink::WebConsoleMessage web_console_message( level, blink::WebString::FromUTF8(message)); blink::WebConsoleMessage::LogWebConsoleMessage(script_context->v8_context(), web_console_message); } v8::Local AsV8Object(v8::Isolate* isolate) { v8::EscapableHandleScope handle_scope(isolate); gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); v8::Local templ = data->GetObjectTemplate(&kWrapperInfo); if (templ.IsEmpty()) { templ = v8::ObjectTemplate::New(isolate); static const struct { const char* name; blink::mojom::ConsoleMessageLevel level; } methods[] = { {"debug", blink::mojom::ConsoleMessageLevel::kVerbose}, {"log", blink::mojom::ConsoleMessageLevel::kInfo}, {"warn", blink::mojom::ConsoleMessageLevel::kWarning}, {"error", blink::mojom::ConsoleMessageLevel::kError}, }; for (const auto& method : methods) { v8::Local function = v8::FunctionTemplate::New( isolate, BoundLogMethodCallback, v8::Integer::New(isolate, static_cast(method.level)), v8::Local(), 0, v8::ConstructorBehavior::kThrow); templ->Set(gin::StringToSymbol(isolate, method.name), function); } data->SetObjectTemplate(&kWrapperInfo, templ); } return handle_scope.Escape( templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked()); } } // namespace console } // namespace extensions