blob: 537df815e3a2e2d0d55ae75e6595b91897c28b65 [file] [log] [blame]
Jungshik Jangdbe6b452014-08-22 13:49:55 +09001/*
2 * Copyright (C) 2014 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
17package com.android.server.hdmi;
18
Jungshik Jang339227d2014-08-25 15:37:20 +090019import android.annotation.Nullable;
Jinsuk Kim4d1189e2014-11-21 10:43:51 +090020import android.os.Build;
Jungshik Jangdbe6b452014-08-22 13:49:55 +090021import android.os.SystemClock;
22import android.util.Pair;
23import android.util.Slog;
Donghyun Cho205fa2a2016-04-01 14:53:10 +090024import android.util.Log;
Jungshik Jangdbe6b452014-08-22 13:49:55 +090025
26import java.util.HashMap;
27
28/**
29 * A logger that prevents spammy log. For the same log message, it logs once every 20seconds.
30 * This class is not thread-safe.
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090031 * <p>
32 * For convenience, use single character prefix for all messages.
33 * Here are common acronyms
34 * <ul>
35 * <li>[T]: Timout
36 * <li>[R]: Received message
37 * <li>[S]: Sent message
38 * <li>[P]: Device polling result
39 * </ul>
Jungshik Jangdbe6b452014-08-22 13:49:55 +090040 */
41final class HdmiLogger {
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090042 private static final String TAG = "HDMI";
Jungshik Jangdbe6b452014-08-22 13:49:55 +090043 // Logging duration for same error message.
44 private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000; // 20s
45
Donghyun Cho205fa2a2016-04-01 14:53:10 +090046 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Jinsuk Kim4d1189e2014-11-21 10:43:51 +090047 private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
Jungshik Jangc94ac5c2014-08-27 13:48:37 +090048
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090049 private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
50
Jungshik Jangdbe6b452014-08-22 13:49:55 +090051 // Key (String): log message.
52 // Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage.
53 // Cache for warning.
54 private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>();
55 // Cache for error.
56 private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>();
Jungshik Jangdbe6b452014-08-22 13:49:55 +090057
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090058 private HdmiLogger() {
Jungshik Jangdbe6b452014-08-22 13:49:55 +090059 }
60
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090061 static final void warning(String logMessage, Object... objs) {
62 getLogger().warningInternal(toLogString(logMessage, objs));
63 }
64
65 private void warningInternal(String logMessage) {
Jungshik Jangc94ac5c2014-08-27 13:48:37 +090066 String log = updateLog(mWarningTimingCache, logMessage);
67 if (!log.isEmpty()) {
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090068 Slog.w(TAG, log);
Jungshik Jangdbe6b452014-08-22 13:49:55 +090069 }
70 }
71
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090072 static final void error(String logMessage, Object... objs) {
73 getLogger().errorInternal(toLogString(logMessage, objs));
74 }
75
76 private void errorInternal(String logMessage) {
Jungshik Jangc94ac5c2014-08-27 13:48:37 +090077 String log = updateLog(mErrorTimingCache, logMessage);
78 if (!log.isEmpty()) {
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090079 Slog.e(TAG, log);
Jungshik Jangdbe6b452014-08-22 13:49:55 +090080 }
81 }
82
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090083 static final void debug(String logMessage, Object... objs) {
84 getLogger().debugInternal(toLogString(logMessage, objs));
85 }
86
87 private void debugInternal(String logMessage) {
Donghyun Cho205fa2a2016-04-01 14:53:10 +090088 if (DEBUG) {
89 Slog.d(TAG, logMessage);
Jungshik Jangc94ac5c2014-08-27 13:48:37 +090090 }
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090091 }
92
93 private static final String toLogString(String logMessage, Object[] objs) {
94 if (objs.length > 0) {
95 return String.format(logMessage, objs);
96 } else {
97 return logMessage;
98 }
99 }
100
101 private static HdmiLogger getLogger() {
102 HdmiLogger logger = sLogger.get();
103 if (logger == null) {
104 logger = new HdmiLogger();
105 sLogger.set(logger);
106 }
107 return logger;
Jungshik Jangdbe6b452014-08-22 13:49:55 +0900108 }
109
Jungshik Jangc94ac5c2014-08-27 13:48:37 +0900110 private static String updateLog(HashMap<String, Pair<Long, Integer>> cache, String logMessage) {
111 long curTime = SystemClock.uptimeMillis();
112 Pair<Long, Integer> timing = cache.get(logMessage);
113 if (shouldLogNow(timing, curTime)) {
114 String log = buildMessage(logMessage, timing);
115 cache.put(logMessage, new Pair<>(curTime, 1));
116 return log;
117 } else {
118 increaseLogCount(cache, logMessage);
119 }
120 return "";
121 }
122
123 private static String buildMessage(String message, @Nullable Pair<Long, Integer> timing) {
124 return new StringBuilder()
125 .append("[").append(timing == null ? 1 : timing.second).append("]:")
126 .append(message).toString();
127 }
128
129 private static void increaseLogCount(HashMap<String, Pair<Long, Integer>> cache,
130 String message) {
Jungshik Jangdbe6b452014-08-22 13:49:55 +0900131 Pair<Long, Integer> timing = cache.get(message);
132 if (timing != null) {
133 cache.put(message, new Pair<>(timing.first, timing.second + 1));
134 }
135 }
136
Jungshik Jangc94ac5c2014-08-27 13:48:37 +0900137 private static boolean shouldLogNow(@Nullable Pair<Long, Integer> timing, long curTime) {
Jungshik Jangdbe6b452014-08-22 13:49:55 +0900138 return timing == null || curTime - timing.first > ERROR_LOG_DURATTION_MILLIS;
139 }
140}