1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/indexed_db/indexed_db_reporting.h"
6 
7 #include <string>
8 
9 #include "base/metrics/histogram_functions.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/strcat.h"
12 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
13 #include "content/browser/indexed_db/indexed_db_leveldb_env.h"
14 #include "url/origin.h"
15 
16 namespace content {
17 namespace indexed_db {
18 
19 namespace {
20 
OriginToCustomHistogramSuffix(const url::Origin & origin)21 std::string OriginToCustomHistogramSuffix(const url::Origin& origin) {
22   if (origin.host() == "docs.google.com")
23     return ".Docs";
24   return std::string();
25 }
26 
ParseAndReportIOErrorDetails(const std::string & histogram_name,const leveldb::Status & s)27 void ParseAndReportIOErrorDetails(const std::string& histogram_name,
28                                   const leveldb::Status& s) {
29   leveldb_env::MethodID method;
30   base::File::Error error = base::File::FILE_OK;
31   leveldb_env::ErrorParsingResult result =
32       leveldb_env::ParseMethodAndError(s, &method, &error);
33   if (result == leveldb_env::NONE)
34     return;
35   base::LinearHistogram::FactoryGet(
36       base::StrCat({histogram_name, ".EnvMethod"}), 1, leveldb_env::kNumEntries,
37       leveldb_env::kNumEntries + 1,
38       base::HistogramBase::kUmaTargetedHistogramFlag)
39       ->Add(method);
40 
41   if (result == leveldb_env::METHOD_AND_BFE) {
42     DCHECK_LT(error, 0);
43     base::LinearHistogram::FactoryGet(
44         base::StrCat(
45             {histogram_name, ".BFE.", leveldb_env::MethodIDToString(method)}),
46         1, -base::File::FILE_ERROR_MAX, -base::File::FILE_ERROR_MAX + 1,
47         base::HistogramBase::kUmaTargetedHistogramFlag)
48         ->Add(-error);
49   }
50 }
51 
ParseAndReportCorruptionDetails(const std::string & histogram_name,const leveldb::Status & status)52 void ParseAndReportCorruptionDetails(const std::string& histogram_name,
53                                      const leveldb::Status& status) {
54   int error = leveldb_env::GetCorruptionCode(status);
55   DCHECK_GE(error, 0);
56   const int kNumPatterns = leveldb_env::GetNumCorruptionCodes();
57   base::LinearHistogram::FactoryGet(
58       base::StrCat({histogram_name, ".Corruption"}), 1, kNumPatterns,
59       kNumPatterns + 1, base::HistogramBase::kUmaTargetedHistogramFlag)
60       ->Add(error);
61 }
62 
63 }  // namespace
64 
ReportOpenStatus(IndexedDBBackingStoreOpenResult result,const url::Origin & origin)65 void ReportOpenStatus(IndexedDBBackingStoreOpenResult result,
66                       const url::Origin& origin) {
67   base::UmaHistogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus",
68                                 result, INDEXED_DB_BACKING_STORE_OPEN_MAX);
69   const std::string suffix = OriginToCustomHistogramSuffix(origin);
70   // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used
71   // to generate a graph. So as not to alter the meaning of that graph,
72   // continue to collect all stats there (above) but also now collect docs stats
73   // separately (below).
74   if (!suffix.empty()) {
75     base::LinearHistogram::FactoryGet(
76         base::StrCat({"WebCore.IndexedDB.BackingStore.OpenStatus", suffix}), 1,
77         INDEXED_DB_BACKING_STORE_OPEN_MAX,
78         INDEXED_DB_BACKING_STORE_OPEN_MAX + 1,
79         base::HistogramBase::kUmaTargetedHistogramFlag)
80         ->Add(result);
81   }
82 }
83 
ReportInternalError(const char * type,IndexedDBBackingStoreErrorSource location)84 void ReportInternalError(const char* type,
85                          IndexedDBBackingStoreErrorSource location) {
86   base::Histogram::FactoryGet(
87       base::StrCat({"WebCore.IndexedDB.BackingStore.", type, "Error"}), 1,
88       INTERNAL_ERROR_MAX, INTERNAL_ERROR_MAX + 1,
89       base::HistogramBase::kUmaTargetedHistogramFlag)
90       ->Add(location);
91 }
92 
ReportSchemaVersion(int version,const url::Origin & origin)93 void ReportSchemaVersion(int version, const url::Origin& origin) {
94   UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.SchemaVersion", version,
95                             kLatestKnownSchemaVersion + 1);
96   const std::string suffix = OriginToCustomHistogramSuffix(origin);
97   if (!suffix.empty()) {
98     base::LinearHistogram::FactoryGet(
99         base::StrCat({"WebCore.IndexedDB.SchemaVersion", suffix}), 0,
100         indexed_db::kLatestKnownSchemaVersion,
101         indexed_db::kLatestKnownSchemaVersion + 1,
102         base::HistogramBase::kUmaTargetedHistogramFlag)
103         ->Add(version);
104   }
105 }
106 
ReportV2Schema(bool has_broken_blobs,const url::Origin & origin)107 void ReportV2Schema(bool has_broken_blobs, const url::Origin& origin) {
108   base::UmaHistogramBoolean("WebCore.IndexedDB.SchemaV2HasBlobs",
109                             has_broken_blobs);
110   const std::string suffix = OriginToCustomHistogramSuffix(origin);
111   if (!suffix.empty()) {
112     base::BooleanHistogram::FactoryGet(
113         base::StrCat({"WebCore.IndexedDB.SchemaV2HasBlobs", suffix}),
114         base::HistogramBase::kUmaTargetedHistogramFlag)
115         ->Add(has_broken_blobs);
116   }
117 }
118 
ReportLevelDBError(const std::string & histogram_name,const leveldb::Status & s)119 void ReportLevelDBError(const std::string& histogram_name,
120                         const leveldb::Status& s) {
121   if (s.ok()) {
122     NOTREACHED();
123     return;
124   }
125   enum {
126     LEVEL_DB_NOT_FOUND,
127     LEVEL_DB_CORRUPTION,
128     LEVEL_DB_IO_ERROR,
129     LEVEL_DB_OTHER,
130     LEVEL_DB_MAX_ERROR
131   };
132   int leveldb_error = LEVEL_DB_OTHER;
133   if (s.IsNotFound())
134     leveldb_error = LEVEL_DB_NOT_FOUND;
135   else if (s.IsCorruption())
136     leveldb_error = LEVEL_DB_CORRUPTION;
137   else if (s.IsIOError())
138     leveldb_error = LEVEL_DB_IO_ERROR;
139   base::Histogram::FactoryGet(histogram_name, 1, LEVEL_DB_MAX_ERROR,
140                               LEVEL_DB_MAX_ERROR + 1,
141                               base::HistogramBase::kUmaTargetedHistogramFlag)
142       ->Add(leveldb_error);
143   if (s.IsIOError())
144     ParseAndReportIOErrorDetails(histogram_name, s);
145   else
146     ParseAndReportCorruptionDetails(histogram_name, s);
147 }
148 
149 }  // namespace indexed_db
150 }  // namespace content
151