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