| // Copyright 2017 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 ANDROID_WEBVIEW_BROWSER_METRICS_AW_METRICS_SERVICE_CLIENT_H_ |
| #define ANDROID_WEBVIEW_BROWSER_METRICS_AW_METRICS_SERVICE_CLIENT_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include "android_webview/browser/lifecycle/webview_app_state_observer.h" |
| #include "base/macros.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/no_destructor.h" |
| #include "base/sequence_checker.h" |
| #include "base/time/time.h" |
| #include "components/embedder_support/android/metrics/android_metrics_service_client.h" |
| #include "components/metrics/enabled_state_provider.h" |
| #include "components/metrics/metrics_log_uploader.h" |
| #include "components/metrics/metrics_service_client.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| |
| namespace android_webview { |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| // TODO(https://crbug.com/1012025): remove this when the kInstallDate pref has |
| // been persisted for one or two milestones. Visible for testing. |
| enum class BackfillInstallDate { |
| kValidInstallDatePref = 0, |
| kCouldNotGetPackageManagerInstallDate = 1, |
| kPersistedPackageManagerInstallDate = 2, |
| kMaxValue = kPersistedPackageManagerInstallDate, |
| }; |
| |
| // AwMetricsServiceClient is a singleton which manages WebView metrics |
| // collection. |
| // |
| // Metrics should be enabled iff all these conditions are met: |
| // - The user has not opted out (controlled by GMS). |
| // - The app has not opted out (controlled by manifest tag). |
| // - This client is in the 2% sample (controlled by client ID hash). |
| // The first two are recorded in |user_consent_| and |app_consent_|, which are |
| // set by SetHaveMetricsConsent(). The last is recorded in |is_in_sample_|. |
| // |
| // Metrics are pseudonymously identified by a randomly-generated "client ID". |
| // WebView stores this in prefs, written to the app's data directory. There's a |
| // different such directory for each user, for each app, on each device. So the |
| // ID should be unique per (device, app, user) tuple. |
| // |
| // To avoid the appearance that we're doing anything sneaky, the client ID |
| // should only be created and retained when neither the user nor the app have |
| // opted out. Otherwise, the presence of the ID could give the impression that |
| // metrics were being collected. |
| // |
| // WebView metrics set up happens like so: |
| // |
| // startup |
| // │ |
| // ├────────────┐ |
| // │ ▼ |
| // │ query GMS for consent |
| // ▼ │ |
| // Initialize() │ |
| // │ ▼ |
| // │ SetHaveMetricsConsent() |
| // │ │ |
| // │ ┌──────────┘ |
| // ▼ ▼ |
| // MaybeStartMetrics() |
| // │ |
| // ▼ |
| // MetricsService::Start() |
| // |
| // All the named functions in this diagram happen on the UI thread. Querying GMS |
| // happens in the background, and the result is posted back to the UI thread, to |
| // SetHaveMetricsConsent(). Querying GMS is slow, so SetHaveMetricsConsent() |
| // typically happens after Initialize(), but it may happen before. |
| // |
| // Each path sets a flag, |init_finished_| or |set_consent_finished_|, to show |
| // that path has finished, and then calls MaybeStartMetrics(). When |
| // MaybeStartMetrics() is called the first time, it sees only one flag is true, |
| // and does nothing. When MaybeStartMetrics() is called the second time, it |
| // decides whether to start metrics. |
| // |
| // If consent was granted, MaybeStartMetrics() determines sampling by hashing |
| // the client ID (generating a new ID if there was none). If this client is in |
| // the sample, it then calls MetricsService::Start(). If consent was not |
| // granted, MaybeStartMetrics() instead clears the client ID, if any. |
| |
| class AwMetricsServiceClient : public ::metrics::AndroidMetricsServiceClient, |
| public WebViewAppStateObserver { |
| friend class base::NoDestructor<AwMetricsServiceClient>; |
| |
| public: |
| // This interface define the tasks that depend on the |
| // android_webview/browser directory. |
| class Delegate { |
| public: |
| Delegate(); |
| virtual ~Delegate(); |
| |
| // Not copyable or movable |
| Delegate(const Delegate&) = delete; |
| Delegate& operator=(const Delegate&) = delete; |
| Delegate(Delegate&&) = delete; |
| Delegate& operator=(Delegate&&) = delete; |
| |
| virtual void RegisterAdditionalMetricsProviders( |
| metrics::MetricsService* service) = 0; |
| virtual void AddWebViewAppStateObserver( |
| WebViewAppStateObserver* observer) = 0; |
| virtual bool HasAwContentsEverCreated() const = 0; |
| }; |
| |
| static AwMetricsServiceClient* GetInstance(); |
| static void SetInstance( |
| std::unique_ptr<AwMetricsServiceClient> aw_metrics_service_client); |
| |
| AwMetricsServiceClient(std::unique_ptr<Delegate> delegate); |
| ~AwMetricsServiceClient() override; |
| |
| // metrics::MetricsServiceClient |
| int32_t GetProduct() override; |
| |
| // WebViewAppStateObserver |
| void OnAppStateChanged(WebViewAppStateObserver::State state) override; |
| |
| // metrics::AndroidMetricsServiceClient: |
| void OnMetricsStart() override; |
| int GetSampleRatePerMille() override; |
| int GetPackageNameLimitRatePerMille() override; |
| void RegisterAdditionalMetricsProviders( |
| metrics::MetricsService* service) override; |
| |
| private: |
| bool app_in_foreground_ = false; |
| std::unique_ptr<Delegate> delegate_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClient); |
| }; |
| |
| } // namespace android_webview |
| |
| #endif // ANDROID_WEBVIEW_BROWSER_METRICS_AW_METRICS_SERVICE_CLIENT_H_ |