summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-03 20:30:43 +0000
committergspencer@chromium.org <gspencer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-03 20:30:43 +0000
commit232ed4691df490e376c74ecf04f2f6092f03427f (patch)
tree3dd09707acccf9eb175e592b4f0fbade06a5015b
parent9a4fd693db2ee9e383f7a826d50bc63bc5bf7db0 (diff)
downloadchromium_src-232ed4691df490e376c74ecf04f2f6092f03427f.zip
chromium_src-232ed4691df490e376c74ecf04f2f6092f03427f.tar.gz
chromium_src-232ed4691df490e376c74ecf04f2f6092f03427f.tar.bz2
This creates a field trial to determine the best level for low memory
notification. It creates a field trial with 7 groups: default (kernel default value), turning notification off (relying on OOM killer only), 0MB, 25MB, 50MB margin, 100MB margin, and 200MB margin. Also, in order to set parameters for the trial, this CL creates an API for setting the low memory margin. BUG=chromium-os:20080 TEST=Ran on device several times, checked that the memory margin was set correctly when the session started, and that different trial groups were selected. Review URL: http://codereview.chromium.org/10206029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135205 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc56
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.h4
-rw-r--r--chrome/browser/low_memory_observer.cc10
-rw-r--r--chrome/browser/low_memory_observer.h5
-rw-r--r--chrome/browser/oom_priority_manager.cc45
-rw-r--r--chrome/browser/ui/views/sad_tab_view.cc43
-rw-r--r--content/browser/zygote_host_impl_linux.cc42
-rw-r--r--content/browser/zygote_host_impl_linux.h3
-rw-r--r--content/public/browser/zygote_host_linux.h6
-rw-r--r--sandbox/linux/suid/process_util.h9
-rw-r--r--sandbox/linux/suid/process_util_linux.c35
-rw-r--r--sandbox/linux/suid/sandbox.c28
-rw-r--r--sandbox/linux/suid/sandbox.h24
-rw-r--r--sandbox/linux/suid/suid_unsafe_environment_variables.h8
-rw-r--r--sandbox/sandbox.gyp1
15 files changed, 275 insertions, 44 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index ea86e8f..5563502 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -49,6 +49,7 @@
#include "chrome/browser/chromeos/web_socket_proxy_controller.h"
#include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/low_memory_observer.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/oom_priority_manager.h"
#include "chrome/browser/policy/browser_policy_connector.h"
@@ -59,6 +60,7 @@
#include "chrome/browser/ui/views/browser_dialogs.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version_info.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
#include "chromeos/dbus/dbus_thread_manager.h"
@@ -285,6 +287,13 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopStart() {
ChromeBrowserMainPartsLinux::PostMainMessageLoopStart();
}
+int ChromeBrowserMainPartsChromeos::PreCreateThreads() {
+ // Set up field trial for low memory headroom settings.
+ SetupLowMemoryHeadroomFieldTrial();
+
+ return ChromeBrowserMainPartsLinux::PreCreateThreads();
+}
+
// Threads are initialized MainMessageLoopStart and MainMessageLoopRun.
void ChromeBrowserMainPartsChromeos::PreMainMessageLoopRun() {
@@ -495,3 +504,50 @@ void ChromeBrowserMainPartsChromeos::PostMainMessageLoopRun() {
ChromeBrowserMainPartsLinux::PostMainMessageLoopRun();
}
+
+void ChromeBrowserMainPartsChromeos::SetupLowMemoryHeadroomFieldTrial() {
+ chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
+ // Only enable this experiment on Canary and Dev, since it's possible
+ // that this will make the machine unstable.
+ // Note that to have this code execute in a developer build,
+ // then chrome::VersionInfo::CHANNEL_UNKNOWN needs to be added here.
+ if (channel == chrome::VersionInfo::CHANNEL_CANARY ||
+ channel == chrome::VersionInfo::CHANNEL_DEV) {
+ const base::FieldTrial::Probability kDivisor = 7;
+ // 1 in 7 probability of being in each group. If the default value for the
+ // kernel matches one of the experiment groups, then they will have
+ // identical results.
+ const base::FieldTrial::Probability kEnableProbability = 1;
+ scoped_refptr<base::FieldTrial> trial =
+ base::FieldTrialList::FactoryGetFieldTrial(
+ "LowMemoryMargin", kDivisor, "default", 2012, 6, 30, NULL);
+ int disable = trial->AppendGroup("off", kEnableProbability);
+ int margin_0mb = trial->AppendGroup("0mb", kEnableProbability);
+ int margin_25mb = trial->AppendGroup("25mb", kEnableProbability);
+ int margin_50mb = trial->AppendGroup("50mb", kEnableProbability);
+ int margin_100mb = trial->AppendGroup("100mb", kEnableProbability);
+ int margin_200mb = trial->AppendGroup("200mb", kEnableProbability);
+ if (trial->group() == disable) {
+ LOG(WARNING) << "low_mem: Part of 'off' experiment";
+ browser::LowMemoryObserver::SetLowMemoryMargin(0);
+ } else if (trial->group() == margin_0mb) {
+ LOG(WARNING) << "low_mem: Part of '0MB' experiment";
+ browser::LowMemoryObserver::SetLowMemoryMargin(50);
+ } else if (trial->group() == margin_25mb) {
+ LOG(WARNING) << "low_mem: Part of '25MB' experiment";
+ browser::LowMemoryObserver::SetLowMemoryMargin(50);
+ } else if (trial->group() == margin_50mb) {
+ LOG(WARNING) << "low_mem: Part of '50MB' experiment";
+ browser::LowMemoryObserver::SetLowMemoryMargin(50);
+ } else if (trial->group() == margin_100mb) {
+ LOG(WARNING) << "low_mem: Part of '100MB' experiment";
+ browser::LowMemoryObserver::SetLowMemoryMargin(100);
+ } else if (trial->group() == margin_200mb) {
+ LOG(WARNING) << "low_mem: Part of '200MB' experiment";
+ browser::LowMemoryObserver::SetLowMemoryMargin(200);
+ } else {
+ LOG(WARNING) << "low_mem: Part of 'default' experiment";
+ }
+ }
+}
+
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index a001ea1..4cc2a61 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -30,6 +30,7 @@ class ChromeBrowserMainPartsChromeos : public ChromeBrowserMainPartsLinux {
virtual void PreEarlyInitialization() OVERRIDE;
virtual void PreMainMessageLoopStart() OVERRIDE;
virtual void PostMainMessageLoopStart() OVERRIDE;
+ virtual int PreCreateThreads() OVERRIDE;
virtual void PreMainMessageLoopRun() OVERRIDE;
// Stages called from PreMainMessageLoopRun.
@@ -40,6 +41,9 @@ class ChromeBrowserMainPartsChromeos : public ChromeBrowserMainPartsLinux {
virtual void PostMainMessageLoopRun() OVERRIDE;
+ // Set up field trial for low memory headroom settings.
+ void SetupLowMemoryHeadroomFieldTrial();
+
private:
scoped_ptr<chromeos::BrightnessObserver> brightness_observer_;
scoped_ptr<chromeos::ResumeObserver> resume_observer_;
diff --git a/chrome/browser/low_memory_observer.cc b/chrome/browser/low_memory_observer.cc
index 8788f03..5396696 100644
--- a/chrome/browser/low_memory_observer.cc
+++ b/chrome/browser/low_memory_observer.cc
@@ -15,6 +15,11 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/oom_priority_manager.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/zygote_host_linux.h"
+
+#if !defined(OS_CHROMEOS)
+#error This file only meant to be compiled on ChromeOS
+#endif
using content::BrowserThread;
@@ -180,4 +185,9 @@ void LowMemoryObserver::Stop() {
observer_.get()));
}
+// static
+void LowMemoryObserver::SetLowMemoryMargin(int64 margin_mb) {
+ content::ZygoteHost::GetInstance()->AdjustLowMemoryMargin(margin_mb);
+}
+
} // namespace browser
diff --git a/chrome/browser/low_memory_observer.h b/chrome/browser/low_memory_observer.h
index 088a74c..1caad25 100644
--- a/chrome/browser/low_memory_observer.h
+++ b/chrome/browser/low_memory_observer.h
@@ -34,6 +34,11 @@ class LowMemoryObserver {
void Start();
void Stop();
+
+ // Sets the threshold level of the low memory notifier in megabytes. Setting
+ // to -1 will turn off the low memory notifier.
+ static void SetLowMemoryMargin(int64 margin_mb);
+
private:
scoped_refptr<LowMemoryObserverImpl> observer_;
diff --git a/chrome/browser/oom_priority_manager.cc b/chrome/browser/oom_priority_manager.cc
index 0d87d4c..60fa186 100644
--- a/chrome/browser/oom_priority_manager.cc
+++ b/chrome/browser/oom_priority_manager.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/process.h"
#include "base/process_util.h"
@@ -51,14 +52,25 @@ namespace browser {
namespace {
+// Name of the experiment to run.
+const char kExperiment[] = "LowMemoryMargin";
+
+#define EXPERIMENT_CUSTOM_COUNTS(name, sample, min, max, buckets) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, buckets); \
+ if (base::FieldTrialList::TrialExists(kExperiment)) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ base::FieldTrial::MakeName(name, kExperiment), \
+ sample, min, max, buckets);
+
// Record a time in seconds, over a potential interval of about a day. Must be a
// macro and not a function because the histograms system requires a unique
// static variable at the site of each call.
-#define UMA_HISTOGRAM_SECONDS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 10000, 50)
+#define EXPERIMENT_HISTOGRAM_SECONDS(name, sample) \
+ EXPERIMENT_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
// Record a size in megabytes, over a potential interval up to 32 GB.
-#define UMA_HISTOGRAM_MEGABYTES(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 32768, 50)
+#define EXPERIMENT_HISTOGRAM_MEGABYTES(name, sample) \
+ EXPERIMENT_CUSTOM_COUNTS(name, sample, 1, 32768, 50)
// The default interval in seconds after which to adjust the oom_score_adj
// value.
@@ -241,11 +253,11 @@ bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) {
void OomPriorityManager::RecordDiscardStatistics() {
// Record a raw count so we can compare to discard reloads.
discard_count_++;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Tabs.Discard.DiscardCount", discard_count_, 1, 1000, 50);
+ EXPERIMENT_CUSTOM_COUNTS("Tabs.Discard.DiscardCount",
+ discard_count_, 1, 1000, 50);
// TODO(jamescook): Maybe incorporate extension count?
- UMA_HISTOGRAM_COUNTS_100("Tabs.Discard.TabCount", GetTabCount());
+ EXPERIMENT_CUSTOM_COUNTS("Tabs.Discard.TabCount", GetTabCount(), 1, 100, 50);
// TODO(jamescook): If the time stats prove too noisy, then divide up users
// based on how heavily they use Chrome using tab count as a proxy.
@@ -254,23 +266,24 @@ void OomPriorityManager::RecordDiscardStatistics() {
// This is the first discard this session.
TimeDelta interval = TimeTicks::Now() - start_time_;
int interval_seconds = static_cast<int>(interval.InSeconds());
- UMA_HISTOGRAM_SECONDS("Tabs.Discard.InitialTime", interval_seconds);
+ EXPERIMENT_HISTOGRAM_SECONDS("Tabs.Discard.InitialTime", interval_seconds);
} else {
// Not the first discard, so compute time since last discard.
TimeDelta interval = TimeTicks::Now() - last_discard_time_;
int interval_seconds = static_cast<int>(interval.InSeconds());
- UMA_HISTOGRAM_SECONDS("Tabs.Discard.IntervalTime", interval_seconds);
+ EXPERIMENT_HISTOGRAM_SECONDS("Tabs.Discard.IntervalTime", interval_seconds);
}
// Record Chrome's concept of system memory usage at the time of the discard.
base::SystemMemoryInfoKB memory;
if (base::GetSystemMemoryInfo(&memory)) {
- int mem_anonymous_kb = memory.active_anon + memory.inactive_anon;
- UMA_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB",
- mem_anonymous_kb / 1024);
- int mem_available_kb =
- memory.active_file + memory.inactive_file + memory.free;
- UMA_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAvailableMB",
- mem_available_kb / 1024);
+ int mem_anonymous_mb = (memory.active_anon + memory.inactive_anon) / 1024;
+ EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB",
+ mem_anonymous_mb);
+
+ int mem_available_mb =
+ (memory.active_file + memory.inactive_file + memory.free) / 1024;
+ EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAvailableMB",
+ mem_available_mb);
}
// Set up to record the next interval.
last_discard_time_ = TimeTicks::Now();
diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc
index d64b2ac..566cf9b 100644
--- a/chrome/browser/ui/views/sad_tab_view.cc
+++ b/chrome/browser/ui/views/sad_tab_view.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/feedback/feedback_util.h"
@@ -28,23 +29,37 @@
using content::OpenURLParams;
using content::WebContents;
-static const int kPadding = 20;
-static const float kMessageSize = 0.65f;
-static const SkColor kTextColor = SK_ColorWHITE;
-static const SkColor kCrashColor = SkColorSetRGB(35, 48, 64);
-static const SkColor kKillColor = SkColorSetRGB(57, 48, 88);
+namespace {
+
+const int kPadding = 20;
+const float kMessageSize = 0.65f;
+const SkColor kTextColor = SK_ColorWHITE;
+const SkColor kCrashColor = SkColorSetRGB(35, 48, 64);
+const SkColor kKillColor = SkColorSetRGB(57, 48, 88);
const char kCategoryTagCrash[] = "Crash";
// Font size correction.
#if defined(CROS_FONTS_USING_BCI)
-static const int kTitleFontSizeDelta = 1;
-static const int kMessageFontSizeDelta = 0;
+const int kTitleFontSizeDelta = 1;
+const int kMessageFontSizeDelta = 0;
#else
-static const int kTitleFontSizeDelta = 2;
-static const int kMessageFontSizeDelta = 1;
+const int kTitleFontSizeDelta = 2;
+const int kMessageFontSizeDelta = 1;
#endif
+// Name of the experiment to run.
+const char kExperiment[] = "LowMemoryMargin";
+
+#define EXPERIMENT_CUSTOM_COUNTS(name, sample, min, max, buckets) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, buckets); \
+ if (base::FieldTrialList::TrialExists(kExperiment)) \
+ UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ base::FieldTrial::MakeName(name, kExperiment), \
+ sample, min, max, buckets);
+
+} // namespace
+
SadTabView::SadTabView(WebContents* web_contents, Kind kind)
: web_contents_(web_contents),
kind_(kind),
@@ -70,14 +85,16 @@ SadTabView::SadTabView(WebContents* web_contents, Kind kind)
switch (kind_) {
case CRASHED: {
static int crashed = 0;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Tabs.SadTab.CrashCreated", ++crashed, 1, 1000, 50);
+ crashed++;
+ EXPERIMENT_CUSTOM_COUNTS(
+ "Tabs.SadTab.CrashCreated", crashed, 1, 1000, 50);
break;
}
case KILLED: {
static int killed = 0;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Tabs.SadTab.KillCreated", ++killed, 1, 1000, 50);
+ killed++;
+ EXPERIMENT_CUSTOM_COUNTS(
+ "Tabs.SadTab.KillCreated", killed, 1, 1000, 50);
break;
}
default:
diff --git a/content/browser/zygote_host_impl_linux.cc b/content/browser/zygote_host_impl_linux.cc
index 519fa12..40dcc6a 100644
--- a/content/browser/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host_impl_linux.cc
@@ -30,6 +30,7 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
+#include "sandbox/linux/suid/sandbox.h"
#include "sandbox/linux/suid/suid_unsafe_environment_variables.h"
#if defined(USE_TCMALLOC)
@@ -371,13 +372,9 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
if (IsHeapProfilerRunning())
return;
#endif
- // The command line switch used for supplying the OOM adjustment score
- // to the setuid sandbox.
- static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
-
std::vector<std::string> adj_oom_score_cmdline;
adj_oom_score_cmdline.push_back(sandbox_binary_);
- adj_oom_score_cmdline.push_back(kAdjustOOMScoreSwitch);
+ adj_oom_score_cmdline.push_back(sandbox::kAdjustOOMScoreSwitch);
adj_oom_score_cmdline.push_back(base::Int64ToString(pid));
adj_oom_score_cmdline.push_back(base::IntToString(score));
@@ -393,6 +390,41 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
}
#endif
+void ZygoteHostImpl::AdjustLowMemoryMargin(int64 margin_mb) {
+#if defined(OS_CHROMEOS)
+ // You can't change the low memory margin unless you're root. Because of this,
+ // we can't set the low memory margin from the browser process.
+ // So, we use the SUID binary to change it for us.
+ if (using_suid_sandbox_) {
+#if defined(USE_TCMALLOC)
+ // If heap profiling is running, these processes are not exiting, at least
+ // on ChromeOS. The easiest thing to do is not launch them when profiling.
+ // TODO(stevenjb): Investigate further and fix.
+ if (IsHeapProfilerRunning())
+ return;
+#endif
+ std::vector<std::string> adj_low_mem_commandline;
+ adj_low_mem_commandline.push_back(sandbox_binary_);
+ adj_low_mem_commandline.push_back(sandbox::kAdjustLowMemMarginSwitch);
+ adj_low_mem_commandline.push_back(base::Int64ToString(margin_mb));
+
+ base::ProcessHandle sandbox_helper_process;
+ if (base::LaunchProcess(adj_low_mem_commandline, base::LaunchOptions(),
+ &sandbox_helper_process)) {
+ base::EnsureProcessGetsReaped(sandbox_helper_process);
+ } else {
+ LOG(ERROR) << "Unable to run suid sandbox to set low memory margin.";
+ }
+ }
+ // Don't adjust memory margin if we're not running with the sandbox: this
+ // isn't very common, and not doing it has little impact.
+#else
+ // Low memory notification is currently only implemented on ChromeOS.
+ NOTREACHED() << "AdjustLowMemoryMargin not implemented";
+#endif // defined(OS_CHROMEOS)
+}
+
+
void ZygoteHostImpl::EnsureProcessTerminated(pid_t process) {
DCHECK(init_);
Pickle pickle;
diff --git a/content/browser/zygote_host_impl_linux.h b/content/browser/zygote_host_impl_linux.h
index 3c6e824..ad8dfac 100644
--- a/content/browser/zygote_host_impl_linux.h
+++ b/content/browser/zygote_host_impl_linux.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -55,6 +55,7 @@ class CONTENT_EXPORT ZygoteHostImpl : public content::ZygoteHost {
virtual int GetSandboxStatus() const OVERRIDE;
virtual void AdjustRendererOOMScore(base::ProcessHandle process_handle,
int score) OVERRIDE;
+ virtual void AdjustLowMemoryMargin(int64 margin_mb) OVERRIDE;
private:
friend struct DefaultSingletonTraits<ZygoteHostImpl>;
diff --git a/content/public/browser/zygote_host_linux.h b/content/public/browser/zygote_host_linux.h
index 2b79b30..cd9932e 100644
--- a/content/public/browser/zygote_host_linux.h
+++ b/content/public/browser/zygote_host_linux.h
@@ -46,6 +46,12 @@ class ZygoteHost {
// likely to be killed by the OOM killer.
virtual void AdjustRendererOOMScore(base::ProcessHandle process_handle,
int score) = 0;
+
+ // Adjust the point at which the low memory notifier in the kernel tells
+ // us that we're low on memory. When there is less than |margin_mb| left,
+ // then the notifier will notify us. Set |margin_mb| to -1 to turn off
+ // low memory notification altogether.
+ virtual void AdjustLowMemoryMargin(int64 margin_mb) = 0;
};
} // namespace content
diff --git a/sandbox/linux/suid/process_util.h b/sandbox/linux/suid/process_util.h
index 1826555..61f7b25 100644
--- a/sandbox/linux/suid/process_util.h
+++ b/sandbox/linux/suid/process_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,6 +7,7 @@
#ifndef SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
#define SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
+#pragma once
#include <stdbool.h>
#include <sys/types.h>
@@ -23,4 +24,10 @@
// values, of course.
BASE_EXPORT bool AdjustOOMScore(pid_t process, int score);
+// This adjusts /sys/kernel/mm/chromeos-low_mem/margin so that
+// the kernel notifies us that we are low on memory when less than
+// |margin_mb| megabytes are available. Setting |margin_mb| to -1
+// turns off low memory notification.
+BASE_EXPORT bool AdjustLowMemoryMargin(int64_t margin_mb);
+
#endif // SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
diff --git a/sandbox/linux/suid/process_util_linux.c b/sandbox/linux/suid/process_util_linux.c
index 13f45ce..1829558 100644
--- a/sandbox/linux/suid/process_util_linux.c
+++ b/sandbox/linux/suid/process_util_linux.c
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -24,6 +24,12 @@
static const int kMaxOomScore = 1000;
static const int kMaxOldOomScore = 15;
+// Kernel pseudo-file that allows setting of the low memory margin.
+static const char kLowMemMarginFile[] =
+ "/sys/kernel/mm/chromeos-low_mem/margin";
+
+// NOTE: This is not the only version of this function in the source:
+// the base library (in process_util_linux.cc) also has its own C++ version.
bool AdjustOOMScore(pid_t process, int score) {
if (score < 0 || score > kMaxOomScore)
return false;
@@ -71,3 +77,30 @@ bool AdjustOOMScore(pid_t process, int score) {
close(fd);
return (bytes_written == len);
}
+
+bool AdjustLowMemoryMargin(int64_t margin_mb) {
+ int file_descriptor = open(kLowMemMarginFile, O_WRONLY);
+ if (file_descriptor < 0)
+ return false;
+
+ // Only allow those values which are reasonable, to prevent mischief.
+ char value[21];
+ switch (margin_mb) {
+ case -1L:
+ snprintf(value, sizeof(value), "off");
+ break;
+ case 0L:
+ case 25L:
+ case 50L:
+ case 100L:
+ case 200L:
+ snprintf(value, sizeof(value), "%zu", margin_mb);
+ break;
+ default:
+ return false;
+ }
+
+ bool success = (write(file_descriptor, value, strlen(value)) >= 0);
+ close(file_descriptor);
+ return success;
+}
diff --git a/sandbox/linux/suid/sandbox.c b/sandbox/linux/suid/sandbox.c
index a83291e..41a68c7 100644
--- a/sandbox/linux/suid/sandbox.c
+++ b/sandbox/linux/suid/sandbox.c
@@ -4,6 +4,8 @@
// http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
+#include "sandbox.h"
+
#define _GNU_SOURCE
#include <asm/unistd.h>
#include <errno.h>
@@ -38,7 +40,6 @@
#define CLONE_NEWNET 0x40000000
#endif
-static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
@@ -405,9 +406,10 @@ int main(int argc, char **argv) {
// when you call it with --find-inode INODE_NUMBER.
if (argc == 3 && (0 == strcmp(argv[1], kFindInodeSwitch))) {
pid_t pid;
- char* endptr;
+ char* endptr = NULL;
+ errno = 0;
ino_t inode = strtoull(argv[2], &endptr, 10);
- if (inode == ULLONG_MAX || *endptr)
+ if (inode == ULLONG_MAX || !endptr || *endptr || errno != 0)
return 1;
if (!FindProcessHoldingSocket(&pid, inode))
return 1;
@@ -417,17 +419,31 @@ int main(int argc, char **argv) {
// Likewise, we cannot adjust /proc/pid/oom_adj for sandboxed renderers
// because those files are owned by root. So we need another helper here.
if (argc == 4 && (0 == strcmp(argv[1], kAdjustOOMScoreSwitch))) {
- char* endptr;
+ char* endptr = NULL;
long score;
+ errno = 0;
unsigned long pid_ul = strtoul(argv[2], &endptr, 10);
- if (pid_ul == ULONG_MAX || *endptr)
+ if (pid_ul == ULONG_MAX || !endptr || *endptr || errno != 0)
return 1;
pid_t pid = pid_ul;
+ endptr = NULL;
+ errno = 0;
score = strtol(argv[3], &endptr, 10);
- if (score == LONG_MAX || score == LONG_MIN || *endptr)
+ if (score == LONG_MAX || score == LONG_MIN ||
+ !endptr || *endptr || errno != 0)
return 1;
return AdjustOOMScore(pid, score);
}
+#if defined(OS_CHROMEOS)
+ if (argc == 3 && (0 == strcmp(argv[1], kAdjustLowMemMarginSwitch))) {
+ char* endptr = NULL;
+ errno = 0;
+ unsigned long margin_mb = strtoul(argv[2], &endptr, 10);
+ if (!endptr || *endptr || errno != 0)
+ return 1;
+ return AdjustLowMemoryMargin(margin_mb);
+ }
+#endif
if (!MoveToNewNamespaces())
return 1;
diff --git a/sandbox/linux/suid/sandbox.h b/sandbox/linux/suid/sandbox.h
new file mode 100644
index 0000000..e9ae90c
--- /dev/null
+++ b/sandbox/linux/suid/sandbox.h
@@ -0,0 +1,24 @@
+// 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 SANDBOX_LINUX_SUID_SANDBOX_H_
+#define SANDBOX_LINUX_SUID_SANDBOX_H_
+#pragma once
+
+#if defined(__cplusplus)
+namespace sandbox {
+#endif
+
+// These are command line switches that may be used by other programs
+// (e.g. Chrome) to construct a command line for the sandbox.
+static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
+#if defined(OS_CHROMEOS)
+static const char kAdjustLowMemMarginSwitch[] = "--adjust-low-mem";
+#endif
+
+#if defined(__cplusplus)
+} // namespace sandbox
+#endif
+
+#endif // SANDBOX_LINUX_SUID_SANDBOX_H_
diff --git a/sandbox/linux/suid/suid_unsafe_environment_variables.h b/sandbox/linux/suid/suid_unsafe_environment_variables.h
index 5862010..d216819 100644
--- a/sandbox/linux/suid/suid_unsafe_environment_variables.h
+++ b/sandbox/linux/suid/suid_unsafe_environment_variables.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -13,6 +13,10 @@
// sysdeps/unix/sysv/linux/i386/dl-librecon.h
// sysdeps/generic/unsecvars.h
+#ifndef SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#define SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#pragma once
+
static const char* kSUIDUnsafeEnvironmentVariables[] = {
"LD_AOUT_LIBRARY_PATH",
"LD_AOUT_PRELOAD",
@@ -57,3 +61,5 @@ static inline char* SandboxSavedEnvironmentVariable(const char* envvar) {
return saved_envvar;
}
+
+#endif // SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp
index 50a9bfe..a3593c6 100644
--- a/sandbox/sandbox.gyp
+++ b/sandbox/sandbox.gyp
@@ -167,6 +167,7 @@
'linux/suid/linux_util.h',
'linux/suid/process_util.h',
'linux/suid/process_util_linux.c',
+ 'linux/suid/sandbox.h',
'linux/suid/sandbox.c',
],
'cflags': [