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 
17 package android.telecom;
18 
19 import java.security.MessageDigest;
20 import java.security.NoSuchAlgorithmException;
21 import java.util.IllegalFormatException;
22 import java.util.Locale;
23 
24 /**
25  * Manages logging for the entire module.
26  *
27  * @hide
28  */
29 final 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 
Log()41     private Log() {}
42 
isLoggable(int level)43     public static boolean isLoggable(int level) {
44         return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
45     }
46 
d(String prefix, String format, Object... args)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 
d(Object objectPrefix, String format, Object... args)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 
i(String prefix, String format, Object... args)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 
i(Object objectPrefix, String format, Object... args)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 
v(String prefix, String format, Object... args)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 
v(Object objectPrefix, String format, Object... args)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 
w(String prefix, String format, Object... args)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 
w(Object objectPrefix, String format, Object... args)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 
e(String prefix, Throwable tr, String format, Object... args)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 
e(Object objectPrefix, Throwable tr, String format, Object... args)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 
wtf(String prefix, Throwable tr, String format, Object... args)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 
wtf(Object objectPrefix, Throwable tr, String format, Object... args)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 
wtf(String prefix, String format, Object... args)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 
wtf(Object objectPrefix, String format, Object... args)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      */
pii(Object pii)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 
secureHash(byte[] input)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 
encodeHex(byte[] bytes)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 
getPrefixFromObject(Object obj)165     private static String getPrefixFromObject(Object obj) {
166         return obj == null ? "<null>" : obj.getClass().getSimpleName();
167     }
168 
buildMessage(String prefix, String format, Object... args)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