blob: 0fe85a85bd4351d85f2fc306cf2485204c7272ce [file] [log] [blame]
// Copyright 2021 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 "net/android/radio_activity_tracker.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "net/base/features.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace net {
namespace android {
namespace {
// The minimum interval for recording possible radio wake-ups. It's unlikely
// that radio state transitions happen in seconds.
constexpr base::TimeDelta kMinimumRecordIntervalForPossibleWakeupTrigger =
base::Seconds(1);
} // namespace
// static
RadioActivityTracker& RadioActivityTracker::GetInstance() {
static base::NoDestructor<RadioActivityTracker> s_instance;
return *s_instance;
}
RadioActivityTracker::RadioActivityTracker() = default;
bool RadioActivityTracker::ShouldRecordActivityForWakeupTrigger() {
if (!base::FeatureList::IsEnabled(features::kRecordRadioWakeupTrigger))
return false;
if (!IsRadioUtilsSupported())
return false;
base::TimeTicks now = base::TimeTicks::Now();
// Check recording interval first to reduce overheads of calling Android's
// platform APIs.
if (!last_check_time_.is_null() &&
now - last_check_time_ < kMinimumRecordIntervalForPossibleWakeupTrigger)
return false;
last_check_time_ = now;
bool should_record = ShouldRecordActivityForWakeupTriggerInternal();
// TODO(crbug.com/1232623): Use "Net." prefix instead of "Network."
base::UmaHistogramTimes(
"Network.Radio.PossibleWakeupTrigger.RadioUtilsOverhead",
base::TimeTicks::Now() - now);
return should_record;
}
bool RadioActivityTracker::IsRadioUtilsSupported() {
return base::android::RadioUtils::IsSupported() ||
radio_activity_override_for_testing_.has_value() ||
radio_type_override_for_testing_.has_value();
}
bool RadioActivityTracker::ShouldRecordActivityForWakeupTriggerInternal() {
base::android::RadioConnectionType radio_type =
radio_type_override_for_testing_.value_or(
base::android::RadioUtils::GetConnectionType());
if (radio_type != base::android::RadioConnectionType::kCell)
return false;
absl::optional<base::android::RadioDataActivity> radio_activity =
radio_activity_override_for_testing_.has_value()
? radio_activity_override_for_testing_
: base::android::RadioUtils::GetCellDataActivity();
if (!radio_activity.has_value())
return false;
// When the last activity was dormant, don't treat this event as a wakeup
// trigger since there could be state transition delay and startup latency.
bool should_record =
*radio_activity == base::android::RadioDataActivity::kDormant &&
last_radio_data_activity_ != base::android::RadioDataActivity::kDormant;
last_radio_data_activity_ = *radio_activity;
return should_record;
}
void MaybeRecordTCPWriteForWakeupTrigger(
const NetworkTrafficAnnotationTag& traffic_annotation) {
if (!RadioActivityTracker::GetInstance()
.ShouldRecordActivityForWakeupTrigger()) {
return;
}
base::UmaHistogramSparse(kUmaNamePossibleWakeupTriggerTCPWriteAnnotationId,
traffic_annotation.unique_id_hash_code);
}
void MaybeRecordUDPWriteForWakeupTrigger(
const NetworkTrafficAnnotationTag& traffic_annotation) {
if (!RadioActivityTracker::GetInstance()
.ShouldRecordActivityForWakeupTrigger()) {
return;
}
base::UmaHistogramSparse(kUmaNamePossibleWakeupTriggerUDPWriteAnnotationId,
traffic_annotation.unique_id_hash_code);
}
} // namespace android
} // namespace net