1/*
2 * Copyright 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 android.telecom;
18
19import java.security.MessageDigest;
20import java.security.NoSuchAlgorithmException;
21import java.util.IllegalFormatException;
22import java.util.Locale;
23
24/**
25 * Manages logging for the entire module.
26 *
27 * @hide
28 */
29final public class Log {
30
31    // Generic tag for all Telecom Framework logging
32    private static final String TAG = "TelecomFramework";
33
34    public static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
35    public static final boolean DEBUG = isLoggable(android.util.Log.DEBUG);
36    public static final boolean INFO = isLoggable(android.util.Log.INFO);
37    public static final boolean VERBOSE = isLoggable(android.util.Log.VERBOSE);
38    public static final boolean WARN = isLoggable(android.util.Log.WARN);
39    public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
40
41    private Log() {}
42
43    public static boolean isLoggable(int level) {
44        return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
45    }
46
47    public static void d(String prefix, String format, Object... args) {
48        if (DEBUG) {
49            android.util.Log.d(TAG, buildMessage(prefix, format, args));
50        }
51    }
52
53    public static void d(Object objectPrefix, String format, Object... args) {
54        if (DEBUG) {
55            android.util.Log.d(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
56        }
57    }
58
59    public static void i(String prefix, String format, Object... args) {
60        if (INFO) {
61            android.util.Log.i(TAG, buildMessage(prefix, format, args));
62        }
63    }
64
65    public static void i(Object objectPrefix, String format, Object... args) {
66        if (INFO) {
67            android.util.Log.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
68        }
69    }
70
71    public static void v(String prefix, String format, Object... args) {
72        if (VERBOSE) {
73            android.util.Log.v(TAG, buildMessage(prefix, format, args));
74        }
75    }
76
77    public static void v(Object objectPrefix, String format, Object... args) {
78        if (VERBOSE) {
79            android.util.Log.v(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
80        }
81    }
82
83    public static void w(String prefix, String format, Object... args) {
84        if (WARN) {
85            android.util.Log.w(TAG, buildMessage(prefix, format, args));
86        }
87    }
88
89    public static void w(Object objectPrefix, String format, Object... args) {
90        if (WARN) {
91            android.util.Log.w(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
92        }
93    }
94
95    public static void e(String prefix, Throwable tr, String format, Object... args) {
96        if (ERROR) {
97            android.util.Log.e(TAG, buildMessage(prefix, format, args), tr);
98        }
99    }
100
101    public static void e(Object objectPrefix, Throwable tr, String format, Object... args) {
102        if (ERROR) {
103            android.util.Log.e(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
104                    tr);
105        }
106    }
107
108    public static void wtf(String prefix, Throwable tr, String format, Object... args) {
109        android.util.Log.wtf(TAG, buildMessage(prefix, format, args), tr);
110    }
111
112    public static void wtf(Object objectPrefix, Throwable tr, String format, Object... args) {
113        android.util.Log.wtf(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
114                tr);
115    }
116
117    public static void wtf(String prefix, String format, Object... args) {
118        String msg = buildMessage(prefix, format, args);
119        android.util.Log.wtf(TAG, msg, new IllegalStateException(msg));
120    }
121
122    public static void wtf(Object objectPrefix, String format, Object... args) {
123        String msg = buildMessage(getPrefixFromObject(objectPrefix), format, args);
124        android.util.Log.wtf(TAG, msg, new IllegalStateException(msg));
125    }
126
127    /**
128     * Redact personally identifiable information for production users.
129     * If we are running in verbose mode, return the original string, otherwise
130     * return a SHA-1 hash of the input string.
131     */
132    public static String pii(Object pii) {
133        if (pii == null || VERBOSE) {
134            return String.valueOf(pii);
135        }
136        return "[" + secureHash(String.valueOf(pii).getBytes()) + "]";
137    }
138
139    private static String secureHash(byte[] input) {
140        MessageDigest messageDigest;
141        try {
142            messageDigest = MessageDigest.getInstance("SHA-1");
143        } catch (NoSuchAlgorithmException e) {
144            return null;
145        }
146        messageDigest.update(input);
147        byte[] result = messageDigest.digest();
148        return encodeHex(result);
149    }
150
151    private static String encodeHex(byte[] bytes) {
152        StringBuffer hex = new StringBuffer(bytes.length * 2);
153
154        for (int i = 0; i < bytes.length; i++) {
155            int byteIntValue = bytes[i] & 0xff;
156            if (byteIntValue < 0x10) {
157                hex.append("0");
158            }
159            hex.append(Integer.toString(byteIntValue, 16));
160        }
161
162        return hex.toString();
163    }
164
165    private static String getPrefixFromObject(Object obj) {
166        return obj == null ? "<null>" : obj.getClass().getSimpleName();
167    }
168
169    private static String buildMessage(String prefix, String format, Object... args) {
170        String msg;
171        try {
172            msg = (args == null || args.length == 0) ? format
173                    : String.format(Locale.US, format, args);
174        } catch (IllegalFormatException ife) {
175            wtf("Log", ife, "IllegalFormatException: formatString='%s' numArgs=%d", format,
176                    args.length);
177            msg = format + " (An error occurred while formatting the message.)";
178        }
179        return String.format(Locale.US, "%s: %s", prefix, msg);
180    }
181}
182