Commit 29ed9114 authored by Sebastien Marchand's avatar Sebastien Marchand Committed by Commit Bot

Add the base for the local site characteristics observations.

Initial piece of the Site Characteristics Local Database[1], this is the
internal class that will be used by the LocalSiteCharacteristicsDataStore.

Bug: 773382
Change-Id: Ic125fb1200b0b22bf4c985eff4f140d7db2357c3

[1] @google: https://docs.google.com/document/d/1OODhTnNu4v9dUv6tl6i2vofh0K2DS1OM6EfKs5ewbPA/edit?usp=sharing

Change-Id: Ic125fb1200b0b22bf4c985eff4f140d7db2357c3
Bug: 773382
Reviewed-on: https://chromium-review.googlesource.com/976603
Commit-Queue: Sébastien Marchand <sebmarchand@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#549521}
parent 2932f6b2
......@@ -2616,6 +2616,9 @@ jumbo_split_static_library("browser") {
"resource_coordinator/lifecycle_unit_source_base.cc",
"resource_coordinator/lifecycle_unit_source_base.h",
"resource_coordinator/lifecycle_unit_source_observer.h",
"resource_coordinator/local_site_characteristics_data_impl.cc",
"resource_coordinator/local_site_characteristics_data_impl.h",
"resource_coordinator/site_characteristic_database.h",
"resource_coordinator/tab_activity_watcher.cc",
"resource_coordinator/tab_activity_watcher.h",
"resource_coordinator/tab_lifecycle_observer.h",
......@@ -2781,6 +2784,7 @@ jumbo_split_static_library("browser") {
"//chrome/app/vector_icons",
"//chrome/browser/policy:path_parser",
"//chrome/browser/profile_resetter:profile_reset_report_proto",
"//chrome/browser/resource_coordinator:site_characteristics_proto",
"//chrome/browser/resource_coordinator:tab_metrics_event_proto",
"//chrome/browser/resources:component_extension_resources",
"//chrome/browser/search:generated",
......
......@@ -10,3 +10,9 @@ proto_library("tab_metrics_event_proto") {
"tab_metrics_event.proto",
]
}
proto_library("site_characteristics_proto") {
sources = [
"site_characteristics.proto",
]
}
// 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/resource_coordinator/local_site_characteristics_data_impl.h"
#include <algorithm>
#include <vector>
#include "chrome/browser/resource_coordinator/time.h"
namespace resource_coordinator {
namespace internal {
namespace {
base::TimeDelta GetTickDeltaSinceEpoch() {
return resource_coordinator::NowTicks() - base::TimeTicks::UnixEpoch();
}
// Returns all the SiteCharacteristicsFeatureProto elements contained in a
// SiteCharacteristicsProto protobuf object.
std::vector<SiteCharacteristicsFeatureProto*> GetAllFeaturesFromProto(
SiteCharacteristicsProto* proto) {
std::vector<SiteCharacteristicsFeatureProto*> ret(
{proto->mutable_updates_favicon_in_background(),
proto->mutable_updates_title_in_background(),
proto->mutable_uses_audio_in_background(),
proto->mutable_uses_notifications_in_background()});
return ret;
}
} // namespace
// static:
const int64_t
LocalSiteCharacteristicsDataImpl::kZeroIntervalInternalRepresentation =
LocalSiteCharacteristicsDataImpl::TimeDeltaToInternalRepresentation(
base::TimeDelta());
LocalSiteCharacteristicsDataImpl::LocalSiteCharacteristicsDataImpl(
const std::string& origin_str)
: origin_str_(origin_str), active_webcontents_count_(0U) {
// Initialize the features element with the default value, this is required
// because some fields might otherwise never be initialized.
for (auto* iter : GetAllFeaturesFromProto(&site_characteristics_))
InitSiteCharacteristicsFeatureProtoWithDefaultValues(iter);
site_characteristics_.set_last_loaded(kZeroIntervalInternalRepresentation);
}
void LocalSiteCharacteristicsDataImpl::NotifySiteLoaded() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Update the last loaded time when this origin gets loaded for the first
// time.
if (active_webcontents_count_ == 0) {
site_characteristics_.set_last_loaded(
TimeDeltaToInternalRepresentation(GetTickDeltaSinceEpoch()));
}
active_webcontents_count_++;
}
void LocalSiteCharacteristicsDataImpl::NotifySiteUnloaded() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
active_webcontents_count_--;
// Only update the last loaded time when there's no more loaded instance of
// this origin.
if (active_webcontents_count_ > 0U)
return;
base::TimeDelta current_unix_time = GetTickDeltaSinceEpoch();
base::TimeDelta extra_observation_duration =
current_unix_time -
InternalRepresentationToTimeDelta(site_characteristics_.last_loaded());
// Update the |last_loaded_time_| field, as the moment this site gets unloaded
// also corresponds to the last moment it was loaded.
site_characteristics_.set_last_loaded(
TimeDeltaToInternalRepresentation(current_unix_time));
// Update the observation duration fields.
for (auto* iter : GetAllFeaturesFromProto(&site_characteristics_))
IncrementFeatureObservationDuration(iter, extra_observation_duration);
}
SiteFeatureUsage LocalSiteCharacteristicsDataImpl::UpdatesFaviconInBackground()
const {
return GetFeatureUsage(site_characteristics_.updates_favicon_in_background(),
GetUpdatesFaviconInBackgroundMinObservationWindow());
}
SiteFeatureUsage LocalSiteCharacteristicsDataImpl::UpdatesTitleInBackground()
const {
return GetFeatureUsage(site_characteristics_.updates_title_in_background(),
GetUpdatesTitleInBackgroundMinObservationWindow());
}
SiteFeatureUsage LocalSiteCharacteristicsDataImpl::UsesAudioInBackground()
const {
return GetFeatureUsage(site_characteristics_.uses_audio_in_background(),
GetUsesAudioInBackgroundMinObservationWindow());
}
SiteFeatureUsage
LocalSiteCharacteristicsDataImpl::UsesNotificationsInBackground() const {
return GetFeatureUsage(
site_characteristics_.uses_notifications_in_background(),
GetUsesNotificationsInBackgroundMinObservationWindow());
}
void LocalSiteCharacteristicsDataImpl::NotifyUpdatesFaviconInBackground() {
NotifyFeatureUsage(
site_characteristics_.mutable_updates_favicon_in_background());
}
void LocalSiteCharacteristicsDataImpl::NotifyUpdatesTitleInBackground() {
NotifyFeatureUsage(
site_characteristics_.mutable_updates_title_in_background());
}
void LocalSiteCharacteristicsDataImpl::NotifyUsesAudioInBackground() {
NotifyFeatureUsage(site_characteristics_.mutable_uses_audio_in_background());
}
void LocalSiteCharacteristicsDataImpl::NotifyUsesNotificationsInBackground() {
NotifyFeatureUsage(
site_characteristics_.mutable_uses_notifications_in_background());
}
base::TimeDelta LocalSiteCharacteristicsDataImpl::FeatureObservationDuration(
const SiteCharacteristicsFeatureProto& feature_proto) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Get the current observation duration value, this'll be equal to 0 for
// features that have been observed.
base::TimeDelta observation_time_for_feature =
InternalRepresentationToTimeDelta(feature_proto.observation_duration());
// If this site is still loaded and the feature isn't in use then the
// observation time since load needs to be added.
if (active_webcontents_count_ > 0U &&
InternalRepresentationToTimeDelta(feature_proto.use_timestamp())
.is_zero()) {
base::TimeDelta observation_time_since_load =
GetTickDeltaSinceEpoch() -
InternalRepresentationToTimeDelta(site_characteristics_.last_loaded());
observation_time_for_feature += observation_time_since_load;
}
return observation_time_for_feature;
}
LocalSiteCharacteristicsDataImpl::~LocalSiteCharacteristicsDataImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// It's currently required that the site gets unloaded before destroying this
// object.
// TODO(sebmarchand): Check if this is a valid assumption.
DCHECK_EQ(0U, active_webcontents_count_);
}
// static:
void LocalSiteCharacteristicsDataImpl::IncrementFeatureObservationDuration(
SiteCharacteristicsFeatureProto* feature_proto,
base::TimeDelta extra_observation_duration) {
if (InternalRepresentationToTimeDelta(feature_proto->use_timestamp())
.is_zero()) {
feature_proto->set_observation_duration(TimeDeltaToInternalRepresentation(
InternalRepresentationToTimeDelta(
feature_proto->observation_duration()) +
extra_observation_duration));
}
}
// static:
void LocalSiteCharacteristicsDataImpl::
InitSiteCharacteristicsFeatureProtoWithDefaultValues(
SiteCharacteristicsFeatureProto* proto) {
DCHECK_NE(nullptr, proto);
proto->set_observation_duration(kZeroIntervalInternalRepresentation);
proto->set_use_timestamp(kZeroIntervalInternalRepresentation);
}
SiteFeatureUsage LocalSiteCharacteristicsDataImpl::GetFeatureUsage(
const SiteCharacteristicsFeatureProto& feature_proto,
const base::TimeDelta min_obs_time) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Checks if this feature has already been observed.
// TODO(sebmarchand): Check the timestamp and reset features that haven't been
// observed in a long time, https://crbug.com/826446.
if (!InternalRepresentationToTimeDelta(feature_proto.use_timestamp())
.is_zero()) {
return SiteFeatureUsage::SITE_FEATURE_IN_USE;
}
if (FeatureObservationDuration(feature_proto) >= min_obs_time)
return SiteFeatureUsage::SITE_FEATURE_NOT_IN_USE;
return SiteFeatureUsage::SITE_FEATURE_USAGE_UNKNOWN;
}
void LocalSiteCharacteristicsDataImpl::NotifyFeatureUsage(
SiteCharacteristicsFeatureProto* feature_proto) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GT(active_webcontents_count_, 0U);
feature_proto->set_use_timestamp(
TimeDeltaToInternalRepresentation(GetTickDeltaSinceEpoch()));
feature_proto->set_observation_duration(kZeroIntervalInternalRepresentation);
}
} // namespace internal
} // namespace resource_coordinator
// 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.
#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_DATA_IMPL_H_
#define CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_DATA_IMPL_H_
#include <string>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/resource_coordinator/site_characteristics.pb.h"
namespace resource_coordinator {
namespace internal {
// A tri-state return value for site feature usage. If a definitive decision
// can't be made then an "unknown" result can be returned.
enum class SiteFeatureUsage {
SITE_FEATURE_NOT_IN_USE,
SITE_FEATURE_IN_USE,
SITE_FEATURE_USAGE_UNKNOWN,
};
// Tracks observations for a given site. This class shouldn't be used
// directly, it's meant to be used internally by the local site heuristic
// database.
class LocalSiteCharacteristicsDataImpl
: public base::RefCounted<LocalSiteCharacteristicsDataImpl> {
public:
explicit LocalSiteCharacteristicsDataImpl(const std::string& origin_str);
// Must be called when a load event is received for this site, this can be
// invoked several time if instances of this class are shared between
// multiple tabs.
void NotifySiteLoaded();
// Must be called when an unload event is received for this site, this can be
// invoked several time if instances of this class are shared between
// multiple tabs.
void NotifySiteUnloaded();
// Returns the usage of a given feature for this origin.
SiteFeatureUsage UpdatesFaviconInBackground() const;
SiteFeatureUsage UpdatesTitleInBackground() const;
SiteFeatureUsage UsesAudioInBackground() const;
SiteFeatureUsage UsesNotificationsInBackground() const;
// Must be called when a feature is used, calling this function updates the
// last observed timestamp for this feature.
void NotifyUpdatesFaviconInBackground();
void NotifyUpdatesTitleInBackground();
void NotifyUsesAudioInBackground();
void NotifyUsesNotificationsInBackground();
// TODO(sebmarchand): Add the methods necessary to record other types of
// observations (e.g. memory and CPU usage).
protected:
friend class base::RefCounted<LocalSiteCharacteristicsDataImpl>;
friend class LocalSiteCharacteristicsDataImplTest;
// Helper functions to convert from/to the internal representation that is
// used to store TimeDelta values in the |SiteCharacteristicsProto| protobuf.
static base::TimeDelta InternalRepresentationToTimeDelta(
::google::protobuf::int64 value) {
return base::TimeDelta::FromSeconds(value);
}
static int64_t TimeDeltaToInternalRepresentation(base::TimeDelta delta) {
return delta.InSeconds();
}
// Returns the minimum observation time before considering a feature as
// unused.
static constexpr base::TimeDelta
GetUpdatesFaviconInBackgroundMinObservationWindow() {
return base::TimeDelta::FromHours(2);
}
static constexpr base::TimeDelta
GetUpdatesTitleInBackgroundMinObservationWindow() {
return base::TimeDelta::FromHours(2);
}
static constexpr base::TimeDelta
GetUsesAudioInBackgroundMinObservationWindow() {
return base::TimeDelta::FromHours(2);
}
static constexpr base::TimeDelta
GetUsesNotificationsInBackgroundMinObservationWindow() {
return base::TimeDelta::FromHours(2);
}
virtual ~LocalSiteCharacteristicsDataImpl();
// Returns the observation duration for a given feature, this is the sum of
// the recorded observation duration and the current observation duration
// since this site has been loaded (if applicable). If a feature has been
// used then it returns 0.
base::TimeDelta FeatureObservationDuration(
const SiteCharacteristicsFeatureProto& feature_proto) const;
// Accessors, for testing:
base::TimeDelta last_loaded_time_for_testing() const {
return InternalRepresentationToTimeDelta(
site_characteristics_.last_loaded());
}
const SiteCharacteristicsProto& site_characteristics_for_testing() const {
return site_characteristics_;
}
static const int64_t kZeroIntervalInternalRepresentation;
private:
// Add |extra_observation_duration| to the observation window of a given
// feature if it hasn't been used yet, do nothing otherwise.
static void IncrementFeatureObservationDuration(
SiteCharacteristicsFeatureProto* feature_proto,
base::TimeDelta extra_observation_duration);
// Initialize a SiteCharacteristicsFeatureProto object with its default
// values.
static void InitSiteCharacteristicsFeatureProtoWithDefaultValues(
SiteCharacteristicsFeatureProto* proto);
// Returns the usage of |site_feature| for this site.
SiteFeatureUsage GetFeatureUsage(
const SiteCharacteristicsFeatureProto& feature_proto,
const base::TimeDelta min_obs_time) const;
// Helper function to update a given |SiteCharacteristicsFeatureProto| when a
// feature gets used.
void NotifyFeatureUsage(SiteCharacteristicsFeatureProto* feature_proto);
// This site's characteristics, contains the features and other values are
// measured.
SiteCharacteristicsProto site_characteristics_;
// This site's origin.
const std::string origin_str_;
// The number of active WebContents for this origin. Several tabs with the
// same origin might share the same instance of this object, this counter
// will allow to properly update the observation time (starts when the first
// tab gets loaded, stops when the last one gets unloaded).
size_t active_webcontents_count_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsDataImpl);
};
} // namespace internal
} // namespace resource_coordinator
#endif // CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_DATA_IMPL_H_
// 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.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
// Contains the information that we want to track about a given site feature.
// Next Id: 3
message SiteCharacteristicsFeatureProto {
// The cumulative observation time for this feature in seconds, set to 0 once
// this feature has been observed.
required int64 observation_duration = 1;
// The time at which this feature has been used (set to 0 if it hasn't been
// used), in seconds since epoch.
required int64 use_timestamp = 2;
}
// Defines the characteristics that we want to track about a given site.
// Next Id: 6
message SiteCharacteristicsProto {
// The last time this site has been in the loaded state, in seconds since
// epoch.
required uint32 last_loaded = 1;
// List of features that we're tracking.
required SiteCharacteristicsFeatureProto updates_favicon_in_background = 2;
required SiteCharacteristicsFeatureProto updates_title_in_background = 3;
required SiteCharacteristicsFeatureProto uses_audio_in_background = 4;
required SiteCharacteristicsFeatureProto uses_notifications_in_background = 5;
}
......@@ -2897,6 +2897,7 @@ test("unit_tests") {
"../browser/resource_coordinator/discard_metrics_lifecycle_unit_observer_unittest.cc",
"../browser/resource_coordinator/lifecycle_unit_base_unittest.cc",
"../browser/resource_coordinator/lifecycle_unit_unittest.cc",
"../browser/resource_coordinator/local_site_characteristics_data_impl_unittest.cc",
"../browser/resource_coordinator/tab_activity_watcher_unittest.cc",
"../browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc",
"../browser/resource_coordinator/tab_lifecycle_unit_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment