crashpad/util/stream/log_output_stream.cc
Joshua Peraza cdb1e7f52b fix flake in LogOutputStreamTest
LogOutputStreamTest.{WriteAbort,FlushAbort} are flaky because the logcat
is sometimes overloaded earlier than expected causing FlushAbort to fail
during Write() or either test to fail to write the abort message.

This change updates LogOutputStream to detect logcat overloads (EAGAIN)
and make one attempt at writing the abort message, even if the output
cap hasn't been reached.

This change also updates LogOutputStream's interface to defer log writes
to a Delegate. In tests, the Delegate implements a mock log and in
production, writes to Android's logcat.

I've removed VerifyGuards because LogOutputStream no longer writes
guards if Write() has never been called and the guards are tested in
other tests.

Change-Id: Icad83524aaf573c3e082469f1de095b6ca2c4839
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2439641
Reviewed-by: Mark Mentovai <mark@chromium.org>
2020-10-26 18:36:11 +00:00

104 lines
2.6 KiB
C++

// Copyright 2019 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.
#include "util/stream/log_output_stream.h"
#include <string.h>
#include <algorithm>
#include "base/check.h"
#include "base/logging.h"
namespace crashpad {
LogOutputStream::LogOutputStream(std::unique_ptr<Delegate> delegate)
: delegate_(std::move(delegate)),
output_count_(0),
flush_needed_(false),
flushed_(false) {
buffer_.reserve(delegate_->LineWidth());
}
LogOutputStream::~LogOutputStream() {
DCHECK(!flush_needed_);
}
bool LogOutputStream::Write(const uint8_t* data, size_t size) {
DCHECK(!flushed_);
static constexpr char kBeginMessage[] = "-----BEGIN CRASHPAD MINIDUMP-----";
if (output_count_ == 0 && WriteToLog(kBeginMessage) < 0) {
return false;
}
flush_needed_ = true;
while (size > 0) {
size_t m = std::min(delegate_->LineWidth() - buffer_.size(), size);
buffer_.append(reinterpret_cast<const char*>(data), m);
data += m;
size -= m;
if (buffer_.size() == delegate_->LineWidth() && !WriteBuffer()) {
return false;
}
}
return true;
}
bool LogOutputStream::WriteBuffer() {
if (buffer_.empty())
return true;
static constexpr char kAbortMessage[] = "-----ABORT CRASHPAD MINIDUMP-----";
output_count_ += buffer_.size();
if (output_count_ > delegate_->OutputCap()) {
WriteToLog(kAbortMessage);
flush_needed_ = false;
return false;
}
int result = WriteToLog(buffer_.c_str());
if (result < 0) {
if (result == -EAGAIN) {
WriteToLog(kAbortMessage);
}
flush_needed_ = false;
return false;
}
buffer_.clear();
return true;
}
int LogOutputStream::WriteToLog(const char* buf) {
return delegate_->Log(buf);
}
bool LogOutputStream::Flush() {
bool result = true;
if (flush_needed_) {
flush_needed_ = false;
flushed_ = true;
static constexpr char kEndMessage[] = "-----END CRASHPAD MINIDUMP-----";
if (!WriteBuffer() || WriteToLog(kEndMessage) < 0) {
result = false;
}
}
return result;
}
} // namespace crashpad