Skip to content

Commit

Permalink
Moved logic for mapping child process FDs for ICU and V8 into child_p…
Browse files Browse the repository at this point in the history
…rocess_launcher.cc

Used to be defined in each app's ContentBrowserClient, but since
content/ is the one that receives the FDs, it makes sense that it should
be the one to send them.

This also removes ChildProcessLauncher::AppendMappedFileCommandLineSwitches
as it is no longer needed.

BUG=394502

Review URL: https://codereview.chromium.org/1182443003

Cr-Commit-Position: refs/heads/master@{#334702}
  • Loading branch information
agrieve authored and Commit bot committed Jun 16, 2015
1 parent ddb8277 commit 228414f
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 458 deletions.
50 changes: 1 addition & 49 deletions ash/shell/content_client/shell_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,14 @@

#include "ash/shell/content_client/shell_browser_main_parts.h"
#include "base/command_line.h"
#include "content/public/common/content_descriptors.h"
#include "content/public/common/content_switches.h"
#include "content/shell/browser/shell_browser_context.h"
#include "gin/v8_initializer.h"
#include "third_party/skia/include/core/SkBitmap.h"

namespace ash {
namespace shell {

ShellContentBrowserClient::ShellContentBrowserClient()
:
#if defined(OS_POSIX) && !defined(OS_MACOSX)
v8_natives_fd_(-1),
v8_snapshot_fd_(-1),
#endif // OS_POSIX && !OS_MACOSX
shell_browser_main_parts_(nullptr) {
: shell_browser_main_parts_(nullptr) {
}

ShellContentBrowserClient::~ShellContentBrowserClient() {
Expand All @@ -43,46 +35,6 @@ net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
request_interceptors.Pass());
}

void ShellContentBrowserClient::AppendMappedFileCommandLineSwitches(
base::CommandLine* command_line) {
#if defined(OS_POSIX) && !defined(OS_MACOSX)
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
std::string process_type =
command_line->GetSwitchValueASCII(switches::kProcessType);
if (process_type != switches::kZygoteProcess) {
DCHECK(natives_fd_exists());
command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
if (snapshot_fd_exists())
command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
}
#endif // V8_USE_EXTERNAL_STARTUP_DATA
#endif // OS_POSIX && !OS_MACOSX
}

#if defined(OS_POSIX) && !defined(OS_MACOSX)
void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
content::FileDescriptorInfo* mappings) {
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
if (!natives_fd_exists()) {
int v8_natives_fd = -1;
int v8_snapshot_fd = -1;
if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
&v8_snapshot_fd)) {
v8_natives_fd_.reset(v8_natives_fd);
v8_snapshot_fd_.reset(v8_snapshot_fd);
}
}
// V8 can't start up without the source of the natives, but it can
// start up (slower) without the snapshot.
DCHECK(natives_fd_exists());
mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
#endif // V8_USE_EXTERNAL_STARTUP_DATA
}
#endif // OS_POSIX && !OS_MACOSX

content::ShellBrowserContext* ShellContentBrowserClient::browser_context() {
return shell_browser_main_parts_->browser_context();
}
Expand Down
16 changes: 0 additions & 16 deletions ash/shell/content_client/shell_content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,10 @@ class ShellContentBrowserClient : public content::ContentBrowserClient {
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors) override;
void AppendMappedFileCommandLineSwitches(
base::CommandLine* command_line) override;
#if defined(OS_POSIX) && !defined(OS_MACOSX)
void GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
content::FileDescriptorInfo* mappings) override;
#endif

content::ShellBrowserContext* browser_context();

private:
#if defined(OS_POSIX) && !defined(OS_MACOSX)
bool natives_fd_exists() { return v8_natives_fd_.is_valid(); }
bool snapshot_fd_exists() { return v8_snapshot_fd_.is_valid(); }

base::ScopedFD v8_natives_fd_;
base::ScopedFD v8_snapshot_fd_;
#endif

ShellBrowserMainParts* shell_browser_main_parts_;

DISALLOW_COPY_AND_ASSIGN(ShellContentBrowserClient);
Expand Down
186 changes: 105 additions & 81 deletions base/i18n/icu_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@
namespace base {
namespace i18n {

// Use an unversioned file name to simplify a icu version update down the road.
// No need to change the filename in multiple places (gyp files, windows
// build pkg configurations, etc). 'l' stands for Little Endian.
// This variable is exported through the header file.
const char kIcuDataFileName[] = "icudtl.dat";
#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
#if defined(OS_WIN)
Expand All @@ -47,44 +42,124 @@ const char kIcuDataFileName[] = "icudtl.dat";
#endif

namespace {

#if !defined(OS_NACL)
#if !defined(NDEBUG)
// Assert that we are not called more than once. Even though calling this
// function isn't harmful (ICU can handle it), being called twice probably
// indicates a programming error.
#if !defined(OS_NACL)
bool g_check_called_once = true;
bool g_called_once = false;
#endif // !defined(NDEBUG)

#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
// Use an unversioned file name to simplify a icu version update down the road.
// No need to change the filename in multiple places (gyp files, windows
// build pkg configurations, etc). 'l' stands for Little Endian.
// This variable is exported through the header file.
const char kIcuDataFileName[] = "icudtl.dat";

// File handle intentionally never closed. Not using File here because its
// Windows implementation guards against two instances owning the same
// PlatformFile (which we allow since we know it is never freed).
const PlatformFile kInvalidPlatformFile =
#if defined(OS_WIN)
INVALID_HANDLE_VALUE;
#else
-1;
#endif
bool g_check_called_once = true;
PlatformFile g_icudtl_pf = kInvalidPlatformFile;
CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, g_icudtl_mapped_file, ());
MemoryMappedFile::Region g_icudtl_region;

void LazyInitIcuDataFile() {
if (g_icudtl_pf != kInvalidPlatformFile) {
return;
}
#if !defined(OS_MACOSX)
FilePath data_path;
#if defined(OS_WIN)
// The data file will be in the same directory as the current module.
bool path_ok = PathService::Get(DIR_MODULE, &data_path);
wchar_t tmp_buffer[_MAX_PATH] = {0};
wcscpy_s(tmp_buffer, data_path.value().c_str());
debug::Alias(tmp_buffer);
CHECK(path_ok); // TODO(scottmg): http://crbug.com/445616
#elif defined(OS_ANDROID)
bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
#else
// For now, expect the data file to be alongside the executable.
// This is sufficient while we work on unit tests, but will eventually
// likely live in a data directory.
bool path_ok = PathService::Get(DIR_EXE, &data_path);
#endif
DCHECK(path_ok);
data_path = data_path.AppendASCII(kIcuDataFileName);

#if defined(OS_WIN)
// TODO(scottmg): http://crbug.com/445616
wchar_t tmp_buffer2[_MAX_PATH] = {0};
wcscpy_s(tmp_buffer2, data_path.value().c_str());
debug::Alias(tmp_buffer2);
#endif

#else
// Assume it is in the framework bundle's Resources directory.
ScopedCFTypeRef<CFStringRef> data_file_name(
SysUTF8ToCFStringRef(kIcuDataFileName));
FilePath data_path = mac::PathForFrameworkBundleResource(data_file_name);
if (data_path.empty()) {
LOG(ERROR) << kIcuDataFileName << " not found in bundle";
return;
}
#endif // !defined(OS_MACOSX)
File file(data_path, File::FLAG_OPEN | File::FLAG_READ);
if (file.IsValid()) {
g_icudtl_pf = file.TakePlatformFile();
g_icudtl_region = MemoryMappedFile::Region::kWholeFile;
}
}

bool InitializeICUWithFileDescriptorInternal(
PlatformFile data_fd,
const MemoryMappedFile::Region& data_region) {
// This can be called multiple times in tests.
if (g_icudtl_mapped_file.IsValid()) {
return true;
}
if (data_fd < 0) {
return false;
}
if (!g_icudtl_mapped_file.Initialize(File(data_fd), data_region)) {
LOG(ERROR) << "Couldn't mmap icu data file";
return false;
}
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(const_cast<uint8*>(g_icudtl_mapped_file.data()), &err);
return err == U_ZERO_ERROR;
}
#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
#endif // !defined(OS_NACL)

} // namespace

#if !defined(OS_NACL)
#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
bool InitializeICUWithFileDescriptor(
PlatformFile data_fd,
MemoryMappedFile::Region data_region) {
const MemoryMappedFile::Region& data_region) {
#if !defined(NDEBUG)
DCHECK(!g_check_called_once || !g_called_once);
g_called_once = true;
#endif

#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
// The ICU data is statically linked.
return true;
#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
if (!mapped_file.IsValid()) {
if (!mapped_file.Initialize(File(data_fd), data_region)) {
LOG(ERROR) << "Couldn't mmap icu data file";
return false;
}
}
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
return err == U_ZERO_ERROR;
#endif // ICU_UTIL_DATA_FILE
return InitializeICUWithFileDescriptorInternal(data_fd, data_region);
}

PlatformFile GetIcuDataFileHandle(MemoryMappedFile::Region* out_region) {
CHECK_NE(g_icudtl_pf, kInvalidPlatformFile);
*out_region = g_icudtl_region;
return g_icudtl_pf;
}
#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE

bool InitializeICU() {
#if !defined(NDEBUG)
Expand Down Expand Up @@ -123,60 +198,9 @@ bool InitializeICU() {
// it is needed. This can fail if the process is sandboxed at that time.
// Instead, we map the file in and hand off the data so the sandbox won't
// cause any problems.

// Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
// be released.
CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
if (!mapped_file.IsValid()) {
#if !defined(OS_MACOSX)
FilePath data_path;
#if defined(OS_WIN)
// The data file will be in the same directory as the current module.
bool path_ok = PathService::Get(DIR_MODULE, &data_path);
wchar_t tmp_buffer[_MAX_PATH] = {0};
wcscpy_s(tmp_buffer, data_path.value().c_str());
debug::Alias(tmp_buffer);
CHECK(path_ok); // TODO(scottmg): http://crbug.com/445616
#elif defined(OS_ANDROID)
bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
#else
// For now, expect the data file to be alongside the executable.
// This is sufficient while we work on unit tests, but will eventually
// likely live in a data directory.
bool path_ok = PathService::Get(DIR_EXE, &data_path);
#endif
DCHECK(path_ok);
data_path = data_path.AppendASCII(kIcuDataFileName);

#if defined(OS_WIN)
// TODO(scottmg): http://crbug.com/445616
wchar_t tmp_buffer2[_MAX_PATH] = {0};
wcscpy_s(tmp_buffer2, data_path.value().c_str());
debug::Alias(tmp_buffer2);
#endif

#else
// Assume it is in the framework bundle's Resources directory.
ScopedCFTypeRef<CFStringRef> data_file_name(
SysUTF8ToCFStringRef(kIcuDataFileName));
FilePath data_path =
mac::PathForFrameworkBundleResource(data_file_name);
if (data_path.empty()) {
LOG(ERROR) << kIcuDataFileName << " not found in bundle";
return false;
}
#endif // OS check
if (!mapped_file.Initialize(data_path)) {
#if defined(OS_WIN)
CHECK(false); // TODO(scottmg): http://crbug.com/445616
#endif
LOG(ERROR) << "Couldn't mmap " << data_path.AsUTF8Unsafe();
return false;
}
}
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
result = (err == U_ZERO_ERROR);
LazyInitIcuDataFile();
result = InitializeICUWithFileDescriptorInternal(
g_icudtl_pf, g_icudtl_region);
#if defined(OS_WIN)
CHECK(result); // TODO(scottmg): http://crbug.com/445616
#endif
Expand All @@ -193,10 +217,10 @@ bool InitializeICU() {
#endif
return result;
}
#endif
#endif // !defined(OS_NACL)

void AllowMultipleInitializeCallsForTesting() {
#if !defined(NDEBUG)
#if !defined(NDEBUG) && !defined(OS_NACL)
g_check_called_once = false;
#endif
}
Expand Down
13 changes: 9 additions & 4 deletions base/i18n/icu_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,24 @@
namespace base {
namespace i18n {

BASE_I18N_EXPORT extern const char kIcuDataFileName[];

#if !defined(OS_NACL)
// Call this function to load ICU's data tables for the current process. This
// function should be called before ICU is used.
BASE_I18N_EXPORT bool InitializeICU();

#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
// Returns the PlatformFile and Region that was initialized by InitializeICU().
// Use with InitializeICUWithFileDescriptor().
BASE_I18N_EXPORT PlatformFile GetIcuDataFileHandle(
MemoryMappedFile::Region* out_region);

// Android and html_viewer use a file descriptor passed by browser process to
// initialize ICU in render processes.
BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
PlatformFile data_fd,
MemoryMappedFile::Region data_region);
#endif
const MemoryMappedFile::Region& data_region);
#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
#endif // !defined(OS_NACL)

// In a test binary, the call above might occur twice.
BASE_I18N_EXPORT void AllowMultipleInitializeCallsForTesting();
Expand Down
Loading

0 comments on commit 228414f

Please sign in to comment.