Chromium Code Reviews| 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..da0b44874913ab8efab4c583ac28ce34cf68ca69 |
| --- /dev/null |
| +++ b/chrome/browser/android/seccomp_support_detector.cc |
| @@ -0,0 +1,132 @@ |
| +// 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 "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::PostTask(BrowserThread::FILE, FROM_HERE, |
| + base::Bind(&SeccompSupportDetector::DetectKernelVersion, detector)); |
| +} |
| + |
| +SeccompSupportDetector::SeccompSupportDetector() : prctl_detected_(false) { |
| +} |
| + |
| +SeccompSupportDetector::~SeccompSupportDetector() { |
| +} |
| + |
| +void SeccompSupportDetector::DetectKernelVersion() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| + |
| + // 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. |
| + |
| + // Support known Android kernel versions, and leave room up to 4.10. |
| + const int kVersionRanges[] = { |
| + 0x00020006, |
| + 0x00030000, |
| + 0x00030003, |
| + 0x00030004, |
| + 0x00030008, |
| + 0x00030010, |
| + 0x00030014, |
| + 0x00030017, |
| + 0x00030018, |
| + 0x00030019, |
| + 0x00040000, |
| + 0x00040001, |
| + 0x00040010, |
| + }; |
| + |
| + 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_CUSTOM_ENUMERATION( |
| + "Android.KernelVersion", version, |
| + base::CustomHistogram::ArrayToCustomRanges( |
| + kVersionRanges, arraysize(kVersionRanges))); |
| + } |
| + } |
| + |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SeccompSupportDetector::DetectSeccomp, this)); |
| +} |
| + |
| +void SeccompSupportDetector::DetectSeccomp() { |
| + DCHECK(BrowserThread::CurrentlyOn(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) { |
| + // 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) { |
| + prctl_detected_ = true; |
| + |
| + UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl", |
| + prctl_supported ? SUPPORTED : NOT_SUPPORTED, |
| + LAST_STATUS); |
| +} |
| + |
| +void SeccompSupportDetector::OnDetectSyscall(bool syscall_supported) { |
| + UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Syscall", |
|
jln (very slow on Chromium)
2015/03/19 00:12:12
DCHECK(prctl_detected); ?
Robert Sesek
2015/03/19 00:18:41
Done.
|
| + 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. |
| +} |