| Index: chrome/browser/android/seccomp_support_detector.cc | 
| diff --git a/chrome/browser/android/seccomp_support_detector.cc b/chrome/browser/android/seccomp_support_detector.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..4488aee11afb63b5c9badec05149704050916f9c | 
| --- /dev/null | 
| +++ b/chrome/browser/android/seccomp_support_detector.cc | 
| @@ -0,0 +1,127 @@ | 
| +// Copyright 2015 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 "chrome/browser/android/seccomp_support_detector.h" | 
| + | 
| +#include <stdio.h> | 
| +#include <sys/utsname.h> | 
| + | 
| +#include "base/message_loop/message_loop_proxy.h" | 
| +#include "base/metrics/histogram_macros.h" | 
| +#include "base/metrics/sparse_histogram.h" | 
| +#include "chrome/common/chrome_utility_messages.h" | 
| +#include "content/public/browser/browser_thread.h" | 
| +#include "content/public/browser/utility_process_host.h" | 
| + | 
| +using content::BrowserThread; | 
| + | 
| +enum AndroidSeccompStatus { | 
| +  DETECTION_FAILED,  // The process crashed during detection. | 
| +  NOT_SUPPORTED,     // Kernel has no seccomp support. | 
| +  SUPPORTED,         // Kernel has seccomp support. | 
| +  LAST_STATUS | 
| +}; | 
| + | 
| +// static | 
| +void SeccompSupportDetector::StartDetection() { | 
| +  // This is instantiated here, and then ownership is maintained by the | 
| +  // Closure objects when the object is being passed between threads. A | 
| +  // reference is also taken by the UtilityProcessHost, which will release | 
| +  // it when the process exits. | 
| +  scoped_refptr<SeccompSupportDetector> detector(new SeccompSupportDetector()); | 
| +  BrowserThread::PostBlockingPoolTask(FROM_HERE, | 
| +      base::Bind(&SeccompSupportDetector::DetectKernelVersion, detector)); | 
| +} | 
| + | 
| +SeccompSupportDetector::SeccompSupportDetector() : prctl_detected_(false) { | 
| +} | 
| + | 
| +SeccompSupportDetector::~SeccompSupportDetector() { | 
| +} | 
| + | 
| +void SeccompSupportDetector::DetectKernelVersion() { | 
| +  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | 
| + | 
| +  // This method will report the kernel major and minor versions by | 
| +  // taking the lower 16 bits of each version number and combining | 
| +  // the two into a 32-bit number. | 
| + | 
| +  utsname uts; | 
| +  if (uname(&uts) == 0) { | 
| +    int major, minor; | 
| +    if (sscanf(uts.release, "%d.%d", &major, &minor) == 2) { | 
| +      int version = ((major & 0xFFFF) << 16) | (minor & 0xFFFF); | 
| +      UMA_HISTOGRAM_SPARSE_SLOWLY("Android.KernelVersion", version); | 
| +    } | 
| +  } | 
| + | 
| +#if defined(USE_SECCOMP_BPF) | 
| +  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 
| +      base::Bind(&SeccompSupportDetector::DetectSeccomp, this)); | 
| +#else | 
| +  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 
| +      base::Bind(&SeccompSupportDetector::OnDetectPrctl, this, false)); | 
| +  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 
| +      base::Bind(&SeccompSupportDetector::OnDetectSyscall, this, false)); | 
| +#endif | 
| +} | 
| + | 
| +void SeccompSupportDetector::DetectSeccomp() { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| + | 
| +  content::UtilityProcessHost* utility_process_host = | 
| +      content::UtilityProcessHost::Create( | 
| +          this, base::MessageLoopProxy::current()); | 
| +  utility_process_host->Send(new ChromeUtilityMsg_DetectSeccompSupport()); | 
| +} | 
| + | 
| +void SeccompSupportDetector::OnProcessCrashed(int exit_code) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  // The process crashed. Since prctl detection happens first, report which | 
| +  // probe failed. | 
| +  if (prctl_detected_) { | 
| +    UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Syscall", | 
| +                              DETECTION_FAILED, | 
| +                              LAST_STATUS); | 
| +  } else { | 
| +    UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl", | 
| +                              DETECTION_FAILED, | 
| +                              LAST_STATUS); | 
| +  } | 
| +} | 
| + | 
| +bool SeccompSupportDetector::OnMessageReceived(const IPC::Message& message) { | 
| +  bool handled = false; | 
| +  IPC_BEGIN_MESSAGE_MAP(SeccompSupportDetector, message) | 
| +    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl, | 
| +                        OnDetectPrctl) | 
| +    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DetectSeccompSupport_ResultSyscall, | 
| +                        OnDetectSyscall) | 
| +    IPC_MESSAGE_UNHANDLED(handled = false) | 
| +  IPC_END_MESSAGE_MAP() | 
| +  return handled; | 
| +} | 
| + | 
| +void SeccompSupportDetector::OnDetectPrctl(bool prctl_supported) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  DCHECK(!prctl_detected_); | 
| + | 
| +  prctl_detected_ = true; | 
| + | 
| +  UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl", | 
| +                            prctl_supported ? SUPPORTED : NOT_SUPPORTED, | 
| +                            LAST_STATUS); | 
| +} | 
| + | 
| +void SeccompSupportDetector::OnDetectSyscall(bool syscall_supported) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  DCHECK(prctl_detected_); | 
| + | 
| +  UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Syscall", | 
| +                            syscall_supported ? SUPPORTED : NOT_SUPPORTED, | 
| +                            LAST_STATUS); | 
| + | 
| +  // The utility process will shutdown after this, and this object will | 
| +  // be deleted when the UtilityProcessHost releases its reference. | 
| +} | 
|  |