1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "SerializedLogChunk.h"
18 
19 #include <android-base/logging.h>
20 
21 #include "CompressionEngine.h"
22 #include "SerializedFlushToState.h"
23 
~SerializedLogChunk()24 SerializedLogChunk::~SerializedLogChunk() {
25     CHECK_EQ(reader_ref_count_, 0U);
26 }
27 
FinishWriting()28 void SerializedLogChunk::FinishWriting() {
29     writer_active_ = false;
30     CHECK_EQ(compressed_log_.size(), 0U);
31     CompressionEngine::GetInstance().Compress(contents_, write_offset_, compressed_log_);
32     LOG(VERBOSE) << "Compressed Log, buffer max size: " << contents_.size()
33                  << " size used: " << write_offset_
34                  << " compressed size: " << compressed_log_.size();
35     if (reader_ref_count_ == 0) {
36         contents_.Resize(0);
37     }
38 }
39 
40 // TODO: Develop a better reference counting strategy to guard against the case where the writer is
41 // much faster than the reader, and we needlessly compess / decompress the logs.
IncReaderRefCount()42 void SerializedLogChunk::IncReaderRefCount() {
43     if (++reader_ref_count_ != 1 || writer_active_) {
44         return;
45     }
46     contents_.Resize(write_offset_);
47     CompressionEngine::GetInstance().Decompress(compressed_log_, contents_);
48 }
49 
DecReaderRefCount()50 void SerializedLogChunk::DecReaderRefCount() {
51     CHECK_NE(reader_ref_count_, 0U);
52     if (--reader_ref_count_ != 0) {
53         return;
54     }
55     if (!writer_active_) {
56         contents_.Resize(0);
57     }
58 }
59 
AttachReader(SerializedFlushToState * reader)60 void SerializedLogChunk::AttachReader(SerializedFlushToState* reader) {
61     readers_.emplace_back(reader);
62     IncReaderRefCount();
63 }
64 
DetachReader(SerializedFlushToState * reader)65 void SerializedLogChunk::DetachReader(SerializedFlushToState* reader) {
66     auto it = std::find(readers_.begin(), readers_.end(), reader);
67     CHECK(readers_.end() != it);
68     readers_.erase(it);
69     DecReaderRefCount();
70 }
71 
NotifyReadersOfPrune(log_id_t log_id)72 void SerializedLogChunk::NotifyReadersOfPrune(log_id_t log_id) {
73     // Readers will call DetachReader() in their Prune() call, so we make a copy of the list first.
74     auto readers = readers_;
75     for (auto& reader : readers) {
76         reader->Prune(log_id);
77     }
78 }
79 
CanLog(size_t len)80 bool SerializedLogChunk::CanLog(size_t len) {
81     return write_offset_ + len <= contents_.size();
82 }
83 
Log(uint64_t sequence,log_time realtime,uid_t uid,pid_t pid,pid_t tid,const char * msg,uint16_t len)84 SerializedLogEntry* SerializedLogChunk::Log(uint64_t sequence, log_time realtime, uid_t uid,
85                                             pid_t pid, pid_t tid, const char* msg, uint16_t len) {
86     auto new_log_address = contents_.data() + write_offset_;
87     auto* entry = new (new_log_address) SerializedLogEntry(uid, pid, tid, sequence, realtime, len);
88     memcpy(entry->msg(), msg, len);
89     write_offset_ += entry->total_len();
90     highest_sequence_number_ = sequence;
91     return entry;
92 }
93