HdmiLogger.java revision 8e609fa657a9fb86779a9d70fcfa9adffc7a28ee
1/*
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
19import android.annotation.Nullable;
20import android.os.Build;
21import android.os.SystemClock;
22import android.util.Pair;
23import android.util.Slog;
24
25import java.util.HashMap;
26
27/**
28 * A logger that prevents spammy log. For the same log message, it logs once every 20seconds.
29 * This class is not thread-safe.
30 * <p>
31 * For convenience, use single character prefix for all messages.
32 * Here are common acronyms
33 * <ul>
34 *   <li>[T]: Timout
35 *   <li>[R]: Received message
36 *   <li>[S]: Sent message
37 *   <li>[P]: Device polling result
38 * </ul>
39 */
40final class HdmiLogger {
41    private static final String TAG = "HDMI";
42    // Logging duration for same error message.
43    private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000;  // 20s
44
45    private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
46
47    private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
48
49    // Key (String): log message.
50    // Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage.
51    // Cache for warning.
52    private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>();
53    // Cache for error.
54    private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>();
55
56    private HdmiLogger() {
57    }
58
59    static final void warning(String logMessage, Object... objs) {
60        getLogger().warningInternal(toLogString(logMessage, objs));
61    }
62
63    private void warningInternal(String logMessage) {
64        String log = updateLog(mWarningTimingCache, logMessage);
65        if (!log.isEmpty()) {
66            Slog.w(TAG, log);
67        }
68    }
69
70    static final void error(String logMessage, Object... objs) {
71        getLogger().errorInternal(toLogString(logMessage, objs));
72    }
73
74    private void errorInternal(String logMessage) {
75        String log = updateLog(mErrorTimingCache, logMessage);
76        if (!log.isEmpty()) {
77            Slog.e(TAG, log);
78        }
79    }
80
81    static final void debug(String logMessage, Object... objs) {
82        getLogger().debugInternal(toLogString(logMessage, objs));
83    }
84
85    private void debugInternal(String logMessage) {
86        if (true || IS_USER_BUILD) {
87            return;
88        }
89        Slog.d(TAG, logMessage);
90    }
91
92    private static final String toLogString(String logMessage, Object[] objs) {
93        if (objs.length > 0) {
94            return String.format(logMessage, objs);
95        } else {
96            return logMessage;
97        }
98    }
99
100    private static HdmiLogger getLogger() {
101        HdmiLogger logger = sLogger.get();
102        if (logger == null) {
103            logger = new HdmiLogger();
104            sLogger.set(logger);
105        }
106        return logger;
107    }
108
109    private static String updateLog(HashMap<String, Pair<Long, Integer>> cache, String logMessage) {
110        long curTime = SystemClock.uptimeMillis();
111        Pair<Long, Integer> timing = cache.get(logMessage);
112        if (shouldLogNow(timing, curTime)) {
113            String log = buildMessage(logMessage, timing);
114            cache.put(logMessage, new Pair<>(curTime, 1));
115            return log;
116        } else {
117            increaseLogCount(cache, logMessage);
118        }
119        return "";
120    }
121
122    private static String buildMessage(String message, @Nullable Pair<Long, Integer> timing) {
123        return new StringBuilder()
124                .append("[").append(timing == null ? 1 : timing.second).append("]:")
125                .append(message).toString();
126    }
127
128    private static void increaseLogCount(HashMap<String, Pair<Long, Integer>> cache,
129            String message) {
130        Pair<Long, Integer> timing = cache.get(message);
131        if (timing != null) {
132            cache.put(message, new Pair<>(timing.first, timing.second + 1));
133        }
134    }
135
136    private static boolean shouldLogNow(@Nullable Pair<Long, Integer> timing, long curTime) {
137        return timing == null || curTime - timing.first > ERROR_LOG_DURATTION_MILLIS;
138    }
139}
140