Commit 8f9673ca authored by Aga Wronska's avatar Aga Wronska Committed by Commit Bot

Populate child status report with app activity data

App activity data are used for Per-App Time Limits feature.

Bug: 1015656
Test: ChildStatusCollectorTest
Change-Id: I75f27bf409db7d2a0ef941cad7e8f9a3e97b70eb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2020530
Commit-Queue: Aga Wronska <agawronska@chromium.org>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735993}
parent b4397b71
......@@ -86,6 +86,7 @@ void ChildStatusReportingService::CreateStatusUploaderIfNeeded(
client,
std::make_unique<policy::ChildStatusCollector>(
pref_change_registrar_->prefs(),
Profile::FromBrowserContext(context_),
system::StatisticsProvider::GetInstance(),
policy::ChildStatusCollector::AndroidStatusFetcher(),
day_reset_time_),
......
......@@ -29,12 +29,10 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
#include "chrome/browser/chromeos/policy/status_collector/child_activity_storage.h"
#include "chrome/browser/chromeos/policy/status_collector/status_collector_state.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chromeos/dbus/util/version_loader.h"
......@@ -50,9 +48,6 @@
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
......@@ -121,12 +116,15 @@ class ChildStatusCollectorState : public StatusCollectorState {
ChildStatusCollector::ChildStatusCollector(
PrefService* pref_service,
Profile* profile,
chromeos::system::StatisticsProvider* provider,
const AndroidStatusFetcher& android_status_fetcher,
TimeDelta activity_day_start)
: StatusCollector(provider, chromeos::CrosSettings::Get()),
pref_service_(pref_service),
profile_(profile),
android_status_fetcher_(android_status_fetcher) {
DCHECK(profile_);
// protected fields of `StatusCollector`.
max_stored_past_activity_interval_ = kMaxStoredPastActivityInterval;
max_stored_future_activity_interval_ = kMaxStoredFutureActivityInterval;
......@@ -203,6 +201,24 @@ void ChildStatusCollector::UpdateReportingSettings() {
&report_boot_mode_);
}
void ChildStatusCollector::OnAppActivityReportSubmitted() {
if (!chromeos::app_time::AppActivityReportInterface::
ShouldReportAppActivity()) {
return;
}
DCHECK(last_report_params_);
if (last_report_params_->anything_reported) {
chromeos::app_time::AppActivityReportInterface* app_activity_reporting =
chromeos::app_time::AppActivityReportInterface::Get(profile_);
DCHECK(app_activity_reporting);
app_activity_reporting->AppActivityReportSubmitted(
last_report_params_->generation_time);
}
last_report_params_.reset();
}
void ChildStatusCollector::OnUsageTimeStateChange(
chromeos::UsageTimeStateNotifier::UsageTimeState state) {
UpdateChildUsageTime();
......@@ -272,6 +288,22 @@ bool ChildStatusCollector::GetActivityTimes(
return anything_reported;
}
bool ChildStatusCollector::GetAppActivity(
em::ChildStatusReportRequest* status) {
if (!chromeos::app_time::AppActivityReportInterface::
ShouldReportAppActivity()) {
return false;
}
const chromeos::app_time::AppActivityReportInterface* app_activity_reporting =
chromeos::app_time::AppActivityReportInterface::Get(profile_);
DCHECK(app_activity_reporting);
last_report_params_ =
app_activity_reporting->GenerateAppActivityReport(status);
return last_report_params_->anything_reported;
}
bool ChildStatusCollector::GetVersionInfo(
em::ChildStatusReportRequest* status) {
status->set_os_version(os_version_);
......@@ -300,13 +332,7 @@ void ChildStatusCollector::GetStatusAsync(
bool ChildStatusCollector::FillUserSpecificFields(
scoped_refptr<ChildStatusCollectorState> state,
em::ChildStatusReportRequest* status,
const user_manager::User* user) {
Profile* const profile =
chromeos::ProfileHelper::Get()->GetProfileByUser(user);
if (!profile)
return false;
em::ChildStatusReportRequest* status) {
// Time zone.
const std::string current_timezone =
base::UTF16ToUTF8(chromeos::system::TimezoneSettings::GetInstance()
......@@ -315,12 +341,11 @@ bool ChildStatusCollector::FillUserSpecificFields(
// Android status.
const bool report_android_status =
profile->GetPrefs()->GetBoolean(prefs::kReportArcStatusEnabled);
profile_->GetPrefs()->GetBoolean(prefs::kReportArcStatusEnabled);
if (report_android_status)
GetAndroidStatus(state);
if (!user->IsDeviceLocalAccount())
status->set_user_dm_token(GetDMTokenForProfile(profile));
status->set_user_dm_token(GetDMTokenForProfile(profile_));
// At least time zone is always reported.
return true;
......@@ -337,16 +362,13 @@ void ChildStatusCollector::FillChildStatusReportRequest(
state->response_params().child_status.get();
bool anything_reported = false;
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
const user_manager::User* const primary_user = user_manager->GetPrimaryUser();
DCHECK(primary_user != nullptr);
anything_reported |= FillUserSpecificFields(state, status, primary_user);
anything_reported |= FillUserSpecificFields(state, status);
if (report_version_info_)
anything_reported |= GetVersionInfo(status);
anything_reported |= GetActivityTimes(status);
anything_reported |= GetAppActivity(status);
if (report_boot_mode_) {
base::Optional<std::string> boot_mode =
......@@ -366,6 +388,7 @@ void ChildStatusCollector::OnSubmittedSuccessfully() {
activity_storage_->TrimActivityPeriods(last_reported_day_,
duration_for_last_reported_day_,
std::numeric_limits<int64_t>::max());
OnAppActivityReportSubmitted();
}
bool ChildStatusCollector::ShouldReportActivityTimes() const {
......
......@@ -16,23 +16,23 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h"
#include "chrome/browser/chromeos/child_accounts/usage_time_state_notifier.h"
#include "chrome/browser/chromeos/policy/status_collector/status_collector.h"
#include "components/policy/proto/device_management_backend.pb.h"
class Profile;
namespace chromeos {
namespace system {
class StatisticsProvider;
}
} // namespace chromeos
namespace user_manager {
class User;
}
class PrefService;
namespace policy {
......@@ -66,6 +66,7 @@ class ChildStatusCollector : public StatusCollector,
// activity reporting daily data aggregation. It is represented by the
// distance from midnight.
ChildStatusCollector(PrefService* pref_service,
Profile* profile,
chromeos::system::StatisticsProvider* provider,
const AndroidStatusFetcher& android_status_fetcher,
base::TimeDelta activity_day_start);
......@@ -103,14 +104,14 @@ class ChildStatusCollector : public StatusCollector,
// session (i.e. it is not device data).
bool FillUserSpecificFields(
scoped_refptr<ChildStatusCollectorState> state,
enterprise_management::ChildStatusReportRequest* status,
const user_manager::User* user);
enterprise_management::ChildStatusReportRequest* status);
// Helpers for the various portions of child status report. Return true if
// they actually report any status. Functions that queue async queries take a
// |ChildStatusCollectorState| instance.
bool GetActivityTimes(
enterprise_management::ChildStatusReportRequest* status);
bool GetAppActivity(enterprise_management::ChildStatusReportRequest* status);
bool GetVersionInfo(enterprise_management::ChildStatusReportRequest* status);
// Queues async queries!
bool GetAndroidStatus(const scoped_refptr<ChildStatusCollectorState>& state);
......@@ -118,9 +119,16 @@ class ChildStatusCollector : public StatusCollector,
// Update the cached values of the reporting settings.
void UpdateReportingSettings();
// Called to update the stored app activity data, after the report with app
// activity was submitted.
void OnAppActivityReportSubmitted();
// Mainly used to store activity periods for reporting. Not owned.
PrefService* const pref_service_;
// Profile of the user that the status is collected for.
Profile* const profile_;
// The last time an active state check was performed.
base::Time last_active_check_;
......@@ -135,6 +143,10 @@ class ChildStatusCollector : public StatusCollector,
int64_t last_reported_day_ = 0;
int duration_for_last_reported_day_ = 0;
// The parameters associated with last app activity report.
base::Optional<chromeos::app_time::AppActivityReportInterface::ReportParams>
last_report_params_;
base::RepeatingTimer update_child_usage_timer_;
std::string os_version_;
......
......@@ -12,24 +12,35 @@
#include "base/bind.h"
#include "base/environment.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_path_override.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/chromeos/child_accounts/child_user_service.h"
#include "chrome/browser/chromeos/child_accounts/child_user_service_factory.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h"
#include "chrome/browser/chromeos/child_accounts/time_limits/app_types.h"
#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
#include "chrome/browser/chromeos/ownership/fake_owner_settings_service.h"
#include "chrome/browser/chromeos/policy/status_collector/child_status_collector.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "chrome/test/base/chrome_unit_test_suite.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
......@@ -94,11 +105,13 @@ class TestingChildStatusCollector : public policy::ChildStatusCollector {
public:
TestingChildStatusCollector(
PrefService* pref_service,
Profile* profile,
chromeos::system::StatisticsProvider* provider,
const policy::StatusCollector::AndroidStatusFetcher&
android_status_fetcher,
TimeDelta activity_day_start)
: policy::ChildStatusCollector(pref_service,
profile,
provider,
android_status_fetcher,
activity_day_start) {
......@@ -234,11 +247,20 @@ class ChildStatusCollectorTest : public testing::Test {
}
void SetUp() override {
scoped_feature_list_.InitWithFeatures(
/* enabled_features */ {{features::kPerAppTimeLimits,
features::kAppActivityReporting}},
/* disabled_features */ {{}});
RestartStatusCollector(base::BindRepeating(&GetEmptyAndroidStatus));
// Disable network interface reporting since it requires additional setup.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
chromeos::kReportDeviceNetworkInterfaces, false);
// Mock clock in task environment is set to Unix Epoch, advance it to avoid
// using times from before Unix Epoch in some tests.
task_environment_.AdvanceClock(base::TimeDelta::FromDays(365));
}
void TearDown() override { status_collector_.reset(); }
......@@ -293,13 +315,34 @@ class ChildStatusCollectorTest : public testing::Test {
}
}
void SimulateAppActivity(const chromeos::app_time::AppId& app_id,
base::TimeDelta duration) {
chromeos::ChildUserService::TestApi child_user_service =
chromeos::ChildUserService::TestApi(
chromeos::ChildUserServiceFactory::GetForBrowserContext(
testing_profile_.get()));
EXPECT_TRUE(child_user_service.app_time_controller());
chromeos::app_time::AppActivityRegistry* app_registry =
chromeos::app_time::AppTimeController::TestApi(
child_user_service.app_time_controller())
.app_registry();
app_registry->OnAppInstalled(app_id);
// Window instance is irrelevant for tests here.
app_registry->OnAppActive(app_id, nullptr /* window */, base::Time::Now());
task_environment_.FastForwardBy(duration);
app_registry->OnAppInactive(app_id, nullptr /* window */,
base::Time::Now());
}
virtual void RestartStatusCollector(
const policy::StatusCollector::AndroidStatusFetcher&
android_status_fetcher,
const TimeDelta activity_day_start = kMidnight) {
status_collector_ = std::make_unique<TestingChildStatusCollector>(
&profile_pref_service_, &fake_statistics_provider_,
android_status_fetcher, activity_day_start);
&profile_pref_service_, testing_profile_.get(),
&fake_statistics_provider_, android_status_fetcher, activity_day_start);
}
void GetStatus() {
......@@ -381,13 +424,16 @@ class ChildStatusCollectorTest : public testing::Test {
// Since this is a unit test running in browser_tests we must do additional
// unit test setup and make a TestingBrowserProcess. Must be first member.
TestingBrowserProcessInitializer initializer_;
content::BrowserTaskEnvironment task_environment_;
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
ChromeContentClient content_client_;
ChromeContentBrowserClient browser_content_client_;
chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
base::test::ScopedFeatureList scoped_feature_list_;
chromeos::FakeOwnerSettingsService owner_settings_service_{
scoped_testing_cros_settings_.device_settings(), nullptr};
std::unique_ptr<TestingProfile> testing_profile_;
......@@ -471,7 +517,7 @@ TEST_F(ChildStatusCollectorTest, ReportingActivityTimesSessionTransistions) {
ExpectChildScreenTimeMilliseconds(5 * ActivePeriodMilliseconds());
}
TEST_F(ChildStatusCollectorTest, ReportingActivityTimesSleepTransistions) {
TEST_F(ChildStatusCollectorTest, ReportingActivityTimesSleepTransitions) {
DeviceStateTransitions test_states[] = {
DeviceStateTransitions::kEnterSessionActive,
DeviceStateTransitions::kPeriodicCheckTriggered,
......@@ -656,4 +702,63 @@ TEST_F(ChildStatusCollectorTest, ClockChanged) {
ExpectChildScreenTimeMilliseconds(ActivePeriodMilliseconds());
}
TEST_F(ChildStatusCollectorTest, ReportingAppActivity) {
// Nothing reported yet.
GetStatus();
EXPECT_EQ(0, child_status_.app_activity_size());
status_collector_->OnSubmittedSuccessfully();
// Report activity for two different apps.
const chromeos::app_time::AppId app1(apps::mojom::AppType::kWeb, "app1");
const chromeos::app_time::AppId app2(apps::mojom::AppType::kExtension,
"app2");
const base::Time start_time = base::Time::Now();
const base::TimeDelta app1_interval = base::TimeDelta::FromMinutes(1);
const base::TimeDelta app2_interval = base::TimeDelta::FromMinutes(2);
SimulateAppActivity(app1, app1_interval);
SimulateAppActivity(app2, app2_interval);
SimulateAppActivity(app1, app1_interval);
SimulateAppActivity(app2, app2_interval);
SimulateAppActivity(app1, app1_interval);
GetStatus();
EXPECT_EQ(2, child_status_.app_activity_size());
for (const auto& app_activity : child_status_.app_activity()) {
if (app_activity.app_info().app_id() == app1.app_id()) {
EXPECT_EQ(em::App::WEB, app_activity.app_info().app_type());
EXPECT_EQ(0, app_activity.app_info().additional_app_id_size());
EXPECT_EQ(em::AppActivity::DEFAULT, app_activity.app_state());
EXPECT_EQ(3, app_activity.active_time_periods_size());
base::Time start = start_time;
for (const auto& active_period : app_activity.active_time_periods()) {
EXPECT_EQ(start.ToJavaTime(), active_period.start_timestamp());
const base::Time end = start + app1_interval;
EXPECT_EQ(end.ToJavaTime(), active_period.end_timestamp());
start = end + app2_interval;
}
continue;
}
if (app_activity.app_info().app_id() == app2.app_id()) {
EXPECT_EQ(em::App::EXTENSION, app_activity.app_info().app_type());
EXPECT_EQ(0, app_activity.app_info().additional_app_id_size());
EXPECT_EQ(em::AppActivity::DEFAULT, app_activity.app_state());
EXPECT_EQ(2, app_activity.active_time_periods_size());
base::Time start = start_time + app1_interval;
for (const auto& active_period : app_activity.active_time_periods()) {
EXPECT_EQ(start.ToJavaTime(), active_period.start_timestamp());
const base::Time end = start + app2_interval;
EXPECT_EQ(end.ToJavaTime(), active_period.end_timestamp());
start = end + app1_interval;
}
continue;
}
}
// After successful report submission 'old' data should be cleared.
status_collector_->OnSubmittedSuccessfully();
GetStatus();
EXPECT_EQ(0, child_status_.app_activity_size());
}
} // namespace policy
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