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