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