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