1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef METRICS_METRICS_LIBRARY_H_
18 #define METRICS_METRICS_LIBRARY_H_
19 
20 #include <sys/types.h>
21 #include <string>
22 #include <unistd.h>
23 
24 #include <base/compiler_specific.h>
25 #include <base/files/file_path.h>
26 #include <base/macros.h>
27 #include <binder/IServiceManager.h>
28 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
29 
30 namespace android {
31 namespace brillo {
32 namespace metrics {
33 class IMetricsd;
34 }  // namespace metrics
35 }  // namespace brillo
36 }  // namespace android
37 
38 class MetricsLibraryInterface {
39  public:
40   virtual void Init() = 0;
41   virtual bool AreMetricsEnabled() = 0;
42   virtual bool SendToUMA(const std::string& name, int sample,
43                          int min, int max, int nbuckets) = 0;
44   virtual bool SendEnumToUMA(const std::string& name, int sample, int max) = 0;
45   virtual bool SendBoolToUMA(const std::string& name, bool sample) = 0;
46   virtual bool SendSparseToUMA(const std::string& name, int sample) = 0;
~MetricsLibraryInterface()47   virtual ~MetricsLibraryInterface() {}
48 };
49 
50 // Library used to send metrics to Chrome/UMA.
51 class MetricsLibrary : public MetricsLibraryInterface {
52  public:
53   MetricsLibrary();
54   virtual ~MetricsLibrary();
55 
56   // Initializes the library.
57   void Init() override;
58 
59   // Initializes the library and disables the cache of whether or not the
60   // metrics collection is enabled.
61   // By disabling this, we may have to check for the metrics status more often
62   // but the result will never be stale.
63   void InitWithNoCaching();
64 
65   // Returns whether or not the machine is running in guest mode.
66   bool IsGuestMode();
67 
68   // Returns whether or not metrics collection is enabled.
69   bool AreMetricsEnabled() override;
70 
71   // Sends histogram data to Chrome for transport to UMA and returns
72   // true on success. This method results in the equivalent of an
73   // asynchronous non-blocking RPC to UMA_HISTOGRAM_CUSTOM_COUNTS
74   // inside Chrome (see base/histogram.h).
75   //
76   // |sample| is the sample value to be recorded (|min| <= |sample| < |max|).
77   // |min| is the minimum value of the histogram samples (|min| > 0).
78   // |max| is the maximum value of the histogram samples.
79   // |nbuckets| is the number of histogram buckets.
80   // [0,min) is the implicit underflow bucket.
81   // [|max|,infinity) is the implicit overflow bucket.
82   //
83   // Note that the memory allocated in Chrome for each histogram is
84   // proportional to the number of buckets. Therefore, it is strongly
85   // recommended to keep this number low (e.g., 50 is normal, while
86   // 100 is high).
87   bool SendToUMA(const std::string& name, int sample,
88                  int min, int max, int nbuckets) override;
89 
90   // Sends linear histogram data to Chrome for transport to UMA and
91   // returns true on success. This method results in the equivalent of
92   // an asynchronous non-blocking RPC to UMA_HISTOGRAM_ENUMERATION
93   // inside Chrome (see base/histogram.h).
94   //
95   // |sample| is the sample value to be recorded (1 <= |sample| < |max|).
96   // |max| is the maximum value of the histogram samples.
97   // 0 is the implicit underflow bucket.
98   // [|max|,infinity) is the implicit overflow bucket.
99   //
100   // An enumeration histogram requires |max| + 1 number of
101   // buckets. Note that the memory allocated in Chrome for each
102   // histogram is proportional to the number of buckets. Therefore, it
103   // is strongly recommended to keep this number low (e.g., 50 is
104   // normal, while 100 is high).
105   bool SendEnumToUMA(const std::string& name, int sample, int max) override;
106 
107   // Specialization of SendEnumToUMA for boolean values.
108   bool SendBoolToUMA(const std::string& name, bool sample) override;
109 
110   // Sends sparse histogram sample to Chrome for transport to UMA.  Returns
111   // true on success.
112   //
113   // |sample| is the 32-bit integer value to be recorded.
114   bool SendSparseToUMA(const std::string& name, int sample) override;
115 
116   // Sends a signal to UMA that a crash of the given |crash_kind|
117   // has occurred.  Used by UMA to generate stability statistics.
118   bool SendCrashToUMA(const char *crash_kind);
119 
120   // Sends a "generic Chrome OS event" to UMA.  This is an event name
121   // that is translated into an enumerated histogram entry.  Event names
122   // are added to metrics_library.cc.  Optionally, they can be added
123   // to histograms.xml---but part of the reason for this is to simplify
124   // the addition of events (at the cost of having to look them up by
125   // number in the histograms dashboard).
126   bool SendCrosEventToUMA(const std::string& event);
127 
128   // Debugging only.
129   // Dumps the histograms aggregated since metricsd started into |dump|.
130   // Returns true iff the dump succeeds.
131   bool GetHistogramsDump(std::string* dump);
132 
133  private:
134   friend class CMetricsLibraryTest;
135   friend class MetricsLibraryTest;
136   friend class UploadServiceTest;
137   FRIEND_TEST(MetricsLibraryTest, AreMetricsEnabled);
138   FRIEND_TEST(MetricsLibraryTest, AreMetricsEnabledNoCaching);
139   FRIEND_TEST(MetricsLibraryTest, FormatChromeMessage);
140   FRIEND_TEST(MetricsLibraryTest, FormatChromeMessageTooLong);
141   FRIEND_TEST(MetricsLibraryTest, IsDeviceMounted);
142   FRIEND_TEST(MetricsLibraryTest, SendMessageToChrome);
143   FRIEND_TEST(MetricsLibraryTest, SendMessageToChromeUMAEventsBadFileLocation);
144 
145   void InitForTest(const base::FilePath& metrics_directory);
146 
147   // Sets |*result| to whether or not the |mounts_file| indicates that
148   // the |device_name| is currently mounted.  Uses |buffer| of
149   // |buffer_size| to read the file.  Returns false if any error.
150   bool IsDeviceMounted(const char* device_name,
151                        const char* mounts_file,
152                        char* buffer, int buffer_size,
153                        bool* result);
154 
155   // Connects to IMetricsd if the proxy does not exist or is not alive.
156   // Don't block if we fail to get the proxy for any reason.
157   bool CheckService();
158 
159   // Time at which we last checked if metrics were enabled.
160   time_t cached_enabled_time_;
161 
162   // Cached state of whether or not metrics were enabled.
163   bool cached_enabled_;
164 
165   // True iff we should cache the enabled/disabled status.
166   bool use_caching_;
167 
168   android::sp<android::IServiceManager> manager_;
169   android::sp<android::brillo::metrics::IMetricsd> metricsd_proxy_;
170   base::FilePath consent_file_;
171 
172   DISALLOW_COPY_AND_ASSIGN(MetricsLibrary);
173 };
174 
175 #endif  // METRICS_METRICS_LIBRARY_H_
176