-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[App-Discovery] Add initial logging to launcher.
Bug: b/267218014 Change-Id: I7b8e33cd110fc363254de7af4e90c0e82175f4b2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4228480 Reviewed-by: Tony Yeoman <tby@chromium.org> Commit-Queue: Jong Ahn <jongahn@chromium.org> Cr-Commit-Position: refs/heads/main@{#1108206}
- Loading branch information
Jong Ahn
authored and
Chromium LUCI CQ
committed
Feb 22, 2023
1 parent
a9f3a2e
commit 3842f9a
Showing
9 changed files
with
389 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
chrome/browser/ash/app_list/search/app_discovery_metrics_manager.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/ash/app_list/search/app_discovery_metrics_manager.h" | ||
|
||
#include "ash/public/cpp/app_list/app_list_metrics.h" | ||
#include "chrome/browser/ash/app_list/search/common/types_util.h" | ||
#include "chrome/browser/sync/sync_service_factory.h" | ||
#include "chromeos/ash/components/string_matching/fuzzy_tokenized_string_match.h" | ||
#include "chromeos/ash/components/string_matching/tokenized_string.h" | ||
#include "components/metrics/structured/structured_events.h" | ||
#include "components/sync/base/model_type.h" | ||
#include "components/sync/driver/sync_service.h" | ||
#include "components/sync/driver/sync_service_utils.h" | ||
|
||
namespace app_list { | ||
|
||
namespace { | ||
|
||
namespace cros_events = metrics::structured::events::v2::cr_os_events; | ||
|
||
bool IsResultAppInstallRelated(ash::SearchResultType result_type) { | ||
return result_type == ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP || | ||
result_type == ash::SearchResultType::GAME_SEARCH || | ||
result_type == ash::SearchResultType::PLAY_STORE_INSTANT_APP; | ||
} | ||
|
||
} // namespace | ||
|
||
AppDiscoveryMetricsManager::AppDiscoveryMetricsManager(Profile* profile) | ||
: profile_(profile) {} | ||
AppDiscoveryMetricsManager::~AppDiscoveryMetricsManager() = default; | ||
|
||
void AppDiscoveryMetricsManager::OnOpenResult(ChromeSearchResult* result, | ||
const std::u16string& query) { | ||
// If the result is not app-install related, then ignore result as it does not | ||
// pertain to app-discovery. | ||
if (!IsResultAppInstallRelated(result->metrics_type())) { | ||
return; | ||
} | ||
|
||
auto app_name = ash::string_matching::TokenizedString(result->title()); | ||
auto tokenized_query = ash::string_matching::TokenizedString(query); | ||
|
||
double string_match_score = | ||
ash::string_matching::FuzzyTokenizedStringMatch::WeightedRatio( | ||
app_name, tokenized_query); | ||
|
||
// If app-sync is disabled, then do not send app_id. | ||
std::string app_id = IsAppSyncEnabled() ? result->id() : ""; | ||
std::u16string app_title = IsAppSyncEnabled() ? result->title() : u""; | ||
|
||
cros_events::AppDiscovery_AppLauncherResultOpened() | ||
.SetAppId(app_id) | ||
.SetAppName(std::string(app_title.begin(), app_title.end())) | ||
.SetFuzzyStringMatch(string_match_score) | ||
.Record(); | ||
} | ||
|
||
void AppDiscoveryMetricsManager::OnLauncherOpen() { | ||
cros_events::AppDiscovery_LauncherOpen().Record(); | ||
} | ||
|
||
bool AppDiscoveryMetricsManager::IsAppSyncEnabled() { | ||
switch (syncer::GetUploadToGoogleState( | ||
SyncServiceFactory::GetForProfile(profile_), syncer::ModelType::APPS)) { | ||
case syncer::UploadState::NOT_ACTIVE: | ||
return false; | ||
case syncer::UploadState::INITIALIZING: | ||
// Note that INITIALIZING is considered good enough, because syncing apps | ||
// is known to be enabled, and transient errors don't really matter here. | ||
case syncer::UploadState::ACTIVE: | ||
return true; | ||
} | ||
} | ||
|
||
} // namespace app_list |
41 changes: 41 additions & 0 deletions
41
chrome/browser/ash/app_list/search/app_discovery_metrics_manager.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_ASH_APP_LIST_SEARCH_APP_DISCOVERY_METRICS_MANAGER_H_ | ||
#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_APP_DISCOVERY_METRICS_MANAGER_H_ | ||
|
||
#include "base/scoped_observation.h" | ||
#include "chrome/browser/ash/app_list/search/chrome_search_result.h" | ||
#include "chrome/browser/profiles/profile.h" | ||
|
||
namespace app_list { | ||
|
||
// Class that manages recording metrics related to app discovery from the | ||
// launcher. | ||
class AppDiscoveryMetricsManager { | ||
public: | ||
explicit AppDiscoveryMetricsManager(Profile* profile); | ||
~AppDiscoveryMetricsManager(); | ||
|
||
AppDiscoveryMetricsManager(const AppDiscoveryMetricsManager&) = delete; | ||
AppDiscoveryMetricsManager& operator=(const AppDiscoveryMetricsManager&) = | ||
delete; | ||
|
||
// Called when the launcher is opened. | ||
void OnLauncherOpen(); | ||
|
||
// Called when a result is launched from the launcher. | ||
void OnOpenResult(ChromeSearchResult* result, const std::u16string& query); | ||
|
||
private: | ||
// Returns whether app sync is enabled for |profile_| or not. | ||
bool IsAppSyncEnabled(); | ||
|
||
// Profile of the current user. | ||
Profile* profile_; | ||
}; | ||
|
||
} // namespace app_list | ||
|
||
#endif // CHROME_BROWSER_ASH_APP_LIST_SEARCH_APP_DISCOVERY_METRICS_MANAGER_H_ |
201 changes: 201 additions & 0 deletions
201
chrome/browser/ash/app_list/search/app_discovery_metrics_manager_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/ash/app_list/search/app_discovery_metrics_manager.h" | ||
|
||
#include "ash/public/cpp/app_list/app_list_metrics.h" | ||
#include "base/memory/raw_ptr.h" | ||
#include "base/run_loop.h" | ||
#include "base/test/bind.h" | ||
#include "chrome/browser/ash/app_list/search/chrome_search_result.h" | ||
#include "chrome/browser/sync/sync_service_factory.h" | ||
#include "chrome/test/base/testing_profile.h" | ||
#include "components/metrics/structured/recorder.h" | ||
#include "components/metrics/structured/structured_events.h" | ||
#include "components/metrics/structured/structured_metrics_features.h" | ||
#include "components/metrics/structured/test/test_structured_metrics_provider.h" | ||
#include "components/sync/test/test_sync_service.h" | ||
#include "components/sync_preferences/testing_pref_service_syncable.h" | ||
#include "content/public/test/browser_task_environment.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
namespace app_list { | ||
namespace { | ||
|
||
namespace cros_events = metrics::structured::events::v2::cr_os_events; | ||
|
||
std::unique_ptr<KeyedService> TestingSyncFactoryFunction( | ||
content::BrowserContext* context) { | ||
return std::make_unique<syncer::TestSyncService>(); | ||
} | ||
|
||
// Impl for testing structured metrics that forwards all writes to the recorder | ||
// directly. | ||
class TestRecorder | ||
: public metrics::structured::StructuredMetricsClient::RecordingDelegate { | ||
public: | ||
TestRecorder() { | ||
metrics::structured::StructuredMetricsClient::Get()->SetDelegate(this); | ||
} | ||
|
||
bool IsReadyToRecord() const override { return true; } | ||
|
||
void RecordEvent(metrics::structured::Event&& event) override { | ||
metrics::structured::Recorder::GetInstance()->RecordEvent(std::move(event)); | ||
} | ||
}; | ||
|
||
class TestSearchResult : public ChromeSearchResult { | ||
public: | ||
TestSearchResult(const std::string& id, | ||
const std::u16string& title, | ||
MetricsType metrics_type) { | ||
set_id(id); | ||
SetTitle(title); | ||
SetMetricsType(metrics_type); | ||
} | ||
|
||
TestSearchResult(const TestSearchResult&) = delete; | ||
TestSearchResult& operator=(const TestSearchResult&) = delete; | ||
|
||
~TestSearchResult() override {} | ||
|
||
// ChromeSearchResult overrides: | ||
void Open(int event_flags) override {} | ||
}; | ||
|
||
} // namespace | ||
|
||
class AppDiscoveryMetricsManagerTest : public testing::Test { | ||
public: | ||
void SetUp() override { | ||
test_recorder_ = std::make_unique<TestRecorder>(); | ||
test_structured_metrics_provider_ = | ||
std::make_unique<metrics::structured::TestStructuredMetricsProvider>(); | ||
test_structured_metrics_provider_->EnableRecording(); | ||
metrics::structured::Recorder::GetInstance()->SetUiTaskRunner( | ||
task_environment_.GetMainThreadTaskRunner()); | ||
|
||
TestingProfile::Builder builder; | ||
builder.AddTestingFactory(SyncServiceFactory::GetInstance(), | ||
SyncServiceFactory::GetDefaultFactory()); | ||
testing_profile_ = builder.Build(); | ||
|
||
sync_service_ = static_cast<syncer::TestSyncService*>( | ||
SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( | ||
testing_profile_.get(), | ||
base::BindRepeating(&TestingSyncFactoryFunction))); | ||
|
||
app_discovery_metrics_ = | ||
std::make_unique<AppDiscoveryMetricsManager>(testing_profile_.get()); | ||
} | ||
|
||
metrics::structured::TestStructuredMetricsProvider* | ||
test_structured_metrics_provider() { | ||
return test_structured_metrics_provider_.get(); | ||
} | ||
|
||
void ValidateAppLaunchEvent(const metrics::structured::Event& event, | ||
const std::string& app_id, | ||
const std::u16string& app_title, | ||
double match_score) { | ||
cros_events::AppDiscovery_AppLauncherResultOpened expected_event; | ||
|
||
EXPECT_EQ(expected_event.project_name(), event.project_name()); | ||
EXPECT_EQ(expected_event.event_name(), event.event_name()); | ||
|
||
expected_event.SetAppId(app_id) | ||
.SetAppName(std::string(app_title.begin(), app_title.end())) | ||
.SetFuzzyStringMatch(match_score); | ||
|
||
EXPECT_EQ(expected_event.metric_values(), event.metric_values()); | ||
} | ||
|
||
void ValidateLauncherOpenEvent(const metrics::structured::Event& event) { | ||
cros_events::AppDiscovery_LauncherOpen expected_event; | ||
|
||
EXPECT_EQ(expected_event.project_name(), event.project_name()); | ||
EXPECT_EQ(expected_event.event_name(), event.event_name()); | ||
} | ||
|
||
TestingProfile* profile() { return testing_profile_.get(); } | ||
|
||
syncer::TestSyncService* sync_service() { return sync_service_; } | ||
|
||
AppDiscoveryMetricsManager* app_discovery_metrics() { | ||
return app_discovery_metrics_.get(); | ||
} | ||
|
||
private: | ||
content::BrowserTaskEnvironment task_environment_; | ||
|
||
std::unique_ptr<TestingProfile> testing_profile_; | ||
raw_ptr<syncer::TestSyncService> sync_service_ = nullptr; | ||
std::unique_ptr<AppDiscoveryMetricsManager> app_discovery_metrics_; | ||
|
||
std::unique_ptr<TestRecorder> test_recorder_; | ||
std::unique_ptr<metrics::structured::TestStructuredMetricsProvider> | ||
test_structured_metrics_provider_; | ||
}; | ||
|
||
TEST_F(AppDiscoveryMetricsManagerTest, OnOpenAppResult) { | ||
const std::u16string app_name = u"app_name"; | ||
const std::u16string query = u"app_name"; | ||
const std::string app_id = "id"; | ||
|
||
TestSearchResult search_result( | ||
app_id, app_name, ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP); | ||
|
||
base::RunLoop run_loop; | ||
auto record_callback = base::BindLambdaForTesting( | ||
[&, this](const metrics::structured::Event& event) { | ||
ValidateAppLaunchEvent(event, app_id, app_name, /*match_score=*/1.0); | ||
run_loop.Quit(); | ||
}); | ||
test_structured_metrics_provider()->SetOnEventsRecordClosure(record_callback); | ||
|
||
app_discovery_metrics()->OnOpenResult(&search_result, query); | ||
run_loop.Run(); | ||
} | ||
|
||
TEST_F(AppDiscoveryMetricsManagerTest, OnOpenAppResultAppSyncDisabled) { | ||
const std::u16string app_name = u"app_name"; | ||
const std::u16string query = u"app_name"; | ||
const std::string app_id = "id"; | ||
|
||
// Disable app-sync. | ||
sync_service()->SetDisableReasons( | ||
syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); | ||
|
||
TestSearchResult search_result( | ||
app_id, app_name, ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP); | ||
|
||
base::RunLoop run_loop; | ||
auto record_callback = base::BindLambdaForTesting( | ||
[&, this](const metrics::structured::Event& event) { | ||
// App ID and app name will be stripped if app sync is disabled. | ||
ValidateAppLaunchEvent(event, /*app_id=*/"", /*app_title=*/u"", | ||
/*match_score=*/1.0); | ||
run_loop.Quit(); | ||
}); | ||
test_structured_metrics_provider()->SetOnEventsRecordClosure(record_callback); | ||
|
||
app_discovery_metrics()->OnOpenResult(&search_result, query); | ||
run_loop.Run(); | ||
} | ||
|
||
TEST_F(AppDiscoveryMetricsManagerTest, OnLauncherOpen) { | ||
base::RunLoop run_loop; | ||
auto record_callback = base::BindLambdaForTesting( | ||
[&, this](const metrics::structured::Event& event) { | ||
ValidateLauncherOpenEvent(event); | ||
run_loop.Quit(); | ||
}); | ||
test_structured_metrics_provider()->SetOnEventsRecordClosure(record_callback); | ||
|
||
app_discovery_metrics()->OnLauncherOpen(); | ||
run_loop.Run(); | ||
} | ||
|
||
} // namespace app_list |
Oops, something went wrong.