Most iOS apps will encapsulate some key tasks into Background Task after entering the background, otherwise the program will be suspended by the system after a few seconds. After starting Background Task, you can get 3 minutes to continue executing the code. I was recently investigating the Background Crash issue in Messenger, and finally traced it back to Background Task. I would like to share some key points with you. Crash Signal Generally, apps have their own crash log collection tools, which generally have three problems. The first is that the crash logs before the tool is started cannot be captured, the second is that if the app crashes at startup, the logs cannot be uploaded, and the third is that the system cannot capture crash signals in some special scenarios.
Apple also has its own crash log collection, but based on user privacy considerations, this crash log is not reliable and has the following main flaws:
Background Task Fancy Crash Background Task's API is very simple. All the codes between begin and end fall into the scope of Background Task. However, simple codes hide considerable risks. Here are three crashes that are more likely to occur. Moreover, these three crashes cannot be captured by the crash collection tools that come with the client. Signals can only be obtained through Apple's crash log. The reason is simple. When these crashes occur, the app is usually in a suspended state and has no chance to execute any code. The system directly sends a SIGKILL signal to kill the app and generate a system log, a log that can only be accessed by Apple. The user must agree to upload and share it first. 0xdead10cc The crash log usually looks like this:
I have introduced the reason before. When your App has Extension, and Extension needs to share data with Host App, the general practice is to put the db file in the shared container directory. At this time, your App is likely to crash. The App goes into the background to run Background Task. After it ends, the App is suspended by the system. If there is any operation to access the database after suspension, the App will be immediately killed by the system. This is for Apple's consideration to protect the integrity of the database file. Therefore, the correct approach is to enclose all db operations that may occur after the App enters the background into the Background Task to ensure safety. It may be more appropriate to write this code in the db layer. Moreover, Apple recommends that when you want to start Background Task, you don’t need to consider whether the current App is in the foreground or background. Even if the App starts Background Task in the foreground, it will not occupy the 3-minute quota after entering the background, so feel free to put the key code into Background Task. 0xbada5e47 When you follow the above advice and generously enclose as much critical code as possible in Background Task, you may encounter the following crash:
The same is true for Background Tasks. Apple thinks you have started too many Background Tasks, so they need to be killed. How many are considered too many? A few dozen is not a lot. The current threshold is 1,000. If the number exceeds 1,000, it will be killed. If your Background Task encapsulation occurs in the db layer, when a large amount of data needs to be stored or read, it is still possible to hit this limit. Another possible reason for 0xbada5e47 is that the Background Task will call the expiry handler after the timeout. No matter how many Background Tasks you have, the execution time of all expiry handlers cannot exceed a certain number of seconds. Once the time exceeds, they will be killed. Therefore, do not have any time-consuming operations such as disk io in the expiry handler. 0x8badf00d Speaking of 0x8badf00d, everyone is familiar with it. When your main thread is stuck for too long, the system's Watchdog will kill your App and generate a crash log with 0x8badf00d. Background Task can also be 0x8badf00d, for example:
When your code logic generates a leaked Background Task, the above system crash log will appear. What is a leaked Background Task? See the code:
If startBgTask is executed twice in the above code, a leaked Background Task will definitely appear, because self.bgTaskID will be assigned a new ID the second time, and the previous task ID will be lost, so end cannot be called correctly. So how do you determine whether 0x8badf00d is caused by the main thread being stuck or a leaked Background Task? It's very simple. Look at the stack of the main thread. If it looks like this:
This stack is very classic and you will see it often. You can know what it is without symbolicating. This is the stack of the UI thread runloop in idle state, waiting for kernel message. It means the UI thread is idle at this time. The system kill in this state is most likely caused by leaked Background Task. Make good use of the local crash log of the device When a user's phone crashes and you can neither reproduce the crash nor find the crash log in the background, your best hope is the local crash log on the phone. The local log is located in Settings -> Privacy -> Analytics -> Analytics Data. Open it and you may find the crash log of the app you developed. I have many logs for WeChat and Alipay on my phone. Logs are sorted first by the name of the App, then by the date the log occurred. If you are investigating a crash involving excessive memory usage, you can view logs starting with JetsamEvent-xxx. If you want to know what abnormal logs the system has before the App crashes, you need to first install a loggingiOS.mobileconfig file on the device. This file basically allows users to authorize you to record system behavior. When a crash occurs, the user presses the two volume buttons + the power button at the same time. After releasing the buttons and vibrating, the system will record the key logs of the past period of time. This is very helpful for analyzing some difficult and complicated problems. This log usually starts with sysdiagnose_xxx. After installing the loggingiOS.mobileconfig file, there is another benefit: Apple will record more and more detailed crash logs, because the user has authorized it, so Apple can do it boldly. The file name of this type of log is generally: stacks + appName - date.ips. If the user's device can reproduce the problem you are investigating, there is another simple and efficient way. Connect the phone to the Mac via USB, and then start the Console App on the Mac. You can then intuitively view all key system logs, such as nsurlsessiond for network exception logs, locationd for location exception logs, and assertiond for Background Task exception logs. You can also filter directly by the process name of your app to view the life cycle and the reason for being killed. Summarize The above is some knowledge points shared from the recent investigation of Background Task crash. I hope it will be helpful to everyone. |
<<: Finally betting on dual SIM cards and dual standby, is iPhone taking the wrong path?
>>: Summary of App Store review of financial apps 3.2.1 rejection and 23 other reasons
The course comes from the eighth session of Xiaom...
ROI is return on investment = total profit/cost*1...
This article was reviewed by Tao Ning, PhD, Assoc...
Due to some irresistible forces, Toutiao 's p...
This is the 5293th article of Da Yi Xiao Hu In th...
Introduction丨The “link between the past and the f...
We also need to arrange a good-looking layout How...
The child is too slow, I have to push him! ! In f...
Recently, a friend from the brand marketing depar...
Audit expert: Ye Haiying Deputy Director of the N...
On March 21, 2018, Tencent announced its fourth q...
Smell the coffee: A foreign experiment was conduc...
Infectious diseases are the endless enemy of huma...
The Musée d'Orsay, which has been open to the...