1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// Copyright 2019 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/arc/arc_ui_availability_reporter.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/arc/arc_optin_uma.h"
#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
#include "chromeos/ash/experiences/arc/session/arc_service_manager.h"
namespace arc {
class ArcUiAvailabilityReporter::ConnectionNotifierBase {
public:
ConnectionNotifierBase(const ConnectionNotifierBase&) = delete;
ConnectionNotifierBase& operator=(const ConnectionNotifierBase&) = delete;
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:
const raw_ptr<ArcUiAvailabilityReporter> owner_;
};
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(const ConnectionNotifier&) = delete;
ConnectionNotifier& operator=(const ConnectionNotifier&) = delete;
~ConnectionNotifier() override { holder_->RemoveObserver(this); }
// ArcUiAvailabilityReporter::ConnectionNotifierBase:
bool IsConnected() override { return holder_->IsConnected(); }
// ConnectionObserver<InstanceType>:
void OnConnectionReady() override { owner()->MaybeReport(); }
private:
const raw_ptr<ConnectionHolder<InstanceType, HostType>> holder_;
};
} // 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
|