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 public class MetricsLogger {
38     // define metric categories in frameworks/base/proto/src/metrics_constants.proto.
39     // mirror changes in native version at system/core/libmetricslogger/metrics_logger.cpp
40 
41     private static MetricsLogger sMetricsLogger;
42 
43     @UnsupportedAppUsage
MetricsLogger()44     public MetricsLogger() {
45     }
46 
getLogger()47     private static MetricsLogger getLogger() {
48         if (sMetricsLogger == null) {
49             sMetricsLogger = new MetricsLogger();
50         }
51         return sMetricsLogger;
52     }
53 
saveLog(LogMaker log)54     protected void saveLog(LogMaker log) {
55         EventLogTags.writeSysuiMultiAction(log.serialize());
56     }
57 
58     public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
59     public static final int LOGTAG = EventLogTags.SYSUI_MULTI_ACTION;
60 
61     /** Write an event log record, consisting of content.serialize(). */
62     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
write(LogMaker content)63     public void write(LogMaker content) {
64         if (content.getType() == MetricsEvent.TYPE_UNKNOWN) {
65             content.setType(MetricsEvent.TYPE_ACTION);
66         }
67         saveLog(content);
68     }
69 
70     /** Add an integer value to the monotonically increasing counter with the given name. */
count(String name, int value)71     public void count(String name, int value) {
72         saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
73                 .setCounterName(name)
74                 .setCounterValue(value));
75     }
76 
77     /** Increment the bucket with the integer label on the histogram with the given name. */
histogram(String name, int bucket)78     public void histogram(String name, int bucket) {
79         // see LogHistogram in system/core/libmetricslogger/metrics_logger.cpp
80         saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
81                 .setCounterName(name)
82                 .setCounterBucket(bucket)
83                 .setCounterValue(1));
84     }
85 
86     /* Legacy logging methods follow.  These are all simple shorthands and can be replaced
87      * with an equivalent write(). */
88 
89     /** Logs an OPEN event on the category.
90      *  Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_OPEN)) */
visible(int category)91     public void visible(int category) throws IllegalArgumentException {
92         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
93             throw new IllegalArgumentException("Must define metric category");
94         }
95         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_OPEN));
96     }
97 
98     /** Logs a CLOSE event on the category.
99      *  Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_CLOSE)) */
hidden(int category)100     public void hidden(int category) throws IllegalArgumentException {
101         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
102             throw new IllegalArgumentException("Must define metric category");
103         }
104         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_CLOSE));
105     }
106 
107     /** Logs an OPEN or CLOSE event on the category, depending on visible.
108      *  Equivalent to write(new LogMaker(category)
109      *                     .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)) */
visibility(int category, boolean visible)110     public void visibility(int category, boolean visible)
111             throws IllegalArgumentException {
112         if (visible) {
113             visible(category);
114         } else {
115             hidden(category);
116         }
117     }
118 
119     /** Logs an OPEN or CLOSE event on the category, depending on vis.
120      *  Equivalent to write(new LogMaker(category)
121                            .setType(vis == View.VISIBLE ?
122                                     MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)) */
visibility(int category, int vis)123     public void visibility(int category, int vis)
124             throws IllegalArgumentException {
125         visibility(category, vis == View.VISIBLE);
126     }
127 
128     /** Logs an ACTION event on the category.
129      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)) */
action(int category)130     public void action(int category) {
131         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION));
132     }
133 
134     /** Logs an ACTION event on the category.
135      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
136                            .setSubtype(value) */
action(int category, int value)137     public void action(int category, int value) {
138         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setSubtype(value));
139     }
140 
141     /** Logs an ACTION event on the category.
142      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
143                            .setSubtype(value ? 1 : 0) */
action(int category, boolean value)144     public void action(int category, boolean value) {
145         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setSubtype(value ? 1 : 0));
146     }
147 
148     /** Logs an ACTION event on the category.
149      * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
150                            .setPackageName(value ? 1 : 0) */
action(int category, String pkg)151     public void action(int category, String pkg) {
152         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
153             throw new IllegalArgumentException("Must define metric category");
154         }
155         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setPackageName(pkg));
156     }
157 
158     /** @deprecated because untestable; use {@link #visible(int)} */
159     @Deprecated
visible(Context context, int category)160     public static void visible(Context context, int category) throws IllegalArgumentException {
161         getLogger().visible(category);
162     }
163 
164     /** @deprecated because untestable; use {@link #hidden(int)} */
165     @Deprecated
hidden(Context context, int category)166     public static void hidden(Context context, int category) throws IllegalArgumentException {
167         getLogger().hidden(category);
168     }
169 
170     /** @deprecated because untestable; use {@link #visibility(int, boolean)} */
171     @Deprecated
visibility(Context context, int category, boolean visibile)172     public static void visibility(Context context, int category, boolean visibile)
173             throws IllegalArgumentException {
174         getLogger().visibility(category, visibile);
175     }
176 
177     /** @deprecated because untestable; use {@link #visibility(int, int)} */
178     @Deprecated
visibility(Context context, int category, int vis)179     public static void visibility(Context context, int category, int vis)
180             throws IllegalArgumentException {
181         visibility(context, category, vis == View.VISIBLE);
182     }
183 
184     /** @deprecated because untestable; use {@link #action(int)} */
185     @Deprecated
action(Context context, int category)186     public static void action(Context context, int category) {
187         getLogger().action(category);
188     }
189 
190     /** @deprecated because untestable; use {@link #action(int, int)} */
191     @Deprecated
action(Context context, int category, int value)192     public static void action(Context context, int category, int value) {
193         getLogger().action(category, value);
194     }
195 
196     /** @deprecated because untestable; use {@link #action(int, boolean)} */
197     @Deprecated
action(Context context, int category, boolean value)198     public static void action(Context context, int category, boolean value) {
199         getLogger().action(category, value);
200     }
201 
202     /** @deprecated because untestable; use {@link #write(LogMaker)} */
203     @Deprecated
action(LogMaker content)204     public static void action(LogMaker content) {
205         getLogger().write(content);
206     }
207 
208     /** @deprecated because untestable; use {@link #action(int, String)} */
209     @Deprecated
action(Context context, int category, String pkg)210     public static void action(Context context, int category, String pkg) {
211         getLogger().action(category, pkg);
212     }
213 
214     /**
215      * Add an integer value to the monotonically increasing counter with the given name.
216      * @deprecated because untestable; use {@link #count(String, int)}
217      */
218     @Deprecated
count(Context context, String name, int value)219     public static void count(Context context, String name, int value) {
220         getLogger().count(name, value);
221     }
222 
223     /**
224      * Increment the bucket with the integer label on the histogram with the given name.
225      * @deprecated use {@link #histogram(String, int)}
226      */
227     @Deprecated
histogram(Context context, String name, int bucket)228     public static void histogram(Context context, String name, int bucket) {
229         getLogger().histogram(name, bucket);
230     }
231 }
232