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