Commit 6ca3ae96 authored by Askar Aitzhan's avatar Askar Aitzhan Committed by Commit Bot

Refactor AppInstall Reporting to report directly to Chrome Reporting API

Currently ARC++ apps stored as protos defined in
components/policy/proto/device_management_backend.proto, and are being
uploaded to DMServer. In turn DMServer converts those reports to a proto
format defined in
google3/chrome/cros/reporting/proto/chrome_app_install_events.proto,
appends serial_number and gaia_id and redirects those reports to Chrome
Reporting API.

Refactor AppInstall Reporting system to report directly to Chrome
Reporting API.

Bug: 996213
Change-Id: I32239e4713f3d2b804d9710fee60141ce39c0c61
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1763421Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Reviewed-by: default avatarRoger Tawa <rogerta@chromium.org>
Reviewed-by: default avatarStefan Kuhne <skuhne@chromium.org>
Reviewed-by: default avatarNathan Parker <nparker@chromium.org>
Commit-Queue: Askar Aitzhan <askaraitzhan@google.com>
Cr-Commit-Position: refs/heads/master@{#694293}
parent d91292f2
......@@ -1483,6 +1483,8 @@ jumbo_split_static_library("browser") {
"profiles/renderer_updater.h",
"profiles/renderer_updater_factory.cc",
"profiles/renderer_updater_factory.h",
"profiles/reporting_util.cc",
"profiles/reporting_util.h",
"profiles/sql_init_error_message_ids.cc",
"profiles/sql_init_error_message_ids.h",
"profiles/storage_partition_descriptor.h",
......
......@@ -1607,6 +1607,8 @@ source_set("chromeos") {
"policy/app_install_event_log_manager_wrapper.h",
"policy/app_install_event_log_uploader.cc",
"policy/app_install_event_log_uploader.h",
"policy/app_install_event_log_util.cc",
"policy/app_install_event_log_util.h",
"policy/app_install_event_logger.cc",
"policy/app_install_event_logger.h",
"policy/auto_enrollment_client.h",
......
......@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_string_value_serializer.h"
#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "base/test/scoped_mock_time_message_loop_task_runner.h"
......@@ -20,10 +21,14 @@
#include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_uploader.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "components/arc/arc_prefs.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_task_environment.h"
......@@ -94,8 +99,37 @@ bool ContainsSameEvents(const Events& expected,
return true;
}
base::Value ConvertEventsToValue(const Events& events, Profile* profile) {
base::Value event_list(base::Value::Type::LIST);
base::Value::ListStorage& mutable_list = event_list.GetList();
for (auto it = events.begin(); it != events.end(); ++it) {
const std::string& package = (*it).first;
for (const em::AppInstallReportLogEvent& app_install_report_log_event :
(*it).second) {
base::Value wrapper;
wrapper =
ConvertEventToValue(package, app_install_report_log_event, profile);
mutable_list.push_back(std::move(wrapper));
}
}
return event_list;
}
MATCHER_P(MatchEvents, expected, "contains events") {
return ContainsSameEvents(expected, arg);
std::string arg_serialized_string;
JSONStringValueSerializer arg_serializer(&arg_serialized_string);
if (!arg_serializer.Serialize(arg))
return false;
DCHECK(expected);
std::string expected_serialized_string;
JSONStringValueSerializer expected_serializer(&expected_serialized_string);
if (!expected_serializer.Serialize(*expected))
return false;
return arg_serialized_string == expected_serialized_string;
}
class TestLogTaskRunnerWrapper
......@@ -124,10 +158,14 @@ class TestLogTaskRunnerWrapper
class AppInstallEventLogManagerTest : public testing::Test {
protected:
AppInstallEventLogManagerTest()
: uploader_(&cloud_policy_client_),
: uploader_(&cloud_policy_client_, nullptr),
log_task_runner_(log_task_runner_wrapper_.test_task_runner()),
log_file_path_(profile_.GetPath().Append(kLogFileName)),
packages_{std::begin(kPackageNames), std::end(kPackageNames)} {}
packages_{std::begin(kPackageNames), std::end(kPackageNames)},
events_value_(base::Value::Type::DICTIONARY),
scoped_fake_statistics_provider_(
std::make_unique<
chromeos::system::ScopedFakeStatisticsProvider>()) {}
// testing::Test:
void SetUp() override {
......@@ -180,10 +218,22 @@ class AppInstallEventLogManagerTest : public testing::Test {
void AddLogEntryForAllApps() { AddLogEntryForsetOfApps(packages_); }
void ClearEventsDict() {
base::DictionaryValue* mutable_dict;
if (events_value_.GetAsDictionary(&mutable_dict))
mutable_dict->Clear();
else
NOTREACHED();
}
void ExpectUploadAndCaptureCallback(
CloudPolicyClient::StatusCallback* callback) {
ClearEventsDict();
events_value_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertEventsToValue(events_, nullptr), reporting::GetContext(nullptr));
EXPECT_CALL(cloud_policy_client_,
UploadAppInstallReport(Pointee(MatchEvents(events_)), _))
UploadRealtimeReport(MatchEvents(&events_value_), _))
.WillOnce(SaveArg<1>(callback));
}
......@@ -193,12 +243,16 @@ class AppInstallEventLogManagerTest : public testing::Test {
}
void ExpectAndCompleteUpload() {
ClearEventsDict();
events_value_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertEventsToValue(events_, nullptr), reporting::GetContext(nullptr));
EXPECT_CALL(cloud_policy_client_,
UploadAppInstallReport(Pointee(MatchEvents(events_)), _))
.WillOnce(Invoke([](const em::AppInstallReportRequest*,
const CloudPolicyClient::StatusCallback& callback) {
callback.Run(true /* success */);
}));
UploadRealtimeReport(MatchEvents(&events_value_), _))
.WillOnce(Invoke(
[](base::Value, const CloudPolicyClient::StatusCallback& callback) {
callback.Run(true /* success */);
}));
}
void FlushNonDelayedTasks() {
......@@ -251,6 +305,9 @@ class AppInstallEventLogManagerTest : public testing::Test {
const base::FilePath log_file_path_;
const std::set<std::string> packages_;
base::Value events_value_;
std::unique_ptr<chromeos::system::ScopedFakeStatisticsProvider>
scoped_fake_statistics_provider_;
em::AppInstallReportLogEvent event_;
Events events_;
......
......@@ -13,8 +13,15 @@
#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace em = enterprise_management;
namespace policy {
namespace {
......@@ -31,8 +38,12 @@ const int kMaxRetryBackoffMs = 24 * 60 * 60 * 1000; // 24 hours
AppInstallEventLogUploader::Delegate::~Delegate() {}
AppInstallEventLogUploader::AppInstallEventLogUploader(
CloudPolicyClient* client)
: client_(client), retry_backoff_ms_(kMinRetryBackoffMs) {
CloudPolicyClient* client,
Profile* profile)
: client_(client),
profile_(profile),
retry_backoff_ms_(kMinRetryBackoffMs) {
DCHECK(client_);
client_->AddObserver(this);
}
......@@ -87,11 +98,14 @@ void AppInstallEventLogUploader::StartSerialization() {
}
void AppInstallEventLogUploader::OnSerialized(
const enterprise_management::AppInstallReportRequest* report) {
const em::AppInstallReportRequest* report) {
base::Value value_report = RealtimeReportingJobConfiguration::BuildReport(
ConvertProtoToValue(report, profile_), reporting::GetContext(profile_));
// base::Unretained() is safe here as the destructor cancels any pending
// upload, after which the |client_| is guaranteed to not call the callback.
client_->UploadAppInstallReport(
report,
client_->UploadRealtimeReport(
std::move(value_report),
base::AdaptCallbackForRepeating(base::BindOnce(
&AppInstallEventLogUploader::OnUploadDone, base::Unretained(this))));
}
......
......@@ -14,6 +14,8 @@ namespace enterprise_management {
class AppInstallReportRequest;
}
class Profile;
namespace policy {
// Adapter between the system that captures and stores app push-install event
......@@ -45,7 +47,7 @@ class AppInstallEventLogUploader : public CloudPolicyClient::Observer {
};
// |client| must outlive |this|.
explicit AppInstallEventLogUploader(CloudPolicyClient* client);
AppInstallEventLogUploader(CloudPolicyClient* client, Profile* profile);
~AppInstallEventLogUploader() override;
// Sets the delegate. The delegate must either outlive |this| or be explicitly
......@@ -101,6 +103,9 @@ class AppInstallEventLogUploader : public CloudPolicyClient::Observer {
// The client used to upload logs to the server.
CloudPolicyClient* client_ = nullptr;
// Profile used to fetch the context attributes for report request.
Profile* profile_ = nullptr;
// The delegate that provides serialized logs to be uploaded.
Delegate* delegate_ = nullptr;
......
......@@ -8,18 +8,23 @@
#include <memory>
#include <string>
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ref_counted.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/app_install_event_log_util.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Invoke;
using testing::Mock;
using testing::Pointee;
using testing::SaveArg;
using testing::WithArgs;
using testing::_;
......@@ -36,8 +41,19 @@ constexpr base::TimeDelta kMaxRetryBackoff = base::TimeDelta::FromDays(1);
static const char kDmToken[] = "token";
static const char kPackageName[] = "package";
MATCHER_P(MatchProto, expected, "matches protobuf") {
return arg.SerializePartialAsString() == expected.SerializePartialAsString();
MATCHER_P(MatchValue, expected, "matches base::Value") {
std::string arg_serialized_string;
JSONStringValueSerializer arg_serializer(&arg_serialized_string);
if (!arg_serializer.Serialize(arg))
return false;
DCHECK(expected);
std::string expected_serialized_string;
JSONStringValueSerializer expected_serializer(&expected_serialized_string);
if (!expected_serializer.Serialize(*expected))
return false;
return arg_serialized_string == expected_serialized_string;
}
ACTION_TEMPLATE(MoveArg,
......@@ -66,13 +82,11 @@ class MockAppInstallEventLogUploaderDelegate
class AppInstallEventLogUploaderTest : public testing::Test {
protected:
AppInstallEventLogUploaderTest() {}
void SetUp() override {
task_runner_ = new base::TestMockTimeTaskRunner();
task_runner_handle_ =
std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
}
AppInstallEventLogUploaderTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME,
base::test::ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY),
value_report_(base::Value::Type::DICTIONARY) {}
void TearDown() override {
Mock::VerifyAndClearExpectations(&client_);
......@@ -91,7 +105,7 @@ class AppInstallEventLogUploaderTest : public testing::Test {
}
void CreateUploader() {
uploader_ = std::make_unique<AppInstallEventLogUploader>(&client_);
uploader_ = std::make_unique<AppInstallEventLogUploader>(&client_, nullptr);
uploader_->SetDelegate(&delegate_);
}
......@@ -108,8 +122,20 @@ class AppInstallEventLogUploaderTest : public testing::Test {
.WillOnce(MoveArg<0>(callback));
}
void ClearReportDict() {
base::DictionaryValue* mutable_dict;
if (value_report_.GetAsDictionary(&mutable_dict))
mutable_dict->Clear();
else
NOTREACHED();
}
void CompleteUpload(bool success) {
EXPECT_CALL(client_, UploadAppInstallReport(Pointee(MatchProto(log_)), _))
ClearReportDict();
value_report_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertProtoToValue(&log_, nullptr), reporting::GetContext(nullptr));
EXPECT_CALL(client_, UploadRealtimeReport(MatchValue(&value_report_), _))
.WillOnce(WithArgs<1>(
Invoke([=](const CloudPolicyClient::StatusCallback& callback) {
callback.Run(success);
......@@ -117,8 +143,12 @@ class AppInstallEventLogUploaderTest : public testing::Test {
}
void CaptureUpload(CloudPolicyClient::StatusCallback* callback) {
ClearReportDict();
value_report_ = RealtimeReportingJobConfiguration::BuildReport(
ConvertProtoToValue(&log_, nullptr), reporting::GetContext(nullptr));
CloudPolicyClient::StatusCallback status_callback;
EXPECT_CALL(client_, UploadAppInstallReport(Pointee(MatchProto(log_)), _))
EXPECT_CALL(client_, UploadRealtimeReport(MatchValue(&value_report_), _))
.WillOnce(SaveArg<1>(callback));
}
......@@ -133,15 +163,14 @@ class AppInstallEventLogUploaderTest : public testing::Test {
CaptureUpload(callback);
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
em::AppInstallReportRequest log_;
base::Value value_report_;
MockCloudPolicyClient client_;
MockAppInstallEventLogUploaderDelegate delegate_;
std::unique_ptr<AppInstallEventLogUploader> uploader_;
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::unique_ptr<base::ThreadTaskRunnerHandle> task_runner_handle_;
private:
DISALLOW_COPY_AND_ASSIGN(AppInstallEventLogUploaderTest);
};
......@@ -219,7 +248,7 @@ TEST_F(AppInstallEventLogUploaderTest, RequestCancelAndSerialize) {
uploader_->CancelUpload();
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0);
EXPECT_CALL(client_, UploadRealtimeReport(_, _)).Times(0);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
std::move(serialization_callback).Run(&log_);
}
......@@ -262,11 +291,12 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) {
base::TimeDelta expected_delay = min_delay;
int max_delay_count = 0;
while (max_delay_count < 2) {
EXPECT_EQ(expected_delay, task_runner_->NextPendingTaskDelay());
EXPECT_EQ(expected_delay,
scoped_task_environment_.NextMainThreadPendingTaskDelay());
CompleteSerializeAndUpload(false /* success */);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
task_runner_->FastForwardBy(expected_delay);
scoped_task_environment_.FastForwardBy(expected_delay);
Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_);
......@@ -276,12 +306,13 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) {
expected_delay = std::min(expected_delay * 2, max_delay);
}
EXPECT_EQ(expected_delay, task_runner_->NextPendingTaskDelay());
EXPECT_EQ(expected_delay,
scoped_task_environment_.NextMainThreadPendingTaskDelay());
log_.add_app_install_reports()->set_package(kPackageName);
CompleteSerializeAndUpload(true /* success */);
EXPECT_CALL(delegate_, OnUploadSuccess());
task_runner_->FastForwardBy(expected_delay);
scoped_task_environment_.FastForwardBy(expected_delay);
Mock::VerifyAndClearExpectations(&delegate_);
Mock::VerifyAndClearExpectations(&client_);
......@@ -289,7 +320,8 @@ TEST_F(AppInstallEventLogUploaderTest, Retry) {
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
uploader_->RequestUpload();
EXPECT_EQ(min_delay, task_runner_->NextPendingTaskDelay());
EXPECT_EQ(min_delay,
scoped_task_environment_.NextMainThreadPendingTaskDelay());
}
// Create the uploader using a client that is not registered with the server
......@@ -368,7 +400,7 @@ TEST_F(AppInstallEventLogUploaderTest,
UnregisterClient();
Mock::VerifyAndClearExpectations(&client_);
EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0);
EXPECT_CALL(client_, UploadRealtimeReport(_, _)).Times(0);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
std::move(serialization_callback).Run(&log_);
Mock::VerifyAndClearExpectations(&delegate_);
......@@ -407,7 +439,7 @@ TEST_F(AppInstallEventLogUploaderTest,
CaptureSerialize(&serialization_callback_2);
RegisterClient();
EXPECT_CALL(client_, UploadAppInstallReport(_, _)).Times(0);
EXPECT_CALL(client_, UploadRealtimeReport(_, _)).Times(0);
EXPECT_CALL(delegate_, OnUploadSuccess()).Times(0);
std::move(serialization_callback_1).Run(&log_);
Mock::VerifyAndClearExpectations(&delegate_);
......
// Copyright 2019 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/chromeos/policy/app_install_event_log_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/system/statistics_provider.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user.h"
namespace em = enterprise_management;
namespace policy {
namespace {
// Key names used when building the dictionary to pass to the Chrome Reporting
// API.
constexpr char kAppPackage[] = "appPackage";
constexpr char kEventType[] = "eventType";
constexpr char kStatefulTotal[] = "statefulTotal";
constexpr char kStatefulFree[] = "statefulFree";
constexpr char kCloudDpsResponse[] = "clouddpsResponse";
constexpr char kOnline[] = "online";
constexpr char kSessionStateChangeType[] = "sessionStateChangeType";
constexpr char kSerialNumber[] = "serialNumber";
constexpr char kGaiaId[] = "gaiaId";
constexpr char kAndroidAppInstallEvent[] = "androidAppInstallEvent";
constexpr char kTime[] = "time";
} // namespace
bool GetGaiaId(Profile* profile, int* gaia_id) {
if (!profile)
return false;
const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
if (!user)
return false;
if (!base::StringToInt(user->GetAccountId().GetGaiaId(), gaia_id))
return false;
return true;
}
std::string GetSerialNumber() {
return chromeos::system::StatisticsProvider::GetInstance()
->GetEnterpriseMachineID();
}
base::Value ConvertProtoToValue(
const em::AppInstallReportRequest* app_install_report_request,
Profile* profile) {
DCHECK(app_install_report_request);
base::Value event_list(base::Value::Type::LIST);
base::Value::ListStorage& mutable_list = event_list.GetList();
for (const em::AppInstallReport& app_install_report :
app_install_report_request->app_install_reports()) {
for (const em::AppInstallReportLogEvent& app_install_report_log_event :
app_install_report.logs()) {
base::Value wrapper;
wrapper = ConvertEventToValue(
app_install_report.has_package() ? app_install_report.package() : "",
app_install_report_log_event, profile);
mutable_list.push_back(std::move(wrapper));
}
}
return event_list;
}
base::Value ConvertEventToValue(
const std::string& package,
const em::AppInstallReportLogEvent& app_install_report_log_event,
Profile* profile) {
base::Value event(base::Value::Type::DICTIONARY);
if (!package.empty())
event.SetStringKey(kAppPackage, package);
if (app_install_report_log_event.has_event_type()) {
event.SetIntKey(kEventType, app_install_report_log_event.event_type());
}
if (app_install_report_log_event.has_stateful_total()) {
event.SetIntKey(kStatefulTotal,
app_install_report_log_event.stateful_total());
}
if (app_install_report_log_event.has_stateful_free()) {
event.SetIntKey(kStatefulFree,
app_install_report_log_event.stateful_free());
}
if (app_install_report_log_event.has_clouddps_response()) {
event.SetIntKey(kCloudDpsResponse,
app_install_report_log_event.clouddps_response());
}
if (app_install_report_log_event.has_online())
event.SetBoolKey(kOnline, app_install_report_log_event.online());
if (app_install_report_log_event.has_session_state_change_type()) {
event.SetIntKey(kSessionStateChangeType,
app_install_report_log_event.session_state_change_type());
}
event.SetStringKey(kSerialNumber, GetSerialNumber());
int gaia_id;
if (GetGaiaId(profile, &gaia_id))
event.SetIntKey(kGaiaId, gaia_id);
base::Value wrapper(base::Value::Type::DICTIONARY);
wrapper.SetKey(kAndroidAppInstallEvent, std::move(event));
if (app_install_report_log_event.has_timestamp()) {
// Format the current time (UTC) in RFC3339 format
base::Time timestamp =
base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(
app_install_report_log_event.timestamp());
base::Time::Exploded time_exploded;
timestamp.UTCExplode(&time_exploded);
std::string time_str = base::StringPrintf(
"%d-%02d-%02dT%02d:%02d:%02d.%03dZ", time_exploded.year,
time_exploded.month, time_exploded.day_of_month, time_exploded.hour,
time_exploded.minute, time_exploded.second, time_exploded.millisecond);
wrapper.SetStringKey(kTime, time_str);
}
return wrapper;
}
} // namespace policy
// Copyright 2019 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_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_UTIL_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_UTIL_H_
#include "components/policy/proto/device_management_backend.pb.h"
namespace base {
class Value;
} // namespace base
class Profile;
namespace em = enterprise_management;
namespace policy {
// Returns true if GAIA ID can be fetched for a given |profile|, and it can be
// converted to a number. If GAIA ID can be fetched, it gets written to
// |gaia_id|, otherwise returns false.
bool GetGaiaId(Profile* profile, int* gaia_id);
// Return serial number of the device.
std::string GetSerialNumber();
// Converts AppInstallReportRequest proto defined in
// components/policy/proto/device_management_backend.proto to a dictionary value
// that corresponds to the definition of Event defined in
// google3/google/internal/chrome/reporting/v1/chromereporting.proto. This is
// done because events to Chrome Reporting API are sent as json over HTTP, and
// has different proto definition compare to the proto used to store events
// locally.
base::Value ConvertProtoToValue(
const em::AppInstallReportRequest* app_install_report_request,
Profile* profile);
// Converts AppInstallReportLogEvent proto defined in
// components/policy/proto/device_management_backend.proto to a dictionary value
// that corresponds to the definition of AndroidAppInstallEvent defined in
// google3/chrome/cros/reporting/proto/chrome_app_install_events.proto.
base::Value ConvertEventToValue(
const std::string& package,
const em::AppInstallReportLogEvent& app_install_report_log_event,
Profile* profile);
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_APP_INSTALL_EVENT_LOG_UTIL_H_
......@@ -279,7 +279,7 @@ void UserCloudPolicyManagerChromeOS::Connect(
}
app_install_event_log_uploader_ =
std::make_unique<AppInstallEventLogUploader>(client());
std::make_unique<AppInstallEventLogUploader>(client(), profile_);
}
void UserCloudPolicyManagerChromeOS::OnAccessTokenAvailable(
......
......@@ -15,6 +15,7 @@
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/common/extensions/api/safe_browsing_private.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
......@@ -70,30 +71,6 @@ SafeBrowsingPrivateEventRouter::SafeBrowsingPrivateEventRouter(
InitRealtimeReportingClient();
}
// TODO(rogerta): once new event types are implemented, will likely want to
// move this to a more common place.
base::Value BuildRealtimeReport(Profile* profile, base::Value event) {
base::Value context(base::Value::Type::DICTIONARY);
ProfileAttributesStorage& storage =
g_browser_process->profile_manager()->GetProfileAttributesStorage();
ProfileAttributesEntry* entry = nullptr;
if (storage.GetProfileAttributesWithPath(profile->GetPath(), &entry)) {
context.SetStringPath("profile.profileName", entry->GetName());
context.SetStringPath("profile.gaiaEmail", entry->GetUserName());
}
context.SetStringPath("profile.profilePath", profile->GetPath().value());
context.SetStringPath("browser.userAgent", GetUserAgent());
base::Value report(base::Value::Type::DICTIONARY);
report.SetKey(policy::RealtimeReportingJobConfiguration::kContextKey,
std::move(context));
report.SetKey(policy::RealtimeReportingJobConfiguration::kEventKey,
std::move(event));
return report;
}
SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() {}
void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected(
......@@ -388,9 +365,13 @@ void SafeBrowsingPrivateEventRouter::ReportRealtimeEvent(const char* name,
wrapper.SetStringKey("time", now_str);
wrapper.SetKey(name, std::move(event));
base::Value event_list(base::Value::Type::LIST);
event_list.GetList().push_back(std::move(wrapper));
client_->UploadRealtimeReport(
BuildRealtimeReport(Profile::FromBrowserContext(context_),
std::move(wrapper)),
policy::RealtimeReportingJobConfiguration::BuildReport(
std::move(event_list),
reporting::GetContext(Profile::FromBrowserContext(context_))),
base::DoNothing());
}
......
......@@ -159,12 +159,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnReuseDetected) {
Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey);
ASSERT_NE(nullptr, wrapper);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type());
base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event =
wrapper->FindKey(SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent);
wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent);
EXPECT_NE(nullptr, event);
EXPECT_EQ("https://phishing.com/",
*event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyUrl));
......@@ -190,12 +194,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnPasswordChanged) {
Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey);
ASSERT_NE(nullptr, wrapper);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type());
base::Value* event = wrapper->FindKey(
SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent);
base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event =
wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent);
EXPECT_NE(nullptr, event);
EXPECT_EQ("user_name_2", *event->FindStringKey(
SafeBrowsingPrivateEventRouter::kKeyUserName));
......@@ -225,11 +233,15 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnDangerousDownloadOpened) {
Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey);
ASSERT_NE(nullptr, wrapper);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type());
base::Value* event = wrapper->FindKey(
base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event = wrapper.FindKey(
SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent);
EXPECT_NE(nullptr, event);
EXPECT_EQ(
......@@ -259,12 +271,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest,
Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey);
ASSERT_NE(nullptr, wrapper);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type());
base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event =
wrapper->FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent);
wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent);
EXPECT_NE(nullptr, event);
EXPECT_EQ("PHISHING",
*event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyReason));
......@@ -295,12 +311,16 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnSecurityInterstitialShown) {
Mock::VerifyAndClearExpectations(client_);
EXPECT_EQ(base::Value::Type::DICTIONARY, report.type());
base::Value* wrapper =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventKey);
ASSERT_NE(nullptr, wrapper);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper->type());
base::Value* event_list =
report.FindKey(policy::RealtimeReportingJobConfiguration::kEventListKey);
ASSERT_NE(nullptr, event_list);
EXPECT_EQ(base::Value::Type::LIST, event_list->type());
base::Value::ListStorage& mutable_list = event_list->GetList();
ASSERT_EQ(1, (int)mutable_list.size());
base::Value wrapper = std::move(mutable_list[0]);
EXPECT_EQ(base::Value::Type::DICTIONARY, wrapper.type());
base::Value* event =
wrapper->FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent);
wrapper.FindKey(SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent);
EXPECT_NE(nullptr, event);
EXPECT_EQ("PHISHING",
*event->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyReason));
......
// Copyright 2019 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/profiles/reporting_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
namespace reporting {
base::Value GetContext(Profile* profile) {
base::Value context(base::Value::Type::DICTIONARY);
context.SetStringPath("browser.userAgent", GetUserAgent());
if (!profile)
return context;
ProfileAttributesStorage& storage =
g_browser_process->profile_manager()->GetProfileAttributesStorage();
ProfileAttributesEntry* entry = nullptr;
if (storage.GetProfileAttributesWithPath(profile->GetPath(), &entry)) {
context.SetStringPath("profile.profileName", entry->GetName());
context.SetStringPath("profile.gaiaEmail", entry->GetUserName());
}
context.SetStringPath("profile.profilePath", profile->GetPath().value());
return context;
}
} // namespace reporting
// Copyright 2019 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_PROFILES_REPORTING_UTIL_H_
#define CHROME_BROWSER_PROFILES_REPORTING_UTIL_H_
class Profile;
namespace base {
class Value;
} // namespace base
namespace reporting {
// Fetches additional information that is common to every event. Fetches and
// returns corresponding info to a Device, Browser and Profile protos defined in
// google3/google/internal/chrome/reporting/v1/chromereporting.proto.
base::Value GetContext(Profile* profile);
} // namespace reporting
#endif // CHROME_BROWSER_PROFILES_REPORTING_UTIL_H_
......@@ -1437,17 +1437,26 @@ TEST_F(CloudPolicyClientTest, UploadRealtimeReport) {
CloudPolicyClient::StatusCallback callback =
base::Bind(&MockStatusCallbackObserver::OnCallbackComplete,
base::Unretained(&callback_observer_));
base::Value report(base::Value::Type::DICTIONARY);
report.SetStringPath("context.gaiaEmail", "name@gmail.com");
report.SetStringPath("context.userAgent", "User-Agent");
report.SetStringPath("context.profileName", "Profile 1");
report.SetStringPath("context.profilePath", "C:\\User Data\\Profile 1");
report.SetStringPath("event.time", "2019-05-22T13:01:45Z");
report.SetStringPath("event.foo.prop1", "value1");
report.SetStringPath("event.foo.prop2", "value2");
report.SetStringPath("event.foo.prop3", "value3");
client_->UploadRealtimeReport(std::move(report), callback);
base::Value context(base::Value::Type::DICTIONARY);
context.SetStringPath("gaiaEmail", "name@gmail.com");
context.SetStringPath("userAgent", "User-Agent");
context.SetStringPath("profileName", "Profile 1");
context.SetStringPath("profilePath", "C:\\User Data\\Profile 1");
base::Value event;
event.SetStringPath("time", "2019-05-22T13:01:45Z");
event.SetStringPath("foo.prop1", "value1");
event.SetStringPath("foo.prop2", "value2");
event.SetStringPath("foo.prop3", "value3");
base::Value event_list(base::Value::Type::LIST);
event_list.GetList().push_back(std::move(event));
client_->UploadRealtimeReport(
std::move(policy::RealtimeReportingJobConfiguration::BuildReport(
std::move(event_list), std::move(context))),
callback);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(
DeviceManagementService::JobConfiguration::TYPE_UPLOAD_REAL_TIME_REPORT,
......
......@@ -20,7 +20,7 @@ namespace em = enterprise_management;
namespace policy {
const char RealtimeReportingJobConfiguration::kContextKey[] = "context";
const char RealtimeReportingJobConfiguration::kEventKey[] = "event";
const char RealtimeReportingJobConfiguration::kEventListKey[] = "eventList";
const char RealtimeReportingJobConfiguration::kBrowserIdKey[] =
"browser.browserId";
......@@ -35,6 +35,15 @@ const char RealtimeReportingJobConfiguration::kMachineUserKey[] =
const char RealtimeReportingJobConfiguration::kOsVersionKey[] =
"device.osVersion";
base::Value RealtimeReportingJobConfiguration::BuildReport(
base::Value events,
base::Value context) {
base::Value value_report(base::Value::Type::DICTIONARY);
value_report.SetKey(kEventListKey, std::move(events));
value_report.SetKey(kContextKey, std::move(context));
return value_report;
}
RealtimeReportingJobConfiguration::RealtimeReportingJobConfiguration(
CloudPolicyClient* client,
std::unique_ptr<DMAuth> auth_data,
......@@ -59,8 +68,8 @@ bool RealtimeReportingJobConfiguration::AddReport(base::Value report) {
return false;
base::Optional<base::Value> context = report.ExtractKey(kContextKey);
base::Optional<base::Value> event = report.ExtractKey(kEventKey);
if (!context || !event)
base::Optional<base::Value> event_list = report.ExtractKey(kEventListKey);
if (!context || !event_list || !event_list->is_list())
return false;
// Move context keys to the payload. It is possible to add multiple reports
......@@ -71,9 +80,11 @@ bool RealtimeReportingJobConfiguration::AddReport(base::Value report) {
payload_.SetKey(item.first, item.second.Clone());
}
// Append event to the list.
base::Value::ListStorage& list = payload_.FindListKey(kEventsKey)->GetList();
list.push_back(std::move(*event));
// Append event_list to the payload.
base::Value::ListStorage& to = payload_.FindListKey(kEventsKey)->GetList();
base::Value::ListStorage& from = event_list->GetList();
to.insert(to.end(), std::make_move_iterator(from.begin()),
std::make_move_iterator(from.end()));
return true;
}
......
......@@ -24,7 +24,7 @@ class POLICY_EXPORT RealtimeReportingJobConfiguration
public:
// Keys used in report dictionary.
static const char kContextKey[];
static const char kEventKey[];
static const char kEventListKey[];
// Keys used in request payload dictionary. Public for testing.
static const char kBrowserIdKey[];
......@@ -41,15 +41,21 @@ class POLICY_EXPORT RealtimeReportingJobConfiguration
const base::Value&)>
Callback;
// Combines the info given in |events| that corresponds to Event proto, and
// info given in |context| that corresponds to the Device, Browser and Profile
// proto, to a UploadEventsRequest proto defined in
// google3/google/internal/chrome/reporting/v1/chromereporting.proto.
static base::Value BuildReport(base::Value events, base::Value context);
RealtimeReportingJobConfiguration(CloudPolicyClient* client,
std::unique_ptr<DMAuth> auth_data,
Callback callback);
~RealtimeReportingJobConfiguration() override;
// Add a new report to the payload. A report is a dictionary that contains
// two keys: "event" and "context". The first key is a dictionary defined by
// the Event message described at
// Add a new report to the payload. A report is a dictionary that
// contains two keys: "events" and "context". The first key is a list of
// dictionaries, where dictionary is defined by the Event message described at
// google/internal/chrome/reporting/v1/chromereporting.proto.
//
// The second is context information about this instance of chrome that
......
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