blob: eb017e050329eabedb27479c9277e99f7e10ba08 [file] [log] [blame]
// Copyright 2018 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/oom_intervention/oom_intervention_config.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/system/sys_info.h"
#include "chrome/common/chrome_features.h"
#include "components/subresource_filter/core/common/common_features.h"
namespace {
const char kUseComponentCallbacks[] = "use_component_callbacks";
const char kSwapFreeThresholdRatioParamName[] = "swap_free_threshold_ratio";
const char kRendererWorkloadThresholdDeprecated[] =
"renderer_workload_threshold";
const char kRendererWorkloadThresholdPercentage[] =
"renderer_workload_threshold_percentage";
const char kRendererPMFThresholdPercentage[] =
"renderer_pmf_threshold_percentage";
const char kRendererSwapThresholdPercentage[] =
"renderer_swap_threshold_percentage";
const char kRendererVirtualMemThresholdPercentage[] =
"renderer_virtual_mem_threshold_percentage";
// Default SwapFree/SwapTotal ratio for detecting near-OOM situation.
// TODO(bashi): Confirm that this is appropriate.
const double kDefaultSwapFreeThresholdRatio = 0.45;
// Field trial parameter names.
const char kRendererPauseParamName[] = "pause_renderer";
const char kNavigateAdsParamName[] = "navigate_ads";
const char kPurgeV8MemoryParamName[] = "purge_v8";
const char kShouldDetectInRenderer[] = "detect_in_renderer";
bool GetThresholdParam(const char* param,
size_t ram_size,
uint64_t* threshold) {
std::string str =
base::GetFieldTrialParamValueByFeature(features::kOomIntervention, param);
uint64_t value = 0;
if (!base::StringToUint64(str, &value))
return false;
*threshold = value * ram_size / 100;
return *threshold > 0;
}
bool GetRendererMemoryThresholds(blink::mojom::DetectionArgsPtr* args) {
static size_t kRAMSize = base::SysInfo::AmountOfPhysicalMemory();
bool has_blink =
GetThresholdParam(kRendererWorkloadThresholdPercentage, kRAMSize,
&(*args)->blink_workload_threshold);
bool has_pmf = GetThresholdParam(kRendererPMFThresholdPercentage, kRAMSize,
&(*args)->private_footprint_threshold);
bool has_swap = GetThresholdParam(kRendererSwapThresholdPercentage, kRAMSize,
&(*args)->swap_threshold);
bool has_vm_size = GetThresholdParam(kRendererVirtualMemThresholdPercentage,
kRAMSize, &(*args)->swap_threshold);
if (has_blink || has_pmf || has_swap || has_vm_size)
return true;
// Check for old trigger param. If the old trigger param is set, then enable
// intervention only on 512MB devices.
if (kRAMSize > 512 * 1024 * 1024)
return false;
std::string threshold_str = base::GetFieldTrialParamValueByFeature(
features::kOomIntervention, kRendererWorkloadThresholdDeprecated);
uint64_t threshold = 0;
if (base::StringToUint64(threshold_str, &threshold) && threshold > 0) {
(*args)->blink_workload_threshold = threshold;
return true;
}
// If no param is set then the intervention is enabled. No default param is
// assumed.
return false;
}
bool GetSwapFreeThreshold(uint64_t* threshold) {
base::SystemMemoryInfoKB memory_info;
if (!base::GetSystemMemoryInfo(&memory_info))
return false;
// If there is no swap (zram) the monitor doesn't work because we use
// SwapFree as the tracking metric.
if (memory_info.swap_total == 0)
return false;
double threshold_ratio = base::GetFieldTrialParamByFeatureAsDouble(
features::kOomIntervention, kSwapFreeThresholdRatioParamName,
kDefaultSwapFreeThresholdRatio);
*threshold = static_cast<uint64_t>(memory_info.swap_total * threshold_ratio);
return true;
}
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class OomInterventionBrowserMonitorStatus {
kEnabledWithValidConfig = 0,
kDisabledWithInvalidParam = 1,
kEnabledWithNoSwap = 2,
kMaxValue = kEnabledWithNoSwap
};
} // namespace
OomInterventionConfig::OomInterventionConfig()
: is_intervention_enabled_(
base::SysInfo::IsLowEndDevice() &&
base::FeatureList::IsEnabled(subresource_filter::kAdTagging) &&
base::FeatureList::IsEnabled(features::kOomIntervention)),
renderer_detection_args_(blink::mojom::DetectionArgs::New()) {
if (!is_intervention_enabled_)
return;
is_renderer_pause_enabled_ = base::GetFieldTrialParamByFeatureAsBool(
features::kOomIntervention, kRendererPauseParamName, true);
is_navigate_ads_enabled_ = base::GetFieldTrialParamByFeatureAsBool(
features::kOomIntervention, kNavigateAdsParamName, true);
is_purge_v8_memory_enabled_ = base::GetFieldTrialParamByFeatureAsBool(
features::kOomIntervention, kPurgeV8MemoryParamName, false);
should_detect_in_renderer_ = base::GetFieldTrialParamByFeatureAsBool(
features::kOomIntervention, kShouldDetectInRenderer, true);
use_components_callback_ = base::GetFieldTrialParamByFeatureAsBool(
features::kOomIntervention, kUseComponentCallbacks, true);
OomInterventionBrowserMonitorStatus status =
OomInterventionBrowserMonitorStatus::kEnabledWithValidConfig;
if (!GetSwapFreeThreshold(&swapfree_threshold_)) {
is_swap_monitor_enabled_ = false;
status = OomInterventionBrowserMonitorStatus::kEnabledWithNoSwap;
}
// If no threshold is specified, set blink_workload_threshold to 10 by
// default, meaning that 10% of the RAM size is set to blink memory usage
// threshold to trigger intervention.
if (!GetRendererMemoryThresholds(&renderer_detection_args_)) {
renderer_detection_args_->blink_workload_threshold = 10;
}
}
// static
const OomInterventionConfig* OomInterventionConfig::GetInstance() {
static OomInterventionConfig* config = new OomInterventionConfig();
return config;
}
blink::mojom::DetectionArgsPtr
OomInterventionConfig::GetRendererOomDetectionArgs() const {
return renderer_detection_args_.Clone();
}