blob: 830578cbd508de157c5d08de27941e99565a25c7 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRASH_REPORTER_CRASH_SERIALIZER_H_
#define CRASH_REPORTER_CRASH_SERIALIZER_H_
#include <memory>
#include <string>
#include <vector>
#include <base/time/clock.h>
#include <base/files/file_path.h>
#include <base/files/file.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "crash-reporter/crash_sender_base.h"
#include "crash-reporter/crash_sender_util.h"
#include "crash-reporter/crash_serializer.pb.h"
namespace crash_serializer {
// A helper class for serializing crashes. Its behaviors can be customized by
// the options struct.
class Serializer : public util::SenderBase {
public:
struct Options : public SenderBase::Options {
// If true, fetch coredumps as well.
bool fetch_coredumps;
// Approximate largest proto size we will write in a single message.
//
// Defaults to 1MiB per
// https://developers.google.com/protocol-buffers/docs/techniques#large-data
// which says, "As a general rule of thumb, if you are dealing in messages
// larger than a megabyte each, it may be time to consider an alternate
// strategy."
//
// Exceptions / caveats:
// * CrashInfo messages are exempt from this as we expect they'll be small.
// * Messages may exceed this size by a few bytes, since we split based only
// on the large fields in a message (for instance, a blob or a core). If
// we start with a 2MiB blob, we'll split the blob across two messages.
// The additional metadata (e.g. crash_id, key, filename) may push the
// message just over 1MiB.
size_t max_proto_bytes = 1 << 20;
};
Serializer(std::unique_ptr<base::Clock> clock, const Options& options);
// Pick crash files to serialize.
void PickCrashFiles(const base::FilePath& crash_dir,
std::vector<util::MetaFile>* to_send);
// Serialize the given crashes to the out file
void SerializeCrashes(const std::vector<util::MetaFile>& crash_meta_files);
// For tests only. Set the serializer to write output to the specified file
// instead of stdout.
void set_output_for_testing(const base::FilePath& file) { out_ = file; }
protected:
// SenderBase method
void RecordCrashRemoveReason(CrashRemoveReason reason) override;
private:
FRIEND_TEST(CrashSerializerParameterizedTest, SerializeCrash);
FRIEND_TEST(CrashSerializerTest, WriteFetchCrashesResponse);
FRIEND_TEST(CrashSerializerTest, WriteFetchCrashesResponse_WriteFail);
FRIEND_TEST(CrashSerializerTest, WriteBlobs_Basic);
FRIEND_TEST(CrashSerializerTest, WriteBlobs_ManySizes);
FRIEND_TEST(CrashSerializerTest, WriteBlobs_Empty);
FRIEND_TEST(CrashSerializerTest, WriteBlobs_Failure);
FRIEND_TEST(CrashSerializerTest, WriteCoredump_Basic);
FRIEND_TEST(CrashSerializerTest, WriteCoredump_LargerThanChunkSize);
FRIEND_TEST(CrashSerializerTest, WriteCoredump_ManySizes);
FRIEND_TEST(CrashSerializerTest, WriteCoredump_Nonexistent);
// Serialize a single crash into the given outputs.
// Populates |core_path| iff fetch_cores_ is true and the core file exists.
// Does NOT read core into memory as it might be quite large.
// Return true on success or false on failure.
// Ignores nonexistent files in info.files, but fails if info.payload is
// missing.
bool SerializeCrash(const util::CrashDetails& details,
crash::CrashInfo* info,
std::vector<crash::CrashBlob>* blobs,
base::FilePath* core_path);
// Write the given FetchCrashesResponse proto to |out_|.
// The serialization format is:
// The size of the serialized protobuf as a big-endian uint64_t,
// followed by the serialized protobuf.
// Format inspired by
// https://developers.google.com/protocol-buffers/docs/techniques#streaming
//
// The 8 bytes for the size are _not_ counted in the size.
// For example, if a protobuf serialized to the 4 bytes aabbccdd, the
// overall serialized data would be:
// 0000 0000 0000 0003 aabb ccdd
// Returns true on a successful write and false otherwise.
bool WriteFetchCrashesResponse(const crash::FetchCrashesResponse& crash_data);
// Write the specified blobs to |out_|, chunking them based on
// |max_message_size_bytes_|.
bool WriteBlobs(int64_t crash_id, const std::vector<crash::CrashBlob>& blobs);
// Read the core dump at the given path and write it to |out_|, chunking it
// based on |max_message_size_bytes_|.
bool WriteCoredump(int64_t crash_id, base::FilePath core_path);
base::FilePath out_;
// True iff we should fetch core dumps.
const bool fetch_cores_;
// Largest proto size we will write in a single message. CrashInfo messages
// are exempt from this limit as we generally expect they'll be small.
const size_t max_message_size_bytes_;
};
} // namespace crash_serializer
#endif // CRASH_REPORTER_CRASH_SERIALIZER_H_