2022-09-06 19:14:07 -04:00
|
|
|
// Copyright 2021 The Crashpad Authors
|
2021-10-14 10:55:03 -04:00
|
|
|
//
|
|
|
|
// 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 "client/ios_handler/in_process_handler.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
#include <algorithm>
|
|
|
|
|
2021-10-14 10:55:03 -04:00
|
|
|
#include "base/logging.h"
|
|
|
|
#include "client/ios_handler/in_process_intermediate_dump_handler.h"
|
2021-10-25 11:35:19 -04:00
|
|
|
#include "client/prune_crash_reports.h"
|
2021-10-14 10:55:03 -04:00
|
|
|
#include "client/settings.h"
|
|
|
|
#include "minidump/minidump_file_writer.h"
|
|
|
|
#include "util/file/directory_reader.h"
|
|
|
|
#include "util/file/filesystem.h"
|
2022-01-20 10:04:00 -07:00
|
|
|
#include "util/ios/raw_logging.h"
|
2021-10-14 10:55:03 -04:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Creates directory at |path|.
|
2021-10-27 12:31:45 -04:00
|
|
|
bool CreateDirectory(const base::FilePath& path) {
|
2021-10-14 10:55:03 -04:00
|
|
|
if (mkdir(path.value().c_str(), 0755) == 0) {
|
2021-10-27 12:31:45 -04:00
|
|
|
return true;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
if (errno != EEXIST) {
|
|
|
|
PLOG(ERROR) << "mkdir " << path.value();
|
2021-10-27 12:31:45 -04:00
|
|
|
return false;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
2021-10-27 12:31:45 -04:00
|
|
|
return true;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2021-10-19 13:53:37 -04:00
|
|
|
// The file extension used to indicate a file is locked.
|
|
|
|
constexpr char kLockedExtension[] = ".locked";
|
|
|
|
|
|
|
|
// The seperator used to break the bundle id (e.g. com.chromium.ios) from the
|
|
|
|
// uuid in the intermediate dump file name.
|
|
|
|
constexpr char kBundleSeperator[] = "@";
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
// Zero-ed codes used by kMachExceptionFromNSException and
|
|
|
|
// kMachExceptionSimulated.
|
|
|
|
constexpr mach_exception_data_type_t kEmulatedMachExceptionCodes[2] = {};
|
|
|
|
|
2021-10-14 10:55:03 -04:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
InProcessHandler::InProcessHandler() = default;
|
|
|
|
|
|
|
|
InProcessHandler::~InProcessHandler() {
|
2022-05-17 15:18:21 -06:00
|
|
|
if (cached_writer_) {
|
|
|
|
cached_writer_->Close();
|
|
|
|
}
|
2022-09-15 13:14:19 -06:00
|
|
|
UpdatePruneAndUploadThreads(false, UploadBehavior::kUploadWhenAppIsActive);
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool InProcessHandler::Initialize(
|
|
|
|
const base::FilePath& database,
|
|
|
|
const std::string& url,
|
2022-09-09 15:25:08 -06:00
|
|
|
const std::map<std::string, std::string>& annotations,
|
|
|
|
ProcessPendingReportsObservationCallback callback) {
|
2021-10-14 10:55:03 -04:00
|
|
|
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
|
|
|
annotations_ = annotations;
|
|
|
|
database_ = CrashReportDatabase::Initialize(database);
|
2021-10-27 12:31:45 -04:00
|
|
|
if (!database_) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-10-19 13:53:37 -04:00
|
|
|
bundle_identifier_and_seperator_ =
|
2022-03-10 14:12:57 -05:00
|
|
|
system_data_.BundleIdentifier() + kBundleSeperator;
|
2021-10-14 10:55:03 -04:00
|
|
|
|
|
|
|
if (!url.empty()) {
|
|
|
|
// TODO(scottmg): options.rate_limit should be removed when we have a
|
|
|
|
// configurable database setting to control upload limiting.
|
|
|
|
// See https://crashpad.chromium.org/bug/23.
|
|
|
|
CrashReportUploadThread::Options upload_thread_options;
|
|
|
|
upload_thread_options.rate_limit = false;
|
|
|
|
upload_thread_options.upload_gzip = true;
|
|
|
|
upload_thread_options.watch_pending_reports = true;
|
|
|
|
upload_thread_options.identify_client_via_url = true;
|
|
|
|
|
|
|
|
upload_thread_.reset(new CrashReportUploadThread(
|
2022-09-09 15:25:08 -06:00
|
|
|
database_.get(), url, upload_thread_options, callback));
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2021-10-27 12:31:45 -04:00
|
|
|
if (!CreateDirectory(database))
|
|
|
|
return false;
|
2021-10-14 10:55:03 -04:00
|
|
|
static constexpr char kPendingSerializediOSDump[] =
|
|
|
|
"pending-serialized-ios-dump";
|
|
|
|
base_dir_ = database.Append(kPendingSerializediOSDump);
|
2021-10-27 12:31:45 -04:00
|
|
|
if (!CreateDirectory(base_dir_))
|
|
|
|
return false;
|
2021-10-14 10:55:03 -04:00
|
|
|
|
2022-03-22 22:37:00 -04:00
|
|
|
bool is_app_extension = system_data_.IsExtension();
|
2021-10-25 11:35:19 -04:00
|
|
|
prune_thread_.reset(new PruneIntermediateDumpsAndCrashReportsThread(
|
|
|
|
database_.get(),
|
|
|
|
PruneCondition::GetDefault(),
|
|
|
|
base_dir_,
|
|
|
|
bundle_identifier_and_seperator_,
|
2022-03-22 22:37:00 -04:00
|
|
|
is_app_extension));
|
|
|
|
if (is_app_extension || system_data_.IsApplicationActive())
|
|
|
|
prune_thread_->Start();
|
|
|
|
|
|
|
|
if (!is_app_extension) {
|
2022-04-11 19:38:51 -04:00
|
|
|
system_data_.SetActiveApplicationCallback([this](bool active) {
|
|
|
|
dispatch_async(
|
|
|
|
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
2022-09-15 13:14:19 -06:00
|
|
|
UpdatePruneAndUploadThreads(active,
|
|
|
|
UploadBehavior::kUploadWhenAppIsActive);
|
2022-04-11 19:38:51 -04:00
|
|
|
});
|
|
|
|
});
|
2022-03-22 22:37:00 -04:00
|
|
|
}
|
2021-10-25 11:35:19 -04:00
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
base::FilePath cached_writer_path = NewLockedFilePath();
|
|
|
|
cached_writer_ = CreateWriterWithPath(cached_writer_path);
|
|
|
|
if (!cached_writer_.get())
|
2021-10-14 10:55:03 -04:00
|
|
|
return false;
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
// Cache the locked and unlocked path here so no allocations are needed during
|
|
|
|
// any exceptions.
|
|
|
|
cached_writer_path_ = cached_writer_path.value();
|
|
|
|
cached_writer_unlocked_path_ =
|
|
|
|
cached_writer_path.RemoveFinalExtension().value();
|
2021-10-14 10:55:03 -04:00
|
|
|
INITIALIZATION_STATE_SET_VALID(initialized_);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-03-10 14:12:57 -05:00
|
|
|
void InProcessHandler::DumpExceptionFromSignal(siginfo_t* siginfo,
|
|
|
|
ucontext_t* context) {
|
2021-10-14 10:55:03 -04:00
|
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
2022-03-08 18:20:41 -05:00
|
|
|
ScopedLockedWriter writer(GetCachedWriter(),
|
|
|
|
cached_writer_path_.c_str(),
|
|
|
|
cached_writer_unlocked_path_.c_str());
|
|
|
|
if (!writer.GetWriter()) {
|
|
|
|
CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer");
|
2022-01-20 10:04:00 -07:00
|
|
|
return;
|
|
|
|
}
|
2022-03-10 14:12:57 -05:00
|
|
|
ScopedReport report(writer.GetWriter(), system_data_, annotations_);
|
2022-03-08 18:20:41 -05:00
|
|
|
InProcessIntermediateDumpHandler::WriteExceptionFromSignal(
|
2022-03-10 14:12:57 -05:00
|
|
|
writer.GetWriter(), system_data_, siginfo, context);
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InProcessHandler::DumpExceptionFromMachException(
|
|
|
|
exception_behavior_t behavior,
|
|
|
|
thread_t thread,
|
|
|
|
exception_type_t exception,
|
|
|
|
const mach_exception_data_type_t* code,
|
|
|
|
mach_msg_type_number_t code_count,
|
|
|
|
thread_state_flavor_t flavor,
|
|
|
|
ConstThreadState old_state,
|
|
|
|
mach_msg_type_number_t old_state_count) {
|
|
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
2022-03-08 18:20:41 -05:00
|
|
|
ScopedLockedWriter writer(GetCachedWriter(),
|
|
|
|
cached_writer_path_.c_str(),
|
|
|
|
cached_writer_unlocked_path_.c_str());
|
|
|
|
if (!writer.GetWriter()) {
|
|
|
|
CRASHPAD_RAW_LOG("Cannot DumpExceptionFromMachException without writer");
|
2022-01-20 10:04:00 -07:00
|
|
|
return;
|
|
|
|
}
|
2022-03-08 18:20:41 -05:00
|
|
|
|
|
|
|
if (mach_exception_callback_for_testing_) {
|
|
|
|
mach_exception_callback_for_testing_();
|
|
|
|
}
|
|
|
|
|
2022-03-10 14:12:57 -05:00
|
|
|
ScopedReport report(writer.GetWriter(), system_data_, annotations_);
|
2022-03-08 18:20:41 -05:00
|
|
|
InProcessIntermediateDumpHandler::WriteExceptionFromMachException(
|
|
|
|
writer.GetWriter(),
|
|
|
|
behavior,
|
|
|
|
thread,
|
|
|
|
exception,
|
|
|
|
code,
|
|
|
|
code_count,
|
|
|
|
flavor,
|
|
|
|
old_state,
|
|
|
|
old_state_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InProcessHandler::DumpExceptionFromNSExceptionWithFrames(
|
2021-10-14 10:55:03 -04:00
|
|
|
const uint64_t* frames,
|
|
|
|
const size_t num_frames) {
|
2022-01-20 10:04:00 -07:00
|
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
2022-03-08 18:20:41 -05:00
|
|
|
ScopedLockedWriter writer(GetCachedWriter(),
|
|
|
|
cached_writer_path_.c_str(),
|
|
|
|
cached_writer_unlocked_path_.c_str());
|
|
|
|
if (!writer.GetWriter()) {
|
2022-01-20 10:04:00 -07:00
|
|
|
CRASHPAD_RAW_LOG(
|
2022-03-08 18:20:41 -05:00
|
|
|
"Cannot DumpExceptionFromNSExceptionWithFrames without writer");
|
2022-01-20 10:04:00 -07:00
|
|
|
return;
|
|
|
|
}
|
2022-03-08 18:20:41 -05:00
|
|
|
ScopedReport report(
|
2022-03-10 14:12:57 -05:00
|
|
|
writer.GetWriter(), system_data_, annotations_, frames, num_frames);
|
2022-03-08 18:20:41 -05:00
|
|
|
InProcessIntermediateDumpHandler::WriteExceptionFromNSException(
|
|
|
|
writer.GetWriter());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InProcessHandler::DumpExceptionFromSimulatedMachException(
|
|
|
|
const NativeCPUContext* context,
|
2022-03-24 19:43:01 -04:00
|
|
|
exception_type_t exception,
|
2022-03-08 18:20:41 -05:00
|
|
|
base::FilePath* path) {
|
|
|
|
base::FilePath locked_path = NewLockedFilePath();
|
|
|
|
*path = locked_path.RemoveFinalExtension();
|
2022-03-24 19:43:01 -04:00
|
|
|
return DumpExceptionFromSimulatedMachExceptionAtPath(
|
|
|
|
context, exception, locked_path);
|
2022-03-08 18:20:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath(
|
|
|
|
const NativeCPUContext* context,
|
2022-03-24 19:43:01 -04:00
|
|
|
exception_type_t exception,
|
2022-03-08 18:20:41 -05:00
|
|
|
const base::FilePath& path) {
|
|
|
|
// This does not use the cached writer. It's expected that simulated
|
|
|
|
// exceptions can be called multiple times and there is no expectation that
|
|
|
|
// the application is in an unsafe state, or will be terminated after this
|
|
|
|
// call.
|
|
|
|
std::unique_ptr<IOSIntermediateDumpWriter> unsafe_writer =
|
|
|
|
CreateWriterWithPath(path);
|
|
|
|
base::FilePath writer_path_unlocked = path.RemoveFinalExtension();
|
|
|
|
ScopedLockedWriter writer(unsafe_writer.get(),
|
|
|
|
path.value().c_str(),
|
|
|
|
writer_path_unlocked.value().c_str());
|
|
|
|
if (!writer.GetWriter()) {
|
|
|
|
CRASHPAD_RAW_LOG(
|
|
|
|
"Cannot DumpExceptionFromSimulatedMachExceptionAtPath without writer");
|
|
|
|
return false;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
2022-03-10 14:12:57 -05:00
|
|
|
ScopedReport report(writer.GetWriter(), system_data_, annotations_);
|
2022-03-08 18:20:41 -05:00
|
|
|
InProcessIntermediateDumpHandler::WriteExceptionFromMachException(
|
|
|
|
writer.GetWriter(),
|
|
|
|
MACH_EXCEPTION_CODES,
|
|
|
|
mach_thread_self(),
|
2022-03-24 19:43:01 -04:00
|
|
|
exception,
|
2022-03-08 18:20:41 -05:00
|
|
|
kEmulatedMachExceptionCodes,
|
|
|
|
std::size(kEmulatedMachExceptionCodes),
|
|
|
|
MACHINE_THREAD_STATE,
|
|
|
|
reinterpret_cast<ConstThreadState>(context),
|
|
|
|
MACHINE_THREAD_STATE_COUNT);
|
|
|
|
return true;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2022-03-24 19:43:01 -04:00
|
|
|
bool InProcessHandler::MoveIntermediateDumpAtPathToPending(
|
|
|
|
const base::FilePath& path) {
|
|
|
|
base::FilePath new_path_unlocked = NewLockedFilePath().RemoveFinalExtension();
|
|
|
|
return MoveFileOrDirectory(path, new_path_unlocked);
|
|
|
|
}
|
2021-10-14 10:55:03 -04:00
|
|
|
void InProcessHandler::ProcessIntermediateDumps(
|
2021-11-10 13:04:10 -05:00
|
|
|
const std::map<std::string, std::string>& annotations) {
|
2021-10-14 10:55:03 -04:00
|
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
|
|
|
|
for (auto& file : PendingFiles())
|
2021-11-10 13:04:10 -05:00
|
|
|
ProcessIntermediateDump(file, annotations);
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InProcessHandler::ProcessIntermediateDump(
|
|
|
|
const base::FilePath& file,
|
2021-11-10 13:04:10 -05:00
|
|
|
const std::map<std::string, std::string>& annotations) {
|
2021-10-14 10:55:03 -04:00
|
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
|
2021-11-10 13:04:10 -05:00
|
|
|
ProcessSnapshotIOSIntermediateDump process_snapshot;
|
2021-11-20 23:03:45 -05:00
|
|
|
if (process_snapshot.InitializeWithFilePath(file, annotations)) {
|
2021-11-10 13:04:10 -05:00
|
|
|
SaveSnapshot(process_snapshot);
|
|
|
|
}
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2022-09-15 13:14:19 -06:00
|
|
|
void InProcessHandler::StartProcessingPendingReports(
|
|
|
|
UploadBehavior upload_behavior) {
|
2022-03-22 22:37:00 -04:00
|
|
|
if (!upload_thread_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
upload_thread_enabled_ = true;
|
2022-04-20 00:09:00 -04:00
|
|
|
|
|
|
|
// This may be a no-op if IsApplicationActive is false, as it is not safe to
|
|
|
|
// start the upload thread when in the background (due to the potential for
|
|
|
|
// flocked files in shared containers).
|
|
|
|
// TODO(crbug.com/crashpad/400): Consider moving prune and upload thread to
|
|
|
|
// BackgroundTasks and/or NSURLSession. This might allow uploads to continue
|
|
|
|
// in the background.
|
2022-09-15 13:14:19 -06:00
|
|
|
UpdatePruneAndUploadThreads(system_data_.IsApplicationActive(),
|
|
|
|
upload_behavior);
|
2022-03-22 22:37:00 -04:00
|
|
|
}
|
|
|
|
|
2022-09-15 13:14:19 -06:00
|
|
|
void InProcessHandler::UpdatePruneAndUploadThreads(
|
|
|
|
bool active,
|
|
|
|
UploadBehavior upload_behavior) {
|
2022-03-22 22:37:00 -04:00
|
|
|
base::AutoLock lock_owner(prune_and_upload_lock_);
|
|
|
|
// TODO(crbug.com/crashpad/400): Consider moving prune and upload thread to
|
|
|
|
// BackgroundTasks and/or NSURLSession. This might allow uploads to continue
|
|
|
|
// in the background.
|
2022-09-15 13:14:19 -06:00
|
|
|
bool threads_should_run;
|
|
|
|
switch (upload_behavior) {
|
|
|
|
case UploadBehavior::kUploadWhenAppIsActive:
|
|
|
|
threads_should_run = active;
|
|
|
|
break;
|
|
|
|
case UploadBehavior::kUploadImmediately:
|
|
|
|
threads_should_run = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (threads_should_run) {
|
2022-03-22 22:37:00 -04:00
|
|
|
if (!prune_thread_->is_running())
|
|
|
|
prune_thread_->Start();
|
|
|
|
if (upload_thread_enabled_ && !upload_thread_->is_running()) {
|
|
|
|
upload_thread_->Start();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (prune_thread_->is_running())
|
|
|
|
prune_thread_->Stop();
|
|
|
|
if (upload_thread_enabled_ && upload_thread_->is_running())
|
|
|
|
upload_thread_->Stop();
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InProcessHandler::SaveSnapshot(
|
|
|
|
ProcessSnapshotIOSIntermediateDump& process_snapshot) {
|
|
|
|
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
|
|
|
CrashReportDatabase::OperationStatus database_status =
|
|
|
|
database_->PrepareNewCrashReport(&new_report);
|
|
|
|
if (database_status != CrashReportDatabase::kNoError) {
|
|
|
|
Metrics::ExceptionCaptureResult(
|
|
|
|
Metrics::CaptureResult::kPrepareNewCrashReportFailed);
|
2022-04-18 14:28:19 -04:00
|
|
|
return;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
process_snapshot.SetReportID(new_report->ReportID());
|
|
|
|
|
2021-11-21 00:46:19 -05:00
|
|
|
UUID client_id;
|
|
|
|
Settings* const settings = database_->GetSettings();
|
|
|
|
if (settings && settings->GetClientID(&client_id)) {
|
|
|
|
process_snapshot.SetClientID(client_id);
|
|
|
|
}
|
|
|
|
|
2021-10-14 10:55:03 -04:00
|
|
|
MinidumpFileWriter minidump;
|
|
|
|
minidump.InitializeFromSnapshot(&process_snapshot);
|
|
|
|
if (!minidump.WriteEverything(new_report->Writer())) {
|
|
|
|
Metrics::ExceptionCaptureResult(
|
|
|
|
Metrics::CaptureResult::kMinidumpWriteFailed);
|
2022-04-18 14:28:19 -04:00
|
|
|
return;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
UUID uuid;
|
|
|
|
database_status =
|
|
|
|
database_->FinishedWritingCrashReport(std::move(new_report), &uuid);
|
|
|
|
if (database_status != CrashReportDatabase::kNoError) {
|
|
|
|
Metrics::ExceptionCaptureResult(
|
|
|
|
Metrics::CaptureResult::kFinishedWritingCrashReportFailed);
|
2022-04-18 14:28:19 -04:00
|
|
|
return;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (upload_thread_) {
|
|
|
|
upload_thread_->ReportPending(uuid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<base::FilePath> InProcessHandler::PendingFiles() {
|
|
|
|
DirectoryReader reader;
|
|
|
|
std::vector<base::FilePath> files;
|
|
|
|
if (!reader.Open(base_dir_)) {
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
base::FilePath file;
|
|
|
|
DirectoryReader::Result result;
|
2021-11-11 06:32:46 -05:00
|
|
|
|
|
|
|
// Because the intermediate dump directory is expected to be shared,
|
|
|
|
// mitigate any spamming by limiting this to |kMaxPendingFiles|.
|
|
|
|
constexpr size_t kMaxPendingFiles = 20;
|
|
|
|
|
|
|
|
// Track other application bundles separately, so they don't spam our
|
|
|
|
// intermediate dumps into never getting processed.
|
|
|
|
std::vector<base::FilePath> other_files;
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
base::FilePath cached_writer_path(cached_writer_path_);
|
2021-10-14 10:55:03 -04:00
|
|
|
while ((result = reader.NextFile(&file)) ==
|
|
|
|
DirectoryReader::Result::kSuccess) {
|
2021-10-19 13:53:37 -04:00
|
|
|
// Don't try to process files marked as 'locked' from a different bundle id.
|
2021-11-11 06:32:46 -05:00
|
|
|
bool bundle_match =
|
|
|
|
file.value().compare(0,
|
2021-10-19 13:53:37 -04:00
|
|
|
bundle_identifier_and_seperator_.size(),
|
2021-11-11 06:32:46 -05:00
|
|
|
bundle_identifier_and_seperator_) == 0;
|
|
|
|
if (!bundle_match && file.FinalExtension() == kLockedExtension) {
|
2021-10-19 13:53:37 -04:00
|
|
|
continue;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
2021-10-19 13:53:37 -04:00
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
// Never process the current cached writer path.
|
2021-10-19 13:53:37 -04:00
|
|
|
file = base_dir_.Append(file);
|
2022-03-08 18:20:41 -05:00
|
|
|
if (file == cached_writer_path)
|
2021-10-19 13:53:37 -04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Otherwise, include any other unlocked, or locked files matching
|
|
|
|
// |bundle_identifier_and_seperator_|.
|
2021-11-11 06:32:46 -05:00
|
|
|
if (bundle_match) {
|
|
|
|
files.push_back(file);
|
|
|
|
if (files.size() >= kMaxPendingFiles)
|
|
|
|
return files;
|
|
|
|
} else {
|
|
|
|
other_files.push_back(file);
|
|
|
|
}
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
2021-11-11 06:32:46 -05:00
|
|
|
|
|
|
|
auto end_iterator =
|
|
|
|
other_files.begin() +
|
|
|
|
std::min(kMaxPendingFiles - files.size(), other_files.size());
|
|
|
|
files.insert(files.end(), other_files.begin(), end_iterator);
|
2021-10-14 10:55:03 -04:00
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
IOSIntermediateDumpWriter* InProcessHandler::GetCachedWriter() {
|
|
|
|
static_assert(
|
|
|
|
std::atomic<uint64_t>::is_always_lock_free,
|
|
|
|
"std::atomic_compare_exchange_strong uint64_t may not be signal-safe");
|
|
|
|
uint64_t thread_self;
|
|
|
|
// This is only safe when passing pthread_self(), otherwise this can lock.
|
|
|
|
pthread_threadid_np(pthread_self(), &thread_self);
|
|
|
|
uint64_t expected = 0;
|
|
|
|
if (!std::atomic_compare_exchange_strong(
|
|
|
|
&exception_thread_id_, &expected, thread_self)) {
|
|
|
|
if (expected == thread_self) {
|
|
|
|
// Another exception came in from this thread, which means it's likely
|
|
|
|
// that our own handler crashed. We could open up a new intermediate dump
|
|
|
|
// and try to save this dump, but we could end up endlessly writing dumps.
|
|
|
|
// Instead, give up.
|
|
|
|
} else {
|
|
|
|
// Another thread is handling a crash. Sleep forever.
|
|
|
|
while (1) {
|
|
|
|
sleep(std::numeric_limits<unsigned int>::max());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-10-14 10:55:03 -04:00
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
return cached_writer_.get();
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
std::unique_ptr<IOSIntermediateDumpWriter>
|
|
|
|
InProcessHandler::CreateWriterWithPath(const base::FilePath& writer_path) {
|
|
|
|
std::unique_ptr<IOSIntermediateDumpWriter> writer =
|
|
|
|
std::make_unique<IOSIntermediateDumpWriter>();
|
|
|
|
if (!writer->Open(writer_path)) {
|
|
|
|
DLOG(ERROR) << "Unable to open intermediate dump file: "
|
|
|
|
<< writer_path.value();
|
|
|
|
return nullptr;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
2022-03-08 18:20:41 -05:00
|
|
|
return writer;
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
const base::FilePath InProcessHandler::NewLockedFilePath() {
|
|
|
|
UUID uuid;
|
|
|
|
uuid.InitializeWithNew();
|
|
|
|
const std::string file_string =
|
|
|
|
bundle_identifier_and_seperator_ + uuid.ToString() + kLockedExtension;
|
|
|
|
return base_dir_.Append(file_string);
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
InProcessHandler::ScopedReport::ScopedReport(
|
|
|
|
IOSIntermediateDumpWriter* writer,
|
|
|
|
const IOSSystemDataCollector& system_data,
|
2021-11-10 13:04:10 -05:00
|
|
|
const std::map<std::string, std::string>& annotations,
|
2021-10-14 10:55:03 -04:00
|
|
|
const uint64_t* frames,
|
|
|
|
const size_t num_frames)
|
2021-11-22 15:18:15 -05:00
|
|
|
: writer_(writer),
|
|
|
|
frames_(frames),
|
|
|
|
num_frames_(num_frames),
|
|
|
|
rootMap_(writer) {
|
2022-01-20 10:04:00 -07:00
|
|
|
DCHECK(writer);
|
2021-10-14 10:55:03 -04:00
|
|
|
InProcessIntermediateDumpHandler::WriteHeader(writer);
|
2021-11-10 13:04:10 -05:00
|
|
|
InProcessIntermediateDumpHandler::WriteProcessInfo(writer, annotations);
|
2021-10-14 10:55:03 -04:00
|
|
|
InProcessIntermediateDumpHandler::WriteSystemInfo(writer, system_data);
|
2021-11-22 15:18:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
InProcessHandler::ScopedReport::~ScopedReport() {
|
|
|
|
// Write threads and modules last (after the exception itself is written by
|
|
|
|
// DumpExceptionFrom*.)
|
|
|
|
InProcessIntermediateDumpHandler::WriteThreadInfo(
|
|
|
|
writer_, frames_, num_frames_);
|
|
|
|
InProcessIntermediateDumpHandler::WriteModuleInfo(writer_);
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
InProcessHandler::ScopedLockedWriter::ScopedLockedWriter(
|
|
|
|
IOSIntermediateDumpWriter* writer,
|
|
|
|
const char* writer_path,
|
|
|
|
const char* writer_unlocked_path)
|
|
|
|
: writer_path_(writer_path),
|
|
|
|
writer_unlocked_path_(writer_unlocked_path),
|
|
|
|
writer_(writer) {}
|
|
|
|
|
|
|
|
InProcessHandler::ScopedLockedWriter::~ScopedLockedWriter() {
|
|
|
|
if (!writer_)
|
|
|
|
return;
|
2021-10-14 10:55:03 -04:00
|
|
|
|
2022-03-08 18:20:41 -05:00
|
|
|
writer_->Close();
|
|
|
|
if (rename(writer_path_, writer_unlocked_path_) != 0) {
|
|
|
|
CRASHPAD_RAW_LOG("Could not remove locked extension.");
|
|
|
|
CRASHPAD_RAW_LOG(writer_path_);
|
|
|
|
CRASHPAD_RAW_LOG(writer_unlocked_path_);
|
2021-10-14 10:55:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace crashpad
|