Skip to content

Commit

Permalink
arc: Add ANR stats per period.
Browse files Browse the repository at this point in the history
This adds ANR rate for starting period and ANR rate on regular basis
taken each 4 hours. Starting period is 10 minutes after ARC start.
Shorter sessions are ignored. Regular period is calculated based on ARC
session activity and updated each 4-hours interval. It also supports
ARC session restarts. That means if session is restarted in the middle
of the period, it would be continued when user logs in the next time.

BUG=b:225214120
TEST=unit test

Change-Id: I5fe522e4fcb051f06470f76969884aa4ff580be9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3537585
Reviewed-by: Muhammad Hasan Khan <mhasank@chromium.org>
Reviewed-by: Yusuke Sato <yusukes@chromium.org>
Commit-Queue: Yury Khmel <khmel@chromium.org>
Cr-Commit-Position: refs/heads/main@{#988608}
  • Loading branch information
Yury Khmel authored and Chromium LUCI CQ committed Apr 4, 2022
1 parent b5360da commit 5f0165a
Show file tree
Hide file tree
Showing 13 changed files with 539 additions and 148 deletions.
3 changes: 3 additions & 0 deletions ash/components/arc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ static_library("arc") {
"memory/arc_memory_bridge.h",
"memory_pressure/arc_memory_pressure_bridge.cc",
"memory_pressure/arc_memory_pressure_bridge.h",
"metrics/arc_metrics_anr.cc",
"metrics/arc_metrics_anr.h",
"metrics/arc_metrics_service.cc",
"metrics/arc_metrics_service.h",
"metrics/stability_metrics_manager.cc",
Expand Down Expand Up @@ -395,6 +397,7 @@ source_set("unit_tests") {
"media_session/arc_media_session_bridge_unittest.cc",
"memory/arc_memory_bridge_unittest.cc",
"memory_pressure/arc_memory_pressure_bridge_unittest.cc",
"metrics/arc_metrics_anr_unittest.cc",
"metrics/arc_metrics_service_unittest.cc",
"metrics/stability_metrics_manager_unittest.cc",
"midis/arc_midis_bridge_unittest.cc",
Expand Down
13 changes: 13 additions & 0 deletions ash/components/arc/arc_prefs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ const char kArcPlayStoreLaunchMetricCanBeRecorded[] =
"arc.playstore_launched_by_user";

// ======== LOCAL STATE PREFS ========
// ANR count which is currently pending counted for ARC start, not flashed to
// UMA.
const char kAnrOnStartPendingCount[] = "arc.anr_pending_count_on_start";

// ANR count which is currently pending, not flashed to UMA.
const char kAnrPendingCount[] = "arc.anr_pending_count";

// Keeps the duration of the current ANR rate period.
const char kAnrPendingDuration[] = "arc.anr_pending_duration";

// A boolean preference that indicates whether this device has run with the
// native bridge 64 bit support experiment enabled. Persisting value in local
Expand Down Expand Up @@ -152,6 +161,10 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kNativeBridge64BitSupportExperimentEnabled,
false);
registry->RegisterDictionaryPref(kStabilityMetrics);

registry->RegisterIntegerPref(kAnrPendingCount, 0);
registry->RegisterIntegerPref(kAnrOnStartPendingCount, 0);
registry->RegisterTimeDeltaPref(kAnrPendingDuration, base::TimeDelta());
}

void RegisterProfilePrefs(PrefRegistrySimple* registry) {
Expand Down
3 changes: 3 additions & 0 deletions ash/components/arc/arc_prefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ ARC_EXPORT extern const char kEngagementPrefsPrefix[];
ARC_EXPORT extern const char kArcPlayStoreLaunchMetricCanBeRecorded[];

// Local state prefs in lexicographical order.
ARC_EXPORT extern const char kAnrOnStartPendingCount[];
ARC_EXPORT extern const char kAnrPendingCount[];
ARC_EXPORT extern const char kAnrPendingDuration[];
ARC_EXPORT extern const char kArcSerialNumberSalt[];
ARC_EXPORT extern const char kArcSnapshotHours[];
ARC_EXPORT extern const char kArcSnapshotInfo[];
Expand Down
147 changes: 147 additions & 0 deletions ash/components/arc/metrics/arc_metrics_anr.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright 2022 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 "ash/components/arc/metrics/arc_metrics_anr.h"

#include <string>

#include "ash/components/arc/arc_prefs.h"
#include "base/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "components/prefs/pref_service.h"

namespace arc {

namespace {
// Intervals to collect ANR rate after login. Collected only once per session.
// In case the session is shorter than |kMinStartPeriodDuration| interval, it
// is discarded. Shorter sessions distort stats due to ANR is long process that
// may take 10, 20 and more seconds. This also done to avoid false reporting
// when session gets restarted due to applying configuration, policy, and so on.
constexpr base::TimeDelta kMaxStartPeriodDuration = base::Minutes(10);
constexpr base::TimeDelta kMinStartPeriodDuration = base::Minutes(2);

// Interval to report ANR rate. ANR rate is reported each interval of ARC
// active state.
constexpr base::TimeDelta kRateInterval = base::Hours(4);

// Interval to update ANR interval. Once accumulated interval is
// greater than |kArcAnrRateInterval| UMA is updated.
constexpr base::TimeDelta kUpdateInterval = base::Minutes(5);

// It is very unlikely to do have more ANR events than
// |kForPeriodMaxCount| times in |kMaxStartPeriodDuration| or
// |kRateInterval|. This acts as an upper bound of UMA buckets.
constexpr int kForPeriodMaxCount = 64;

constexpr char kStartPeriodHistogram[] = "Arc.Anr.First10MinutesAfterStart";
constexpr char kRegularPeriodHistogram[] = "Arc.Anr.Per4Hours";

// App types to report.
constexpr char kAppTypeArcAppLauncher[] = "ArcAppLauncher";
constexpr char kAppTypeArcOther[] = "ArcOther";
constexpr char kAppTypeFirstParty[] = "FirstParty";
constexpr char kAppTypeGmsCore[] = "GmsCore";
constexpr char kAppTypePlayStore[] = "PlayStore";
constexpr char kAppTypeSystemServer[] = "SystemServer";
constexpr char kAppTypeSystem[] = "SystemApp";
constexpr char kAppTypeOther[] = "Other";

std::string SourceToTableName(mojom::AnrSource value) {
switch (value) {
case mojom::AnrSource::OTHER:
return kAppTypeOther;
case mojom::AnrSource::SYSTEM_SERVER:
return kAppTypeSystemServer;
case mojom::AnrSource::SYSTEM_APP:
return kAppTypeSystem;
case mojom::AnrSource::GMS_CORE:
return kAppTypeGmsCore;
case mojom::AnrSource::PLAY_STORE:
return kAppTypePlayStore;
case mojom::AnrSource::FIRST_PARTY:
return kAppTypeFirstParty;
case mojom::AnrSource::ARC_OTHER:
return kAppTypeArcOther;
case mojom::AnrSource::ARC_APP_LAUNCHER:
return kAppTypeArcAppLauncher;
default:
LOG(ERROR) << "Unrecognized source ANR " << value;
return kAppTypeOther;
}
}

} // namespace

ArcMetricsAnr::ArcMetricsAnr(PrefService* prefs) : prefs_(prefs) {
pending_start_timer_.Start(
FROM_HERE, kMinStartPeriodDuration,
base::BindOnce(&ArcMetricsAnr::SetLogOnStartPending,
base::Unretained(this)));
start_timer_.Start(
FROM_HERE, kMaxStartPeriodDuration,
base::BindOnce(&ArcMetricsAnr::LogOnStart, base::Unretained(this)));
period_updater_.Start(
FROM_HERE, kUpdateInterval,
base::BindRepeating(&ArcMetricsAnr::UpdateRate, base::Unretained(this)));

if (prefs_->HasPrefPath(prefs::kAnrOnStartPendingCount)) {
base::UmaHistogramExactLinear(
kStartPeriodHistogram,
prefs_->GetInteger(prefs::kAnrOnStartPendingCount), kForPeriodMaxCount);
prefs_->ClearPref(prefs::kAnrOnStartPendingCount);
}
}

ArcMetricsAnr::~ArcMetricsAnr() {
if (log_on_start_pending_) {
// Session is shorter than |kMaxStartPeriodDuration| but longer than
// |kMinStartPeriodDuration|. Save current counter and report on next
// login.
prefs_->SetInteger(prefs::kAnrOnStartPendingCount,
count_10min_after_start_);
}
}

void ArcMetricsAnr::Report(mojom::AnrPtr anr) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// TODO (b/227337741): Retire these in favor of ANR rate.
base::UmaHistogramEnumeration("Arc.Anr.Overall", anr->type);
base::UmaHistogramEnumeration("Arc.Anr." + SourceToTableName(anr->source),
anr->type);
++count_10min_after_start_;
prefs_->SetInteger(prefs::kAnrPendingCount,
prefs_->GetInteger(prefs::kAnrPendingCount) + 1);
}

void ArcMetricsAnr::LogOnStart() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::UmaHistogramExactLinear(kStartPeriodHistogram, count_10min_after_start_,
kForPeriodMaxCount);
// We already reported ANR count on start for this session.
log_on_start_pending_ = false;
}

void ArcMetricsAnr::UpdateRate() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);

base::TimeDelta duration =
prefs_->GetTimeDelta(prefs::kAnrPendingDuration) + kUpdateInterval;
if (duration >= kRateInterval) {
duration = base::TimeDelta();
base::UmaHistogramExactLinear(kRegularPeriodHistogram,
prefs_->GetInteger(prefs::kAnrPendingCount),
kForPeriodMaxCount);
prefs_->SetInteger(prefs::kAnrPendingCount, 0);
}

prefs_->SetTimeDelta(prefs::kAnrPendingDuration, duration);
}

void ArcMetricsAnr::SetLogOnStartPending() {
log_on_start_pending_ = true;
}

} // namespace arc
49 changes: 49 additions & 0 deletions ash/components/arc/metrics/arc_metrics_anr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2022 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 ASH_COMPONENTS_ARC_METRICS_ARC_METRICS_ANR_H_
#define ASH_COMPONENTS_ARC_METRICS_ARC_METRICS_ANR_H_

#include "ash/components/arc/mojom/anr.mojom.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"

class PrefService;

namespace arc {

// Handles ANR events and supports UMA metrics.
class ArcMetricsAnr {
public:
explicit ArcMetricsAnr(PrefService* prefs);

ArcMetricsAnr(const ArcMetricsAnr&) = delete;
ArcMetricsAnr& operator=(const ArcMetricsAnr&) = delete;

~ArcMetricsAnr();

void Report(mojom::AnrPtr anr);

private:
void LogOnStart();
void UpdateRate();
void SetLogOnStartPending();

// ANR count for first 10 minitues after start.
int count_10min_after_start_ = 0;
// Set to true in case |count_10min_after_start_| is pending and has to be
// persisted on restart. Once ANR count on start is reported this is set to
// false.
bool log_on_start_pending_ = false;
base::OneShotTimer start_timer_;
base::OneShotTimer pending_start_timer_;
base::RepeatingTimer period_updater_;
PrefService* const prefs_ = nullptr;

THREAD_CHECKER(thread_checker_);
};

} // namespace arc

#endif // ASH_COMPONENTS_ARC_METRICS_ARC_METRICS_ANR_H_

0 comments on commit 5f0165a

Please sign in to comment.