In this tutorial, you will learn some common crash log cases, and how to get crash log files from development devices and itunes Connect. You will also learn to symbolize (symbolication), from log tracking to code. You will also learn to debug an application that will be rolled out in a pending situation. Let's get started!
What is a crash log and where can I get it?When an app on an iOS device flashes, the operating system generates a crash report, also known as a crash log, to be on the device. The crash log has a lot of useful information, including what the app is for. Typically, there is full stack trace information for each executing thread, so you can learn what each thread is doing when the flashback occurs, and tell which thread the flashback occurred on. There are several ways to get crash logs from your device. after syncing with the itunes Store on your computer, the crash log will be saved on your computer. Depending on your computer's operating system, the crash log will be saved in the following location: Mac OS x:~/library/logs/crashreporter/mobiledevice/ windows xp: c:documents and Settings<username>application Dataapple computerlogscrashreportermobiledevice<device_name> Windows Vista or 7: c:users<username>appdataroamingapple computerlogscrashreportermobiledevice< device_name> When a user complains about a flashback, you can ask him to have the device sync with itunes and, depending on the operating system, download the crash log to the above location and send it to you via email. You must try to get all the crash logs generated by the user device. Because the more crash logs, the easier it is to diagnose the problem! in addition, if you have Xcode, you can easily get the crash log from your device via Xcode. Connect your iOS device to your computer, and then turn on Xcode. Select Window menu from the menu bar and select Organizer (Shortcut is shift-cmd-2). On the Organizer window, select the Devices tab bar. On the left side of the navigation panel, select device logs, as shown in the: look, there are several Device Logs menu items on the left. LIBRARY The following device logs is a log of all your devices (once connected to Xcode). The device Logs under each unit is the log of the corresponding device. After the app is submitted to the App Store, you can also get a crash log from ITunes connect to the user. Log on to ITunes Connect, select Manage Your applications, click the appropriate app, click the view details button below the app icon, then click cras in the Links section on the right column H reports . If there is no crash log, try clicking the Refresh button and refreshing it. If your app isn't selling much, or it's just been on the shelves, there may not be any crash logs on your ITunes connect account. If there is a crash log on itunes Connect, you will see the crash report as: Sometimes, despite the user reporting the flashback, you still don't see it. At this point, it's a good idea to let users send crash reports directly to you.
what happens when a crash log is generated?There are two main scenarios that create a crash log:
1. Application violates operating system rules.
2. There are bugs in the application. Violating IOS rules includes watchdog timeouts on startup, recovery, suspend, exit, user forced exit, and low memory termination. Let us have a detailed look at it.
Watchdog Timeout mechanismStarting with iOS 4.x, when exiting the app, the app does not terminate immediately, but instead comes back to the background. However, if your app responds quickly enough, the operating system may terminate your app and generate a crash log. These events correspond to the following uiapplicationdelegate: application:didFinishLaunchingWithOptions:applicationWillResignActive: ApplicationDidEnterBackground:applicationWillEnterForeground:applicationDidBecomeActive: Applicationwillterminate: Above all of these methods, the application has only a limited amount of time to complete processing. If it takes too long, the operating system terminates the app. Note: This is very easy to do if you do not place operations that take longer (such as network access) on a background thread. For information on avoiding this situation, please refer to our other two tutorials: Grand Central Dispatch and Nsoperations.
User forced ExitIOS 4.x starts to support multitasking. If you apply a blocking interface and stop responding, the user can terminate the app by double-clicking the Home button on the home screen. At this point, the action app will generate a crash log. Note: When you double-click the Home button, you'll see all the apps you've run. Those apps aren't necessarily running, or they're not necessarily suspended. Typically, when a user taps the home button, the app remains in the background for about 10 minutes, and then the operating system automatically terminates it. So double-clicking the Home button shows a list of apps that are just a series of apps that have been opened in the past. Deleting icons for those apps does not generate any crash logs.
Low Memory terminationWhen you subclass Uiviewcontroller, you may have noticed the didreceivememorywarning method. Apps running in the foreground have the highest level of optimization for accessing and using memory. However, this does not mean that the app can use all the available memory on the device--only a fraction of the available memory can be used per app. When memory usage reaches a certain level, the operating system issues a uiapplicationdidreceivememorywarningnotification notification. Also, call the Didreceivememorywarning method. At this point, in order for the app to continue to function properly, the operating system starts terminating other apps in the background to free up some memory. After all the background apps have been terminated, if your app needs more memory, the operating system will also terminate your app and generate a crash log. In this case, the background app is terminated, and the crash log is not generated.
Note:Depending on the Apple documentation, Xcode does not automatically add a low memory log. You must manually get the logs. However, based on my personal experience, using Xcode 4.5.2, low memory logs are also automatically imported, except that the "Process" and "Type" properties are labeled Unknown (unknown). Also, it is worth mentioning that allocating a large chunk of memory in a very short period of time will be a huge burden on system memory. In this way, a memory warning notification is also generated.
There are bugs in the appAs you can imagine, most of the flashbacks are due to bugs in the app, so most crash logs are caused by bugs in the app. There are many kinds of bugs. In the latter part of the tutorial, you'll learn how to find the problem and fix it by debugging an app with bugs that will generate a crash log!
instance of crash logLet's take a look at an example of a crash log so that you have a mental spectrum before dealing with some practical problems. without further ado, meet your new friend: the report looks like a heavenly book. :) We'll read it in a few points.: (1) process information The first part is the information about the process of the flash-back. incident identifier is a unique identifier for the crash report. The crashreporter key is a unique key value that corresponds to the device identity. Although it is not a true device identifier, it is also a very useful intelligence: if you see the Crashreporter key value of 100 crash logs is the same, or only a few different crashreport values, it is not a common problem, Occurs on only one or a few devices. hardware model identifies the device type. If many crash logs come from the same device type, the app only has a problem with a particular type of device. In the above log, the crash log produced the device is the iphone 4s. Process is the app name. The numbers inside the brackets are the process IDs that are applied when the flash is rolled out. The next few lines are self-explanatory, no need to repeat. (2) Basic information This section gives some basic information, including the date and time of the flashback, the iOS version of the device. If there are many crash logs from iOS 6.0, the problem only occurs on iOS 6.0. (3) exception in this section, you can see the type of exception thrown when a flashback occurs. You can also see the exception code and the thread that throws the exception. Depending on the type of crash report, you can see some additional information in this section. (4) Thread backtracking This section provides a backtracking log of all threads in the app. Backtracking is the list of all active frames when a flashback occurs. It contains a list of functions that are called when a flashback occurs. Look at the following line of logs: It includes four columns: Frame number--here is 2. The name of the binary library-here is xyzlib. The address of the calling method--here is 0x34648e88. The fourth column is divided into two sub-columns, one base address and one offset. Here is 0x83000 + 8740, the first digit pointing to the file, and the second number pointing to the line of code in the file. (5) thread state This part is the value in the register when the Flash is rolled back. This part of the information is generally not needed, because the information in the backtracking section is enough to let you find out where the problem lies. (6) Binary image This section lists the binaries that were loaded when the flash was rolled out.
Symbolic SymbolicationThe first time you see backtracking on a crash log, you may find it meaningless. We are accustomed to using the method name and the number of rows, rather than mysterious places like this: the process of translating these hexadecimal addresses into the method name and the number of rows is called symbolization. After a few seconds after getting the crash log from the Organizer window of Xcode, the crash log is automatically symbolized. The following signed version of the above line is as follows: When Xcode signs the crash log, it needs to access the corresponding application binaries on the App Store and the. DSYM file that was generated when the binaries were built. Must match exactly. Otherwise, the log will not be fully symbolized. Therefore, it is important to keep each compiled version that is distributed to the user. When you archive your app before submitting it, Xcode saves the app's binaries. All archived app files can be found under the Archives tab bar in Xcode organizer. When a crash log is found, Xcode automatically signs the crash log if there is a matching. dsym file and application binaries. If you switch to another computer or create a new account, be sure to move all binaries to the correct location so that Xcode can find them. (
Note:You must keep both the app binaries and the. dsym file in order to symbolize the crash log intact. Every build that is submitted to itunes Connect must be archived.. dsym files and binaries are specific bindings for each build and subsequent build, and even from the same source code files, each build is different from other constructs and cannot be replaced with each other. If you use the build and Archive commands, these files are automatically placed in place. If you are not using the build and archive commands, place them in a location that spotlight can search (such as the home directory). )
low memory Flash backBecause the low memory crash log is slightly different from the normal crash log, this tutorial is specifically explained separately. When the iOS device detects low memory, the virtual memory system sends a notification request that the app frees the memory. These notifications are sent to all running apps and processes, trying to reclaim some memory. If memory usage remains high, the system terminates the background thread to relieve memory pressure. If enough memory is available, the app will be able to continue running without generating a crash report. Otherwise, the app will be terminated by iOS and generate a low memory crash report. There is no stack backtracking on the application thread on the low memory crash log. Instead, it shows the amount of memory used per process in memory pages. (When writing this article, the size of a memory page is 4KB.) You will see the jettisoned word after the process name that was terminated by iOS for releasing the memory page. If you see that it appears behind your app's name, your app is terminated because it uses too much memory. A low memory crash log looks like this: When an app has a low memory flash, you need to look at how memory is used in your app and how to handle low memory warnings. You can use the instruments tool to use allocations and leaks to discover memory allocation problems and memory leak issues. If you don't know how to use Instruments to check for memory problems, you can take a look at this tutorial. Also, don't forget the virtual memory! The leaks and allocations of the instruments tool cannot track memory usage. You must use VM Tracker to view memory usage. VM Tracker is turned off by default. Open instrument, manually check the automatic snapshotting flag or press the snapshot Now button. Later in this tutorial, you will learn how to study low memory crash logs.
Exception EncodingBefore studying the real-world flashback scenario, there is one more point to highlight: The interesting exception codes. You can find the exception code in the exception section of the report-the 3rd part of the preceding code. Some encodings are more common. Typically, the exception code begins with some text, followed by one or more hexadecimal values, which is exactly where the underlying nature of the flashback is. From these encodings, it is possible to distinguish between a program error, illegal memory access, or other reasons. Here are some common exception codes: 0x8badf00d: Read "ate bad food"! (Does the number change to a letter, does it look like:p) The code indicates that the app was terminated by iOS because of a watchdog timeout. It is usually the application that takes too much time to start, stop, or ring the application system events. 0xbad22222: This code indicates that the VoIP application was terminated because it was restarted too frequently. 0xdead10cc: Read "dead lock"! This code indicates that the app is terminated because it consumes system resources when it is running in the background, such as when the Contacts database is not released. 0XDEADFA11: Read "Dead Fall"! This code indicates that the app was forcibly exited by the user. According to the Apple documentation, the force exit occurs when the user presses the switch button until the "swipe to shut down" appears, and then long press the home button. Forcing the exit will result in a crash log containing the 0XDEADFA11 exception encoding because most of the forced exits are due to the application blocking the interface. (
Note:Shutting down suspended apps in the background tasks list does not result in a crash log. Once the application is suspended, it is justified when it is terminated. Therefore, the crash log is not generated. It's time to do your job! You have learned all the basics of analyzing crash logs and fixing bugs! Suppose you just entered Rage-o-rage Co., Ltd. to work. The company has a hot-selling app on the app store called Rage Masters. Your boss, Andy, wants you to help out. Several users often complain about the flash-back problem. Your task is to study these flashbacks, symbolize the user-provided crash logs, find the problem, and fix it. You can download the app's source code from here. (
Note:If you want to regenerate the crash report yourself, follow these guidelines: 1. Download the source code and open the project file in Xcode. 2. Connect to the iOS device using the correct provisioning profile. 3. Select iOS device from the Xcode toolbar--not the simulator as target, then build the app. 4. When you are on the device to the default page (full screen image applied), immediately click on the Stop button on Xcode. 5. Turn off Xcode. 6. Open the app directly on the device. 7. Test the scene, connect the device to the computer when finished, and get the crash log through Xcode. )
Scenario 1: Bad codeA message from the user: "Big Brother, your application is a piece of excrement!" I downloaded it to my own ipod Touch and iphone and downloaded it to my son's ipod touch. On all the equipment, it is not open on the flash back ... " A message from the user says, "I downloaded your app and just turned it back on." It's so sad ... " Another message is more specific: "Your app won't work." I downloaded it to my wife's device. All devices are on the blink of an open ... "Well, don't lose heart!" What do these opinions hide? Let's look at the crash log: Did you find the problem? The exception code is 0x000000008badf00d, and there is a later report: This shows that the app is flashing at startup, and the iOS watchdog mechanism terminates the application. Handsome! Found a problem, but why did it happen? Then look down at the log. Reads the backtracking log from the bottom up. The bottom frame 25:libdyld.dylib is the first call, then the frame, Rage Masters, Main (main.m:16), and so on. The frames associated with the application source code are the most important. Ignore system libraries and frameworks. The next frame associated with the code is: The application is rolled out when executing the rmappdelegate (rmappdelegate.m:35) class Application:didfinishlaunchingwithoptions: The 35th line of code. Open Xcode and look at that line of code: that's it! Call the Web service synchronously?! On the main thread?! On the Application:didfinishlaunchingwithoptions: Method?!! Who wrote the code?! Network calls on the main thread makes kittens sad. In any case, you have to fix the problem. This call must be done asynchronously, and even more ideally, the Web service will be executed in the other part after Application:didfinishlaunchingwithoptions: return yes. Calls in other places may require more modifications. At the moment, we just have to make the app non-refundable. Better design can be achieved in the future. Replace the nasty code above (and the three lines below) with the following asynchronous version:
Scenario 2: A button that cannot respond to an eventOne user said, "I can't add a rage master to a bookmark." I want to add a time when the app will flash back ... " With a user said: "Bookmarks can not be used ... On the detailed page, click on the Bookmark button and the app will flash back! "The above complaint is not very clear, the cause of the problem must be varied. Look at the crash log: The exception code is SIGABRT. Typically, a SIGABRT exception is caused by an object that receives an implementation message. Or, in simple terms, a non-existent method is called on an object. This generally does not occur because the A object calls the B method, and if the B method does not exist, the compiler will error. However, if you are using selector to indirectly invoke the method, the compiler cannot detect whether the object exists for that method. Back to the crash log. It indicates that the flashback occurred on a thread numbered 0. This means that it is possible to invoke a method on the main thread that an object is not implemented. If you continue to read the backtracking log, you will find that the only frame that is related to your code is main.m:16. It's not much help. Continue to view the frame call up, this appears: This is not the code you wrote yourself. But at least it confirms that the object called a method that was not implemented. Go back to the rmdetailviewcontroller.m file, because that's where the bookmark button implements the action. Find the Bookmark function code: Look no problem, check the storyboard (xib file), confirm the correctness of the button connection. That's it! In Mainstoryboard.storyboard, the button is connected to bookmarkbuttonpressed: instead of bookmarkbuttonpressed (note that the following semicolon indicates that the method has a parameter). Just modify the method signature above to fix the problem: Of course, you can simply delete the wrong connection on the Xib file, and then reconnect the method so that the Xib file is connected to the correct method. Both methods are OK. and a flash-back problem, good work.
Scenario 3: Bugs on the tableAnother user complained, "Cannot delete bookmarks on Bookmark view ..." There is another user complaining about the same problem, "when I try to delete a bookmark, the app Flash back ..." These messages don't work, or look at the crash log! It looks like the crash log in front of me. is another SIGABRT exception. You may wonder if the same question is being sent to an object that does not implement the appropriate method? Let's look at the backtracking logs to see which methods are called. Starting at the bottom, your source code is finally called Frame 6: This is a method of Uitableviewdatasource. Oh?! There is no doubt that Apple has implemented the method-you can reload it, but it doesn't seem to have been implemented yet. Also, this is an optional delegation method. So the problem is not to call a method that is not implemented. Then look at the frames above: frame 5, UITableView called its own other method deleterowsatindexpaths:withrowanimation: And then it looks like the Apple internal method _ Endcellanimationswithcontext: called. Then the foundation framework has an exception handleFailureInMethod:object:file:lineNumber:description:. These analyses, combined with user complaints, appear to be a bug in the process of handling uitableview delete rows. Back to Xcode. Do you know where to look? Can you tell from the crash log? is the 68th line of the rmbookmarksviewcontroller.m file: Did you find the problem? Give you some time to take a closer look. Find it! What about the data source? The code deletes a row on the table view, but does not modify the data source behind it. Replace the above code with the following to fix the problem: it's done! Go, nasty bug!!.
Scenario 4: When you eat a lollipop, you are back!User email says, "When rage Master eats lollipops, the app will flash back ..." Another user said, "I let rage master eat Lollipop, and not a few times the app just flashed back!" Crash log below: This log is much different from what we saw earlier. This is a low memory crash log from iOS 6. As we said earlier, low memory crash logs are very different from other types of crash logs, and they do not point to specific files and lines of code. Instead, they draw a graph of the memory usage on the device during the flash-back. At the very least, the head is similar to the other crash logs: Provides information such as Incident Identifier, Crashreporter Key, Hardware Model, OS version, and more. The next section is specific to the low memory crash log: Free pages refers to the number of available memory pages. The size of each page is approximately 4KB, the above log, the available memory is approximately 3,872 KB (or 3.9 MB). Purgeable pages is the portion of memory that can be purged or reused. In the above log, it is 0KB. Largest process is the name of the app that uses most of the memory when it's rolled back, and it's your app in the log above! Processes shows the list of processes at the time of the flashback and also contains memory usage. Contains the process name (first column), the process unique identifier (second name), the number of memory pages used by the process (third column). The last column is the status of each app. Typically, the state of the app that has a flashback is frontmost. Here is Rage Masters, using 28591 pages (or 114.364 MB) of memory-too much memory! through, the maximum process and frontmost state of the application is the same, but also caused low memory flash application process. However, it is also possible to see the maximum process and frontmost states applying different examples. For example, if the maximum process is springboard, ignore it, because the springboard process is the app that displays the home screen, appears when you double-click the Home button, and so on, and it's always active. When low memory occurs, iOS emits a low memory warning to the active app and terminates the background app. If the foreground app continues to grow memory, iOS will terminate it. to find the cause of a low memory problem, you must use instruments to profile your app. If you don't know what to do, take a look at one of our tutorials on this. :] In addition, you can take shortcuts to respond to low memory warning notifications to resolve partial flashback issues. Back to XCOde View the Rmlollipoplicker.m file. This is the realization of eating lollipop view controller. Look at the source code: when the user clicks the Run button, the app starts a background thread, calls the Licklollipop method several times, and then updates the interface to reflect the number of lollipops eaten. The Licklollipop method reads a long string from the property list file (PLIST) file and then adds it to the array. This data is not important and can be recreated without compromising the user experience. It's a good practice to use every situation that clears and rebuilds data without impacting the user experience. This makes it easy to free up memory and reduce low memory warnings. So, how do you improve the quality of your code? Implement the Didreceivememorywarning method, which processes the data as follows:
with crash capture and collection, you can collect exceptions to published apps (games), so that developers find and modify bugs, which is a great help in improving software quality. This article describes the principles and procedures for capturing and collecting crashes in iOS and Android platforms, but if you are developing applications or have no special restrictions, you don't have to look down, and just add the league SDK (a statistical analysis SDK) to the project and it's all right. The error logging feature fully satisfies the requirements and does not require additional preparation for the receiving server. But if you are more interested in its principles, or as I have to be compatible with the company's existing bug collection system, the following things are worth seeing.
There are a few of the main difficulties to achieve crash capture and collection:
1, how to catch crashes (such as C + + common wild pointer errors or memory read and write out of bounds, when these situations occur when the program is not an abnormal exit, how can we capture it)
2, how to get stack information (tell us which function crashes, even the first few lines, so that we can reproduce and modify the problem)
3, upload the error log to the designated server (this is the best)
Let's start with a brief overview. The code that causes the crash is essentially two types, one is the C + + language level error, such as the wild pointer, except 0, memory access exception, and so on, and the other is the uncaught exception (uncaught Exception), The most common under iOS is the Objective-c nsexception (thrown by @throw, for example, the Nsarray access element out of bounds), Android is the exception thrown by Java. If these exceptions do not reside in the top-level try, then the program crashes. Whether iOS or Android, the underlying UNIX or Unix-like system, for the first class of language-level errors can be captured by signaling mechanisms (signal or sigaction, do not mix with QT signal slots), That is, any system error will throw an error signal, we can set a callback function, and then print in the callback function and send the error log.
One, the iOS platform crash capture and collection
1. Set turn on crash capture
[CPP]View Plaincopy
- static int s_fatal_signals[] = {
- SIGABRT,
- Sigbus,
- SIGFPE,
- Sigill,
- SIGSEGV,
- SIGTRAP,
- SIGTERM,
- SIGKILL,
- };
- Static const char* s_fatal_signal_names[] = {
- "SIGABRT",
- "Sigbus",
- "SIGFPE",
- "Sigill",
- "SIGSEGV",
- "SIGTRAP",
- "SIGTERM",
- "SIGKILL",
- };
- static int s_fatal_signal_num = sizeof (s_fatal_signals)/ sizeof (s_fatal_signals[0]);
- void Initcrashreport ()
- {
- //1 Linux error signal capture
- For (int i = 0; i < S_fatal_signal_num; ++i) {
- Signal (S_fatal_signals[i], signalhandler);
- }
- //2 objective-c Catch of uncaught exception
- Nssetuncaughtexceptionhandler (&handleexception);
- }
At the beginning of the game call the Initcrashreport () function to turn on crash capture. Note 1 corresponds to the first type of crash described above, and note 2 corresponds to an exception that is thrown but not handled by the objective-c (or Uikit Framework).
2. Printing stack information
[CPP]View Plaincopy
- + (Nsarray *) backtrace
- {
- void* callstack[128];
- int frames = BackTrace (callstack, 128);
- char **strs = backtrace_symbols (callstack, frames);
- int i;
- Nsmutablearray *backtrace = [Nsmutablearray arraywithcapacity:frames];
- For (i = kskipaddresscount;
- I < __min (Kskipaddresscount + kreportaddresscount, frames);
- ++i) {
- [BackTrace addobject:[nsstring Stringwithutf8string:strs[i]];
- }
- Free (STRs);
- return backtrace;
- }
Fortunately, Apple's iOS system supports BackTrace, which lets you print out the call stack of a program crash directly. The advantage is that no symbol function table is required, and you do not need to save the published version to view the crash stack directly. The disadvantage is that you can not print out exactly which line crashes, many problems know which function collapsed, but still can't find out because of what collapsed
3, log upload, this need to see the actual needs, such as our company is to put the crash information http POST to a PHP server. There's not much to declare here.
4, the skill---after the crash program maintains the state of operation and does not exit
[CPP]View Plaincopy
- Cfrunloopref Runloop = Cfrunloopgetcurrent ();
- Cfarrayref allmodes = Cfrunloopcopyallmodes (Runloop);
- While (!dismissed)
- {
- For (NSString *mode in (__bridge Nsarray *) allmodes)
- {
- Cfrunloopruninmode ((__bridge cfstringref) mode, 0.001, false);
- }
- }
- Cfrelease (Allmodes);
After the crash handler has uploaded the log information, call the code above to rebuild the program's main loop. In this way, even if the program crashes, it can still run normally (of course, this time is in an unstable state, but because the handheld games and applications are mostly short-term operation, there will be no hang-up this argument, so stability is irrelevant). The player does not even feel the crash.
Here is to explain a gratitude, that is, "reentrant (reentrant)." Simply put, when our crash callback function is reentrant, the new function can still be run again when the crash occurs again, but it will not work if it is not re-entered (this time it is completely dead). To achieve the effect described above, it is almost impossible to ensure that the callback function is reentrant. So, the result of my test is how many times Objective-c's abnormal triggering can work. However, if the error signal is triggered multiple times, the program will die. So be careful to decide whether you want to apply this technique.
IOS App crash log analysis