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 package com.android.internal.logging;
17 
18 import android.compat.annotation.UnsupportedAppUsage;
19 import android.content.Context;
20 import android.metrics.LogMaker;
21 import android.os.Build;
22 import android.util.StatsLog;
23 import android.view.View;
24 
25 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
26 
27 /**
28  * Writes sysui_multi_event records to the system event log.
29  *
30  * Prefer the methods write(LogMaker), or count() or histogram(). Replace legacy methods with
31  * their current equivalents when the opportunity arises.
32  *
33  * This class is a lightweight dependency barrier - it is cheap and easy to construct.
34  * Logging is also cheap, so it is not normally necessary to move logging off of the UI thread.
35  *
36  * @hide
37  */
38 public class MetricsLogger {
39     // define metric categories in frameworks/base/proto/src/metrics_constants.proto.
40     // mirror changes in native version at system/core/libmetricslogger/metrics_logger.cpp
41 
42     private static MetricsLogger sMetricsLogger;
43 
44     @UnsupportedAppUsage
MetricsLogger()45     public MetricsLogger() {
46     }
47 
getLogger()48     private static MetricsLogger getLogger() {
49         if (sMetricsLogger == null) {
50             sMetricsLogger = new MetricsLogger();
51         }
52         return sMetricsLogger;
53     }
54 
saveLog(LogMaker log)55     protected void saveLog(LogMaker log) {
56         // TODO(b/116684537): Flag guard logging to event log and statsd socket.
57         EventLogTags.writeSysuiMultiAction(log.serialize());
58         StatsLog.write(StatsLog.KEY_VALUE_PAIRS_ATOM, /* UID is retrieved from statsd side */ 0,
59                 log.getEntries());
60     }
61 
62     public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
63     public static final int LOGTAG = EventLogTags.SYSUI_MULTI_ACTION;
64 
65     /** Write an event log record, consisting of content.serialize(). */
66     @UnsupportedAppUsage
write(LogMaker content)67     public void write(LogMaker content) {
68         if (content.getType() == MetricsEvent.TYPE_UNKNOWN) {
69             content.setType(MetricsEvent.TYPE_ACTION);
70         }
71         saveLog(content);
72     }
73 
74     /** Add an integer value to the monotonically increasing counter with the given name. */
count(String name, int value)75     public void count(String name, int value) {
76         saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
77                 .setCounterName(name)
78                 .setCounterValue(value));
79     }
80 
81     /** Increment the bucket with the integer label on the histogram with the given name. */
histogram(String name, int bucket)82     public void histogram(String name, int bucket) {
83         // see LogHistogram in system/core/libmetricslogger/metrics_logger.cpp
84         saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
85                 .setCounterName(name)
86                 .setCounterBucket(bucket)
87                 .setCounterValue(1));
88     }
89 
90     /* Legacy logging methods follow.  These are all simple shorthands and can be replaced
91      * with an equivalent write(). */
92 
93     /** Logs an OPEN event on the category.
94      *  Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_OPEN)) */
visible(int category)95     public void visible(int category) throws IllegalArgumentException {
96         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
97             throw new IllegalArgumentException("Must define metric category");
98         }
99         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_OPEN));
100     }
101 
102     /** Logs a CLOSE event on the category.
103      *  Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_CLOSE)) */
hidden(int category)104     public void hidden(int category) throws IllegalArgumentException {
105         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
106             throw new IllegalArgumentException("Must define metric category");
107         }
108         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_CLOSE));
109     }
110 
111     /** Logs an OPEN or CLOSE event on the category, depending on visible.
112      *  Equivalent to write(new LogMaker(category)
113      *                     .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)) */
visibility(int category, boolean visible)114     public void visibility(int category, boolean visible)
115             throws IllegalArgumentException {
116         if (visible) {
117             visible(category);
118         } else {
119             hidden(category);
120         }
121     }
122 
123     /** Logs an OPEN or CLOSE event on the category, depending on vis.
124      *  Equivalent to write(new LogMaker(category)
125                            .setType(vis == View.VISIBLE ?
126                                     MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)) */
visibility(int category, int vis)127     public void visibility(int category, int vis)
128             throws IllegalArgumentException {
129         visibility(category, vis == View.VISIBLE);
130     }
131 
132     /** Logs an ACTION event on the category.
133      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)) */
action(int category)134     public void action(int category) {
135         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION));
136     }
137 
138     /** Logs an ACTION event on the category.
139      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
140                            .setSubtype(value) */
action(int category, int value)141     public void action(int category, int value) {
142         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setSubtype(value));
143     }
144 
145     /** Logs an ACTION event on the category.
146      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
147                            .setSubtype(value ? 1 : 0) */
action(int category, boolean value)148     public void action(int category, boolean value) {
149         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setSubtype(value ? 1 : 0));
150     }
151 
152     /** Logs an ACTION event on the category.
153      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
154                            .setPackageName(value ? 1 : 0) */
action(int category, String pkg)155     public void action(int category, String pkg) {
156         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
157             throw new IllegalArgumentException("Must define metric category");
158         }
159         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setPackageName(pkg));
160     }
161 
162     /** @deprecated because untestable; use {@link #visible(int)} */
163     @Deprecated
visible(Context context, int category)164     public static void visible(Context context, int category) throws IllegalArgumentException {
165         getLogger().visible(category);
166     }
167 
168     /** @deprecated because untestable; use {@link #hidden(int)} */
169     @Deprecated
hidden(Context context, int category)170     public static void hidden(Context context, int category) throws IllegalArgumentException {
171         getLogger().hidden(category);
172     }
173 
174     /** @deprecated because untestable; use {@link #visibility(int, boolean)} */
175     @Deprecated
visibility(Context context, int category, boolean visibile)176     public static void visibility(Context context, int category, boolean visibile)
177             throws IllegalArgumentException {
178         getLogger().visibility(category, visibile);
179     }
180 
181     /** @deprecated because untestable; use {@link #visibility(int, int)} */
182     @Deprecated
visibility(Context context, int category, int vis)183     public static void visibility(Context context, int category, int vis)
184             throws IllegalArgumentException {
185         visibility(context, category, vis == View.VISIBLE);
186     }
187 
188     /** @deprecated because untestable; use {@link #action(int)} */
189     @Deprecated
action(Context context, int category)190     public static void action(Context context, int category) {
191         getLogger().action(category);
192     }
193 
194     /** @deprecated because untestable; use {@link #action(int, int)} */
195     @Deprecated
action(Context context, int category, int value)196     public static void action(Context context, int category, int value) {
197         getLogger().action(category, value);
198     }
199 
200     /** @deprecated because untestable; use {@link #action(int, boolean)} */
201     @Deprecated
action(Context context, int category, boolean value)202     public static void action(Context context, int category, boolean value) {
203         getLogger().action(category, value);
204     }
205 
206     /** @deprecated because untestable; use {@link #write(LogMaker)} */
207     @Deprecated
action(LogMaker content)208     public static void action(LogMaker content) {
209         getLogger().write(content);
210     }
211 
212     /** @deprecated because untestable; use {@link #action(int, String)} */
213     @Deprecated
action(Context context, int category, String pkg)214     public static void action(Context context, int category, String pkg) {
215         getLogger().action(category, pkg);
216     }
217 
218     /**
219      * Add an integer value to the monotonically increasing counter with the given name.
220      * @deprecated because untestable; use {@link #count(String, int)}
221      */
222     @Deprecated
count(Context context, String name, int value)223     public static void count(Context context, String name, int value) {
224         getLogger().count(name, value);
225     }
226 
227     /**
228      * Increment the bucket with the integer label on the histogram with the given name.
229      * @deprecated use {@link #histogram(String, int)}
230      */
231     @Deprecated
histogram(Context context, String name, int bucket)232     public static void histogram(Context context, String name, int bucket) {
233         getLogger().histogram(name, bucket);
234     }
235 }
236