📜 ⬆️ ⬇️

New API in Gingerbread - StrictMode. Or we struggle with ANR-dialogues

Recently discovered StrictMode by reading an article on the Android Developers Blog. Below I present to you her translation.

image

Behind the scenes


One of the coolest things about Google is “20% of the time”: 20% of your working time you have the right to engage in projects that have nothing to do with your main project. When I came to Google, I constantly switched from a project to a project and often joked about it that I had 7 such 20% projects. One of the projects I was constantly returning to was Android. I liked the openness of the platform, which gave me the opportunity to do everything I wanted, including opening the doors of my garage when I drove up to my house on a motorcycle. I really wanted this project to be successful, but I was worried about one thing: Android was never fast. Braking animations and user interface elements that do not always immediately respond to data entry. It was obvious that the reason for this was tasks that were running in the wrong thread.
')
I am an active SMS user and one of my 20% projects during the preparation of Cupcake release (Android 1.5) was the optimization of the messaging application. I optimized it and made it smoother, and then continued to rush between my other 20% projects. After the release of the Donut release (Android 1.6), I noticed that some of my optimizations were accidentally broken. I was a little offended, but then I realized that Android really was never enough, because it was a ready-to-use, built-in, all-pervasive performance monitoring tool.

I joined the Android full-time development team just over a year ago and spent a lot of time researching performance problems at Froyo. In particular, I spent a lot of time dealing with ANR dialogs (you see these annoying dialogs when the application performs lengthy operations inside the main UI thread). Debugging these dialogs using the available tools was difficult and tedious. They were not enough to find the cause, especially when several processes interact (for example, accessing Binder or ContentResolvers to Services or ContentProviders in other processes). A more advanced tool was needed to track interface stuttering or ANR dialogs.


StrictMode


StrictMode is a new API available starting with Gingerbread, which allows you to set policies on threads that regulate the list of operations that are not allowed to run on them. Without going too deep into the implementation details, this is just a bitmask stored in the tread-local variable.

By default, all operations are allowed, and nothing stands in your way until you want it. Flags that you can control through policies include:



In addition, StrictMode has several hooks in most places that perform disk accesses (in java.io.* , android.database.sqlite.* , Etc.) and networks ( java.net.* ) That check compliance current stream of established policies, responding accordingly.

The strength of StrictMode is that in each thread, policies are triggered whenever Binder executes IPC requests to other Services or ContentProviders, while the stack of traces are glued together, despite the number of interprocess calls.

No one wants to be slow


You can know all the places where your application performs disk I / O operations, but do you know all the places where system services and providers do it? Me not. I'm trying to find such places, but the source code of the platform is too large. We are constantly working to improve the SDK documentation, adding performance tips to it, but I usually rely on StrictMode to find random disk access to the code.

Disk access in mobile devices


Just a minute! What could be wrong with disk accesses? After all, all Android devices use flash memory. This is almost a super-fast SSD, without moving parts? I should not worry about it? Unfortunately not.

You can not rely on the fact that all flash components or file systems used in most Android devices are fast. YAFFS - the file system used in many Android devices has a global lock on each operation. For the entire device, only one operation can be performed at a time. Even a simple “stat” operation can take a long time if you are unlucky. Other devices with more traditional file systems also have a number of drawbacks, for example, when the garbage collector decides to start performing slow operations to free up flash memory. (This problem is described here in more detail)

The conclusion from the above is as follows: despite the fact that the file system on mobile devices is usually fast, however, in 90% of cases, at the time when the delay happens it will be very large. In addition, the performance of most file systems decreases with decreasing free disk space. (See slides from the Google I / O Zippy Android App)

Main application flow


Various Android callbacks and life cycle events are usually processed in the main application thread (aka UI-thread). In most cases, it makes life easier, but it also forces you to be careful, because all the animations, scrolling, etc. are also performed in this thread.

If you want to start the animation at a speed of 60 fps and suddenly the event is triggered (also in the main thread), you have 16 ms to run the code that responds to this event. If you spend time more than 16 ms, for example, because of a write operation to a disk, you will get a hangup. Usually disk accesses take significantly less time than 16 ms, but sometimes this may not be the case. For example, in the case of a YAFFS file system, if you wait until the file system resource is released by another process that is currently in the middle of the write process.

Network operations are especially slow and unpredictable, so you should never make calls to network resources from the main application flow. For the same reason, in the upcoming Honeycomb release, we made it so that network requests in the main thread would lead to a fatal error (If your application has a targetSdkVersion version of the Honeycomb API and targetSdkVersion ). Therefore, if you want to prepare your application for the Honeycomb output, make sure that you never make network requests in the UI stream. (see "Increase smoothness" below).

Turn on StrictMode


The recommended way to use StrictMode is to enable it in the development process, analyze the output, and then disable it before releasing the application.

For example, you can include it in the onCreate() application or component:

  public void onCreate() { if (DEVELOPER_MODE) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .build()); } super.onCreate(); } 


Or simply:

  public void onCreate() { if (DEVELOPER_MODE) { StrictMode.enableDefaults(); } super.onCreate(); } 


The latter method was added specifically so that you can continue to use the pre-Gingerbread API while still having the ability to easily enable StrictMode using reflection or other techniques. For example, you could targetApi as targetApi Donut (Android 1.6), but still use StrictMode if you are testing the app on a Gingerbread device or emulator.

StrictMode analysis


If you are using penaltyLog() by default, just run adb logcat and read the terminal output. Any policy violations will fall into your console.

If you want to find suspicious places in the code, turn on penaltyDropbox () and they will StrictMode write their output to DropBoxManager , from where you can extract it later using adb shell dumpsys dropbox data_app_strictmode --print

Increase smoothness


In addition to streams and j ava.util.concurrent.* You have the opportunity to use some Android API, such as Handler , AsyncTask , AsyncQueryHandler and IntentService .

Our experience


While working on the code for the platform itself, we received a “dogfood” -bild every day, which was used by the entire team. During the development of Gingerbread, we collected builds every day with StrictMode turned on and registered all violations found for further analysis. Every hour, MapReduce started a process that collected an interactive report containing all violations, their stack traces (including interprocess calls), their duration, processes and packages in which they occurred, etc.

Using data from StrictMode, we fixed hundreds of errors and increased the smoothness of the animation and responsiveness throughout the system. We optimized the Android kernel (for example, system services and providers), so this will benefit all programs in the system, and also fix a lot of errors directly in the applications (both in AOSP applications and Google). Even if you are still using Froyo, the latest updates for GMail, Google Maps, YouTube still contain fixes that improve their performance, obtained by analyzing the data collected using StrictMode.

Where we could not automatically speed up the system, we added a new API to make the use of certain patterns more simple and effective. For example, there is a new SharedPreferences.Editor.apply() method that you should use instead of commit() if you don’t need commit() return value (It turns out almost no one ever uses it). You can even use reflection to determine right in runtime that you use apply() or commit() , depending on the platform version.

Users who have switched from Froyo to Gingerbread have been shocked by how much faster their system has become. Our friends from the Chrome team also recently added something similar. Of course, StrictMode can not assume all the glory associated with the acceleration of the system, the new garbage collector also played a big role in this.

What's next?


StrictMode API and its capabilities will continue to evolve. We’ve already added some cool StrictMode related to Honeycomb, but let us know what else you would like to see in it! I will answer your questions with the "strictmode" tag on stackoverflow.com. Thank!

Source: https://habr.com/ru/post/152571/


All Articles