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