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