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