| // 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/arc/arc_ui_availability_reporter.h" |
| |
| #include "chrome/browser/chromeos/arc/arc_optin_uma.h" |
| #include "components/arc/arc_service_manager.h" |
| #include "components/arc/session/arc_bridge_service.h" |
| |
| namespace arc { |
| |
| class ArcUiAvailabilityReporter::ConnectionNotifierBase { |
| public: |
| virtual ~ConnectionNotifierBase() = default; |
| |
| // Returns true if connection is ready. |
| virtual bool IsConnected() = 0; |
| |
| protected: |
| explicit ConnectionNotifierBase(ArcUiAvailabilityReporter* owner) |
| : owner_(owner) {} |
| |
| ArcUiAvailabilityReporter* owner() { return owner_; } |
| |
| private: |
| ArcUiAvailabilityReporter* const owner_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ConnectionNotifierBase); |
| }; |
| |
| namespace { |
| |
| template <typename InstanceType, typename HostType> |
| class ConnectionNotifier |
| : public ArcUiAvailabilityReporter::ConnectionNotifierBase, |
| public ConnectionObserver<InstanceType> { |
| public: |
| // |owner_| owns this object and |ConnectionNotifier| is destroyed in case |
| // statistics is reported or ARC session is terminated on user log-out and |
| // this automatically destroys this object at time of destroying |owner_|. |
| // |holder_| is owned by ArcBridgeService this lives longer than |
| // |ArcUiAvailabilityReporter|. |
| ConnectionNotifier(ArcUiAvailabilityReporter* owner, |
| ConnectionHolder<InstanceType, HostType>* holder) |
| : ArcUiAvailabilityReporter::ConnectionNotifierBase(owner), |
| holder_(holder) { |
| DCHECK(!holder_->IsConnected()); |
| holder_->AddObserver(this); |
| } |
| |
| ~ConnectionNotifier() override { holder_->RemoveObserver(this); } |
| |
| // ArcUiAvailabilityReporter::ConnectionNotifierBase: |
| bool IsConnected() override { return holder_->IsConnected(); } |
| |
| // ConnectionObserver<InstanceType>: |
| void OnConnectionReady() override { owner()->MaybeReport(); } |
| |
| private: |
| ConnectionHolder<InstanceType, HostType>* const holder_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ConnectionNotifier); |
| }; |
| |
| } // namespace |
| |
| ArcUiAvailabilityReporter::ArcUiAvailabilityReporter(Profile* profile, |
| Mode mode) |
| : profile_(profile), mode_(mode), start_ticks_(base::TimeTicks::Now()) { |
| DCHECK(profile); |
| // Some unit tests may not have |ArcServiceManager| set. |
| ArcServiceManager* const service_manager = ArcServiceManager::Get(); |
| if (!service_manager) |
| return; |
| // |initiated_from_oobe| must be set only if |initial_start| is set. |
| auto* const arc_bridge = ArcServiceManager::Get()->arc_bridge_service(); |
| // Not expected instances are connected at the time of creation, however this |
| // is not always preserved in tests. |
| if (arc_bridge->app()->IsConnected() || |
| arc_bridge->intent_helper()->IsConnected()) { |
| LOG(ERROR) << "App and/or intent_helper instances are already connected. " |
| << "This is not expected in production."; |
| return; |
| } |
| |
| connection_notifiers_.emplace_back( |
| std::make_unique<ConnectionNotifier<mojom::AppInstance, mojom::AppHost>>( |
| this, arc_bridge->app())); |
| connection_notifiers_.emplace_back( |
| std::make_unique<ConnectionNotifier<mojom::IntentHelperInstance, |
| mojom::IntentHelperHost>>( |
| this, arc_bridge->intent_helper())); |
| } |
| |
| ArcUiAvailabilityReporter::~ArcUiAvailabilityReporter() = default; |
| |
| // static |
| std::string ArcUiAvailabilityReporter::GetHistogramNameForMode(Mode mode) { |
| switch (mode) { |
| case Mode::kOobeProvisioning: |
| return "OobeProvisioning"; |
| case Mode::kInSessionProvisioning: |
| return "InSessionProvisioning"; |
| case Mode::kAlreadyProvisioned: |
| return "AlreadyProvisioned"; |
| } |
| } |
| |
| void ArcUiAvailabilityReporter::MaybeReport() { |
| DCHECK(!connection_notifiers_.empty()); |
| |
| // Check that all tracked instance are connected. |
| for (const auto& connection_notifier : connection_notifiers_) { |
| if (!connection_notifier->IsConnected()) |
| return; |
| } |
| |
| UpdateArcUiAvailableTime(base::TimeTicks::Now() - start_ticks_, |
| GetHistogramNameForMode(mode_), profile_); |
| |
| // No more reporting is expected. |
| connection_notifiers_.clear(); |
| } |
| |
| } // namespace arc |