blob: 4ee66581d1b353b3e8ef436469af2200e04b5db7 [file] [log] [blame]
// Copyright 2020 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/metrics/authenticator_utility.h"
#include <memory>
#include "base/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/rand_util.h"
#include "base/task/thread_pool.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h"
#include "content/public/browser/authenticator_request_client_delegate.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/is_uvpaa.h"
#if defined(OS_MAC)
#include "device/fido/mac/authenticator.h"
#endif
#if defined(OS_WIN)
#include "device/fido/win/webauthn_api.h"
#endif
namespace authenticator_utility {
void ReportAvailability(bool available) {
base::UmaHistogramBoolean(
"WebAuthentication.IsUVPlatformAuthenticatorAvailable", available);
}
#if defined(OS_MAC)
void ReportUVPlatformAuthenticatorAvailabilityWithConfig(
base::Optional<device::fido::mac::AuthenticatorConfig> config) {
if (!config) {
ReportAvailability(false);
return;
}
content::IsUVPlatformAuthenticatorAvailable(
*config, base::BindOnce(&ReportAvailability));
}
void ReportUVPlatformAuthenticatorAvailabilityMainThreadMac() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Tests can shut down before this task is run.
if (!g_browser_process)
return;
// Startup metrics are recording during PostBrowserStart() which is after
// profile initialization. However some tests run PostBrowserStart() without
// setting up profiles so there still needs to be a guard.
ProfileManager* profile_manager = g_browser_process->profile_manager();
if (!profile_manager || !g_browser_process->local_state()) {
return;
}
Profile* profile = profile_manager->GetProfileByPath(
profile_manager->GetLastUsedProfileDir(profile_manager->user_data_dir()));
// Some tests have profiles but do not load the last profile before
// PostBrowserStart().
if (!profile) {
return;
}
// Return to a low-priority thread for the actual check.
base::ThreadPool::PostTask(
FROM_HERE, {base::TaskPriority::BEST_EFFORT},
base::BindOnce(&ReportUVPlatformAuthenticatorAvailabilityWithConfig,
ChromeAuthenticatorRequestDelegate::
TouchIdAuthenticatorConfigForProfile(profile)));
}
#endif
void ReportUVPlatformAuthenticatorAvailability() {
// This only reports metrics for desktop platforms. For mobile devices, the
// platform version is an exact proxy for whether a platform authenticator
// can be used.
#if defined(OS_MAC)
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// IsUVPAA() is prone to crashes/hangs on macOS. Downsample metric collection
// to make occurrences less likely while we mitigate/fix the underlying issue.
// (See crbug.com/1169928).
if (base::RandGenerator(10'000) != 0u) {
return;
}
// Getting the profile has to be done on the main thread to avoid race
// conditions.
content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
->PostTask(FROM_HERE,
base::BindOnce(
&ReportUVPlatformAuthenticatorAvailabilityMainThreadMac));
#elif defined(OS_WIN)
content::IsUVPlatformAuthenticatorAvailable(
device::WinWebAuthnApi::GetDefault(),
base::BindOnce(&ReportAvailability));
#elif BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/1181426): Reenable the IsUVPAA() startup metric on CrOS.
#endif
}
} // namespace authenticator_utility