Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2006 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 android.util;
     18 
     19 import android.annotation.IntDef;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.annotation.UnsupportedAppUsage;
     23 import android.os.DeadSystemException;
     24 
     25 import com.android.internal.os.RuntimeInit;
     26 import com.android.internal.util.FastPrintWriter;
     27 import com.android.internal.util.LineBreakBufferedWriter;
     28 
     29 import java.io.PrintWriter;
     30 import java.io.StringWriter;
     31 import java.io.Writer;
     32 import java.lang.annotation.Retention;
     33 import java.lang.annotation.RetentionPolicy;
     34 import java.net.UnknownHostException;
     35 
     36 /**
     37  * API for sending log output.
     38  *
     39  * <p>Generally, you should use the {@link #v Log.v()}, {@link #d Log.d()},
     40  * {@link #i Log.i()}, {@link #w Log.w()}, and {@link #e Log.e()} methods to write logs.
     41  * You can then <a href="{@docRoot}studio/debug/am-logcat.html">view the logs in logcat</a>.
     42  *
     43  * <p>The order in terms of verbosity, from least to most is
     44  * ERROR, WARN, INFO, DEBUG, VERBOSE.  Verbose should never be compiled
     45  * into an application except during development.  Debug logs are compiled
     46  * in but stripped at runtime.  Error, warning and info logs are always kept.
     47  *
     48  * <p><b>Tip:</b> A good convention is to declare a <code>TAG</code> constant
     49  * in your class:
     50  *
     51  * <pre>private static final String TAG = "MyActivity";</pre>
     52  *
     53  * and use that in subsequent calls to the log methods.
     54  * </p>
     55  *
     56  * <p><b>Tip:</b> Don't forget that when you make a call like
     57  * <pre>Log.v(TAG, "index=" + i);</pre>
     58  * that when you're building the string to pass into Log.d, the compiler uses a
     59  * StringBuilder and at least three allocations occur: the StringBuilder
     60  * itself, the buffer, and the String object.  Realistically, there is also
     61  * another buffer allocation and copy, and even more pressure on the gc.
     62  * That means that if your log message is filtered out, you might be doing
     63  * significant work and incurring significant overhead.
     64  */
     65 public final class Log {
     66     /** @hide */
     67     @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE})
     68     @Retention(RetentionPolicy.SOURCE)
     69     public @interface Level {}
     70 
     71     /**
     72      * Priority constant for the println method; use Log.v.
     73      */
     74     public static final int VERBOSE = 2;
     75 
     76     /**
     77      * Priority constant for the println method; use Log.d.
     78      */
     79     public static final int DEBUG = 3;
     80 
     81     /**
     82      * Priority constant for the println method; use Log.i.
     83      */
     84     public static final int INFO = 4;
     85 
     86     /**
     87      * Priority constant for the println method; use Log.w.
     88      */
     89     public static final int WARN = 5;
     90 
     91     /**
     92      * Priority constant for the println method; use Log.e.
     93      */
     94     public static final int ERROR = 6;
     95 
     96     /**
     97      * Priority constant for the println method.
     98      */
     99     public static final int ASSERT = 7;
    100 
    101     /**
    102      * Exception class used to capture a stack trace in {@link #wtf}.
    103      * @hide
    104      */
    105     public static class TerribleFailure extends Exception {
    106         TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
    107     }
    108 
    109     /**
    110      * Interface to handle terrible failures from {@link #wtf}.
    111      *
    112      * @hide
    113      */
    114     public interface TerribleFailureHandler {
    115         void onTerribleFailure(String tag, TerribleFailure what, boolean system);
    116     }
    117 
    118     private static TerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {
    119             public void onTerribleFailure(String tag, TerribleFailure what, boolean system) {
    120                 RuntimeInit.wtf(tag, what, system);
    121             }
    122         };
    123 
    124     private Log() {
    125     }
    126 
    127     /**
    128      * Send a {@link #VERBOSE} log message.
    129      * @param tag Used to identify the source of a log message.  It usually identifies
    130      *        the class or activity where the log call occurs.
    131      * @param msg The message you would like logged.
    132      */
    133     public static int v(@Nullable String tag, @NonNull String msg) {
    134         return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
    135     }
    136 
    137     /**
    138      * Send a {@link #VERBOSE} log message and log the exception.
    139      * @param tag Used to identify the source of a log message.  It usually identifies
    140      *        the class or activity where the log call occurs.
    141      * @param msg The message you would like logged.
    142      * @param tr An exception to log
    143      */
    144     public static int v(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
    145         return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr);
    146     }
    147 
    148     /**
    149      * Send a {@link #DEBUG} log message.
    150      * @param tag Used to identify the source of a log message.  It usually identifies
    151      *        the class or activity where the log call occurs.
    152      * @param msg The message you would like logged.
    153      */
    154     public static int d(@Nullable String tag, @NonNull String msg) {
    155         return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
    156     }
    157 
    158     /**
    159      * Send a {@link #DEBUG} log message and log the exception.
    160      * @param tag Used to identify the source of a log message.  It usually identifies
    161      *        the class or activity where the log call occurs.
    162      * @param msg The message you would like logged.
    163      * @param tr An exception to log
    164      */
    165     public static int d(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
    166         return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr);
    167     }
    168 
    169     /**
    170      * Send an {@link #INFO} log message.
    171      * @param tag Used to identify the source of a log message.  It usually identifies
    172      *        the class or activity where the log call occurs.
    173      * @param msg The message you would like logged.
    174      */
    175     public static int i(@Nullable String tag, @NonNull String msg) {
    176         return println_native(LOG_ID_MAIN, INFO, tag, msg);
    177     }
    178 
    179     /**
    180      * Send a {@link #INFO} log message and log the exception.
    181      * @param tag Used to identify the source of a log message.  It usually identifies
    182      *        the class or activity where the log call occurs.
    183      * @param msg The message you would like logged.
    184      * @param tr An exception to log
    185      */
    186     public static int i(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
    187         return printlns(LOG_ID_MAIN, INFO, tag, msg, tr);
    188     }
    189 
    190     /**
    191      * Send a {@link #WARN} log message.
    192      * @param tag Used to identify the source of a log message.  It usually identifies
    193      *        the class or activity where the log call occurs.
    194      * @param msg The message you would like logged.
    195      */
    196     public static int w(@Nullable String tag, @NonNull String msg) {
    197         return println_native(LOG_ID_MAIN, WARN, tag, msg);
    198     }
    199 
    200     /**
    201      * Send a {@link #WARN} log message and log the exception.
    202      * @param tag Used to identify the source of a log message.  It usually identifies
    203      *        the class or activity where the log call occurs.
    204      * @param msg The message you would like logged.
    205      * @param tr An exception to log
    206      */
    207     public static int w(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
    208         return printlns(LOG_ID_MAIN, WARN, tag, msg, tr);
    209     }
    210 
    211     /**
    212      * Checks to see whether or not a log for the specified tag is loggable at the specified level.
    213      *
    214      *  The default level of any tag is set to INFO. This means that any level above and including
    215      *  INFO will be logged. Before you make any calls to a logging method you should check to see
    216      *  if your tag should be logged. You can change the default level by setting a system property:
    217      *      'setprop log.tag.&lt;YOUR_LOG_TAG> &lt;LEVEL>'
    218      *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, or ASSERT.
    219      *  You can also create a local.prop file that with the following in it:
    220      *      'log.tag.&lt;YOUR_LOG_TAG>=&lt;LEVEL>'
    221      *  and place that in /data/local.prop.
    222      *
    223      * @param tag The tag to check.
    224      * @param level The level to check.
    225      * @return Whether or not that this is allowed to be logged.
    226      * @throws IllegalArgumentException is thrown if the tag.length() > 23
    227      *         for Nougat (7.0) releases (API <= 23) and prior, there is no
    228      *         tag limit of concern after this API level.
    229      */
    230     public static native boolean isLoggable(@Nullable String tag, @Level int level);
    231 
    232     /**
    233      * Send a {@link #WARN} log message and log the exception.
    234      * @param tag Used to identify the source of a log message.  It usually identifies
    235      *        the class or activity where the log call occurs.
    236      * @param tr An exception to log
    237      */
    238     public static int w(@Nullable String tag, @Nullable Throwable tr) {
    239         return printlns(LOG_ID_MAIN, WARN, tag, "", tr);
    240     }
    241 
    242     /**
    243      * Send an {@link #ERROR} log message.
    244      * @param tag Used to identify the source of a log message.  It usually identifies
    245      *        the class or activity where the log call occurs.
    246      * @param msg The message you would like logged.
    247      */
    248     public static int e(@Nullable String tag, @NonNull String msg) {
    249         return println_native(LOG_ID_MAIN, ERROR, tag, msg);
    250     }
    251 
    252     /**
    253      * Send a {@link #ERROR} log message and log the exception.
    254      * @param tag Used to identify the source of a log message.  It usually identifies
    255      *        the class or activity where the log call occurs.
    256      * @param msg The message you would like logged.
    257      * @param tr An exception to log
    258      */
    259     public static int e(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
    260         return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr);
    261     }
    262 
    263     /**
    264      * What a Terrible Failure: Report a condition that should never happen.
    265      * The error will always be logged at level ASSERT with the call stack.
    266      * Depending on system configuration, a report may be added to the
    267      * {@link android.os.DropBoxManager} and/or the process may be terminated
    268      * immediately with an error dialog.
    269      * @param tag Used to identify the source of a log message.
    270      * @param msg The message you would like logged.
    271      */
    272     public static int wtf(@Nullable String tag, @Nullable String msg) {
    273         return wtf(LOG_ID_MAIN, tag, msg, null, false, false);
    274     }
    275 
    276     /**
    277      * Like {@link #wtf(String, String)}, but also writes to the log the full
    278      * call stack.
    279      * @hide
    280      */
    281     public static int wtfStack(@Nullable String tag, @Nullable String msg) {
    282         return wtf(LOG_ID_MAIN, tag, msg, null, true, false);
    283     }
    284 
    285     /**
    286      * What a Terrible Failure: Report an exception that should never happen.
    287      * Similar to {@link #wtf(String, String)}, with an exception to log.
    288      * @param tag Used to identify the source of a log message.
    289      * @param tr An exception to log.
    290      */
    291     public static int wtf(@Nullable String tag, @NonNull Throwable tr) {
    292         return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false, false);
    293     }
    294 
    295     /**
    296      * What a Terrible Failure: Report an exception that should never happen.
    297      * Similar to {@link #wtf(String, Throwable)}, with a message as well.
    298      * @param tag Used to identify the source of a log message.
    299      * @param msg The message you would like logged.
    300      * @param tr An exception to log.  May be null.
    301      */
    302     public static int wtf(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) {
    303         return wtf(LOG_ID_MAIN, tag, msg, tr, false, false);
    304     }
    305 
    306     @UnsupportedAppUsage
    307     static int wtf(int logId, @Nullable String tag, @Nullable String msg, @Nullable Throwable tr,
    308             boolean localStack, boolean system) {
    309         TerribleFailure what = new TerribleFailure(msg, tr);
    310         // Only mark this as ERROR, do not use ASSERT since that should be
    311         // reserved for cases where the system is guaranteed to abort.
    312         // The onTerribleFailure call does not always cause a crash.
    313         int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr);
    314         sWtfHandler.onTerribleFailure(tag, what, system);
    315         return bytes;
    316     }
    317 
    318     static void wtfQuiet(int logId, @Nullable String tag, @Nullable String msg, boolean system) {
    319         TerribleFailure what = new TerribleFailure(msg, null);
    320         sWtfHandler.onTerribleFailure(tag, what, system);
    321     }
    322 
    323     /**
    324      * Sets the terrible failure handler, for testing.
    325      *
    326      * @return the old handler
    327      *
    328      * @hide
    329      */
    330     @NonNull
    331     public static TerribleFailureHandler setWtfHandler(@NonNull TerribleFailureHandler handler) {
    332         if (handler == null) {
    333             throw new NullPointerException("handler == null");
    334         }
    335         TerribleFailureHandler oldHandler = sWtfHandler;
    336         sWtfHandler = handler;
    337         return oldHandler;
    338     }
    339 
    340     /**
    341      * Handy function to get a loggable stack trace from a Throwable
    342      * @param tr An exception to log
    343      */
    344     @NonNull
    345     public static String getStackTraceString(@Nullable Throwable tr) {
    346         if (tr == null) {
    347             return "";
    348         }
    349 
    350         // This is to reduce the amount of log spew that apps do in the non-error
    351         // condition of the network being unavailable.
    352         Throwable t = tr;
    353         while (t != null) {
    354             if (t instanceof UnknownHostException) {
    355                 return "";
    356             }
    357             t = t.getCause();
    358         }
    359 
    360         StringWriter sw = new StringWriter();
    361         PrintWriter pw = new FastPrintWriter(sw, false, 256);
    362         tr.printStackTrace(pw);
    363         pw.flush();
    364         return sw.toString();
    365     }
    366 
    367     /**
    368      * Low-level logging call.
    369      * @param priority The priority/type of this log message
    370      * @param tag Used to identify the source of a log message.  It usually identifies
    371      *        the class or activity where the log call occurs.
    372      * @param msg The message you would like logged.
    373      * @return The number of bytes written.
    374      */
    375     public static int println(@Level int priority, @Nullable String tag, @NonNull String msg) {
    376         return println_native(LOG_ID_MAIN, priority, tag, msg);
    377     }
    378 
    379     /** @hide */ public static final int LOG_ID_MAIN = 0;
    380     /** @hide */ public static final int LOG_ID_RADIO = 1;
    381     /** @hide */ public static final int LOG_ID_EVENTS = 2;
    382     /** @hide */ public static final int LOG_ID_SYSTEM = 3;
    383     /** @hide */ public static final int LOG_ID_CRASH = 4;
    384 
    385     /** @hide */
    386     @UnsupportedAppUsage
    387     public static native int println_native(int bufID, int priority, String tag, String msg);
    388 
    389     /**
    390      * Return the maximum payload the log daemon accepts without truncation.
    391      * @return LOGGER_ENTRY_MAX_PAYLOAD.
    392      */
    393     private static native int logger_entry_max_payload_native();
    394 
    395     /**
    396      * Helper function for long messages. Uses the LineBreakBufferedWriter to break
    397      * up long messages and stacktraces along newlines, but tries to write in large
    398      * chunks. This is to avoid truncation.
    399      * @hide
    400      */
    401     public static int printlns(int bufID, int priority, @Nullable String tag, @NonNull String msg,
    402             @Nullable Throwable tr) {
    403         ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
    404         // Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
    405         // and the length of the tag.
    406         // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It
    407         //       is too expensive to compute that ahead of time.
    408         int bufferSize = PreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD    // Base.
    409                 - 2                                                // Two terminators.
    410                 - (tag != null ? tag.length() : 0)                 // Tag length.
    411                 - 32;                                              // Some slack.
    412         // At least assume you can print *some* characters (tag is not too large).
    413         bufferSize = Math.max(bufferSize, 100);
    414 
    415         LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize);
    416 
    417         lbbw.println(msg);
    418 
    419         if (tr != null) {
    420             // This is to reduce the amount of log spew that apps do in the non-error
    421             // condition of the network being unavailable.
    422             Throwable t = tr;
    423             while (t != null) {
    424                 if (t instanceof UnknownHostException) {
    425                     break;
    426                 }
    427                 if (t instanceof DeadSystemException) {
    428                     lbbw.println("DeadSystemException: The system died; "
    429                             + "earlier logs will point to the root cause");
    430                     break;
    431                 }
    432                 t = t.getCause();
    433             }
    434             if (t == null) {
    435                 tr.printStackTrace(lbbw);
    436             }
    437         }
    438 
    439         lbbw.flush();
    440 
    441         return logWriter.getWritten();
    442     }
    443 
    444     /**
    445      * PreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
    446      * a JNI call during logging.
    447      */
    448     static class PreloadHolder {
    449         public final static int LOGGER_ENTRY_MAX_PAYLOAD =
    450                 logger_entry_max_payload_native();
    451     }
    452 
    453     /**
    454      * Helper class to write to the logcat. Different from LogWriter, this writes
    455      * the whole given buffer and does not break along newlines.
    456      */
    457     private static class ImmediateLogWriter extends Writer {
    458 
    459         private int bufID;
    460         private int priority;
    461         private String tag;
    462 
    463         private int written = 0;
    464 
    465         /**
    466          * Create a writer that immediately writes to the log, using the given
    467          * parameters.
    468          */
    469         public ImmediateLogWriter(int bufID, int priority, String tag) {
    470             this.bufID = bufID;
    471             this.priority = priority;
    472             this.tag = tag;
    473         }
    474 
    475         public int getWritten() {
    476             return written;
    477         }
    478 
    479         @Override
    480         public void write(char[] cbuf, int off, int len) {
    481             // Note: using String here has a bit of overhead as a Java object is created,
    482             //       but using the char[] directly is not easier, as it needs to be translated
    483             //       to a C char[] for logging.
    484             written += println_native(bufID, priority, tag, new String(cbuf, off, len));
    485         }
    486 
    487         @Override
    488         public void flush() {
    489             // Ignored.
    490         }
    491 
    492         @Override
    493         public void close() {
    494             // Ignored.
    495         }
    496     }
    497 }
    498