Are Android logging functions such as Log.d() and __android_log_print() safe to use in a multithreaded context? In particular, I'm wondering if it's guaranteed there will be no instability and that individual log messages won't be interleaved at the character level or otherwise jumbled.
It would seem this should be easy information to find, but for some reason I haven't been able to find anything conclusive. The documentation for Log and for the corresponding native functions doesn't seem to address the issue. In the documentation for Logger it's mentioned that all methods are thread safe, but it's the lower-level functions I'm wondering about specifically.
One would expect these functions to be thread safe, given that logging from multiple threads is probably common. Also, by default at least, in Android Studio each log message includes a thread identifier, and it would seem odd for the logger to be thread-aware but not thread safe.
I highly doubt there's anything to worry about here, but when it comes to multithreading it seems like a guarantee would be preferable, even when it seems obvious that the functionality in question must be thread safe.
Is this documented somewhere, and I've just missed it? If not, is it reasonable to assume that the functions in question are thread safe?
Related
Android documentation, tutorials, videos and the like are filled with best practice on how to avoid non-essential processing on the UI thread. However, when creating a big app or using external components it can be hard to remember which methods block the UI thread and which do not. I've often seen threading mentioned in comments, but that seems error prone for lazy/rushed situations, and not everything gets an ideal code review.
What naming, annotation, or other conventions exist to help developers quickly determine if the methods they are considering are UI thread optimized or not?
In the Android SDK documentation, the page entitled "Using DDMS" has the following comment under the subheading "How DDMS Interacts with a Debugger":
Known debugging issues with Dalvik - Debugging an application in the Dalvik VM should work the same as it does in other VMs. However, when single-stepping out of synchronized code, the "current line" cursor may jump to the last line in the method for one step.
In this context, I've two questions:
a) I'm not sure what "synchronized code" refers too? Are we talking about "debug" code or code using the "synchronized" keyword, or something else? I'm lacking a definition on the page, and synchronized is a generic term so it's not clear to me where the limitation actually lies.
b) Depending on the answer from "b", I suspect my second question would be what does stepping "out" of synchronized code mean?
Your help in explaining this would be appreciated with thanks.
I believe they simply meant "synchronous code". Asynchronous code might jump to other threads as the scheduler sees fit, but synchronous code should proceed in order. They have mentioned a known peculiarity with the Dalvik debugger, that it makes a seemingly inexplicable jump when it should step from one line of execution to the next. That issue has actually confused me once or twice...
synchronized is a keyword you may use either on methods or on blocks. It is helpful when using threads.
Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods.
http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
I'm trying to follow Android best practices, so in debug mode I turn all the following on:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); //detect and log all thread violations
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); //detect and log all virtual machine violations
Android now yells at me when I try to use any sort of file access or SQL in the main (UI) thread. But I see so many recommendations to use file access and/or SQL in the main thread. For example, the main activity should load default preference values inside onCreate() in case they haven't been set yet:
PreferenceManager.setDefaultValues(context, resId, readAgain);
Oops---that results in a file access on the first application execution, because onCreate() is called on the UI thread. The only way around it I can see is to start a separate thread---which introduces a race condition with other UI code that might read the preferences and expect the default values to already be set.
Think also of services such as the DownloadManager. (Actually, it's so buggy that it's useless in real life, but let's pretend it works for a second.) If you queue up a download, you get an event (on the main thread) telling you a download has finished. To actually get information about that download (it only gives you a download ID), you have to query the DownloadManager---which involves a cursor, giving you an error if you have a strict policy turned on.
So what's the story---is it fine to access cursors in the main thread? Or is it a bad thing, and half the Android development team and Android book authors forgot about that?
The only way around it I can see is to start a separate thread---which introduces a race condition with other UI code that might read the preferences and expect the default values to already be set.
Then use an AsyncTask, putting the setDefaultValues() call in doInBackground() and the "other UI code that might read the preferences" in onPostExecute().
To actually get information about that download (it only gives you a download ID), you have to query the DownloadManager---which involves a cursor, giving you an error if you have a strict policy turned on.
So query the DownloadManager in a background thread.
So what's the story---is it fine to access cursors in the main thread?
That depends on your definition of "fine".
On Android 1.x and most 2.x devices, the filesystem used is YAFFS2, which basically serializes all disk access across all processes. The net effect is that while your code may appear sufficiently performant in isolation, it appears sluggish at times in production because of other things going on in the background (e.g., downloading new email).
While this is a bit less of an issue in Android 3.x and above (they switched to ext4), there's no question that flash I/O is still relatively slow -- it will just be a bit more predictably slow.
StrictMode is designed to point out where sluggishness may occur. It is up to you to determine which are benign and which are not. In an ideal world, you'd clean up them all; in an ideal world, I'd have hair.
Or is it a bad thing, and half the Android development team and Android book authors forgot about that?
It's always been a "bad thing".
I cannot speak for "half the Android development team". I presume that, early on, they expected developers to apply their existing development expertise to detect sluggish behavior -- this is not significantly different than performance issues in any other platform. Over time, they have been offering more patterns to steer developers in a positive path (e.g., the Loader framework), in addition to system-level changes (e.g., YAFFS2->ext4) to make this less of a problem. In part, they are trying to address places where Android introduces distinct performance-related challenges, such as the single-threaded UI.
Similarly, I cannot speak for all Android book authors. I certainly didn't focus on performance issues in early editions of my books, as I was focusing on Android features and functions. Over time, I have added more advice in these areas. I have also contributed open source code related to these topics. In 2012, I'll be making massive revisions to my books, and creating more open source projects, to continue addressing these issues. I suspect, given your tone, that I (and probably others) are complete failures in your eyes in this regard, and you are certainly welcome to your opinion.
Is there a way to somehow intercept calls to the standard Log in android and perform some other action?
In desktop Java one would usually get some logger so there are ways to install a different logging handler / implementation. However, Android seems to have a static call to Log, and I could not find any information about replacing the default behavior.
I realize I can monitor the device log through ADB, but I'd like to have a different behavior in running apps on a device who opt in (e.g., by executing a certain instruction when the program starts out).
As AedonEtLIRA points out Log is final so you need to roll/borrow a new one. I've been using Prasanta Paul's "MLog": http://prasanta-paul.blogspot.com/2010/07/custom-logger-for-android.html
It makes it easy to save logs to a text file and/or disable logging completely.
If it doesn't already do what you need, it is a good base for managing logging.
I think your best solution would be to replace all the Log calls in your application with your own class, MyLog, then call Log if they don't opt-in, and call your special logging feature if they opt-in.
Replacing all the Log calls shouldn't be hard, just a find and replace.
In addition to MLog proposed by #Darrell, there are several other logging frameworks for Android, including:
logback-android
log4j-android
microlog4android
Of the three, logback (the next-gen log4j) seems to be the most capable and have the richest API (and lots of documentation), while microlog is the most compact (but limited in features...but maybe it does all you need). All three support the SLF4J logging facade, so you can easily swap out microlog for logback, log4j, jul, or some newer framework down the road.
As with MLog, these frameworks require replacing the calls to android.os.util.Log (it doesn't "intercept" the calls as you might be after).
Because Log is final, I think you will have to write your own logging system and implement that if you want to change anything.
The Andoid UI toolkit is not thread-safe, when you try to modify the UI from a worker thread you get the CalledFrowWrongThreadException (or something like that).
Moreover, the dev guide say:
[Manipulating the UI from a worker thread] can result in undefined and
unexpected behavior, which can be
difficult and time-consuming to track
down.
But it does not seem to me very difficult to understand what a CalledFrowWrongThreadException mean.
Does the documentation was written before the introduction of CalledFrowWrongThreadException or are there still cases where the exception is not thrown? (or where the error is indeed difficult and time-consuming to track down)
The main issue here is that checking what thread is calling a given function incurs a processing overhead; there are almost certainly calls that don't check for precisely this reason - it would slow down the UI rendering.
By extension, the reason UI functions aren't thread-safe is that if you through mutex code into the equation, the performance hit becomes even greater.
Just like Swing in Java, and WinForms in .NET, there may be cases where the method in question does not check to determine that you are calling from the proper thread, and therefore does not necessarily throw the expected exception.
Providing the above documentation is a way to cover themselves and explain a simple idea that actually requires a lot of effort to work around if you do not know it, or understand it, before the wrong thread exception is ever thrown by offending code, which may be much later down the road.