Index: content/browser/zygote_main_linux.cc |
diff --git a/content/browser/zygote_main_linux.cc b/content/browser/zygote_main_linux.cc |
index aad52839e9691ad989211561585fd1dc595fc307..10c4983e208df9284bb4620da576bd2b4cdda9ca 100644 |
--- a/content/browser/zygote_main_linux.cc |
+++ b/content/browser/zygote_main_linux.cc |
@@ -96,6 +96,10 @@ class Zygote { |
public: |
Zygote(int sandbox_flags, ZygoteForkDelegate* helper) |
: sandbox_flags_(sandbox_flags), helper_(helper) { |
+ if (helper_) |
+ helper_->InitialUMA(&initial_uma_name_, |
+ &initial_uma_sample_, |
+ &initial_uma_boundary_value_); |
} |
bool ProcessRequests() { |
@@ -253,10 +257,16 @@ class Zygote { |
// This is equivalent to fork(), except that, when using the SUID |
// sandbox, it returns the real PID of the child process as it |
// appears outside the sandbox, rather than returning the PID inside |
- // the sandbox. |
+ // the sandbox. Optionally, it fills in uma_name et al with a report |
+ // the helper wants to make via UMA_HISTOGRAM_ENUMERATION. |
int ForkWithRealPid(const std::string& process_type, std::vector<int>& fds, |
- const std::string& channel_switch) { |
- const bool use_helper = (helper_ && helper_->CanHelp(process_type)); |
+ const std::string& channel_switch, |
+ std::string* uma_name, |
+ int* uma_sample, int* uma_boundary_value) { |
+ const bool use_helper = (helper_ && helper_->CanHelp(process_type, |
+ uma_name, |
+ uma_sample, |
+ uma_boundary_value)); |
if (!(use_helper || g_suid_sandbox_active)) { |
return fork(); |
} |
@@ -382,7 +392,10 @@ class Zygote { |
// process and the child process ID to the parent process, like fork(). |
base::ProcessId ReadArgsAndFork(const Pickle& pickle, |
void* iter, |
- std::vector<int>& fds) { |
+ std::vector<int>& fds, |
+ std::string* uma_name, |
+ int* uma_sample, |
+ int* uma_boundary_value) { |
std::vector<std::string> args; |
int argc = 0; |
int numfds = 0; |
@@ -422,7 +435,9 @@ class Zygote { |
static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); |
// Returns twice, once per process. |
- base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id); |
+ base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id, |
+ uma_name, uma_sample, |
+ uma_boundary_value); |
if (!child_pid) { |
// This is the child process. |
#if defined(SECCOMP_SANDBOX) |
@@ -470,14 +485,36 @@ class Zygote { |
// child_pid of -1 on error. |
bool HandleForkRequest(int fd, const Pickle& pickle, |
void* iter, std::vector<int>& fds) { |
- base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds); |
+ std::string uma_name; |
+ int uma_sample; |
+ int uma_boundary_value; |
+ base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds, |
+ &uma_name, &uma_sample, |
+ &uma_boundary_value); |
if (child_pid == 0) |
return true; |
for (std::vector<int>::const_iterator |
i = fds.begin(); i != fds.end(); ++i) |
close(*i); |
+ if (uma_name.empty()) { |
+ // There is no UMA report from this particular fork. |
+ // Use the initial UMA report if any, and clear that record for next time. |
+ // Note the swap method here is the efficient way to do this, since |
+ // we know uma_name is empty. |
+ uma_name.swap(initial_uma_name_); |
+ uma_sample = initial_uma_sample_; |
+ uma_boundary_value = initial_uma_boundary_value_; |
+ } |
// Must always send reply, as ZygoteHost blocks while waiting for it. |
- if (HANDLE_EINTR(write(fd, &child_pid, sizeof(child_pid))) < 0) |
+ Pickle reply_pickle; |
+ reply_pickle.WriteInt(child_pid); |
+ reply_pickle.WriteString(uma_name); |
+ if (!uma_name.empty()) { |
+ reply_pickle.WriteInt(uma_sample); |
+ reply_pickle.WriteInt(uma_boundary_value); |
+ } |
+ if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != |
+ static_cast<ssize_t> (reply_pickle.size())) |
PLOG(ERROR) << "write"; |
return false; |
} |
@@ -499,6 +536,12 @@ class Zygote { |
const int sandbox_flags_; |
ZygoteForkDelegate* helper_; |
+ |
+ // These might be set by helper_->InitialUMA. They supply a UMA |
+ // enumeration sample we should report on the first fork. |
+ std::string initial_uma_name_; |
+ int initial_uma_sample_; |
+ int initial_uma_boundary_value_; |
}; |
// With SELinux we can carve out a precise sandbox, so we don't have to play |