Home | History | Annotate | Download | only in telecom
      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 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