mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-14 18:51:28 +00:00
Bug 1035275 - Remove unused base Chromium code. r=bbondy
This commit is contained in:
parent
e02ddd1af3
commit
d1da9cff99
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2006-2008 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 "base/base_paths.h"
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
bool PathProvider(int key, FilePath* result) {
|
||||
// NOTE: DIR_CURRENT is a special case in PathService::Get
|
||||
|
||||
FilePath cur;
|
||||
switch (key) {
|
||||
case DIR_EXE:
|
||||
PathService::Get(FILE_EXE, &cur);
|
||||
cur = cur.DirName();
|
||||
break;
|
||||
case DIR_MODULE:
|
||||
PathService::Get(FILE_MODULE, &cur);
|
||||
cur = cur.DirName();
|
||||
break;
|
||||
case DIR_TEMP:
|
||||
if (!file_util::GetTempDir(&cur))
|
||||
return false;
|
||||
break;
|
||||
case DIR_TEST_DATA:
|
||||
if (!PathService::Get(DIR_SOURCE_ROOT, &cur))
|
||||
return false;
|
||||
cur = cur.Append(FILE_PATH_LITERAL("base"));
|
||||
cur = cur.Append(FILE_PATH_LITERAL("test"));
|
||||
cur = cur.Append(FILE_PATH_LITERAL("data"));
|
||||
if (!base::PathExists(cur)) // We don't want to create this.
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -1,208 +0,0 @@
|
||||
// Copyright (c) 2012 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 <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/win/scoped_co_mem.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
using base::FilePath;
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetQuickLaunchPath(bool default_user, FilePath* result) {
|
||||
if (default_user) {
|
||||
wchar_t system_buffer[MAX_PATH];
|
||||
system_buffer[0] = 0;
|
||||
// As per MSDN, passing -1 for |hToken| indicates the Default user:
|
||||
// http://msdn.microsoft.com/library/windows/desktop/bb762181.aspx
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA,
|
||||
reinterpret_cast<HANDLE>(-1), SHGFP_TYPE_CURRENT,
|
||||
system_buffer))) {
|
||||
return false;
|
||||
}
|
||||
*result = FilePath(system_buffer);
|
||||
} else if (!PathService::Get(base::DIR_APP_DATA, result)) {
|
||||
// For the current user, grab the APPDATA directory directly from the
|
||||
// PathService cache.
|
||||
return false;
|
||||
}
|
||||
// According to various sources, appending
|
||||
// "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
|
||||
// reliable way to get the quick launch folder across all versions of Windows.
|
||||
// http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
|
||||
// http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
|
||||
*result = result->AppendASCII("Microsoft");
|
||||
*result = result->AppendASCII("Internet Explorer");
|
||||
*result = result->AppendASCII("Quick Launch");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace base {
|
||||
|
||||
bool PathProviderWin(int key, FilePath* result) {
|
||||
// We need to go compute the value. It would be nice to support paths with
|
||||
// names longer than MAX_PATH, but the system functions don't seem to be
|
||||
// designed for it either, with the exception of GetTempPath (but other
|
||||
// things will surely break if the temp path is too long, so we don't bother
|
||||
// handling it.
|
||||
wchar_t system_buffer[MAX_PATH];
|
||||
system_buffer[0] = 0;
|
||||
|
||||
FilePath cur;
|
||||
switch (key) {
|
||||
case base::FILE_EXE:
|
||||
GetModuleFileName(NULL, system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::FILE_MODULE: {
|
||||
// the resource containing module is assumed to be the one that
|
||||
// this code lives in, whether that's a dll or exe
|
||||
HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
GetModuleFileName(this_module, system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
}
|
||||
case base::DIR_WINDOWS:
|
||||
GetWindowsDirectory(system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_SYSTEM:
|
||||
GetSystemDirectory(system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_PROGRAM_FILESX86:
|
||||
if (base::win::OSInfo::GetInstance()->architecture() !=
|
||||
base::win::OSInfo::X86_ARCHITECTURE) {
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
}
|
||||
// Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
|
||||
case base::DIR_PROGRAM_FILES:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_IE_INTERNET_CACHE:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_COMMON_START_MENU:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_START_MENU:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_APP_DATA:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
|
||||
system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_COMMON_APP_DATA:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_PROFILE:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
|
||||
system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_LOCAL_APP_DATA_LOW:
|
||||
if (win::GetVersion() < win::VERSION_VISTA)
|
||||
return false;
|
||||
|
||||
// TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
|
||||
system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow");
|
||||
break;
|
||||
case base::DIR_LOCAL_APP_DATA:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_SOURCE_ROOT: {
|
||||
FilePath executableDir;
|
||||
// On Windows, unit tests execute two levels deep from the source root.
|
||||
// For example: chrome/{Debug|Release}/ui_tests.exe
|
||||
PathService::Get(base::DIR_EXE, &executableDir);
|
||||
cur = executableDir.DirName().DirName();
|
||||
break;
|
||||
}
|
||||
case base::DIR_APP_SHORTCUTS: {
|
||||
if (win::GetVersion() < win::VERSION_WIN8)
|
||||
return false;
|
||||
|
||||
base::win::ScopedCoMem<wchar_t> path_buf;
|
||||
if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
|
||||
&path_buf)))
|
||||
return false;
|
||||
|
||||
cur = FilePath(string16(path_buf));
|
||||
break;
|
||||
}
|
||||
case base::DIR_USER_DESKTOP:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer))) {
|
||||
return false;
|
||||
}
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_COMMON_DESKTOP:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer))) {
|
||||
return false;
|
||||
}
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_USER_QUICK_LAUNCH:
|
||||
if (!GetQuickLaunchPath(false, &cur))
|
||||
return false;
|
||||
break;
|
||||
case base::DIR_DEFAULT_USER_QUICK_LAUNCH:
|
||||
if (!GetQuickLaunchPath(true, &cur))
|
||||
return false;
|
||||
break;
|
||||
case base::DIR_TASKBAR_PINS:
|
||||
if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
|
||||
return false;
|
||||
cur = cur.AppendASCII("User Pinned");
|
||||
cur = cur.AppendASCII("TaskBar");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -1,424 +0,0 @@
|
||||
// Copyright (c) 2012 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 "base/command_line.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
using base::FilePath;
|
||||
|
||||
CommandLine* CommandLine::current_process_commandline_ = NULL;
|
||||
|
||||
namespace {
|
||||
const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
|
||||
const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
|
||||
// Since we use a lazy match, make sure that longer versions (like "--") are
|
||||
// listed before shorter versions (like "-") of similar prefixes.
|
||||
#if defined(OS_WIN)
|
||||
const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
|
||||
#elif defined(OS_POSIX)
|
||||
// Unixes don't use slash as a switch.
|
||||
const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"};
|
||||
#endif
|
||||
|
||||
size_t GetSwitchPrefixLength(const CommandLine::StringType& string) {
|
||||
for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
|
||||
CommandLine::StringType prefix(kSwitchPrefixes[i]);
|
||||
if (string.compare(0, prefix.length(), prefix) == 0)
|
||||
return prefix.length();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fills in |switch_string| and |switch_value| if |string| is a switch.
|
||||
// This will preserve the input switch prefix in the output |switch_string|.
|
||||
bool IsSwitch(const CommandLine::StringType& string,
|
||||
CommandLine::StringType* switch_string,
|
||||
CommandLine::StringType* switch_value) {
|
||||
switch_string->clear();
|
||||
switch_value->clear();
|
||||
size_t prefix_length = GetSwitchPrefixLength(string);
|
||||
if (prefix_length == 0 || prefix_length == string.length())
|
||||
return false;
|
||||
|
||||
const size_t equals_position = string.find(kSwitchValueSeparator);
|
||||
*switch_string = string.substr(0, equals_position);
|
||||
if (equals_position != CommandLine::StringType::npos)
|
||||
*switch_value = string.substr(equals_position + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append switches and arguments, keeping switches before arguments.
|
||||
void AppendSwitchesAndArguments(CommandLine& command_line,
|
||||
const CommandLine::StringVector& argv) {
|
||||
bool parse_switches = true;
|
||||
for (size_t i = 1; i < argv.size(); ++i) {
|
||||
CommandLine::StringType arg = argv[i];
|
||||
TrimWhitespace(arg, TRIM_ALL, &arg);
|
||||
|
||||
CommandLine::StringType switch_string;
|
||||
CommandLine::StringType switch_value;
|
||||
parse_switches &= (arg != kSwitchTerminator);
|
||||
if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
|
||||
#if defined(OS_WIN)
|
||||
command_line.AppendSwitchNative(WideToASCII(switch_string), switch_value);
|
||||
#elif defined(OS_POSIX)
|
||||
command_line.AppendSwitchNative(switch_string, switch_value);
|
||||
#endif
|
||||
} else {
|
||||
command_line.AppendArgNative(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lowercase switches for backwards compatiblity *on Windows*.
|
||||
std::string LowerASCIIOnWindows(const std::string& string) {
|
||||
#if defined(OS_WIN)
|
||||
return StringToLowerASCII(string);
|
||||
#elif defined(OS_POSIX)
|
||||
return string;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
|
||||
std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) {
|
||||
// We follow the quoting rules of CommandLineToArgvW.
|
||||
// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
|
||||
// No quoting necessary.
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::wstring out;
|
||||
out.push_back(L'"');
|
||||
for (size_t i = 0; i < arg.size(); ++i) {
|
||||
if (arg[i] == '\\') {
|
||||
// Find the extent of this run of backslashes.
|
||||
size_t start = i, end = start + 1;
|
||||
for (; end < arg.size() && arg[end] == '\\'; ++end)
|
||||
/* empty */;
|
||||
size_t backslash_count = end - start;
|
||||
|
||||
// Backslashes are escapes only if the run is followed by a double quote.
|
||||
// Since we also will end the string with a double quote, we escape for
|
||||
// either a double quote or the end of the string.
|
||||
if (end == arg.size() || arg[end] == '"') {
|
||||
// To quote, we need to output 2x as many backslashes.
|
||||
backslash_count *= 2;
|
||||
}
|
||||
for (size_t j = 0; j < backslash_count; ++j)
|
||||
out.push_back('\\');
|
||||
|
||||
// Advance i to one before the end to balance i++ in loop.
|
||||
i = end - 1;
|
||||
} else if (arg[i] == '"') {
|
||||
out.push_back('\\');
|
||||
out.push_back('"');
|
||||
} else {
|
||||
out.push_back(arg[i]);
|
||||
}
|
||||
}
|
||||
out.push_back('"');
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
CommandLine::CommandLine(NoProgram no_program)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(const FilePath& program)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
SetProgram(program);
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
InitFromArgv(argc, argv);
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(const StringVector& argv)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
InitFromArgv(argv);
|
||||
}
|
||||
|
||||
CommandLine::~CommandLine() {
|
||||
}
|
||||
|
||||
// static
|
||||
bool CommandLine::Init(int argc, const char* const* argv) {
|
||||
if (current_process_commandline_) {
|
||||
// If this is intentional, Reset() must be called first. If we are using
|
||||
// the shared build mode, we have to share a single object across multiple
|
||||
// shared libraries.
|
||||
return false;
|
||||
}
|
||||
|
||||
current_process_commandline_ = new CommandLine(NO_PROGRAM);
|
||||
#if defined(OS_WIN)
|
||||
current_process_commandline_->ParseFromString(::GetCommandLineW());
|
||||
#elif defined(OS_POSIX)
|
||||
current_process_commandline_->InitFromArgv(argc, argv);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void CommandLine::Reset() {
|
||||
DCHECK(current_process_commandline_);
|
||||
delete current_process_commandline_;
|
||||
current_process_commandline_ = NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
CommandLine* CommandLine::ForCurrentProcess() {
|
||||
DCHECK(current_process_commandline_);
|
||||
return current_process_commandline_;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CommandLine::InitializedForCurrentProcess() {
|
||||
return !!current_process_commandline_;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// static
|
||||
CommandLine CommandLine::FromString(const std::wstring& command_line) {
|
||||
CommandLine cmd(NO_PROGRAM);
|
||||
cmd.ParseFromString(command_line);
|
||||
return cmd;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CommandLine::InitFromArgv(int argc,
|
||||
const CommandLine::CharType* const* argv) {
|
||||
StringVector new_argv;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
new_argv.push_back(argv[i]);
|
||||
InitFromArgv(new_argv);
|
||||
}
|
||||
|
||||
void CommandLine::InitFromArgv(const StringVector& argv) {
|
||||
argv_ = StringVector(1);
|
||||
switches_.clear();
|
||||
begin_args_ = 1;
|
||||
SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
|
||||
AppendSwitchesAndArguments(*this, argv);
|
||||
}
|
||||
|
||||
CommandLine::StringType CommandLine::GetCommandLineString() const {
|
||||
StringType string(argv_[0]);
|
||||
#if defined(OS_WIN)
|
||||
string = QuoteForCommandLineToArgvW(string);
|
||||
#endif
|
||||
StringType params(GetArgumentsString());
|
||||
if (!params.empty()) {
|
||||
string.append(StringType(FILE_PATH_LITERAL(" ")));
|
||||
string.append(params);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
CommandLine::StringType CommandLine::GetArgumentsString() const {
|
||||
StringType params;
|
||||
// Append switches and arguments.
|
||||
bool parse_switches = true;
|
||||
for (size_t i = 1; i < argv_.size(); ++i) {
|
||||
StringType arg = argv_[i];
|
||||
StringType switch_string;
|
||||
StringType switch_value;
|
||||
parse_switches &= arg != kSwitchTerminator;
|
||||
if (i > 1)
|
||||
params.append(StringType(FILE_PATH_LITERAL(" ")));
|
||||
if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
|
||||
params.append(switch_string);
|
||||
if (!switch_value.empty()) {
|
||||
#if defined(OS_WIN)
|
||||
switch_value = QuoteForCommandLineToArgvW(switch_value);
|
||||
#endif
|
||||
params.append(kSwitchValueSeparator + switch_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if defined(OS_WIN)
|
||||
arg = QuoteForCommandLineToArgvW(arg);
|
||||
#endif
|
||||
params.append(arg);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
FilePath CommandLine::GetProgram() const {
|
||||
return FilePath(argv_[0]);
|
||||
}
|
||||
|
||||
void CommandLine::SetProgram(const FilePath& program) {
|
||||
TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
|
||||
}
|
||||
|
||||
bool CommandLine::HasSwitch(const std::string& switch_string) const {
|
||||
return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end();
|
||||
}
|
||||
|
||||
std::string CommandLine::GetSwitchValueASCII(
|
||||
const std::string& switch_string) const {
|
||||
StringType value = GetSwitchValueNative(switch_string);
|
||||
if (!IsStringASCII(value)) {
|
||||
DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
|
||||
return std::string();
|
||||
}
|
||||
#if defined(OS_WIN)
|
||||
return WideToASCII(value);
|
||||
#else
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
FilePath CommandLine::GetSwitchValuePath(
|
||||
const std::string& switch_string) const {
|
||||
return FilePath(GetSwitchValueNative(switch_string));
|
||||
}
|
||||
|
||||
CommandLine::StringType CommandLine::GetSwitchValueNative(
|
||||
const std::string& switch_string) const {
|
||||
SwitchMap::const_iterator result = switches_.end();
|
||||
result = switches_.find(LowerASCIIOnWindows(switch_string));
|
||||
return result == switches_.end() ? StringType() : result->second;
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitch(const std::string& switch_string) {
|
||||
AppendSwitchNative(switch_string, StringType());
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitchPath(const std::string& switch_string,
|
||||
const FilePath& path) {
|
||||
AppendSwitchNative(switch_string, path.value());
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitchNative(const std::string& switch_string,
|
||||
const CommandLine::StringType& value) {
|
||||
std::string switch_key(LowerASCIIOnWindows(switch_string));
|
||||
#if defined(OS_WIN)
|
||||
StringType combined_switch_string(ASCIIToWide(switch_key));
|
||||
#elif defined(OS_POSIX)
|
||||
StringType combined_switch_string(switch_string);
|
||||
#endif
|
||||
size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
|
||||
switches_[switch_key.substr(prefix_length)] = value;
|
||||
// Preserve existing switch prefixes in |argv_|; only append one if necessary.
|
||||
if (prefix_length == 0)
|
||||
combined_switch_string = kSwitchPrefixes[0] + combined_switch_string;
|
||||
if (!value.empty())
|
||||
combined_switch_string += kSwitchValueSeparator + value;
|
||||
// Append the switch and update the switches/arguments divider |begin_args_|.
|
||||
argv_.insert(argv_.begin() + begin_args_++, combined_switch_string);
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitchASCII(const std::string& switch_string,
|
||||
const std::string& value_string) {
|
||||
#if defined(OS_WIN)
|
||||
AppendSwitchNative(switch_string, ASCIIToWide(value_string));
|
||||
#elif defined(OS_POSIX)
|
||||
AppendSwitchNative(switch_string, value_string);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CommandLine::CopySwitchesFrom(const CommandLine& source,
|
||||
const char* const switches[],
|
||||
size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (source.HasSwitch(switches[i]))
|
||||
AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i]));
|
||||
}
|
||||
}
|
||||
|
||||
CommandLine::StringVector CommandLine::GetArgs() const {
|
||||
// Gather all arguments after the last switch (may include kSwitchTerminator).
|
||||
StringVector args(argv_.begin() + begin_args_, argv_.end());
|
||||
// Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
|
||||
StringVector::iterator switch_terminator =
|
||||
std::find(args.begin(), args.end(), kSwitchTerminator);
|
||||
if (switch_terminator != args.end())
|
||||
args.erase(switch_terminator);
|
||||
return args;
|
||||
}
|
||||
|
||||
void CommandLine::AppendArg(const std::string& value) {
|
||||
#if defined(OS_WIN)
|
||||
DCHECK(IsStringUTF8(value));
|
||||
AppendArgNative(UTF8ToWide(value));
|
||||
#elif defined(OS_POSIX)
|
||||
AppendArgNative(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CommandLine::AppendArgPath(const FilePath& path) {
|
||||
AppendArgNative(path.value());
|
||||
}
|
||||
|
||||
void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
|
||||
argv_.push_back(value);
|
||||
}
|
||||
|
||||
void CommandLine::AppendArguments(const CommandLine& other,
|
||||
bool include_program) {
|
||||
if (include_program)
|
||||
SetProgram(other.GetProgram());
|
||||
AppendSwitchesAndArguments(*this, other.argv());
|
||||
}
|
||||
|
||||
void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
|
||||
if (wrapper.empty())
|
||||
return;
|
||||
// The wrapper may have embedded arguments (like "gdb --args"). In this case,
|
||||
// we don't pretend to do anything fancy, we just split on spaces.
|
||||
StringVector wrapper_argv;
|
||||
base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
|
||||
// Prepend the wrapper and update the switches/arguments |begin_args_|.
|
||||
argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
|
||||
begin_args_ += wrapper_argv.size();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void CommandLine::ParseFromString(const std::wstring& command_line) {
|
||||
std::wstring command_line_string;
|
||||
TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
|
||||
if (command_line_string.empty())
|
||||
return;
|
||||
|
||||
int num_args = 0;
|
||||
wchar_t** args = NULL;
|
||||
args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
|
||||
|
||||
DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
|
||||
<< command_line;
|
||||
InitFromArgv(num_args, args);
|
||||
LocalFree(args);
|
||||
}
|
||||
#endif
|
@ -1,178 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
// This class works with command lines: building and parsing.
|
||||
// Arguments with prefixes ('--', '-', and on Windows, '/') are switches.
|
||||
// Switches will precede all other arguments without switch prefixes.
|
||||
// Switches can optionally have values, delimited by '=', e.g., "-switch=value".
|
||||
// An argument of "--" will terminate switch parsing during initialization,
|
||||
// interpreting subsequent tokens as non-switch arguments, regardless of prefix.
|
||||
|
||||
// There is a singleton read-only CommandLine that represents the command line
|
||||
// that the current process was started with. It must be initialized in main().
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H_
|
||||
#define BASE_COMMAND_LINE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
class BASE_EXPORT CommandLine {
|
||||
public:
|
||||
#if defined(OS_WIN)
|
||||
// The native command line string type.
|
||||
typedef std::wstring StringType;
|
||||
#elif defined(OS_POSIX)
|
||||
typedef std::string StringType;
|
||||
#endif
|
||||
|
||||
typedef StringType::value_type CharType;
|
||||
typedef std::vector<StringType> StringVector;
|
||||
typedef std::map<std::string, StringType> SwitchMap;
|
||||
|
||||
// A constructor for CommandLines that only carry switches and arguments.
|
||||
enum NoProgram { NO_PROGRAM };
|
||||
explicit CommandLine(NoProgram no_program);
|
||||
|
||||
// Construct a new command line with |program| as argv[0].
|
||||
explicit CommandLine(const base::FilePath& program);
|
||||
|
||||
// Construct a new command line from an argument list.
|
||||
CommandLine(int argc, const CharType* const* argv);
|
||||
explicit CommandLine(const StringVector& argv);
|
||||
|
||||
~CommandLine();
|
||||
|
||||
// Initialize the current process CommandLine singleton. On Windows, ignores
|
||||
// its arguments (we instead parse GetCommandLineW() directly) because we
|
||||
// don't trust the CRT's parsing of the command line, but it still must be
|
||||
// called to set up the command line. Returns false if initialization has
|
||||
// already occurred, and true otherwise. Only the caller receiving a 'true'
|
||||
// return value should take responsibility for calling Reset.
|
||||
static bool Init(int argc, const char* const* argv);
|
||||
|
||||
// Destroys the current process CommandLine singleton. This is necessary if
|
||||
// you want to reset the base library to its initial state (for example, in an
|
||||
// outer library that needs to be able to terminate, and be re-initialized).
|
||||
// If Init is called only once, as in main(), Reset() is not necessary.
|
||||
static void Reset();
|
||||
|
||||
// Get the singleton CommandLine representing the current process's
|
||||
// command line. Note: returned value is mutable, but not thread safe;
|
||||
// only mutate if you know what you're doing!
|
||||
static CommandLine* ForCurrentProcess();
|
||||
|
||||
// Returns true if the CommandLine has been initialized for the given process.
|
||||
static bool InitializedForCurrentProcess();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
static CommandLine FromString(const std::wstring& command_line);
|
||||
#endif
|
||||
|
||||
// Initialize from an argv vector.
|
||||
void InitFromArgv(int argc, const CharType* const* argv);
|
||||
void InitFromArgv(const StringVector& argv);
|
||||
|
||||
// Constructs and returns the represented command line string.
|
||||
// CAUTION! This should be avoided on POSIX because quoting behavior is
|
||||
// unclear.
|
||||
StringType GetCommandLineString() const;
|
||||
|
||||
// Constructs and returns the represented arguments string.
|
||||
// CAUTION! This should be avoided on POSIX because quoting behavior is
|
||||
// unclear.
|
||||
StringType GetArgumentsString() const;
|
||||
|
||||
// Returns the original command line string as a vector of strings.
|
||||
const StringVector& argv() const { return argv_; }
|
||||
|
||||
// Get and Set the program part of the command line string (the first item).
|
||||
base::FilePath GetProgram() const;
|
||||
void SetProgram(const base::FilePath& program);
|
||||
|
||||
// Returns true if this command line contains the given switch.
|
||||
// (Switch names are case-insensitive).
|
||||
bool HasSwitch(const std::string& switch_string) const;
|
||||
|
||||
// Returns the value associated with the given switch. If the switch has no
|
||||
// value or isn't present, this method returns the empty string.
|
||||
std::string GetSwitchValueASCII(const std::string& switch_string) const;
|
||||
base::FilePath GetSwitchValuePath(const std::string& switch_string) const;
|
||||
StringType GetSwitchValueNative(const std::string& switch_string) const;
|
||||
|
||||
// Get a copy of all switches, along with their values.
|
||||
const SwitchMap& GetSwitches() const { return switches_; }
|
||||
|
||||
// Append a switch [with optional value] to the command line.
|
||||
// Note: Switches will precede arguments regardless of appending order.
|
||||
void AppendSwitch(const std::string& switch_string);
|
||||
void AppendSwitchPath(const std::string& switch_string,
|
||||
const base::FilePath& path);
|
||||
void AppendSwitchNative(const std::string& switch_string,
|
||||
const StringType& value);
|
||||
void AppendSwitchASCII(const std::string& switch_string,
|
||||
const std::string& value);
|
||||
|
||||
// Copy a set of switches (and any values) from another command line.
|
||||
// Commonly used when launching a subprocess.
|
||||
void CopySwitchesFrom(const CommandLine& source,
|
||||
const char* const switches[],
|
||||
size_t count);
|
||||
|
||||
// Get the remaining arguments to the command.
|
||||
StringVector GetArgs() const;
|
||||
|
||||
// Append an argument to the command line. Note that the argument is quoted
|
||||
// properly such that it is interpreted as one argument to the target command.
|
||||
// AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8.
|
||||
// Note: Switches will precede arguments regardless of appending order.
|
||||
void AppendArg(const std::string& value);
|
||||
void AppendArgPath(const base::FilePath& value);
|
||||
void AppendArgNative(const StringType& value);
|
||||
|
||||
// Append the switches and arguments from another command line to this one.
|
||||
// If |include_program| is true, include |other|'s program as well.
|
||||
void AppendArguments(const CommandLine& other, bool include_program);
|
||||
|
||||
// Insert a command before the current command.
|
||||
// Common for debuggers, like "valgrind" or "gdb --args".
|
||||
void PrependWrapper(const StringType& wrapper);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Initialize by parsing the given command line string.
|
||||
// The program name is assumed to be the first item in the string.
|
||||
void ParseFromString(const std::wstring& command_line);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Disallow default constructor; a program name must be explicitly specified.
|
||||
CommandLine();
|
||||
// Allow the copy constructor. A common pattern is to copy of the current
|
||||
// process's command line and then add some flags to it. For example:
|
||||
// CommandLine cl(*CommandLine::ForCurrentProcess());
|
||||
// cl.AppendSwitch(...);
|
||||
|
||||
// The singleton CommandLine representing the current process's command line.
|
||||
static CommandLine* current_process_commandline_;
|
||||
|
||||
// The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* }
|
||||
StringVector argv_;
|
||||
|
||||
// Parsed-out switch keys and values.
|
||||
SwitchMap switches_;
|
||||
|
||||
// The index after the program and switches, any arguments start here.
|
||||
size_t begin_args_;
|
||||
};
|
||||
|
||||
#endif // BASE_COMMAND_LINE_H_
|
@ -1,37 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_CRITICAL_CLOSURE_H_
|
||||
#define BASE_CRITICAL_CLOSURE_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Returns a closure that will continue to run for a period of time when the
|
||||
// application goes to the background if possible on platforms where
|
||||
// applications don't execute while backgrounded, otherwise the original task is
|
||||
// returned.
|
||||
//
|
||||
// Example:
|
||||
// file_message_loop_proxy_->PostTask(
|
||||
// FROM_HERE,
|
||||
// MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
|
||||
//
|
||||
// Note new closures might be posted in this closure. If the new closures need
|
||||
// background running time, |MakeCriticalClosure| should be applied on them
|
||||
// before posting.
|
||||
#if defined(OS_IOS)
|
||||
base::Closure MakeCriticalClosure(const base::Closure& closure);
|
||||
#else
|
||||
inline base::Closure MakeCriticalClosure(const base::Closure& closure) {
|
||||
// No-op for platforms where the application does not need to acquire
|
||||
// background time for closures to finish when it goes into the background.
|
||||
return closure;
|
||||
}
|
||||
#endif // !defined(OS_IOS)
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CRITICAL_CLOSURE_H_
|
@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#ifndef BASE_ENVIRONMENT_H_
|
||||
#define BASE_ENVIRONMENT_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace env_vars {
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
BASE_EXPORT extern const char kHome[];
|
||||
#endif
|
||||
|
||||
} // namespace env_vars
|
||||
|
||||
class BASE_EXPORT Environment {
|
||||
public:
|
||||
virtual ~Environment();
|
||||
|
||||
// Static factory method that returns the implementation that provide the
|
||||
// appropriate platform-specific instance.
|
||||
static Environment* Create();
|
||||
|
||||
// Gets an environment variable's value and stores it in |result|.
|
||||
// Returns false if the key is unset.
|
||||
virtual bool GetVar(const char* variable_name, std::string* result) = 0;
|
||||
|
||||
// Syntactic sugar for GetVar(variable_name, NULL);
|
||||
virtual bool HasVar(const char* variable_name);
|
||||
|
||||
// Returns true on success, otherwise returns false.
|
||||
virtual bool SetVar(const char* variable_name,
|
||||
const std::string& new_value) = 0;
|
||||
|
||||
// Returns true on success, otherwise returns false.
|
||||
virtual bool UnSetVar(const char* variable_name) = 0;
|
||||
};
|
||||
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
typedef string16 NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
// Returns a modified environment vector constructed from the given environment
|
||||
// and the list of changes given in |changes|. Each key in the environment is
|
||||
// matched against the first element of the pairs. In the event of a match, the
|
||||
// value is replaced by the second of the pair, unless the second is empty, in
|
||||
// which case the key-value is removed.
|
||||
//
|
||||
// This Windows version takes and returns a Windows-style environment block
|
||||
// which is a concatenated list of null-terminated 16-bit strings. The end is
|
||||
// marked by a double-null terminator. The size of the returned string will
|
||||
// include the terminators.
|
||||
BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
|
||||
const EnvironmentMap& changes);
|
||||
|
||||
#elif defined(OS_POSIX)
|
||||
|
||||
typedef std::string NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
// See general comments for the Windows version above.
|
||||
//
|
||||
// This Posix version takes and returns a Posix-style environment block, which
|
||||
// is a null-terminated list of pointers to null-terminated strings. The
|
||||
// returned array will have appended to it the storage for the array itself so
|
||||
// there is only one pointer to manage, but this means that you can't copy the
|
||||
// array without keeping the original around.
|
||||
BASE_EXPORT scoped_ptr<char*[]> AlterEnvironment(
|
||||
const char* const* env,
|
||||
const EnvironmentMap& changes);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ENVIRONMENT_H_
|
@ -1,264 +0,0 @@
|
||||
// Copyright (c) 2012 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 "base/file_util.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "base/files/file_enumerator.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
|
||||
|
||||
// The maximum number of 'uniquified' files we will try to create.
|
||||
// This is used when the filename we're trying to download is already in use,
|
||||
// so we create a new unique filename by appending " (nnn)" before the
|
||||
// extension, where 1 <= nnn <= kMaxUniqueFiles.
|
||||
// Also used by code that cleans up said files.
|
||||
static const int kMaxUniqueFiles = 100;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool g_bug108724_debug = false;
|
||||
|
||||
int64 ComputeDirectorySize(const FilePath& root_path) {
|
||||
int64 running_size = 0;
|
||||
FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
|
||||
while (!file_iter.Next().empty())
|
||||
running_size += file_iter.GetInfo().GetSize();
|
||||
return running_size;
|
||||
}
|
||||
|
||||
bool Move(const FilePath& from_path, const FilePath& to_path) {
|
||||
if (from_path.ReferencesParent() || to_path.ReferencesParent())
|
||||
return false;
|
||||
return internal::MoveUnsafe(from_path, to_path);
|
||||
}
|
||||
|
||||
bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
|
||||
if (from_path.ReferencesParent() || to_path.ReferencesParent())
|
||||
return false;
|
||||
return internal::CopyFileUnsafe(from_path, to_path);
|
||||
}
|
||||
|
||||
bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
|
||||
// We open the file in binary format even if they are text files because
|
||||
// we are just comparing that bytes are exactly same in both files and not
|
||||
// doing anything smart with text formatting.
|
||||
std::ifstream file1(filename1.value().c_str(),
|
||||
std::ios::in | std::ios::binary);
|
||||
std::ifstream file2(filename2.value().c_str(),
|
||||
std::ios::in | std::ios::binary);
|
||||
|
||||
// Even if both files aren't openable (and thus, in some sense, "equal"),
|
||||
// any unusable file yields a result of "false".
|
||||
if (!file1.is_open() || !file2.is_open())
|
||||
return false;
|
||||
|
||||
const int BUFFER_SIZE = 2056;
|
||||
char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
|
||||
do {
|
||||
file1.read(buffer1, BUFFER_SIZE);
|
||||
file2.read(buffer2, BUFFER_SIZE);
|
||||
|
||||
if ((file1.eof() != file2.eof()) ||
|
||||
(file1.gcount() != file2.gcount()) ||
|
||||
(memcmp(buffer1, buffer2, file1.gcount()))) {
|
||||
file1.close();
|
||||
file2.close();
|
||||
return false;
|
||||
}
|
||||
} while (!file1.eof() || !file2.eof());
|
||||
|
||||
file1.close();
|
||||
file2.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
|
||||
std::ifstream file1(filename1.value().c_str(), std::ios::in);
|
||||
std::ifstream file2(filename2.value().c_str(), std::ios::in);
|
||||
|
||||
// Even if both files aren't openable (and thus, in some sense, "equal"),
|
||||
// any unusable file yields a result of "false".
|
||||
if (!file1.is_open() || !file2.is_open())
|
||||
return false;
|
||||
|
||||
do {
|
||||
std::string line1, line2;
|
||||
getline(file1, line1);
|
||||
getline(file2, line2);
|
||||
|
||||
// Check for mismatched EOF states, or any error state.
|
||||
if ((file1.eof() != file2.eof()) ||
|
||||
file1.bad() || file2.bad()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trim all '\r' and '\n' characters from the end of the line.
|
||||
std::string::size_type end1 = line1.find_last_not_of("\r\n");
|
||||
if (end1 == std::string::npos)
|
||||
line1.clear();
|
||||
else if (end1 + 1 < line1.length())
|
||||
line1.erase(end1 + 1);
|
||||
|
||||
std::string::size_type end2 = line2.find_last_not_of("\r\n");
|
||||
if (end2 == std::string::npos)
|
||||
line2.clear();
|
||||
else if (end2 + 1 < line2.length())
|
||||
line2.erase(end2 + 1);
|
||||
|
||||
if (line1 != line2)
|
||||
return false;
|
||||
} while (!file1.eof() || !file2.eof());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFileToString(const FilePath& path, std::string* contents) {
|
||||
if (path.ReferencesParent())
|
||||
return false;
|
||||
FILE* file = file_util::OpenFile(path, "rb");
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[1 << 16];
|
||||
size_t len;
|
||||
while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
|
||||
if (contents)
|
||||
contents->append(buf, len);
|
||||
}
|
||||
file_util::CloseFile(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace file_util {
|
||||
|
||||
using base::FileEnumerator;
|
||||
using base::FilePath;
|
||||
using base::kExtensionSeparator;
|
||||
using base::kMaxUniqueFiles;
|
||||
|
||||
bool IsDirectoryEmpty(const FilePath& dir_path) {
|
||||
FileEnumerator files(dir_path, false,
|
||||
FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
|
||||
if (files.Next().empty())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* CreateAndOpenTemporaryFile(FilePath* path) {
|
||||
FilePath directory;
|
||||
if (!GetTempDir(&directory))
|
||||
return NULL;
|
||||
|
||||
return CreateAndOpenTemporaryFileInDir(directory, path);
|
||||
}
|
||||
|
||||
bool CreateDirectory(const base::FilePath& full_path) {
|
||||
return CreateDirectoryAndGetError(full_path, NULL);
|
||||
}
|
||||
|
||||
bool GetFileSize(const FilePath& file_path, int64* file_size) {
|
||||
base::PlatformFileInfo info;
|
||||
if (!GetFileInfo(file_path, &info))
|
||||
return false;
|
||||
*file_size = info.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchFile(const FilePath& path,
|
||||
const base::Time& last_accessed,
|
||||
const base::Time& last_modified) {
|
||||
int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
|
||||
if (DirectoryExists(path))
|
||||
flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
|
||||
#endif // OS_WIN
|
||||
|
||||
const base::PlatformFile file =
|
||||
base::CreatePlatformFile(path, flags, NULL, NULL);
|
||||
if (file != base::kInvalidPlatformFileValue) {
|
||||
bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
|
||||
base::ClosePlatformFile(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetLastModifiedTime(const FilePath& path,
|
||||
const base::Time& last_modified) {
|
||||
return TouchFile(path, last_modified, last_modified);
|
||||
}
|
||||
|
||||
bool CloseFile(FILE* file) {
|
||||
if (file == NULL)
|
||||
return true;
|
||||
return fclose(file) == 0;
|
||||
}
|
||||
|
||||
bool TruncateFile(FILE* file) {
|
||||
if (file == NULL)
|
||||
return false;
|
||||
long current_offset = ftell(file);
|
||||
if (current_offset == -1)
|
||||
return false;
|
||||
#if defined(OS_WIN)
|
||||
int fd = _fileno(file);
|
||||
if (_chsize(fd, current_offset) != 0)
|
||||
return false;
|
||||
#else
|
||||
int fd = fileno(file);
|
||||
if (ftruncate(fd, current_offset) != 0)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int GetUniquePathNumber(
|
||||
const FilePath& path,
|
||||
const FilePath::StringType& suffix) {
|
||||
bool have_suffix = !suffix.empty();
|
||||
if (!PathExists(path) &&
|
||||
(!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FilePath new_path;
|
||||
for (int count = 1; count <= kMaxUniqueFiles; ++count) {
|
||||
new_path =
|
||||
path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
|
||||
if (!PathExists(new_path) &&
|
||||
(!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace file_util
|
@ -1,87 +0,0 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#ifndef BASE_FILE_VERSION_INFO_H__
|
||||
#define BASE_FILE_VERSION_INFO_H__
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
#endif // OS_WIN
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
// Provides an interface for accessing the version information for a file. This
|
||||
// is the information you access when you select a file in the Windows Explorer,
|
||||
// right-click select Properties, then click the Version tab, and on the Mac
|
||||
// when you select a file in the Finder and do a Get Info.
|
||||
//
|
||||
// This list of properties is straight out of Win32's VerQueryValue
|
||||
// <http://msdn.microsoft.com/en-us/library/ms647464.aspx> and the Mac
|
||||
// version returns values from the Info.plist as appropriate. TODO(avi): make
|
||||
// this a less-obvious Windows-ism.
|
||||
|
||||
class FileVersionInfo {
|
||||
public:
|
||||
virtual ~FileVersionInfo() {}
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
// Creates a FileVersionInfo for the specified path. Returns NULL if something
|
||||
// goes wrong (typically the file does not exit or cannot be opened). The
|
||||
// returned object should be deleted when you are done with it.
|
||||
BASE_EXPORT static FileVersionInfo* CreateFileVersionInfo(
|
||||
const base::FilePath& file_path);
|
||||
#endif // OS_WIN || OS_MACOSX
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Creates a FileVersionInfo for the specified module. Returns NULL in case
|
||||
// of error. The returned object should be deleted when you are done with it.
|
||||
BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForModule(
|
||||
HMODULE module);
|
||||
|
||||
// Creates a FileVersionInfo for the current module. Returns NULL in case
|
||||
// of error. The returned object should be deleted when you are done with it.
|
||||
// This function should be inlined so that the "current module" is evaluated
|
||||
// correctly, instead of being the module that contains base.
|
||||
__forceinline static FileVersionInfo*
|
||||
CreateFileVersionInfoForCurrentModule() {
|
||||
HMODULE module = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
return CreateFileVersionInfoForModule(module);
|
||||
}
|
||||
#else
|
||||
// Creates a FileVersionInfo for the current module. Returns NULL in case
|
||||
// of error. The returned object should be deleted when you are done with it.
|
||||
BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
|
||||
#endif // OS_WIN
|
||||
|
||||
// Accessors to the different version properties.
|
||||
// Returns an empty string if the property is not found.
|
||||
virtual string16 company_name() = 0;
|
||||
virtual string16 company_short_name() = 0;
|
||||
virtual string16 product_name() = 0;
|
||||
virtual string16 product_short_name() = 0;
|
||||
virtual string16 internal_name() = 0;
|
||||
virtual string16 product_version() = 0;
|
||||
virtual string16 private_build() = 0;
|
||||
virtual string16 special_build() = 0;
|
||||
virtual string16 comments() = 0;
|
||||
virtual string16 original_filename() = 0;
|
||||
virtual string16 file_description() = 0;
|
||||
virtual string16 file_version() = 0;
|
||||
virtual string16 legal_copyright() = 0;
|
||||
virtual string16 legal_trademarks() = 0;
|
||||
virtual string16 last_change() = 0;
|
||||
virtual bool is_official_build() = 0;
|
||||
};
|
||||
|
||||
#endif // BASE_FILE_VERSION_INFO_H__
|
@ -1,62 +0,0 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#ifndef BASE_FILE_VERSION_INFO_WIN_H_
|
||||
#define BASE_FILE_VERSION_INFO_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/file_version_info.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
struct tagVS_FIXEDFILEINFO;
|
||||
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
|
||||
|
||||
class FileVersionInfoWin : public FileVersionInfo {
|
||||
public:
|
||||
BASE_EXPORT FileVersionInfoWin(void* data, int language, int code_page);
|
||||
BASE_EXPORT ~FileVersionInfoWin();
|
||||
|
||||
// Accessors to the different version properties.
|
||||
// Returns an empty string if the property is not found.
|
||||
virtual string16 company_name() OVERRIDE;
|
||||
virtual string16 company_short_name() OVERRIDE;
|
||||
virtual string16 product_name() OVERRIDE;
|
||||
virtual string16 product_short_name() OVERRIDE;
|
||||
virtual string16 internal_name() OVERRIDE;
|
||||
virtual string16 product_version() OVERRIDE;
|
||||
virtual string16 private_build() OVERRIDE;
|
||||
virtual string16 special_build() OVERRIDE;
|
||||
virtual string16 comments() OVERRIDE;
|
||||
virtual string16 original_filename() OVERRIDE;
|
||||
virtual string16 file_description() OVERRIDE;
|
||||
virtual string16 file_version() OVERRIDE;
|
||||
virtual string16 legal_copyright() OVERRIDE;
|
||||
virtual string16 legal_trademarks() OVERRIDE;
|
||||
virtual string16 last_change() OVERRIDE;
|
||||
virtual bool is_official_build() OVERRIDE;
|
||||
|
||||
// Lets you access other properties not covered above.
|
||||
BASE_EXPORT bool GetValue(const wchar_t* name, std::wstring* value);
|
||||
|
||||
// Similar to GetValue but returns a wstring (empty string if the property
|
||||
// does not exist).
|
||||
BASE_EXPORT std::wstring GetStringValue(const wchar_t* name);
|
||||
|
||||
// Get the fixed file info if it exists. Otherwise NULL
|
||||
VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; }
|
||||
|
||||
private:
|
||||
scoped_ptr_malloc<char> data_;
|
||||
int language_;
|
||||
int code_page_;
|
||||
// This is a pointer into the data_ if it exists. Otherwise NULL.
|
||||
VS_FIXEDFILEINFO* fixed_file_info_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FileVersionInfoWin);
|
||||
};
|
||||
|
||||
#endif // BASE_FILE_VERSION_INFO_WIN_H_
|
@ -1,73 +0,0 @@
|
||||
// Copyright (c) 2009 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.
|
||||
|
||||
#ifndef BASE_FORMAT_MACROS_H_
|
||||
#define BASE_FORMAT_MACROS_H_
|
||||
|
||||
// This file defines the format macros for some integer types.
|
||||
|
||||
// To print a 64-bit value in a portable way:
|
||||
// int64_t value;
|
||||
// printf("xyz:%" PRId64, value);
|
||||
// The "d" in the macro corresponds to %d; you can also use PRIu64 etc.
|
||||
//
|
||||
// For wide strings, prepend "Wide" to the macro:
|
||||
// int64_t value;
|
||||
// StringPrintf(L"xyz: %" WidePRId64, value);
|
||||
//
|
||||
// To print a size_t value in a portable way:
|
||||
// size_t size;
|
||||
// printf("xyz: %" PRIuS, size);
|
||||
// The "u" in the macro corresponds to %u, and S is for "size".
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
|
||||
#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
|
||||
#error "inttypes.h has already been included before this header file, but "
|
||||
#error "without __STDC_FORMAT_MACROS defined."
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_FORMAT_MACROS)
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
// GCC will concatenate wide and narrow strings correctly, so nothing needs to
|
||||
// be done here.
|
||||
#define WidePRId64 PRId64
|
||||
#define WidePRIu64 PRIu64
|
||||
#define WidePRIx64 PRIx64
|
||||
|
||||
#if !defined(PRIuS)
|
||||
#define PRIuS "zu"
|
||||
#endif
|
||||
|
||||
#else // OS_WIN
|
||||
|
||||
#if !defined(PRId64)
|
||||
#define PRId64 "I64d"
|
||||
#endif
|
||||
|
||||
#if !defined(PRIu64)
|
||||
#define PRIu64 "I64u"
|
||||
#endif
|
||||
|
||||
#if !defined(PRIx64)
|
||||
#define PRIx64 "I64x"
|
||||
#endif
|
||||
|
||||
#define WidePRId64 L"I64d"
|
||||
#define WidePRIu64 L"I64u"
|
||||
#define WidePRIx64 L"I64x"
|
||||
|
||||
#if !defined(PRIuS)
|
||||
#define PRIuS "Iu"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BASE_FORMAT_MACROS_H_
|
@ -1,866 +0,0 @@
|
||||
// Copyright (c) 2012 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 "base/logging.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
typedef HANDLE FileHandle;
|
||||
typedef HANDLE MutexHandle;
|
||||
// Windows warns on using write(). It prefers _write().
|
||||
#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
|
||||
// Windows doesn't define STDERR_FILENO. Define it here.
|
||||
#define STDERR_FILENO 2
|
||||
#elif defined(OS_MACOSX)
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#elif defined(OS_POSIX)
|
||||
#if defined(OS_NACL)
|
||||
#include <sys/time.h> // timespec doesn't seem to be in <time.h>
|
||||
#else
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#define MAX_PATH PATH_MAX
|
||||
typedef FILE* FileHandle;
|
||||
typedef pthread_mutex_t* MutexHandle;
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/base_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/debug/alias.h"
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/debug/stack_trace.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/synchronization/lock_impl.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "base/vlog.h"
|
||||
#if defined(OS_POSIX)
|
||||
#include "base/safe_strerror_posix.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
namespace logging {
|
||||
|
||||
DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
|
||||
|
||||
DcheckState get_dcheck_state() {
|
||||
return g_dcheck_state;
|
||||
}
|
||||
|
||||
void set_dcheck_state(DcheckState state) {
|
||||
g_dcheck_state = state;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
VlogInfo* g_vlog_info = NULL;
|
||||
VlogInfo* g_vlog_info_prev = NULL;
|
||||
|
||||
const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
|
||||
"INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
|
||||
|
||||
int min_log_level = 0;
|
||||
|
||||
LoggingDestination logging_destination = LOG_DEFAULT;
|
||||
|
||||
// For LOG_ERROR and above, always print to stderr.
|
||||
const int kAlwaysPrintErrorLevel = LOG_ERROR;
|
||||
|
||||
// Which log file to use? This is initialized by InitLogging or
|
||||
// will be lazily initialized to the default value when it is
|
||||
// first needed.
|
||||
#if defined(OS_WIN)
|
||||
typedef std::wstring PathString;
|
||||
#else
|
||||
typedef std::string PathString;
|
||||
#endif
|
||||
PathString* log_file_name = NULL;
|
||||
|
||||
// this file is lazily opened and the handle may be NULL
|
||||
FileHandle log_file = NULL;
|
||||
|
||||
// what should be prepended to each message?
|
||||
bool log_process_id = false;
|
||||
bool log_thread_id = false;
|
||||
bool log_timestamp = true;
|
||||
bool log_tickcount = false;
|
||||
|
||||
// Should we pop up fatal debug messages in a dialog?
|
||||
bool show_error_dialogs = false;
|
||||
|
||||
// An assert handler override specified by the client to be called instead of
|
||||
// the debug message dialog and process termination.
|
||||
LogAssertHandlerFunction log_assert_handler = NULL;
|
||||
// An report handler override specified by the client to be called instead of
|
||||
// the debug message dialog.
|
||||
LogReportHandlerFunction log_report_handler = NULL;
|
||||
// A log message handler that gets notified of every log message we process.
|
||||
LogMessageHandlerFunction log_message_handler = NULL;
|
||||
|
||||
// Helper functions to wrap platform differences.
|
||||
|
||||
int32 CurrentProcessId() {
|
||||
#if defined(OS_WIN)
|
||||
return GetCurrentProcessId();
|
||||
#elif defined(OS_POSIX)
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64 TickCount() {
|
||||
#if defined(OS_WIN)
|
||||
return GetTickCount();
|
||||
#elif defined(OS_MACOSX)
|
||||
return mach_absolute_time();
|
||||
#elif defined(OS_NACL)
|
||||
// NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h
|
||||
// So we have to use clock() for now.
|
||||
return clock();
|
||||
#elif defined(OS_POSIX)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
uint64 absolute_micro =
|
||||
static_cast<int64>(ts.tv_sec) * 1000000 +
|
||||
static_cast<int64>(ts.tv_nsec) / 1000;
|
||||
|
||||
return absolute_micro;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DeleteFilePath(const PathString& log_name) {
|
||||
#if defined(OS_WIN)
|
||||
DeleteFile(log_name.c_str());
|
||||
#elif defined (OS_NACL)
|
||||
// Do nothing; unlink() isn't supported on NaCl.
|
||||
#else
|
||||
unlink(log_name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
PathString GetDefaultLogFile() {
|
||||
#if defined(OS_WIN)
|
||||
// On Windows we use the same path as the exe.
|
||||
wchar_t module_name[MAX_PATH];
|
||||
GetModuleFileName(NULL, module_name, MAX_PATH);
|
||||
|
||||
PathString log_file = module_name;
|
||||
PathString::size_type last_backslash =
|
||||
log_file.rfind('\\', log_file.size());
|
||||
if (last_backslash != PathString::npos)
|
||||
log_file.erase(last_backslash + 1);
|
||||
log_file += L"debug.log";
|
||||
return log_file;
|
||||
#elif defined(OS_POSIX)
|
||||
// On other platforms we just use the current directory.
|
||||
return PathString("debug.log");
|
||||
#endif
|
||||
}
|
||||
|
||||
// This class acts as a wrapper for locking the logging files.
|
||||
// LoggingLock::Init() should be called from the main thread before any logging
|
||||
// is done. Then whenever logging, be sure to have a local LoggingLock
|
||||
// instance on the stack. This will ensure that the lock is unlocked upon
|
||||
// exiting the frame.
|
||||
// LoggingLocks can not be nested.
|
||||
class LoggingLock {
|
||||
public:
|
||||
LoggingLock() {
|
||||
LockLogging();
|
||||
}
|
||||
|
||||
~LoggingLock() {
|
||||
UnlockLogging();
|
||||
}
|
||||
|
||||
static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
|
||||
if (initialized)
|
||||
return;
|
||||
lock_log_file = lock_log;
|
||||
if (lock_log_file == LOCK_LOG_FILE) {
|
||||
#if defined(OS_WIN)
|
||||
if (!log_mutex) {
|
||||
std::wstring safe_name;
|
||||
if (new_log_file)
|
||||
safe_name = new_log_file;
|
||||
else
|
||||
safe_name = GetDefaultLogFile();
|
||||
// \ is not a legal character in mutex names so we replace \ with /
|
||||
std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
|
||||
std::wstring t(L"Global\\");
|
||||
t.append(safe_name);
|
||||
log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
|
||||
|
||||
if (log_mutex == NULL) {
|
||||
#if DEBUG
|
||||
// Keep the error code for debugging
|
||||
int error = GetLastError(); // NOLINT
|
||||
base::debug::BreakDebugger();
|
||||
#endif
|
||||
// Return nicely without putting initialized to true.
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
log_lock = new base::internal::LockImpl();
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private:
|
||||
static void LockLogging() {
|
||||
if (lock_log_file == LOCK_LOG_FILE) {
|
||||
#if defined(OS_WIN)
|
||||
::WaitForSingleObject(log_mutex, INFINITE);
|
||||
// WaitForSingleObject could have returned WAIT_ABANDONED. We don't
|
||||
// abort the process here. UI tests might be crashy sometimes,
|
||||
// and aborting the test binary only makes the problem worse.
|
||||
// We also don't use LOG macros because that might lead to an infinite
|
||||
// loop. For more info see http://crbug.com/18028.
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_mutex_lock(&log_mutex);
|
||||
#endif
|
||||
} else {
|
||||
// use the lock
|
||||
log_lock->Lock();
|
||||
}
|
||||
}
|
||||
|
||||
static void UnlockLogging() {
|
||||
if (lock_log_file == LOCK_LOG_FILE) {
|
||||
#if defined(OS_WIN)
|
||||
ReleaseMutex(log_mutex);
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_mutex_unlock(&log_mutex);
|
||||
#endif
|
||||
} else {
|
||||
log_lock->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// The lock is used if log file locking is false. It helps us avoid problems
|
||||
// with multiple threads writing to the log file at the same time. Use
|
||||
// LockImpl directly instead of using Lock, because Lock makes logging calls.
|
||||
static base::internal::LockImpl* log_lock;
|
||||
|
||||
// When we don't use a lock, we are using a global mutex. We need to do this
|
||||
// because LockFileEx is not thread safe.
|
||||
#if defined(OS_WIN)
|
||||
static MutexHandle log_mutex;
|
||||
#elif defined(OS_POSIX)
|
||||
static pthread_mutex_t log_mutex;
|
||||
#endif
|
||||
|
||||
static bool initialized;
|
||||
static LogLockingState lock_log_file;
|
||||
};
|
||||
|
||||
// static
|
||||
bool LoggingLock::initialized = false;
|
||||
// static
|
||||
base::internal::LockImpl* LoggingLock::log_lock = NULL;
|
||||
// static
|
||||
LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// static
|
||||
MutexHandle LoggingLock::log_mutex = NULL;
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
// Called by logging functions to ensure that debug_file is initialized
|
||||
// and can be used for writing. Returns false if the file could not be
|
||||
// initialized. debug_file will be NULL in this case.
|
||||
bool InitializeLogFileHandle() {
|
||||
if (log_file)
|
||||
return true;
|
||||
|
||||
if (!log_file_name) {
|
||||
// Nobody has called InitLogging to specify a debug log file, so here we
|
||||
// initialize the log file name to a default.
|
||||
log_file_name = new PathString(GetDefaultLogFile());
|
||||
}
|
||||
|
||||
if ((logging_destination & LOG_TO_FILE) != 0) {
|
||||
#if defined(OS_WIN)
|
||||
log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
|
||||
// try the current directory
|
||||
log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
|
||||
log_file = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SetFilePointer(log_file, 0, 0, FILE_END);
|
||||
#elif defined(OS_POSIX)
|
||||
log_file = fopen(log_file_name->c_str(), "a");
|
||||
if (log_file == NULL)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CloseFile(FileHandle log) {
|
||||
#if defined(OS_WIN)
|
||||
CloseHandle(log);
|
||||
#else
|
||||
fclose(log);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseLogFileUnlocked() {
|
||||
if (!log_file)
|
||||
return;
|
||||
|
||||
CloseFile(log_file);
|
||||
log_file = NULL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LoggingSettings::LoggingSettings()
|
||||
: logging_dest(LOG_DEFAULT),
|
||||
log_file(NULL),
|
||||
lock_log(LOCK_LOG_FILE),
|
||||
delete_old(APPEND_TO_OLD_LOG_FILE),
|
||||
dcheck_state(DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) {}
|
||||
|
||||
bool BaseInitLoggingImpl(const LoggingSettings& settings) {
|
||||
#if defined(OS_NACL)
|
||||
// Can log only to the system debug log.
|
||||
CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
|
||||
#endif
|
||||
g_dcheck_state = settings.dcheck_state;
|
||||
CommandLine* command_line = CommandLine::ForCurrentProcess();
|
||||
// Don't bother initializing g_vlog_info unless we use one of the
|
||||
// vlog switches.
|
||||
if (command_line->HasSwitch(switches::kV) ||
|
||||
command_line->HasSwitch(switches::kVModule)) {
|
||||
// NOTE: If g_vlog_info has already been initialized, it might be in use
|
||||
// by another thread. Don't delete the old VLogInfo, just create a second
|
||||
// one. We keep track of both to avoid memory leak warnings.
|
||||
CHECK(!g_vlog_info_prev);
|
||||
g_vlog_info_prev = g_vlog_info;
|
||||
|
||||
g_vlog_info =
|
||||
new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
|
||||
command_line->GetSwitchValueASCII(switches::kVModule),
|
||||
&min_log_level);
|
||||
}
|
||||
|
||||
logging_destination = settings.logging_dest;
|
||||
|
||||
// ignore file options unless logging to file is set.
|
||||
if ((logging_destination & LOG_TO_FILE) == 0)
|
||||
return true;
|
||||
|
||||
LoggingLock::Init(settings.lock_log, settings.log_file);
|
||||
LoggingLock logging_lock;
|
||||
|
||||
// Calling InitLogging twice or after some log call has already opened the
|
||||
// default log file will re-initialize to the new options.
|
||||
CloseLogFileUnlocked();
|
||||
|
||||
if (!log_file_name)
|
||||
log_file_name = new PathString();
|
||||
*log_file_name = settings.log_file;
|
||||
if (settings.delete_old == DELETE_OLD_LOG_FILE)
|
||||
DeleteFilePath(*log_file_name);
|
||||
|
||||
return InitializeLogFileHandle();
|
||||
}
|
||||
|
||||
void SetMinLogLevel(int level) {
|
||||
min_log_level = std::min(LOG_ERROR_REPORT, level);
|
||||
}
|
||||
|
||||
int GetMinLogLevel() {
|
||||
return min_log_level;
|
||||
}
|
||||
|
||||
int GetVlogVerbosity() {
|
||||
return std::max(-1, LOG_INFO - GetMinLogLevel());
|
||||
}
|
||||
|
||||
int GetVlogLevelHelper(const char* file, size_t N) {
|
||||
DCHECK_GT(N, 0U);
|
||||
// Note: g_vlog_info may change on a different thread during startup
|
||||
// (but will always be valid or NULL).
|
||||
VlogInfo* vlog_info = g_vlog_info;
|
||||
return vlog_info ?
|
||||
vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
|
||||
GetVlogVerbosity();
|
||||
}
|
||||
|
||||
void SetLogItems(bool enable_process_id, bool enable_thread_id,
|
||||
bool enable_timestamp, bool enable_tickcount) {
|
||||
log_process_id = enable_process_id;
|
||||
log_thread_id = enable_thread_id;
|
||||
log_timestamp = enable_timestamp;
|
||||
log_tickcount = enable_tickcount;
|
||||
}
|
||||
|
||||
void SetShowErrorDialogs(bool enable_dialogs) {
|
||||
show_error_dialogs = enable_dialogs;
|
||||
}
|
||||
|
||||
void SetLogAssertHandler(LogAssertHandlerFunction handler) {
|
||||
log_assert_handler = handler;
|
||||
}
|
||||
|
||||
void SetLogReportHandler(LogReportHandlerFunction handler) {
|
||||
log_report_handler = handler;
|
||||
}
|
||||
|
||||
void SetLogMessageHandler(LogMessageHandlerFunction handler) {
|
||||
log_message_handler = handler;
|
||||
}
|
||||
|
||||
LogMessageHandlerFunction GetLogMessageHandler() {
|
||||
return log_message_handler;
|
||||
}
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
// Explicit instantiations for commonly used comparisons.
|
||||
template std::string* MakeCheckOpString<int, int>(
|
||||
const int&, const int&, const char* names);
|
||||
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
|
||||
const unsigned long&, const unsigned long&, const char* names);
|
||||
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
|
||||
const unsigned long&, const unsigned int&, const char* names);
|
||||
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
|
||||
const unsigned int&, const unsigned long&, const char* names);
|
||||
template std::string* MakeCheckOpString<std::string, std::string>(
|
||||
const std::string&, const std::string&, const char* name);
|
||||
#endif
|
||||
|
||||
// Displays a message box to the user with the error message in it.
|
||||
// Used for fatal messages, where we close the app simultaneously.
|
||||
// This is for developers only; we don't use this in circumstances
|
||||
// (like release builds) where users could see it, since users don't
|
||||
// understand these messages anyway.
|
||||
void DisplayDebugMessageInDialog(const std::string& str) {
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
if (!show_error_dialogs)
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// For Windows programs, it's possible that the message loop is
|
||||
// messed up on a fatal error, and creating a MessageBox will cause
|
||||
// that message loop to be run. Instead, we try to spawn another
|
||||
// process that displays its command line. We look for "Debug
|
||||
// Message.exe" in the same directory as the application. If it
|
||||
// exists, we use it, otherwise, we use a regular message box.
|
||||
wchar_t prog_name[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, prog_name, MAX_PATH);
|
||||
wchar_t* backslash = wcsrchr(prog_name, '\\');
|
||||
if (backslash)
|
||||
backslash[1] = 0;
|
||||
wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
|
||||
|
||||
std::wstring cmdline = UTF8ToWide(str);
|
||||
if (cmdline.empty())
|
||||
return;
|
||||
|
||||
STARTUPINFO startup_info;
|
||||
memset(&startup_info, 0, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
|
||||
NULL, &startup_info, &process_info)) {
|
||||
WaitForSingleObject(process_info.hProcess, INFINITE);
|
||||
CloseHandle(process_info.hThread);
|
||||
CloseHandle(process_info.hProcess);
|
||||
} else {
|
||||
// debug process broken, let's just do a message box
|
||||
MessageBoxW(NULL, &cmdline[0], L"Fatal error",
|
||||
MB_OK | MB_ICONHAND | MB_TOPMOST);
|
||||
}
|
||||
#else
|
||||
// We intentionally don't implement a dialog on other platforms.
|
||||
// You can just look at stderr.
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
|
||||
}
|
||||
|
||||
LogMessage::SaveLastError::~SaveLastError() {
|
||||
::SetLastError(last_error_);
|
||||
}
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
||||
int ctr)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line)
|
||||
: severity_(LOG_INFO), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, std::string* result)
|
||||
: severity_(LOG_FATAL), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
stream_ << "Check failed: " << *result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
||||
std::string* result)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
stream_ << "Check failed: " << *result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
LogMessage::~LogMessage() {
|
||||
#if !defined(NDEBUG) && !defined(OS_NACL)
|
||||
if (severity_ == LOG_FATAL) {
|
||||
// Include a stack trace on a fatal.
|
||||
base::debug::StackTrace trace;
|
||||
stream_ << std::endl; // Newline to separate from log message.
|
||||
trace.OutputToStream(&stream_);
|
||||
}
|
||||
#endif
|
||||
stream_ << std::endl;
|
||||
std::string str_newline(stream_.str());
|
||||
|
||||
// Give any log message handler first dibs on the message.
|
||||
if (log_message_handler &&
|
||||
log_message_handler(severity_, file_, line_,
|
||||
message_start_, str_newline)) {
|
||||
// The handler took care of it, no further processing.
|
||||
return;
|
||||
}
|
||||
|
||||
if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
|
||||
#if defined(OS_WIN)
|
||||
OutputDebugStringA(str_newline.c_str());
|
||||
#elif defined(OS_ANDROID)
|
||||
android_LogPriority priority =
|
||||
(severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
|
||||
switch (severity_) {
|
||||
case LOG_INFO:
|
||||
priority = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
priority = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
case LOG_ERROR_REPORT:
|
||||
priority = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
priority = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
}
|
||||
__android_log_write(priority, "chromium", str_newline.c_str());
|
||||
#endif
|
||||
fprintf(stderr, "%s", str_newline.c_str());
|
||||
fflush(stderr);
|
||||
} else if (severity_ >= kAlwaysPrintErrorLevel) {
|
||||
// When we're only outputting to a log file, above a certain log level, we
|
||||
// should still output to stderr so that we can better detect and diagnose
|
||||
// problems with unit tests, especially on the buildbots.
|
||||
fprintf(stderr, "%s", str_newline.c_str());
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
// write to log file
|
||||
if ((logging_destination & LOG_TO_FILE) != 0) {
|
||||
// We can have multiple threads and/or processes, so try to prevent them
|
||||
// from clobbering each other's writes.
|
||||
// If the client app did not call InitLogging, and the lock has not
|
||||
// been created do it now. We do this on demand, but if two threads try
|
||||
// to do this at the same time, there will be a race condition to create
|
||||
// the lock. This is why InitLogging should be called from the main
|
||||
// thread at the beginning of execution.
|
||||
LoggingLock::Init(LOCK_LOG_FILE, NULL);
|
||||
LoggingLock logging_lock;
|
||||
if (InitializeLogFileHandle()) {
|
||||
#if defined(OS_WIN)
|
||||
SetFilePointer(log_file, 0, 0, SEEK_END);
|
||||
DWORD num_written;
|
||||
WriteFile(log_file,
|
||||
static_cast<const void*>(str_newline.c_str()),
|
||||
static_cast<DWORD>(str_newline.length()),
|
||||
&num_written,
|
||||
NULL);
|
||||
#else
|
||||
fprintf(log_file, "%s", str_newline.c_str());
|
||||
fflush(log_file);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (severity_ == LOG_FATAL) {
|
||||
// Ensure the first characters of the string are on the stack so they
|
||||
// are contained in minidumps for diagnostic purposes.
|
||||
char str_stack[1024];
|
||||
str_newline.copy(str_stack, arraysize(str_stack));
|
||||
base::debug::Alias(str_stack);
|
||||
|
||||
// display a message or break into the debugger on a fatal error
|
||||
if (base::debug::BeingDebugged()) {
|
||||
base::debug::BreakDebugger();
|
||||
} else {
|
||||
if (log_assert_handler) {
|
||||
// make a copy of the string for the handler out of paranoia
|
||||
log_assert_handler(std::string(stream_.str()));
|
||||
} else {
|
||||
// Don't use the string with the newline, get a fresh version to send to
|
||||
// the debug message process. We also don't display assertions to the
|
||||
// user in release mode. The enduser can't do anything with this
|
||||
// information, and displaying message boxes when the application is
|
||||
// hosed can cause additional problems.
|
||||
#ifndef NDEBUG
|
||||
DisplayDebugMessageInDialog(stream_.str());
|
||||
#endif
|
||||
// Crash the process to generate a dump.
|
||||
base::debug::BreakDebugger();
|
||||
}
|
||||
}
|
||||
} else if (severity_ == LOG_ERROR_REPORT) {
|
||||
// We are here only if the user runs with --enable-dcheck in release mode.
|
||||
if (log_report_handler) {
|
||||
log_report_handler(std::string(stream_.str()));
|
||||
} else {
|
||||
DisplayDebugMessageInDialog(stream_.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writes the common header info to the stream
|
||||
void LogMessage::Init(const char* file, int line) {
|
||||
base::StringPiece filename(file);
|
||||
size_t last_slash_pos = filename.find_last_of("\\/");
|
||||
if (last_slash_pos != base::StringPiece::npos)
|
||||
filename.remove_prefix(last_slash_pos + 1);
|
||||
|
||||
// TODO(darin): It might be nice if the columns were fixed width.
|
||||
|
||||
stream_ << '[';
|
||||
if (log_process_id)
|
||||
stream_ << CurrentProcessId() << ':';
|
||||
if (log_thread_id)
|
||||
stream_ << base::PlatformThread::CurrentId() << ':';
|
||||
if (log_timestamp) {
|
||||
time_t t = time(NULL);
|
||||
struct tm local_time = {0};
|
||||
#if _MSC_VER >= 1400
|
||||
localtime_s(&local_time, &t);
|
||||
#else
|
||||
localtime_r(&t, &local_time);
|
||||
#endif
|
||||
struct tm* tm_time = &local_time;
|
||||
stream_ << std::setfill('0')
|
||||
<< std::setw(2) << 1 + tm_time->tm_mon
|
||||
<< std::setw(2) << tm_time->tm_mday
|
||||
<< '/'
|
||||
<< std::setw(2) << tm_time->tm_hour
|
||||
<< std::setw(2) << tm_time->tm_min
|
||||
<< std::setw(2) << tm_time->tm_sec
|
||||
<< ':';
|
||||
}
|
||||
if (log_tickcount)
|
||||
stream_ << TickCount() << ':';
|
||||
if (severity_ >= 0)
|
||||
stream_ << log_severity_names[severity_];
|
||||
else
|
||||
stream_ << "VERBOSE" << -severity_;
|
||||
|
||||
stream_ << ":" << filename << "(" << line << ")] ";
|
||||
|
||||
message_start_ = stream_.tellp();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// This has already been defined in the header, but defining it again as DWORD
|
||||
// ensures that the type used in the header is equivalent to DWORD. If not,
|
||||
// the redefinition is a compile error.
|
||||
typedef DWORD SystemErrorCode;
|
||||
#endif
|
||||
|
||||
SystemErrorCode GetLastSystemErrorCode() {
|
||||
#if defined(OS_WIN)
|
||||
return ::GetLastError();
|
||||
#elif defined(OS_POSIX)
|
||||
return errno;
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err,
|
||||
const char* module)
|
||||
: err_(err),
|
||||
module_(module),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err)
|
||||
: err_(err),
|
||||
module_(NULL),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
Win32ErrorLogMessage::~Win32ErrorLogMessage() {
|
||||
const int error_message_buffer_size = 256;
|
||||
char msgbuf[error_message_buffer_size];
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
HMODULE hmod;
|
||||
if (module_) {
|
||||
hmod = GetModuleHandleA(module_);
|
||||
if (hmod) {
|
||||
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
} else {
|
||||
// This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
|
||||
// so it will not call GetModuleHandle, so recursive errors are
|
||||
// impossible.
|
||||
DPLOG(WARNING) << "Couldn't open module " << module_
|
||||
<< " for error message query";
|
||||
}
|
||||
} else {
|
||||
hmod = NULL;
|
||||
}
|
||||
DWORD len = FormatMessageA(flags,
|
||||
hmod,
|
||||
err_,
|
||||
0,
|
||||
msgbuf,
|
||||
sizeof(msgbuf) / sizeof(msgbuf[0]),
|
||||
NULL);
|
||||
if (len) {
|
||||
while ((len > 0) &&
|
||||
isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
|
||||
msgbuf[--len] = 0;
|
||||
}
|
||||
stream() << ": " << msgbuf;
|
||||
} else {
|
||||
stream() << ": Error " << GetLastError() << " while retrieving error "
|
||||
<< err_;
|
||||
}
|
||||
// We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
|
||||
// field) and use Alias in hopes that it makes it into crash dumps.
|
||||
DWORD last_error = err_;
|
||||
base::debug::Alias(&last_error);
|
||||
}
|
||||
#elif defined(OS_POSIX)
|
||||
ErrnoLogMessage::ErrnoLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err)
|
||||
: err_(err),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
ErrnoLogMessage::~ErrnoLogMessage() {
|
||||
stream() << ": " << safe_strerror(err_);
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
void CloseLogFile() {
|
||||
LoggingLock logging_lock;
|
||||
CloseLogFileUnlocked();
|
||||
}
|
||||
|
||||
void RawLog(int level, const char* message) {
|
||||
if (level >= min_log_level) {
|
||||
size_t bytes_written = 0;
|
||||
const size_t message_len = strlen(message);
|
||||
int rv;
|
||||
while (bytes_written < message_len) {
|
||||
rv = HANDLE_EINTR(
|
||||
write(STDERR_FILENO, message + bytes_written,
|
||||
message_len - bytes_written));
|
||||
if (rv < 0) {
|
||||
// Give up, nothing we can do now.
|
||||
break;
|
||||
}
|
||||
bytes_written += rv;
|
||||
}
|
||||
|
||||
if (message_len > 0 && message[message_len - 1] != '\n') {
|
||||
do {
|
||||
rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
|
||||
if (rv < 0) {
|
||||
// Give up, nothing we can do now.
|
||||
break;
|
||||
}
|
||||
} while (rv != 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (level == LOG_FATAL)
|
||||
base::debug::BreakDebugger();
|
||||
}
|
||||
|
||||
// This was defined at the beginning of this file.
|
||||
#undef write
|
||||
|
||||
#if defined(OS_WIN)
|
||||
std::wstring GetLogFileFullPath() {
|
||||
if (log_file_name)
|
||||
return *log_file_name;
|
||||
return std::wstring();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace logging
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
|
||||
return out << WideToUTF8(std::wstring(wstr));
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
// Copyright (c) 2011 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 "base/logging_win.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include <initguid.h> // NOLINT
|
||||
|
||||
namespace logging {
|
||||
|
||||
using base::win::EtwEventLevel;
|
||||
using base::win::EtwMofEvent;
|
||||
|
||||
DEFINE_GUID(kLogEventId,
|
||||
0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
|
||||
|
||||
LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
|
||||
}
|
||||
|
||||
LogEventProvider* LogEventProvider::GetInstance() {
|
||||
return Singleton<LogEventProvider,
|
||||
StaticMemorySingletonTraits<LogEventProvider> >::get();
|
||||
}
|
||||
|
||||
bool LogEventProvider::LogMessage(logging::LogSeverity severity,
|
||||
const char* file, int line, size_t message_start,
|
||||
const std::string& message) {
|
||||
EtwEventLevel level = TRACE_LEVEL_NONE;
|
||||
|
||||
// Convert the log severity to the most appropriate ETW trace level.
|
||||
if (severity >= 0) {
|
||||
switch (severity) {
|
||||
case LOG_INFO:
|
||||
level = TRACE_LEVEL_INFORMATION;
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
level = TRACE_LEVEL_WARNING;
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
case LOG_ERROR_REPORT:
|
||||
level = TRACE_LEVEL_ERROR;
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
level = TRACE_LEVEL_FATAL;
|
||||
break;
|
||||
}
|
||||
} else { // severity < 0 is VLOG verbosity levels.
|
||||
level = TRACE_LEVEL_INFORMATION - severity;
|
||||
}
|
||||
|
||||
// Bail if we're not logging, not at that level,
|
||||
// or if we're post-atexit handling.
|
||||
LogEventProvider* provider = LogEventProvider::GetInstance();
|
||||
if (provider == NULL || level > provider->enable_level())
|
||||
return false;
|
||||
|
||||
// And now log the event.
|
||||
if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
|
||||
EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
|
||||
event.SetField(0, message.length() + 1 - message_start,
|
||||
message.c_str() + message_start);
|
||||
|
||||
provider->Log(event.get());
|
||||
} else {
|
||||
const size_t kMaxBacktraceDepth = 32;
|
||||
void* backtrace[kMaxBacktraceDepth];
|
||||
DWORD depth = 0;
|
||||
|
||||
// Capture a stack trace if one is requested.
|
||||
// requested per our enable flags.
|
||||
if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
|
||||
depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
|
||||
|
||||
EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
|
||||
if (file == NULL)
|
||||
file = "";
|
||||
|
||||
// Add the stack trace.
|
||||
event.SetField(0, sizeof(depth), &depth);
|
||||
event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
|
||||
// The line.
|
||||
event.SetField(2, sizeof(line), &line);
|
||||
// The file.
|
||||
event.SetField(3, strlen(file) + 1, file);
|
||||
// And finally the message.
|
||||
event.SetField(4, message.length() + 1 - message_start,
|
||||
message.c_str() + message_start);
|
||||
|
||||
provider->Log(event.get());
|
||||
}
|
||||
|
||||
// Don't increase verbosity in other log destinations.
|
||||
if (severity < provider->old_log_level_)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LogEventProvider::Initialize(const GUID& provider_name) {
|
||||
LogEventProvider* provider = LogEventProvider::GetInstance();
|
||||
|
||||
provider->set_provider_name(provider_name);
|
||||
provider->Register();
|
||||
|
||||
// Register our message handler with logging.
|
||||
SetLogMessageHandler(LogMessage);
|
||||
}
|
||||
|
||||
void LogEventProvider::Uninitialize() {
|
||||
LogEventProvider::GetInstance()->Unregister();
|
||||
}
|
||||
|
||||
void LogEventProvider::OnEventsEnabled() {
|
||||
// Grab the old log level so we can restore it later.
|
||||
old_log_level_ = GetMinLogLevel();
|
||||
|
||||
// Convert the new trace level to a logging severity
|
||||
// and enable logging at that level.
|
||||
EtwEventLevel level = enable_level();
|
||||
if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
|
||||
SetMinLogLevel(LOG_FATAL);
|
||||
} else if (level == TRACE_LEVEL_ERROR) {
|
||||
SetMinLogLevel(LOG_ERROR);
|
||||
} else if (level == TRACE_LEVEL_WARNING) {
|
||||
SetMinLogLevel(LOG_WARNING);
|
||||
} else if (level == TRACE_LEVEL_INFORMATION) {
|
||||
SetMinLogLevel(LOG_INFO);
|
||||
} else if (level >= TRACE_LEVEL_VERBOSE) {
|
||||
// Above INFO, we enable verbose levels with negative severities.
|
||||
SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
|
||||
}
|
||||
}
|
||||
|
||||
void LogEventProvider::OnEventsDisabled() {
|
||||
// Restore the old log level.
|
||||
SetMinLogLevel(old_log_level_);
|
||||
}
|
||||
|
||||
} // namespace logging
|
@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_LOGGING_WIN_H_
|
||||
#define BASE_LOGGING_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/win/event_trace_provider.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
template <typename Type>
|
||||
struct StaticMemorySingletonTraits;
|
||||
|
||||
namespace logging {
|
||||
|
||||
// Event ID for the log messages we generate.
|
||||
EXTERN_C BASE_EXPORT const GUID kLogEventId;
|
||||
|
||||
// Feature enable mask for LogEventProvider.
|
||||
enum LogEnableMask {
|
||||
// If this bit is set in our provider enable mask, we will include
|
||||
// a stack trace with every log message.
|
||||
ENABLE_STACK_TRACE_CAPTURE = 0x0001,
|
||||
// If this bit is set in our provider enable mask, the provider will log
|
||||
// a LOG message with only the textual content of the message, and no
|
||||
// stack trace.
|
||||
ENABLE_LOG_MESSAGE_ONLY = 0x0002,
|
||||
};
|
||||
|
||||
// The message types our log event provider generates.
|
||||
// ETW likes user message types to start at 10.
|
||||
enum LogMessageTypes {
|
||||
// A textual only log message, contains a zero-terminated string.
|
||||
LOG_MESSAGE = 10,
|
||||
// A message with a stack trace, followed by the zero-terminated
|
||||
// message text.
|
||||
LOG_MESSAGE_WITH_STACKTRACE = 11,
|
||||
// A message with:
|
||||
// a stack trace,
|
||||
// the line number as a four byte integer,
|
||||
// the file as a zero terminated UTF8 string,
|
||||
// the zero-terminated UTF8 message text.
|
||||
LOG_MESSAGE_FULL = 12,
|
||||
};
|
||||
|
||||
// Trace provider class to drive log control and transport
|
||||
// with Event Tracing for Windows.
|
||||
class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider {
|
||||
public:
|
||||
static LogEventProvider* GetInstance();
|
||||
|
||||
static bool LogMessage(logging::LogSeverity severity, const char* file,
|
||||
int line, size_t message_start, const std::string& str);
|
||||
|
||||
static void Initialize(const GUID& provider_name);
|
||||
static void Uninitialize();
|
||||
|
||||
protected:
|
||||
// Overridden to manipulate the log level on ETW control callbacks.
|
||||
virtual void OnEventsEnabled();
|
||||
virtual void OnEventsDisabled();
|
||||
|
||||
private:
|
||||
LogEventProvider();
|
||||
|
||||
// The log severity prior to OnEventsEnabled,
|
||||
// restored in OnEventsDisabled.
|
||||
logging::LogSeverity old_log_level_;
|
||||
|
||||
friend struct StaticMemorySingletonTraits<LogEventProvider>;
|
||||
DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
|
||||
};
|
||||
|
||||
} // namespace logging
|
||||
|
||||
#endif // BASE_LOGGING_WIN_H_
|
@ -1,217 +0,0 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#ifndef BASE_OBSERVER_LIST_H__
|
||||
#define BASE_OBSERVER_LIST_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OVERVIEW:
|
||||
//
|
||||
// A container for a list of observers. Unlike a normal STL vector or list,
|
||||
// this container can be modified during iteration without invalidating the
|
||||
// iterator. So, it safely handles the case of an observer removing itself
|
||||
// or other observers from the list while observers are being notified.
|
||||
//
|
||||
// TYPICAL USAGE:
|
||||
//
|
||||
// class MyWidget {
|
||||
// public:
|
||||
// ...
|
||||
//
|
||||
// class Observer {
|
||||
// public:
|
||||
// virtual void OnFoo(MyWidget* w) = 0;
|
||||
// virtual void OnBar(MyWidget* w, int x, int y) = 0;
|
||||
// };
|
||||
//
|
||||
// void AddObserver(Observer* obs) {
|
||||
// observer_list_.AddObserver(obs);
|
||||
// }
|
||||
//
|
||||
// void RemoveObserver(Observer* obs) {
|
||||
// observer_list_.RemoveObserver(obs);
|
||||
// }
|
||||
//
|
||||
// void NotifyFoo() {
|
||||
// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
|
||||
// }
|
||||
//
|
||||
// void NotifyBar(int x, int y) {
|
||||
// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// ObserverList<Observer> observer_list_;
|
||||
// };
|
||||
//
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename ObserverType>
|
||||
class ObserverListThreadSafe;
|
||||
|
||||
template <class ObserverType>
|
||||
class ObserverListBase
|
||||
: public base::SupportsWeakPtr<ObserverListBase<ObserverType> > {
|
||||
public:
|
||||
// Enumeration of which observers are notified.
|
||||
enum NotificationType {
|
||||
// Specifies that any observers added during notification are notified.
|
||||
// This is the default type if non type is provided to the constructor.
|
||||
NOTIFY_ALL,
|
||||
|
||||
// Specifies that observers added while sending out notification are not
|
||||
// notified.
|
||||
NOTIFY_EXISTING_ONLY
|
||||
};
|
||||
|
||||
// An iterator class that can be used to access the list of observers. See
|
||||
// also the FOR_EACH_OBSERVER macro defined below.
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(ObserverListBase<ObserverType>& list)
|
||||
: list_(list.AsWeakPtr()),
|
||||
index_(0),
|
||||
max_index_(list.type_ == NOTIFY_ALL ?
|
||||
std::numeric_limits<size_t>::max() :
|
||||
list.observers_.size()) {
|
||||
++list_->notify_depth_;
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
if (list_.get() && --list_->notify_depth_ == 0)
|
||||
list_->Compact();
|
||||
}
|
||||
|
||||
ObserverType* GetNext() {
|
||||
if (!list_.get())
|
||||
return NULL;
|
||||
ListType& observers = list_->observers_;
|
||||
// Advance if the current element is null
|
||||
size_t max_index = std::min(max_index_, observers.size());
|
||||
while (index_ < max_index && !observers[index_])
|
||||
++index_;
|
||||
return index_ < max_index ? observers[index_++] : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
base::WeakPtr<ObserverListBase<ObserverType> > list_;
|
||||
size_t index_;
|
||||
size_t max_index_;
|
||||
};
|
||||
|
||||
ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
|
||||
explicit ObserverListBase(NotificationType type)
|
||||
: notify_depth_(0), type_(type) {}
|
||||
|
||||
// Add an observer to the list. An observer should not be added to
|
||||
// the same list more than once.
|
||||
void AddObserver(ObserverType* obs) {
|
||||
if (std::find(observers_.begin(), observers_.end(), obs)
|
||||
!= observers_.end()) {
|
||||
NOTREACHED() << "Observers can only be added once!";
|
||||
return;
|
||||
}
|
||||
observers_.push_back(obs);
|
||||
}
|
||||
|
||||
// Remove an observer from the list if it is in the list.
|
||||
void RemoveObserver(ObserverType* obs) {
|
||||
typename ListType::iterator it =
|
||||
std::find(observers_.begin(), observers_.end(), obs);
|
||||
if (it != observers_.end()) {
|
||||
if (notify_depth_) {
|
||||
*it = 0;
|
||||
} else {
|
||||
observers_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HasObserver(ObserverType* observer) const {
|
||||
for (size_t i = 0; i < observers_.size(); ++i) {
|
||||
if (observers_[i] == observer)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
if (notify_depth_) {
|
||||
for (typename ListType::iterator it = observers_.begin();
|
||||
it != observers_.end(); ++it) {
|
||||
*it = 0;
|
||||
}
|
||||
} else {
|
||||
observers_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t size() const { return observers_.size(); }
|
||||
|
||||
void Compact() {
|
||||
observers_.erase(
|
||||
std::remove(observers_.begin(), observers_.end(),
|
||||
static_cast<ObserverType*>(NULL)), observers_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ObserverListThreadSafe<ObserverType>;
|
||||
|
||||
typedef std::vector<ObserverType*> ListType;
|
||||
|
||||
ListType observers_;
|
||||
int notify_depth_;
|
||||
NotificationType type_;
|
||||
|
||||
friend class ObserverListBase::Iterator;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
|
||||
};
|
||||
|
||||
template <class ObserverType, bool check_empty = false>
|
||||
class ObserverList : public ObserverListBase<ObserverType> {
|
||||
public:
|
||||
typedef typename ObserverListBase<ObserverType>::NotificationType
|
||||
NotificationType;
|
||||
|
||||
ObserverList() {}
|
||||
explicit ObserverList(NotificationType type)
|
||||
: ObserverListBase<ObserverType>(type) {}
|
||||
|
||||
~ObserverList() {
|
||||
// When check_empty is true, assert that the list is empty on destruction.
|
||||
if (check_empty) {
|
||||
ObserverListBase<ObserverType>::Compact();
|
||||
DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
|
||||
}
|
||||
}
|
||||
|
||||
bool might_have_observers() const {
|
||||
return ObserverListBase<ObserverType>::size() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
|
||||
do { \
|
||||
if ((observer_list).might_have_observers()) { \
|
||||
ObserverListBase<ObserverType>::Iterator \
|
||||
it_inside_observer_macro(observer_list); \
|
||||
ObserverType* obs; \
|
||||
while ((obs = it_inside_observer_macro.GetNext()) != NULL) \
|
||||
obs->func; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // BASE_OBSERVER_LIST_H__
|
@ -1,295 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
|
||||
#define BASE_OBSERVER_LIST_THREADSAFE_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/message_loop/message_loop_proxy.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OVERVIEW:
|
||||
//
|
||||
// A thread-safe container for a list of observers.
|
||||
// This is similar to the observer_list (see observer_list.h), but it
|
||||
// is more robust for multi-threaded situations.
|
||||
//
|
||||
// The following use cases are supported:
|
||||
// * Observers can register for notifications from any thread.
|
||||
// Callbacks to the observer will occur on the same thread where
|
||||
// the observer initially called AddObserver() from.
|
||||
// * Any thread may trigger a notification via Notify().
|
||||
// * Observers can remove themselves from the observer list inside
|
||||
// of a callback.
|
||||
// * If one thread is notifying observers concurrently with an observer
|
||||
// removing itself from the observer list, the notifications will
|
||||
// be silently dropped.
|
||||
//
|
||||
// The drawback of the threadsafe observer list is that notifications
|
||||
// are not as real-time as the non-threadsafe version of this class.
|
||||
// Notifications will always be done via PostTask() to another thread,
|
||||
// whereas with the non-thread-safe observer_list, notifications happen
|
||||
// synchronously and immediately.
|
||||
//
|
||||
// IMPLEMENTATION NOTES
|
||||
// The ObserverListThreadSafe maintains an ObserverList for each thread
|
||||
// which uses the ThreadSafeObserver. When Notifying the observers,
|
||||
// we simply call PostTask to each registered thread, and then each thread
|
||||
// will notify its regular ObserverList.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Forward declaration for ObserverListThreadSafeTraits.
|
||||
template <class ObserverType>
|
||||
class ObserverListThreadSafe;
|
||||
|
||||
// An UnboundMethod is a wrapper for a method where the actual object is
|
||||
// provided at Run dispatch time.
|
||||
template <class T, class Method, class Params>
|
||||
class UnboundMethod {
|
||||
public:
|
||||
UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
|
||||
COMPILE_ASSERT(
|
||||
(base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
|
||||
badunboundmethodparams);
|
||||
}
|
||||
void Run(T* obj) const {
|
||||
DispatchToMethod(obj, m_, p_);
|
||||
}
|
||||
private:
|
||||
Method m_;
|
||||
Params p_;
|
||||
};
|
||||
|
||||
// This class is used to work around VS2005 not accepting:
|
||||
//
|
||||
// friend class
|
||||
// base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
|
||||
//
|
||||
// Instead of friending the class, we could friend the actual function
|
||||
// which calls delete. However, this ends up being
|
||||
// RefCountedThreadSafe::DeleteInternal(), which is private. So we
|
||||
// define our own templated traits class so we can friend it.
|
||||
template <class T>
|
||||
struct ObserverListThreadSafeTraits {
|
||||
static void Destruct(const ObserverListThreadSafe<T>* x) {
|
||||
delete x;
|
||||
}
|
||||
};
|
||||
|
||||
template <class ObserverType>
|
||||
class ObserverListThreadSafe
|
||||
: public base::RefCountedThreadSafe<
|
||||
ObserverListThreadSafe<ObserverType>,
|
||||
ObserverListThreadSafeTraits<ObserverType> > {
|
||||
public:
|
||||
typedef typename ObserverList<ObserverType>::NotificationType
|
||||
NotificationType;
|
||||
|
||||
ObserverListThreadSafe()
|
||||
: type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
|
||||
explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
|
||||
|
||||
// Add an observer to the list. An observer should not be added to
|
||||
// the same list more than once.
|
||||
void AddObserver(ObserverType* obs) {
|
||||
// If there is not a current MessageLoop, it is impossible to notify on it,
|
||||
// so do not add the observer.
|
||||
if (!base::MessageLoop::current())
|
||||
return;
|
||||
|
||||
ObserverList<ObserverType>* list = NULL;
|
||||
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
if (observer_lists_.find(thread_id) == observer_lists_.end())
|
||||
observer_lists_[thread_id] = new ObserverListContext(type_);
|
||||
list = &(observer_lists_[thread_id]->list);
|
||||
}
|
||||
list->AddObserver(obs);
|
||||
}
|
||||
|
||||
// Remove an observer from the list if it is in the list.
|
||||
// If there are pending notifications in-transit to the observer, they will
|
||||
// be aborted.
|
||||
// If the observer to be removed is in the list, RemoveObserver MUST
|
||||
// be called from the same thread which called AddObserver.
|
||||
void RemoveObserver(ObserverType* obs) {
|
||||
ObserverListContext* context = NULL;
|
||||
ObserverList<ObserverType>* list = NULL;
|
||||
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
typename ObserversListMap::iterator it = observer_lists_.find(thread_id);
|
||||
if (it == observer_lists_.end()) {
|
||||
// This will happen if we try to remove an observer on a thread
|
||||
// we never added an observer for.
|
||||
return;
|
||||
}
|
||||
context = it->second;
|
||||
list = &context->list;
|
||||
|
||||
// If we're about to remove the last observer from the list,
|
||||
// then we can remove this observer_list entirely.
|
||||
if (list->HasObserver(obs) && list->size() == 1)
|
||||
observer_lists_.erase(it);
|
||||
}
|
||||
list->RemoveObserver(obs);
|
||||
|
||||
// If RemoveObserver is called from a notification, the size will be
|
||||
// nonzero. Instead of deleting here, the NotifyWrapper will delete
|
||||
// when it finishes iterating.
|
||||
if (list->size() == 0)
|
||||
delete context;
|
||||
}
|
||||
|
||||
// Verifies that the list is currently empty (i.e. there are no observers).
|
||||
void AssertEmpty() const {
|
||||
base::AutoLock lock(list_lock_);
|
||||
DCHECK(observer_lists_.empty());
|
||||
}
|
||||
|
||||
// Notify methods.
|
||||
// Make a thread-safe callback to each Observer in the list.
|
||||
// Note, these calls are effectively asynchronous. You cannot assume
|
||||
// that at the completion of the Notify call that all Observers have
|
||||
// been Notified. The notification may still be pending delivery.
|
||||
template <class Method>
|
||||
void Notify(Method m) {
|
||||
UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
|
||||
Notify<Method, Tuple0>(method);
|
||||
}
|
||||
|
||||
template <class Method, class A>
|
||||
void Notify(Method m, const A& a) {
|
||||
UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
|
||||
Notify<Method, Tuple1<A> >(method);
|
||||
}
|
||||
|
||||
template <class Method, class A, class B>
|
||||
void Notify(Method m, const A& a, const B& b) {
|
||||
UnboundMethod<ObserverType, Method, Tuple2<A, B> > method(
|
||||
m, MakeTuple(a, b));
|
||||
Notify<Method, Tuple2<A, B> >(method);
|
||||
}
|
||||
|
||||
template <class Method, class A, class B, class C>
|
||||
void Notify(Method m, const A& a, const B& b, const C& c) {
|
||||
UnboundMethod<ObserverType, Method, Tuple3<A, B, C> > method(
|
||||
m, MakeTuple(a, b, c));
|
||||
Notify<Method, Tuple3<A, B, C> >(method);
|
||||
}
|
||||
|
||||
template <class Method, class A, class B, class C, class D>
|
||||
void Notify(Method m, const A& a, const B& b, const C& c, const D& d) {
|
||||
UnboundMethod<ObserverType, Method, Tuple4<A, B, C, D> > method(
|
||||
m, MakeTuple(a, b, c, d));
|
||||
Notify<Method, Tuple4<A, B, C, D> >(method);
|
||||
}
|
||||
|
||||
// TODO(mbelshe): Add more wrappers for Notify() with more arguments.
|
||||
|
||||
private:
|
||||
// See comment above ObserverListThreadSafeTraits' definition.
|
||||
friend struct ObserverListThreadSafeTraits<ObserverType>;
|
||||
|
||||
struct ObserverListContext {
|
||||
explicit ObserverListContext(NotificationType type)
|
||||
: loop(base::MessageLoopProxy::current()),
|
||||
list(type) {
|
||||
}
|
||||
|
||||
scoped_refptr<base::MessageLoopProxy> loop;
|
||||
ObserverList<ObserverType> list;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
|
||||
};
|
||||
|
||||
~ObserverListThreadSafe() {
|
||||
STLDeleteValues(&observer_lists_);
|
||||
}
|
||||
|
||||
template <class Method, class Params>
|
||||
void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
|
||||
base::AutoLock lock(list_lock_);
|
||||
typename ObserversListMap::iterator it;
|
||||
for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
|
||||
ObserverListContext* context = (*it).second;
|
||||
context->loop->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&ObserverListThreadSafe<ObserverType>::
|
||||
template NotifyWrapper<Method, Params>, this, context, method));
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper which is called to fire the notifications for each thread's
|
||||
// ObserverList. This function MUST be called on the thread which owns
|
||||
// the unsafe ObserverList.
|
||||
template <class Method, class Params>
|
||||
void NotifyWrapper(ObserverListContext* context,
|
||||
const UnboundMethod<ObserverType, Method, Params>& method) {
|
||||
|
||||
// Check that this list still needs notifications.
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
typename ObserversListMap::iterator it =
|
||||
observer_lists_.find(base::PlatformThread::CurrentId());
|
||||
|
||||
// The ObserverList could have been removed already. In fact, it could
|
||||
// have been removed and then re-added! If the master list's loop
|
||||
// does not match this one, then we do not need to finish this
|
||||
// notification.
|
||||
if (it == observer_lists_.end() || it->second != context)
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
typename ObserverList<ObserverType>::Iterator it(context->list);
|
||||
ObserverType* obs;
|
||||
while ((obs = it.GetNext()) != NULL)
|
||||
method.Run(obs);
|
||||
}
|
||||
|
||||
// If there are no more observers on the list, we can now delete it.
|
||||
if (context->list.size() == 0) {
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
// Remove |list| if it's not already removed.
|
||||
// This can happen if multiple observers got removed in a notification.
|
||||
// See http://crbug.com/55725.
|
||||
typename ObserversListMap::iterator it =
|
||||
observer_lists_.find(base::PlatformThread::CurrentId());
|
||||
if (it != observer_lists_.end() && it->second == context)
|
||||
observer_lists_.erase(it);
|
||||
}
|
||||
delete context;
|
||||
}
|
||||
}
|
||||
|
||||
// Key by PlatformThreadId because in tests, clients can attempt to remove
|
||||
// observers without a MessageLoop. If this were keyed by MessageLoop, that
|
||||
// operation would be silently ignored, leaving garbage in the ObserverList.
|
||||
typedef std::map<base::PlatformThreadId, ObserverListContext*>
|
||||
ObserversListMap;
|
||||
|
||||
mutable base::Lock list_lock_; // Protects the observer_lists_.
|
||||
ObserversListMap observer_lists_;
|
||||
const NotificationType type_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
|
||||
};
|
||||
|
||||
#endif // BASE_OBSERVER_LIST_THREADSAFE_H_
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_OS_COMPAT_NACL_H_
|
||||
#define BASE_OS_COMPAT_NACL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined (__GLIBC__)
|
||||
// NaCl has no timegm().
|
||||
extern "C" time_t timegm(struct tm* const t);
|
||||
#endif // !defined (__GLIBC__)
|
||||
|
||||
#endif // BASE_OS_COMPAT_NACL_H_
|
||||
|
@ -1,336 +0,0 @@
|
||||
// Copyright (c) 2012 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 "base/path_service.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/lazy_instance.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
using base::FilePath;
|
||||
using base::MakeAbsoluteFilePath;
|
||||
|
||||
namespace base {
|
||||
bool PathProvider(int key, FilePath* result);
|
||||
#if defined(OS_WIN)
|
||||
bool PathProviderWin(int key, FilePath* result);
|
||||
#elif defined(OS_MACOSX)
|
||||
bool PathProviderMac(int key, FilePath* result);
|
||||
#elif defined(OS_ANDROID)
|
||||
bool PathProviderAndroid(int key, FilePath* result);
|
||||
#elif defined(OS_POSIX)
|
||||
// PathProviderPosix is the default path provider on POSIX OSes other than
|
||||
// Mac and Android.
|
||||
bool PathProviderPosix(int key, FilePath* result);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
typedef base::hash_map<int, FilePath> PathMap;
|
||||
|
||||
// We keep a linked list of providers. In a debug build we ensure that no two
|
||||
// providers claim overlapping keys.
|
||||
struct Provider {
|
||||
PathService::ProviderFunc func;
|
||||
struct Provider* next;
|
||||
#ifndef NDEBUG
|
||||
int key_start;
|
||||
int key_end;
|
||||
#endif
|
||||
bool is_static;
|
||||
};
|
||||
|
||||
Provider base_provider = {
|
||||
base::PathProvider,
|
||||
NULL,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_START,
|
||||
base::PATH_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
|
||||
#if defined(OS_WIN)
|
||||
Provider base_provider_win = {
|
||||
base::PathProviderWin,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_WIN_START,
|
||||
base::PATH_WIN_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
Provider base_provider_mac = {
|
||||
base::PathProviderMac,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_MAC_START,
|
||||
base::PATH_MAC_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
Provider base_provider_android = {
|
||||
base::PathProviderAndroid,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_ANDROID_START,
|
||||
base::PATH_ANDROID_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
|
||||
Provider base_provider_posix = {
|
||||
base::PathProviderPosix,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_POSIX_START,
|
||||
base::PATH_POSIX_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct PathData {
|
||||
base::Lock lock;
|
||||
PathMap cache; // Cache mappings from path key to path value.
|
||||
PathMap overrides; // Track path overrides.
|
||||
Provider* providers; // Linked list of path service providers.
|
||||
bool cache_disabled; // Don't use cache if true;
|
||||
|
||||
PathData() : cache_disabled(false) {
|
||||
#if defined(OS_WIN)
|
||||
providers = &base_provider_win;
|
||||
#elif defined(OS_MACOSX)
|
||||
providers = &base_provider_mac;
|
||||
#elif defined(OS_ANDROID)
|
||||
providers = &base_provider_android;
|
||||
#elif defined(OS_POSIX)
|
||||
providers = &base_provider_posix;
|
||||
#endif
|
||||
}
|
||||
|
||||
~PathData() {
|
||||
Provider* p = providers;
|
||||
while (p) {
|
||||
Provider* next = p->next;
|
||||
if (!p->is_static)
|
||||
delete p;
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
static PathData* GetPathData() {
|
||||
return g_path_data.Pointer();
|
||||
}
|
||||
|
||||
// Tries to find |key| in the cache. |path_data| should be locked by the caller!
|
||||
bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
|
||||
if (path_data->cache_disabled)
|
||||
return false;
|
||||
// check for a cached version
|
||||
PathMap::const_iterator it = path_data->cache.find(key);
|
||||
if (it != path_data->cache.end()) {
|
||||
*result = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tries to find |key| in the overrides map. |path_data| should be locked by the
|
||||
// caller!
|
||||
bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
|
||||
// check for an overridden version.
|
||||
PathMap::const_iterator it = path_data->overrides.find(key);
|
||||
if (it != path_data->overrides.end()) {
|
||||
if (!path_data->cache_disabled)
|
||||
path_data->cache[key] = it->second;
|
||||
*result = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
|
||||
// characters). This isn't supported very well by Windows right now, so it is
|
||||
// moot, but we should keep this in mind for the future.
|
||||
// static
|
||||
bool PathService::Get(int key, FilePath* result) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
DCHECK(result);
|
||||
DCHECK_GE(key, base::DIR_CURRENT);
|
||||
|
||||
// special case the current directory because it can never be cached
|
||||
if (key == base::DIR_CURRENT)
|
||||
return file_util::GetCurrentDirectory(result);
|
||||
|
||||
Provider* provider = NULL;
|
||||
{
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
if (LockedGetFromCache(key, path_data, result))
|
||||
return true;
|
||||
|
||||
if (LockedGetFromOverrides(key, path_data, result))
|
||||
return true;
|
||||
|
||||
// Get the beginning of the list while it is still locked.
|
||||
provider = path_data->providers;
|
||||
}
|
||||
|
||||
FilePath path;
|
||||
|
||||
// Iterating does not need the lock because only the list head might be
|
||||
// modified on another thread.
|
||||
while (provider) {
|
||||
if (provider->func(key, &path))
|
||||
break;
|
||||
DCHECK(path.empty()) << "provider should not have modified path";
|
||||
provider = provider->next;
|
||||
}
|
||||
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
if (path.ReferencesParent()) {
|
||||
// Make sure path service never returns a path with ".." in it.
|
||||
path = MakeAbsoluteFilePath(path);
|
||||
if (path.empty())
|
||||
return false;
|
||||
}
|
||||
*result = path;
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
if (!path_data->cache_disabled)
|
||||
path_data->cache[key] = path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool PathService::Override(int key, const FilePath& path) {
|
||||
// Just call the full function with true for the value of |create|.
|
||||
return OverrideAndCreateIfNeeded(key, path, true);
|
||||
}
|
||||
|
||||
// static
|
||||
bool PathService::OverrideAndCreateIfNeeded(int key,
|
||||
const FilePath& path,
|
||||
bool create) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
|
||||
|
||||
FilePath file_path = path;
|
||||
|
||||
// For some locations this will fail if called from inside the sandbox there-
|
||||
// fore we protect this call with a flag.
|
||||
if (create) {
|
||||
// Make sure the directory exists. We need to do this before we translate
|
||||
// this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
|
||||
// if called on a non-existent path.
|
||||
if (!base::PathExists(file_path) &&
|
||||
!file_util::CreateDirectory(file_path))
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to have an absolute path.
|
||||
file_path = MakeAbsoluteFilePath(file_path);
|
||||
if (file_path.empty())
|
||||
return false;
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
|
||||
// Clear the cache now. Some of its entries could have depended
|
||||
// on the value we are overriding, and are now out of sync with reality.
|
||||
path_data->cache.clear();
|
||||
|
||||
path_data->overrides[key] = file_path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool PathService::RemoveOverride(int key) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
|
||||
if (path_data->overrides.find(key) == path_data->overrides.end())
|
||||
return false;
|
||||
|
||||
// Clear the cache now. Some of its entries could have depended on the value
|
||||
// we are going to remove, and are now out of sync.
|
||||
path_data->cache.clear();
|
||||
|
||||
path_data->overrides.erase(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void PathService::RegisterProvider(ProviderFunc func, int key_start,
|
||||
int key_end) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
DCHECK_GT(key_end, key_start);
|
||||
|
||||
Provider* p;
|
||||
|
||||
p = new Provider;
|
||||
p->is_static = false;
|
||||
p->func = func;
|
||||
#ifndef NDEBUG
|
||||
p->key_start = key_start;
|
||||
p->key_end = key_end;
|
||||
#endif
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
|
||||
#ifndef NDEBUG
|
||||
Provider *iter = path_data->providers;
|
||||
while (iter) {
|
||||
DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
|
||||
"path provider collision";
|
||||
iter = iter->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
p->next = path_data->providers;
|
||||
path_data->providers = p;
|
||||
}
|
||||
|
||||
// static
|
||||
void PathService::DisableCache() {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
path_data->cache.clear();
|
||||
path_data->cache_disabled = true;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#ifndef PENDING_TASK_H_
|
||||
#define PENDING_TASK_H_
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/location.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/tracking_info.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue
|
||||
// for use by classes that queue and execute tasks.
|
||||
struct BASE_EXPORT PendingTask : public TrackingInfo {
|
||||
#if _MSC_VER >= 1700
|
||||
PendingTask();
|
||||
#endif
|
||||
PendingTask(const tracked_objects::Location& posted_from,
|
||||
const Closure& task);
|
||||
PendingTask(const tracked_objects::Location& posted_from,
|
||||
const Closure& task,
|
||||
TimeTicks delayed_run_time,
|
||||
bool nestable);
|
||||
~PendingTask();
|
||||
|
||||
// Used to support sorting.
|
||||
bool operator<(const PendingTask& other) const;
|
||||
|
||||
// The task to run.
|
||||
Closure task;
|
||||
|
||||
// The site this PendingTask was posted from.
|
||||
tracked_objects::Location posted_from;
|
||||
|
||||
// Secondary sort key for run time.
|
||||
int sequence_num;
|
||||
|
||||
// OK to dispatch from a nested loop.
|
||||
bool nestable;
|
||||
};
|
||||
|
||||
// Wrapper around std::queue specialized for PendingTask which adds a Swap
|
||||
// helper method.
|
||||
class BASE_EXPORT TaskQueue : public std::queue<PendingTask> {
|
||||
public:
|
||||
void Swap(TaskQueue* queue);
|
||||
};
|
||||
|
||||
// PendingTasks are sorted by their |delayed_run_time| property.
|
||||
typedef std::priority_queue<base::PendingTask> DelayedTaskQueue;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // PENDING_TASK_H_
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2011 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 "base/platform_file.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
PlatformFileInfo::PlatformFileInfo()
|
||||
: size(0),
|
||||
is_directory(false),
|
||||
is_symbolic_link(false) {
|
||||
}
|
||||
|
||||
PlatformFileInfo::~PlatformFileInfo() {}
|
||||
|
||||
#if !defined(OS_NACL)
|
||||
PlatformFile CreatePlatformFile(const FilePath& name,
|
||||
int flags,
|
||||
bool* created,
|
||||
PlatformFileError* error) {
|
||||
if (name.ReferencesParent()) {
|
||||
if (error)
|
||||
*error = PLATFORM_FILE_ERROR_ACCESS_DENIED;
|
||||
return kInvalidPlatformFileValue;
|
||||
}
|
||||
return CreatePlatformFileUnsafe(name, flags, created, error);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace base
|
@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
// This is a glue file, which allows third party code to call into our profiler
|
||||
// without having to include most any functions from base.
|
||||
|
||||
#ifndef BASE_PROFILER_ALTERNATE_TIMER_H_
|
||||
#define BASE_PROFILER_ALTERNATE_TIMER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
enum TimeSourceType {
|
||||
TIME_SOURCE_TYPE_WALL_TIME,
|
||||
TIME_SOURCE_TYPE_TCMALLOC
|
||||
};
|
||||
|
||||
// Provide type for an alternate timer function.
|
||||
typedef unsigned int NowFunction();
|
||||
|
||||
// Environment variable name that is used to activate alternate timer profiling
|
||||
// (such as using TCMalloc allocations to provide a pseudo-timer) for tasks
|
||||
// instead of wall clock profiling.
|
||||
BASE_EXPORT extern const char kAlternateProfilerTime[];
|
||||
|
||||
// Set an alternate timer function to replace the OS time function when
|
||||
// profiling. Typically this is called by an allocator that is providing a
|
||||
// function that indicates how much memory has been allocated on any given
|
||||
// thread.
|
||||
BASE_EXPORT void SetAlternateTimeSource(NowFunction* now_function,
|
||||
TimeSourceType type);
|
||||
|
||||
// Gets the pointer to a function that was set via SetAlternateTimeSource().
|
||||
// Returns NULL if no set was done prior to calling GetAlternateTimeSource.
|
||||
NowFunction* GetAlternateTimeSource();
|
||||
|
||||
// Returns the type of the currently set time source.
|
||||
BASE_EXPORT TimeSourceType GetTimeSourceType();
|
||||
|
||||
} // namespace tracked_objects
|
||||
|
||||
#endif // BASE_PROFILER_ALTERNATE_TIMER_H_
|
@ -1,71 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_PROFILER_TRACKED_TIME_H_
|
||||
#define BASE_PROFILER_TRACKED_TIME_H_
|
||||
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on
|
||||
// windows, a 64 bit timer is expensive to even obtain. We use a simple
|
||||
// millisecond counter for most of our time values, as well as millisecond units
|
||||
// of duration between those values. This means we can only handle durations
|
||||
// up to 49 days (range), or 24 days (non-negative time durations).
|
||||
// We only define enough methods to service the needs of the tracking classes,
|
||||
// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we
|
||||
// can swap them into place if we want to use the "real" classes).
|
||||
|
||||
class BASE_EXPORT Duration { // Similar to base::TimeDelta.
|
||||
public:
|
||||
Duration();
|
||||
|
||||
Duration& operator+=(const Duration& other);
|
||||
Duration operator+(const Duration& other) const;
|
||||
|
||||
bool operator==(const Duration& other) const;
|
||||
bool operator!=(const Duration& other) const;
|
||||
bool operator>(const Duration& other) const;
|
||||
|
||||
static Duration FromMilliseconds(int ms);
|
||||
|
||||
int32 InMilliseconds() const;
|
||||
|
||||
private:
|
||||
friend class TrackedTime;
|
||||
explicit Duration(int32 duration);
|
||||
|
||||
// Internal time is stored directly in milliseconds.
|
||||
int32 ms_;
|
||||
};
|
||||
|
||||
class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
|
||||
public:
|
||||
TrackedTime();
|
||||
explicit TrackedTime(const base::TimeTicks& time);
|
||||
|
||||
static TrackedTime Now();
|
||||
Duration operator-(const TrackedTime& other) const;
|
||||
TrackedTime operator+(const Duration& other) const;
|
||||
bool is_null() const;
|
||||
|
||||
static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
|
||||
|
||||
private:
|
||||
friend class Duration;
|
||||
explicit TrackedTime(int32 ms);
|
||||
|
||||
// Internal duration is stored directly in milliseconds.
|
||||
uint32 ms_;
|
||||
};
|
||||
|
||||
} // namespace tracked_objects
|
||||
|
||||
#endif // BASE_PROFILER_TRACKED_TIME_H_
|
@ -1,124 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_RUN_LOOP_H_
|
||||
#define BASE_RUN_LOOP_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
|
||||
namespace base {
|
||||
#if defined(OS_ANDROID)
|
||||
class MessagePumpForUI;
|
||||
#endif
|
||||
|
||||
#if defined(OS_IOS)
|
||||
class MessagePumpUIApplication;
|
||||
#endif
|
||||
|
||||
// Helper class to Run a nested MessageLoop. Please do not use nested
|
||||
// MessageLoops in production code! If you must, use this class instead of
|
||||
// calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once
|
||||
// per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run
|
||||
// a nested MessageLoop.
|
||||
class BASE_EXPORT RunLoop {
|
||||
public:
|
||||
RunLoop();
|
||||
#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
|
||||
!defined(USE_GTK_MESSAGE_PUMP)
|
||||
explicit RunLoop(MessageLoop::Dispatcher* dispatcher);
|
||||
#endif
|
||||
~RunLoop();
|
||||
|
||||
#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
|
||||
!defined(USE_GTK_MESSAGE_PUMP)
|
||||
void set_dispatcher(MessageLoop::Dispatcher* dispatcher) {
|
||||
dispatcher_ = dispatcher;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Run the current MessageLoop. This blocks until Quit is called. Before
|
||||
// calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to
|
||||
// stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will
|
||||
// also trigger a return from Run, but those are deprecated.
|
||||
void Run();
|
||||
|
||||
// Run the current MessageLoop until it doesn't find any tasks or messages in
|
||||
// the queue (it goes idle). WARNING: This may never return! Only use this
|
||||
// when repeating tasks such as animated web pages have been shut down.
|
||||
void RunUntilIdle();
|
||||
|
||||
bool running() const { return running_; }
|
||||
|
||||
// Quit an earlier call to Run(). There can be other nested RunLoops servicing
|
||||
// the same task queue (MessageLoop); Quitting one RunLoop has no bearing on
|
||||
// the others. Quit can be called before, during or after Run. If called
|
||||
// before Run, Run will return immediately when called. Calling Quit after the
|
||||
// RunLoop has already finished running has no effect.
|
||||
//
|
||||
// WARNING: You must NEVER assume that a call to Quit will terminate the
|
||||
// targetted message loop. If a nested message loop continues running, the
|
||||
// target may NEVER terminate. It is very easy to livelock (run forever) in
|
||||
// such a case.
|
||||
void Quit();
|
||||
|
||||
// Convenience method to get a closure that safely calls Quit (has no effect
|
||||
// if the RunLoop instance is gone).
|
||||
//
|
||||
// Example:
|
||||
// RunLoop run_loop;
|
||||
// PostTask(run_loop.QuitClosure());
|
||||
// run_loop.Run();
|
||||
base::Closure QuitClosure();
|
||||
|
||||
private:
|
||||
friend class MessageLoop;
|
||||
#if defined(OS_ANDROID)
|
||||
// Android doesn't support the blocking MessageLoop::Run, so it calls
|
||||
// BeforeRun and AfterRun directly.
|
||||
friend class base::MessagePumpForUI;
|
||||
#endif
|
||||
|
||||
#if defined(OS_IOS)
|
||||
// iOS doesn't support the blocking MessageLoop::Run, so it calls
|
||||
// BeforeRun directly.
|
||||
friend class base::MessagePumpUIApplication;
|
||||
#endif
|
||||
|
||||
// Return false to abort the Run.
|
||||
bool BeforeRun();
|
||||
void AfterRun();
|
||||
|
||||
MessageLoop* loop_;
|
||||
|
||||
// WeakPtrFactory for QuitClosure safety.
|
||||
base::WeakPtrFactory<RunLoop> weak_factory_;
|
||||
|
||||
// Parent RunLoop or NULL if this is the top-most RunLoop.
|
||||
RunLoop* previous_run_loop_;
|
||||
|
||||
#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
|
||||
!defined(USE_GTK_MESSAGE_PUMP)
|
||||
MessageLoop::Dispatcher* dispatcher_;
|
||||
#endif
|
||||
|
||||
// Used to count how many nested Run() invocations are on the stack.
|
||||
int run_depth_;
|
||||
|
||||
bool run_called_;
|
||||
bool quit_called_;
|
||||
bool running_;
|
||||
|
||||
// Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
|
||||
// that we should quit Run once it becomes idle.
|
||||
bool quit_when_idle_received_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RunLoop);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_RUN_LOOP_H_
|
@ -1,113 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_SYS_INFO_H_
|
||||
#define BASE_SYS_INFO_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class BASE_EXPORT SysInfo {
|
||||
public:
|
||||
// Return the number of logical processors/cores on the current machine.
|
||||
static int NumberOfProcessors();
|
||||
|
||||
// Return the number of bytes of physical memory on the current machine.
|
||||
static int64 AmountOfPhysicalMemory();
|
||||
|
||||
// Return the number of bytes of current available physical memory on the
|
||||
// machine.
|
||||
static int64 AmountOfAvailablePhysicalMemory();
|
||||
|
||||
// Return the number of megabytes of physical memory on the current machine.
|
||||
static int AmountOfPhysicalMemoryMB() {
|
||||
return static_cast<int>(AmountOfPhysicalMemory() / 1024 / 1024);
|
||||
}
|
||||
|
||||
// Return the available disk space in bytes on the volume containing |path|,
|
||||
// or -1 on failure.
|
||||
static int64 AmountOfFreeDiskSpace(const FilePath& path);
|
||||
|
||||
// Returns system uptime in milliseconds.
|
||||
static int64 Uptime();
|
||||
|
||||
// Returns the name of the host operating system.
|
||||
static std::string OperatingSystemName();
|
||||
|
||||
// Returns the version of the host operating system.
|
||||
static std::string OperatingSystemVersion();
|
||||
|
||||
// Retrieves detailed numeric values for the OS version.
|
||||
// TODO(port): Implement a Linux version of this method and enable the
|
||||
// corresponding unit test.
|
||||
// DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release
|
||||
// for OS version-specific feature checks and workarounds. If you must use
|
||||
// an OS version check instead of a feature check, use the base::mac::IsOS*
|
||||
// family from base/mac/mac_util.h, or base::win::GetVersion from
|
||||
// base/win/windows_version.h.
|
||||
static void OperatingSystemVersionNumbers(int32* major_version,
|
||||
int32* minor_version,
|
||||
int32* bugfix_version);
|
||||
|
||||
// Returns the architecture of the running operating system.
|
||||
// Exact return value may differ across platforms.
|
||||
// e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86",
|
||||
// whereas a x86-64 kernel on the same CPU will return "x86_64"
|
||||
static std::string OperatingSystemArchitecture();
|
||||
|
||||
// Avoid using this. Use base/cpu.h to get information about the CPU instead.
|
||||
// http://crbug.com/148884
|
||||
// Returns the CPU model name of the system. If it can not be figured out,
|
||||
// an empty string is returned.
|
||||
static std::string CPUModelName();
|
||||
|
||||
// Return the smallest amount of memory (in bytes) which the VM system will
|
||||
// allocate.
|
||||
static size_t VMAllocationGranularity();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||
// Returns the maximum SysV shared memory segment size.
|
||||
static size_t MaxSharedMemorySize();
|
||||
#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
|
||||
|
||||
#if defined(OS_CHROMEOS)
|
||||
// Returns the name of the version entry we wish to look up in the
|
||||
// Linux Standard Base release information file.
|
||||
static std::string GetLinuxStandardBaseVersionKey();
|
||||
|
||||
// Parses /etc/lsb-release to get version information for Google Chrome OS.
|
||||
// Declared here so it can be exposed for unit testing.
|
||||
static void ParseLsbRelease(const std::string& lsb_release,
|
||||
int32* major_version,
|
||||
int32* minor_version,
|
||||
int32* bugfix_version);
|
||||
|
||||
// Returns the path to the lsb-release file.
|
||||
static FilePath GetLsbReleaseFilePath();
|
||||
#endif // defined(OS_CHROMEOS)
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// Returns the Android build's codename.
|
||||
static std::string GetAndroidBuildCodename();
|
||||
|
||||
// Returns the Android build ID.
|
||||
static std::string GetAndroidBuildID();
|
||||
|
||||
// Returns the device's name.
|
||||
static std::string GetDeviceName();
|
||||
|
||||
static int DalvikHeapSizeMB();
|
||||
static int DalvikHeapGrowthLimitMB();
|
||||
#endif // defined(OS_ANDROID)
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SYS_INFO_H_
|
@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_THREAD_TASK_RUNNER_HANDLE_H_
|
||||
#define BASE_THREAD_TASK_RUNNER_HANDLE_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class SingleThreadTaskRunner;
|
||||
|
||||
// ThreadTaskRunnerHandle stores a reference to a thread's TaskRunner
|
||||
// in thread-local storage. Callers can then retrieve the TaskRunner
|
||||
// for the current thread by calling ThreadTaskRunnerHandle::Get().
|
||||
// At most one TaskRunner may be bound to each thread at a time.
|
||||
class BASE_EXPORT ThreadTaskRunnerHandle {
|
||||
public:
|
||||
// Gets the SingleThreadTaskRunner for the current thread.
|
||||
static scoped_refptr<SingleThreadTaskRunner> Get();
|
||||
|
||||
// Returns true if the SingleThreadTaskRunner is already created for
|
||||
// the current thread.
|
||||
static bool IsSet();
|
||||
|
||||
// Binds |task_runner| to the current thread. |task_runner| must belong
|
||||
// to the current thread for this to succeed.
|
||||
explicit ThreadTaskRunnerHandle(
|
||||
const scoped_refptr<SingleThreadTaskRunner>& task_runner);
|
||||
~ThreadTaskRunnerHandle();
|
||||
|
||||
private:
|
||||
scoped_refptr<SingleThreadTaskRunner> task_runner_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_THREAD_TASK_RUNNER_HANDLE_H_
|
@ -1,93 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
|
||||
#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
// Wrapper for thread local storage. This class doesn't do much except provide
|
||||
// an API for portability.
|
||||
class BASE_EXPORT ThreadLocalStorage {
|
||||
public:
|
||||
|
||||
// Prototype for the TLS destructor function, which can be optionally used to
|
||||
// cleanup thread local storage on thread exit. 'value' is the data that is
|
||||
// stored in thread local storage.
|
||||
typedef void (*TLSDestructorFunc)(void* value);
|
||||
|
||||
// StaticSlot uses its own struct initializer-list style static
|
||||
// initialization, as base's LINKER_INITIALIZED requires a constructor and on
|
||||
// some compilers (notably gcc 4.4) this still ends up needing runtime
|
||||
// initialization.
|
||||
#define TLS_INITIALIZER {0}
|
||||
|
||||
// A key representing one value stored in TLS.
|
||||
// Initialize like
|
||||
// ThreadLocalStorage::StaticSlot my_slot = TLS_INITIALIZER;
|
||||
// If you're not using a static variable, use the convenience class
|
||||
// ThreadLocalStorage::Slot (below) instead.
|
||||
struct BASE_EXPORT StaticSlot {
|
||||
// Set up the TLS slot. Called by the constructor.
|
||||
// 'destructor' is a pointer to a function to perform per-thread cleanup of
|
||||
// this object. If set to NULL, no cleanup is done for this TLS slot.
|
||||
// Returns false on error.
|
||||
bool Initialize(TLSDestructorFunc destructor);
|
||||
|
||||
// Free a previously allocated TLS 'slot'.
|
||||
// If a destructor was set for this slot, removes
|
||||
// the destructor so that remaining threads exiting
|
||||
// will not free data.
|
||||
void Free();
|
||||
|
||||
// Get the thread-local value stored in slot 'slot'.
|
||||
// Values are guaranteed to initially be zero.
|
||||
void* Get() const;
|
||||
|
||||
// Set the thread-local value stored in slot 'slot' to
|
||||
// value 'value'.
|
||||
void Set(void* value);
|
||||
|
||||
bool initialized() const { return initialized_; }
|
||||
|
||||
// The internals of this struct should be considered private.
|
||||
bool initialized_;
|
||||
#if defined(OS_WIN)
|
||||
int slot_;
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_key_t key_;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
// A convenience wrapper around StaticSlot with a constructor. Can be used
|
||||
// as a member variable.
|
||||
class BASE_EXPORT Slot : public StaticSlot {
|
||||
public:
|
||||
// Calls StaticSlot::Initialize().
|
||||
explicit Slot(TLSDestructorFunc destructor = NULL);
|
||||
|
||||
private:
|
||||
using StaticSlot::initialized_;
|
||||
#if defined(OS_WIN)
|
||||
using StaticSlot::slot_;
|
||||
#elif defined(OS_POSIX)
|
||||
using StaticSlot::key_;
|
||||
#endif
|
||||
DISALLOW_COPY_AND_ASSIGN(Slot);
|
||||
};
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_THREADING_THREAD_LOCAL_STORAGE_H_
|
@ -1,55 +0,0 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
// This is a simple struct with tracking information that is stored
|
||||
// with a PendingTask (when message_loop is handling the task).
|
||||
// Only the information that is shared with the profiler in tracked_objects
|
||||
// are included in this structure.
|
||||
|
||||
|
||||
#ifndef BASE_TRACKING_INFO_H_
|
||||
#define BASE_TRACKING_INFO_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/profiler/tracked_time.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
class Location;
|
||||
class Births;
|
||||
}
|
||||
|
||||
namespace base {
|
||||
|
||||
// This structure is copied around by value.
|
||||
struct BASE_EXPORT TrackingInfo {
|
||||
TrackingInfo();
|
||||
TrackingInfo(const tracked_objects::Location& posted_from,
|
||||
base::TimeTicks delayed_run_time);
|
||||
~TrackingInfo();
|
||||
|
||||
// To avoid conflating our stats with the delay duration in a PostDelayedTask,
|
||||
// we identify such tasks, and replace their post_time with the time they
|
||||
// were scheduled (requested?) to emerge from the delayed task queue. This
|
||||
// means that queuing delay for such tasks will show how long they went
|
||||
// unserviced, after they *could* be serviced. This is the same stat as we
|
||||
// have for non-delayed tasks, and we consistently call it queuing delay.
|
||||
tracked_objects::TrackedTime EffectiveTimePosted() const {
|
||||
return tracked_objects::TrackedTime(
|
||||
delayed_run_time.is_null() ? time_posted : delayed_run_time);
|
||||
}
|
||||
|
||||
// Record of location and thread that the task came from.
|
||||
tracked_objects::Births* birth_tally;
|
||||
|
||||
// Time when the related task was posted.
|
||||
base::TimeTicks time_posted;
|
||||
|
||||
// The time when the task should be run.
|
||||
base::TimeTicks delayed_run_time;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_TRACKING_INFO_H_
|
Loading…
Reference in New Issue
Block a user