Home | History | Annotate | Download | only in hdmi
      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 
     17 package com.android.server.hdmi;
     18 
     19 import android.annotation.Nullable;
     20 import android.os.Build;
     21 import android.os.SystemClock;
     22 import android.util.Pair;
     23 import android.util.Slog;
     24 import android.util.Log;
     25 
     26 import 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.
     31  * <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>
     40  */
     41 final class HdmiLogger {
     42     private static final String TAG = "HDMI";
     43     // Logging duration for same error message.
     44     private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000;  // 20s
     45 
     46     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     47 
     48     private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
     49 
     50     // Key (String): log message.
     51     // Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage.
     52     // Cache for warning.
     53     private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>();
     54     // Cache for error.
     55     private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>();
     56 
     57     private HdmiLogger() {
     58     }
     59 
     60     static final void warning(String logMessage, Object... objs) {
     61         getLogger().warningInternal(toLogString(logMessage, objs));
     62     }
     63 
     64     private void warningInternal(String logMessage) {
     65         String log = updateLog(mWarningTimingCache, logMessage);
     66         if (!log.isEmpty()) {
     67             Slog.w(TAG, log);
     68         }
     69     }
     70 
     71     static final void error(String logMessage, Object... objs) {
     72         getLogger().errorInternal(toLogString(logMessage, objs));
     73     }
     74 
     75     private void errorInternal(String logMessage) {
     76         String log = updateLog(mErrorTimingCache, logMessage);
     77         if (!log.isEmpty()) {
     78             Slog.e(TAG, log);
     79         }
     80     }
     81 
     82     static final void debug(String logMessage, Object... objs) {
     83         getLogger().debugInternal(toLogString(logMessage, objs));
     84     }
     85 
     86     private void debugInternal(String logMessage) {
     87         if (DEBUG) {
     88             Slog.d(TAG, logMessage);
     89         }
     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