blob: ff7681f2ea3da9f577f24b76d3151f7516d21a67 [file] [log] [blame]
// 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/data_usage/tab_data_use_entry.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/android/data_usage/data_use_tab_model.h"
#include "chrome/browser/android/data_usage/external_data_use_observer.h"
#include "components/variations/variations_associated_data.h"
namespace {
const char kUMATrackingSessionLifetimeHistogram[] =
"DataUsage.TabModel.TrackingSessionLifetime";
const char kUMAOldInactiveSessionRemovalDurationHistogram[] =
"DataUsage.TabModel.OldInactiveSessionRemovalDuration";
} // namespace
namespace chrome {
namespace android {
TabDataUseEntry::TabDataUseEntry(DataUseTabModel* tab_model)
: is_custom_tab_package_match_(false), tab_model_(tab_model) {
DCHECK(tab_model_);
}
TabDataUseEntry::TabDataUseEntry(const TabDataUseEntry& other) = default;
TabDataUseEntry::~TabDataUseEntry() {}
bool TabDataUseEntry::StartTracking(const std::string& label) {
DCHECK(!label.empty());
DCHECK(tab_close_time_.is_null());
if (IsTrackingDataUse())
return false; // Duplicate start events.
// TODO(rajendrant): Explore ability to handle changes in label for current
// session.
sessions_.push_back(TabDataUseTrackingSession(label, tab_model_->NowTicks()));
CompactSessionHistory();
return true;
}
bool TabDataUseEntry::EndTracking() {
DCHECK(tab_close_time_.is_null());
if (!IsTrackingDataUse())
return false; // Duplicate end events.
TabSessions::reverse_iterator back_iterator = sessions_.rbegin();
if (back_iterator == sessions_.rend())
return false;
back_iterator->end_time = tab_model_->NowTicks();
UMA_HISTOGRAM_CUSTOM_TIMES(
kUMATrackingSessionLifetimeHistogram,
back_iterator->end_time - back_iterator->start_time,
base::TimeDelta::FromSeconds(1), base::TimeDelta::FromHours(1), 50);
return true;
}
bool TabDataUseEntry::EndTrackingWithLabel(const std::string& label) {
if (!sessions_.empty() && sessions_.back().label == label)
return EndTracking();
return false;
}
void TabDataUseEntry::OnTabCloseEvent() {
DCHECK(!IsTrackingDataUse());
tab_close_time_ = tab_model_->NowTicks();
}
bool TabDataUseEntry::IsExpired() const {
const base::TimeTicks now = tab_model_->NowTicks();
if (!tab_close_time_.is_null()) {
// Closed tab entry.
return ((now - tab_close_time_) >
tab_model_->closed_tab_expiration_duration());
}
const base::TimeTicks latest_session_time = GetLatestStartOrEndTime();
if (latest_session_time.is_null() ||
((now - latest_session_time) >
tab_model_->open_tab_expiration_duration())) {
return true;
}
return false;
}
bool TabDataUseEntry::GetLabel(const base::TimeTicks& data_use_time,
std::string* output_label) const {
*output_label = "";
// Find a tracking session in history that was active at |data_use_time|.
for (TabSessions::const_reverse_iterator session_iterator =
sessions_.rbegin();
session_iterator != sessions_.rend(); ++session_iterator) {
if (session_iterator->start_time <= data_use_time &&
(session_iterator->end_time.is_null() ||
session_iterator->end_time >= data_use_time)) {
*output_label = session_iterator->label;
return true;
}
if (!session_iterator->end_time.is_null() &&
session_iterator->end_time < data_use_time) {
// Older sessions in history will end before |data_use_time| and will not
// match.
break;
}
}
return false;
}
bool TabDataUseEntry::IsTrackingDataUse() const {
TabSessions::const_reverse_iterator back_iterator = sessions_.rbegin();
if (back_iterator == sessions_.rend())
return false;
return back_iterator->end_time.is_null();
}
const base::TimeTicks TabDataUseEntry::GetLatestStartOrEndTime() const {
TabSessions::const_reverse_iterator back_iterator = sessions_.rbegin();
if (back_iterator == sessions_.rend())
return base::TimeTicks(); // No tab session found.
if (!back_iterator->end_time.is_null())
return back_iterator->end_time;
DCHECK(!back_iterator->start_time.is_null());
return back_iterator->start_time;
}
const std::string TabDataUseEntry::GetActiveTrackingSessionLabel() const {
TabSessions::const_reverse_iterator back_iterator = sessions_.rbegin();
if (back_iterator == sessions_.rend() || !IsTrackingDataUse())
return std::string();
return back_iterator->label;
}
void TabDataUseEntry::set_custom_tab_package_match(
bool is_custom_tab_package_match) {
DCHECK(IsTrackingDataUse());
DCHECK(!GetActiveTrackingSessionLabel().empty());
is_custom_tab_package_match_ = is_custom_tab_package_match;
}
void TabDataUseEntry::CompactSessionHistory() {
while (sessions_.size() > tab_model_->max_sessions_per_tab()) {
const auto& front = sessions_.front();
DCHECK(!front.end_time.is_null());
// Track how often old sessions are lost.
UMA_HISTOGRAM_CUSTOM_TIMES(kUMAOldInactiveSessionRemovalDurationHistogram,
tab_model_->NowTicks() - front.end_time,
base::TimeDelta::FromSeconds(1),
base::TimeDelta::FromHours(1), 50);
sessions_.pop_front();
}
}
} // namespace android
} // namespace chrome