| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/crash/core/app/crashpad.h" |
| |
| #include <vector> |
| |
| #include "base/apple/bridging.h" |
| #include "base/apple/bundle_locations.h" |
| #include "base/apple/foundation_util.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "build/branding_buildflags.h" |
| #include "components/crash/core/app/crash_reporter_client.h" |
| #include "third_party/crashpad/crashpad/client/crash_report_database.h" |
| #include "third_party/crashpad/crashpad/client/crashpad_client.h" |
| #include "third_party/crashpad/crashpad/client/settings.h" |
| #include "third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer.h" |
| #include "third_party/crashpad/crashpad/minidump/minidump_file_writer.h" |
| #include "third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer.h" |
| #include "third_party/crashpad/crashpad/util/misc/metrics.h" |
| |
| namespace crash_reporter { |
| |
| namespace { |
| |
| const std::map<std::string, std::string>& GetProcessSimpleAnnotations() { |
| static std::map<std::string, std::string> annotations = []() -> auto { |
| std::map<std::string, std::string> process_annotations; |
| @autoreleasepool { |
| NSBundle* outer_bundle = base::apple::OuterBundle(); |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| process_annotations["prod"] = "Chrome_iOS"; |
| #else |
| NSString* product = base::apple::ObjCCast<NSString>( |
| [outer_bundle objectForInfoDictionaryKey:base::apple::CFToNSPtrCast( |
| kCFBundleNameKey)]); |
| process_annotations["prod"] = |
| base::SysNSStringToUTF8(product).append("_iOS"); |
| #endif |
| |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| // Empty means stable. |
| const bool allow_empty_channel = true; |
| #else |
| const bool allow_empty_channel = false; |
| #endif |
| NSString* channel = base::apple::ObjCCast<NSString>( |
| [outer_bundle objectForInfoDictionaryKey:@"KSChannelID"]); |
| // Must be a developer build. |
| if (!allow_empty_channel && (!channel || !channel.length)) |
| channel = @"developer"; |
| process_annotations["channel"] = base::SysNSStringToUTF8(channel); |
| NSString* version = |
| base::apple::ObjCCast<NSString>([base::apple::FrameworkBundle() |
| objectForInfoDictionaryKey:@"CFBundleVersion"]); |
| process_annotations["ver"] = base::SysNSStringToUTF8(version); |
| process_annotations["plat"] = std::string("iOS"); |
| process_annotations["crashpad"] = std::string("yes"); |
| } // @autoreleasepool |
| return process_annotations; |
| } |
| (); |
| return annotations; |
| } |
| |
| } // namespace |
| |
| void ProcessIntermediateDumps( |
| const std::map<std::string, std::string>& annotations) { |
| GetCrashpadClient().ProcessIntermediateDumps(annotations); |
| } |
| |
| void ProcessIntermediateDump( |
| const base::FilePath& file, |
| const std::map<std::string, std::string>& annotations) { |
| GetCrashpadClient().ProcessIntermediateDump(file, annotations); |
| } |
| |
| bool ProcessExternalDump( |
| const std::string& source, |
| base::span<const uint8_t> data, |
| const std::map<std::string, std::string>& override_annotations) { |
| auto crashpad_info_stream = |
| std::make_unique<crashpad::MinidumpCrashpadInfoWriter>(); |
| |
| auto simple_string_dictionary_writer = |
| std::make_unique<crashpad::MinidumpSimpleStringDictionaryWriter>(); |
| |
| std::map<std::string, std::string> annotations = |
| GetProcessSimpleAnnotations(); |
| annotations["prod"] = annotations["prod"] + "_" + source; |
| |
| for (auto& entry : override_annotations) { |
| annotations[entry.first] = entry.second; |
| } |
| |
| for (auto& entry : annotations) { |
| auto writer = |
| std::make_unique<crashpad::MinidumpSimpleStringDictionaryEntryWriter>(); |
| writer->SetKeyValue(entry.first, entry.second); |
| simple_string_dictionary_writer->AddEntry(std::move(writer)); |
| } |
| |
| crashpad_info_stream->SetSimpleAnnotations( |
| std::move(simple_string_dictionary_writer)); |
| |
| crashpad::CrashReportDatabase* database = internal::GetCrashReportDatabase(); |
| if (!database) { |
| return false; |
| } |
| std::unique_ptr<crashpad::CrashReportDatabase::NewReport> new_report; |
| crashpad::CrashReportDatabase::OperationStatus database_status = |
| database->PrepareNewCrashReport(&new_report); |
| if (database_status != crashpad::CrashReportDatabase::kNoError) { |
| return false; |
| } |
| |
| crashpad::MinidumpFileWriter minidump; |
| |
| crashpad_info_stream->SetReportID(new_report->ReportID()); |
| crashpad::Settings* const settings = database->GetSettings(); |
| crashpad::UUID client_id; |
| if (settings && settings->GetClientID(&client_id)) { |
| crashpad_info_stream->SetClientID(client_id); |
| } |
| |
| bool add_stream_result = minidump.AddStream(std::move(crashpad_info_stream)); |
| DCHECK(add_stream_result); |
| |
| if (data.size() > 0) { |
| crashpad::FileWriter* attachment_writer = new_report->AddAttachment(source); |
| attachment_writer->Write(data.data(), data.size()); |
| } |
| |
| if (!minidump.WriteEverything(new_report->Writer())) { |
| return false; |
| } |
| |
| crashpad::UUID uuid; |
| database_status = |
| database->FinishedWritingCrashReport(std::move(new_report), &uuid); |
| if (database_status != crashpad::CrashReportDatabase::kNoError) { |
| return false; |
| } |
| return true; |
| } |
| |
| void StartProcessingPendingReports() { |
| GetCrashpadClient().StartProcessingPendingReports(); |
| } |
| |
| namespace internal { |
| |
| bool PlatformCrashpadInitialization( |
| bool initial_client, |
| bool browser_process, |
| bool embedded_handler, |
| const std::string& user_data_dir, |
| const base::FilePath& exe_path, |
| const std::vector<std::string>& initial_arguments, |
| base::FilePath* database_path) { |
| DCHECK(!embedded_handler); // This is not used on iOS. |
| DCHECK(exe_path.empty()); // This is not used on iOS. |
| DCHECK(initial_arguments.empty()); |
| DCHECK(initial_client); |
| |
| @autoreleasepool { |
| CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); |
| crash_reporter_client->GetCrashDumpLocation(database_path); |
| // Don't pass `url` to extensions since they never upload minidumps. |
| std::string url = [NSBundle.mainBundle.bundlePath hasSuffix:@"appex"] |
| ? "" |
| : crash_reporter_client->GetUploadUrl(); |
| return GetCrashpadClient().StartCrashpadInProcessHandler( |
| *database_path, url, GetProcessSimpleAnnotations(), |
| crashpad::CrashpadClient::ProcessPendingReportsObservationCallback()); |
| } // @autoreleasepool |
| } |
| |
| } // namespace internal |
| } // namespace crash_reporter |