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