ios: Add iOS crashpad overview documentation.

Adds an overview of the limitations of crashpad on the iOS platform,
including explanations of the in-process client and handler, and the
intermediate dump format used.

Bug: crashpad: 31
Change-Id: I1eb6add115570147e2de1be1002c5a4aa366184b
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2706018
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Justin Cohen 2021-03-24 18:22:41 -04:00 committed by Commit Bot
parent 6b55b8adba
commit 2dbd019bc2
6 changed files with 184 additions and 10 deletions

View File

@ -485,18 +485,37 @@ class CrashpadClient {
//! \brief Requests that the handler begin in-process uploading of any
//! pending reports.
//!
//! Once called the handler will start looking for pending reports to upload
//! on another thread. This method does not block.
//!
//! A handler must have already been installed before calling this method.
void EnableUploading();
void StartProcesingPendingReports();
// TODO(justincohen): This method is purely for bringing up iOS interfaces.
//! \brief Requests that the handler capture a dump even though there hasn't
//! been a crash.
//! \brief Requests that the handler capture an intermediate dump even though
//! there hasn't been a crash. The intermediate dump will be converted
//! to a mindump immediately. If StartProcesingPendingReports() has been
//! called, this will also trigger an upload.
//!
//! For internal use only. Clients should use CRASHPAD_SIMULATE_CRASH().
//!
//! A handler must have already been installed before calling this method.
//!
//! \param[in] context A NativeCPUContext, generally captured by
//! CaptureContext() or similar.
static void DumpWithoutCrash(NativeCPUContext* context);
//! \brief Requests that the handler capture an intermediate dump even though
//! there hasn't been a crash. The intermediate dump will not be converted
//! to a mindump until ProcessIntermediateDumps() is called.
//!
//! For internal use only. Clients should use
//! CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING().
//!
//! A handler must have already been installed before calling this method.
//!
//! \param[in] context A NativeCPUContext, generally captured by
//! CaptureContext() or similar.
static void DumpWithoutCrashAndDeferProcessing(NativeCPUContext* context);
#endif
#if defined(OS_APPLE) || DOXYGEN

View File

@ -234,7 +234,7 @@ void CrashpadClient::ProcessIntermediateDumps(
}
// static
void CrashpadClient::EnableUploading() {
void CrashpadClient::StartProcesingPendingReports() {
// TODO(justincohen): Start the CrashReportUploadThread.
}
@ -243,7 +243,17 @@ void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) {
CrashHandler* crash_handler = CrashHandler::Get();
DCHECK(crash_handler);
crash_handler->DumpWithoutCrash(context);
// TODO(justincohen): Change this to only process the dump from above, not all
// intermediate dump files.
crash_handler->ProcessIntermediateDumps();
}
// static
void CrashpadClient::DumpWithoutCrashAndDeferProcessing(
NativeCPUContext* context) {
CrashHandler* crash_handler = CrashHandler::Get();
DCHECK(crash_handler);
crash_handler->DumpWithoutCrash(context);
}
} // namespace crashpad

View File

@ -18,6 +18,7 @@
#include <vector>
#include "client/simulate_crash.h"
#include "gtest/gtest.h"
#include "test/scoped_temp_dir.h"
#include "testing/platform_test.h"
@ -33,9 +34,7 @@ TEST_F(CrashpadIOSClient, DumpWithoutCrash) {
ScopedTempDir database_dir;
client.StartCrashpadInProcessHandler(
base::FilePath(database_dir.path()), "", {});
NativeCPUContext context;
CaptureContext(&context);
client.DumpWithoutCrash(&context);
CRASHPAD_SIMULATE_CRASH();
}
// This test is covered by a similar XCUITest, but for development purposes it's

View File

@ -20,7 +20,11 @@
//! \file
//! \brief Captures the CPU context and captures a dump without an exception.
//! \brief Captures the CPU context and creates a minidump dump without an
//! exception. The minidump will immediately become eligible for further
//! processing, including upload.
//!
//! \sa CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING
#define CRASHPAD_SIMULATE_CRASH() \
do { \
crashpad::NativeCPUContext cpu_context; \
@ -28,4 +32,19 @@
crashpad::CrashpadClient::DumpWithoutCrash(&cpu_context); \
} while (false)
//! \brief Captures the CPU context and captures an intermediate dump without an
//! exception. Does not convert the intermediate dump into a minidump.
//!
//! Deferring processing is useful when the application may be in an unstable
//! state, such as during a hang.
//!
//! \sa CRASHPAD_SIMULATE_CRASH
#define CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING() \
do { \
crashpad::NativeCPUContext cpu_context; \
crashpad::CaptureContext(&cpu_context); \
crashpad::CrashpadClient::DumpWithoutCrashAndDeferProcessing( \
&cpu_context); \
} while (false)
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_IOS_H_

104
doc/ios_overview_design.md Normal file
View File

@ -0,0 +1,104 @@
<!--
Copyright 2021 The Crashpad Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# iOS Crashpad Overview Design
[TOC]
## iOS Limitations
Crashpad on other platforms captures exceptions out-of-process. The iOS sandbox,
however, restricts applications from delegating work to separate processes.
This limitation means Crashpad on iOS must combine the work of the handler and
the client into the same process as the main application.
## The Crashpad In-Process Handler
In-process handling comes with a number of limitations and difficulties. It is
not possible to catch the specific Mach exception `EXC_CRASH`, so certain groups
of crashes cannot be captured. This includes some major ones, like out-of-memory
crashes. This also introduces difficulties in capturing all the relevant crash
data and writing the minidump, as the process itself is in an unsafe state.
While handling an exception, the handler may not, for example:
- Allocate memory.
- Use libc, or most any library call.
While handling an exception, the handler may only:
- Use audited syscalls.
- access memory via `vm_read`.
In conjunction with Crashpads existing minidump writer and structural
limitations of the minidump format, it is not possible to write a minidump
immediately from the crash handler. Instead, an intermediate dump is written
when a handler would normally write a minidump (such as during an exception or a
forced dump without crashing). The intermediate dump file will be converted to
a minidump on the next run (or when the application decides it's safe to do so).
During Crashpad initialization, the handler gathers basic system information
and opens a pending intermediate dump adjacent to the Crashpad database.
## The Crashpad IntermediateDump Format
Due to the limitations of in-process handling, an intermediate dump file is
written during exceptions. The data is streamed to a file, which will be used to
generate a final minidump when appropriate.
The file format is similar to binary JSON, supporting keyed properties, maps and
arrays.
- `Property` [key:int, length:int, value:intarray]
- `StartMap` [key:int], followed by repeating Properties until `EndMap`
- `StartArray` [key:int], followed by repeating Maps until `EndArray`
- `EndMap`, `EndArray`, `EndDocument`
Similar to JSON, maps can contain other maps, arrays and properties.
## The Crashpad In-Process Client
Other Crashpad platforms handle exceptions and upload minidumps out-of-process.
On iOS, everything must happen in-process. Once started, the client will
automatically handle exceptions and capture the crashed process state in an
intermediate dump file. Converting that intermediate dump file into a minidump
is likely not safe to do from within a crashed process, and uploading a minidump
is definitely unsafe to do at crash time. Applications are expected to process
intermediate dumps into pending minidumps and begin processing pending
minidumps, possibly for upload, at suitable times following the next application
restart.
### `ProcessIntermediateDumps`
For performance and stability reasons applications may choose the correct time
to convert intermediate dumps, as well as append metadata to the pending
intermediate dumps. This is expected to happen during application startup, when
suitable. After converting, a minidump will be written to the Crashpad database,
similar to how other platforms write a minidump on exception handling. If
uploading is enabled, this minidump will also be immediately uploaded. New
intermediate dumps generated by exceptions or by
`CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING` will will not be processed until
the next call to `ProcessIntermediateDumps`. Conversely,
`CRASHPAD_SIMULATE_CRASH` can be called when the client has no performance or
stability concerns. In this case, intermediate dumps are automatically
converted to minidumps and immediately eligable for uploading.
### `StartProcesingPendingReports`
For similar reasons, applications may choose the correct time to begin uploading
pending reports, such as when ideal network conditions exist. By default,
clients start with uploading disabled. Applications should call this API when
it is determined that it is appropriate to do so (such as on a few seconds after
startup, or when network connectivity is appropriate).

View File

@ -93,7 +93,8 @@ The handler runs in a separate process from the client or clients. It is
responsible for snapshotting the crashing client process state on a crash,
saving it to a crash dump, and transmitting the crash dump to an upstream
server. Clients register with the handler to allow it to capture and upload
their crashes.
their crashes. On iOS, there is no separate process for the handler.
[This is a limitation of iOS.](ios_overview_design.md#ios-limitations)
### The Crashpad handler
@ -213,6 +214,12 @@ Crashpad provides a facility for a process to disassociate (unregister) with an
existing crash handler, which can be necessary when an older client spawns an
updated version.
#### iOS
iOS registers both a signal handler for `SIGABRT` and a Mach exception handler
with a subset of available exceptions. [This is a limitation of
iOS.](ios_overview_design.md#ios-limitations)
#### Windows
There are two modes of registration on Windows. In both cases the handler is
@ -272,6 +279,14 @@ dispatched to the Mach port by the kernel, on macOS, exceptions can be handled
entirely from the Crashpad handler without the need to run any code in the crash
process at the time of the exception.
#### iOS
On iOS, the operating system will notify the handler of crashes via the Mach
exception port or the signal handler. As exceptions are handled in-process, an
intermediate dump file is generated rather than a minidump. See more
information about the [iOS in-process
handler.](ios_overview_design.md#ios-in-process-handler)
#### Windows
On Windows, the OS dispatches exceptions in the context of the crashing thread.
@ -415,6 +430,14 @@ details of how these properties are stored vary between platforms.
The macOS implementation simply stores database properties on the minidump files
in filesystem extended attributes.
#### iOS
The iOS implementation also stores database properties of minidump files in
filesystem extended attributes. Separate from the database, iOS also stores its
intermediate dump files adjacent to the database. See more information about
[iOS intermediate
dumps.](ios_overview_design.md#the-crashpad-intermediatedump-format)
#### Windows
The Windows implementation stores database properties in a binary file named