crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.cc
Justin Cohen 30b2f4ba38 ios: Add crashpad_uptime_ns crash key to iOS reports.
This CL introduces a new crash key 'crashpad_uptime_ns' that records the
number of nanoseconds between when Crashpad was initialized and when a
snapshot is generated.

Crashpad minidumps record the MDRawMiscInfo process_create_time using a
sysctl(KERN_PROC).kp_proc.p_starttime. This time is used to display the
'uptime' of a process.  However, iOS 15 and later has a feature that
'prewarms' the app to reduce the amount of time the user waits before
the app is usable. This mean crashes that may happen immediately on
startup would appear to happen minutes or hours after process creation
time.

While initial implementations of prewarming would include some parts of
main, since iOS16 prewarming is complete before main, and therefore
before Crashpad is typically initialized.

Bug: crashpad:472
Change-Id: Iff960e37ae40121bd5927d319a2767d1cafce846
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/5171091
Reviewed-by: Ben Hamilton <benhamilton@google.com>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Justin Cohen <justincohen@chromium.org>
2024-01-11 16:42:54 +00:00

261 lines
8.6 KiB
C++

// Copyright 2020 The Crashpad Authors
//
// 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.
#include "snapshot/ios/system_snapshot_ios_intermediate_dump.h"
#include <mach/mach.h>
#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <algorithm>
#include "base/apple/mach_logging.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "snapshot/cpu_context.h"
#include "snapshot/ios/intermediate_dump_reader_util.h"
#include "snapshot/posix/timezone.h"
#include "util/ios/ios_intermediate_dump_data.h"
#include "util/mac/mac_util.h"
#include "util/numeric/in_range_cast.h"
namespace crashpad {
namespace internal {
using Key = IntermediateDumpKey;
SystemSnapshotIOSIntermediateDump::SystemSnapshotIOSIntermediateDump()
: SystemSnapshot(),
os_version_build_(),
machine_description_(),
os_version_major_(0),
os_version_minor_(0),
os_version_bugfix_(0),
active_(0),
inactive_(0),
wired_(0),
free_(0),
cpu_count_(0),
cpu_vendor_(),
dst_status_(),
standard_offset_seconds_(0),
daylight_offset_seconds_(0),
standard_name_(),
daylight_name_(),
address_mask_(0),
initialized_() {}
SystemSnapshotIOSIntermediateDump::~SystemSnapshotIOSIntermediateDump() {}
void SystemSnapshotIOSIntermediateDump::Initialize(
const IOSIntermediateDumpMap* system_data) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
GetDataStringFromMap(system_data, Key::kOSVersionBuild, &os_version_build_);
GetDataStringFromMap(
system_data, Key::kMachineDescription, &machine_description_);
GetDataStringFromMap(system_data, Key::kCpuVendor, &cpu_vendor_);
GetDataStringFromMap(system_data, Key::kStandardName, &standard_name_);
GetDataStringFromMap(system_data, Key::kDaylightName, &daylight_name_);
GetDataValueFromMap(system_data, Key::kOSVersionMajor, &os_version_major_);
GetDataValueFromMap(system_data, Key::kOSVersionMinor, &os_version_minor_);
GetDataValueFromMap(system_data, Key::kOSVersionBugfix, &os_version_bugfix_);
GetDataValueFromMap(system_data, Key::kCpuCount, &cpu_count_);
GetDataValueFromMap(
system_data, Key::kStandardOffsetSeconds, &standard_offset_seconds_);
GetDataValueFromMap(
system_data, Key::kDaylightOffsetSeconds, &daylight_offset_seconds_);
bool has_daylight_saving_time;
GetDataValueFromMap(
system_data, Key::kHasDaylightSavingTime, &has_daylight_saving_time);
bool is_daylight_saving_time;
GetDataValueFromMap(
system_data, Key::kIsDaylightSavingTime, &is_daylight_saving_time);
if (has_daylight_saving_time) {
dst_status_ = is_daylight_saving_time
? SystemSnapshot::kObservingDaylightSavingTime
: SystemSnapshot::kObservingStandardTime;
} else {
dst_status_ = SystemSnapshot::kDoesNotObserveDaylightSavingTime;
}
GetDataValueFromMap(system_data, Key::kAddressMask, &address_mask_);
vm_size_t page_size;
if (GetDataValueFromMap(system_data, Key::kPageSize, &page_size)) {
const IOSIntermediateDumpMap* vm_stat =
GetMapFromMap(system_data, Key::kVMStat);
if (vm_stat) {
GetDataValueFromMap(vm_stat, Key::kActive, &active_);
active_ *= page_size;
GetDataValueFromMap(vm_stat, Key::kInactive, &inactive_);
inactive_ *= page_size;
GetDataValueFromMap(vm_stat, Key::kWired, &wired_);
wired_ *= page_size;
GetDataValueFromMap(vm_stat, Key::kFree, &free_);
free_ *= page_size;
}
}
GetDataValueFromMap(system_data, Key::kCrashpadUptime, &crashpad_uptime_ns_);
INITIALIZATION_STATE_SET_VALID(initialized_);
}
CPUArchitecture SystemSnapshotIOSIntermediateDump::GetCPUArchitecture() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_64)
return kCPUArchitectureX86_64;
#elif defined(ARCH_CPU_ARM64)
return kCPUArchitectureARM64;
#endif
}
uint32_t SystemSnapshotIOSIntermediateDump::CPURevision() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): sysctlbyname machdep.cpu.* returns -1 on iOS/ARM64, but
// consider recording this for X86_64 only.
return 0;
}
uint8_t SystemSnapshotIOSIntermediateDump::CPUCount() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return cpu_count_;
}
std::string SystemSnapshotIOSIntermediateDump::CPUVendor() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return cpu_vendor_;
}
void SystemSnapshotIOSIntermediateDump::CPUFrequency(uint64_t* current_hz,
uint64_t* max_hz) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): sysctlbyname hw.cpufrequency returns -1 on iOS/ARM64,
// but consider recording this for X86_64 only.
*current_hz = 0;
*max_hz = 0;
}
uint32_t SystemSnapshotIOSIntermediateDump::CPUX86Signature() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): Consider recording this for X86_64 only.
return 0;
}
uint64_t SystemSnapshotIOSIntermediateDump::CPUX86Features() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): Consider recording this for X86_64 only.
return 0;
}
uint64_t SystemSnapshotIOSIntermediateDump::CPUX86ExtendedFeatures() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): Consider recording this for X86_64 only.
return 0;
}
uint32_t SystemSnapshotIOSIntermediateDump::CPUX86Leaf7Features() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): Consider recording this for X86_64 only.
return 0;
}
bool SystemSnapshotIOSIntermediateDump::CPUX86SupportsDAZ() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): Consider recording this for X86_64 only.
return false;
}
SystemSnapshot::OperatingSystem
SystemSnapshotIOSIntermediateDump::GetOperatingSystem() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return kOperatingSystemIOS;
}
bool SystemSnapshotIOSIntermediateDump::OSServer() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return false;
}
void SystemSnapshotIOSIntermediateDump::OSVersion(int* major,
int* minor,
int* bugfix,
std::string* build) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*major = os_version_major_;
*minor = os_version_minor_;
*bugfix = os_version_bugfix_;
build->assign(os_version_build_);
}
std::string SystemSnapshotIOSIntermediateDump::OSVersionFull() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return base::StringPrintf("%d.%d.%d %s",
os_version_major_,
os_version_minor_,
os_version_bugfix_,
os_version_build_.c_str());
}
std::string SystemSnapshotIOSIntermediateDump::MachineDescription() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return machine_description_;
}
bool SystemSnapshotIOSIntermediateDump::NXEnabled() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
// TODO(justincohen): Consider using kern.nx when available (pre-iOS 13,
// pre-OS X 10.15). Otherwise the bit is always enabled.
return true;
}
void SystemSnapshotIOSIntermediateDump::TimeZone(
DaylightSavingTimeStatus* dst_status,
int* standard_offset_seconds,
int* daylight_offset_seconds,
std::string* standard_name,
std::string* daylight_name) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*dst_status = dst_status_;
*standard_offset_seconds = standard_offset_seconds_;
*daylight_offset_seconds = daylight_offset_seconds_;
standard_name->assign(standard_name_);
daylight_name->assign(daylight_name_);
}
uint64_t SystemSnapshotIOSIntermediateDump::AddressMask() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return address_mask_;
}
uint64_t SystemSnapshotIOSIntermediateDump::CrashpadUptime() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return crashpad_uptime_ns_;
}
} // namespace internal
} // namespace crashpad