1 // Copyright 2019 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/array.h>
8 #include <fbl/function.h>
9 #include <lib/inspect/block.h>
10 #include <lib/zx/vmo.h>
11 #include <unistd.h>
12 #include <zircon/types.h>
13 
14 namespace inspect {
15 
16 // |Snapshot| parses an incoming VMO buffer and produces a snapshot of
17 // the VMO contents. |Snapshot::Options| determines the behavior of
18 // snapshotting if a concurrent write potentially occurred.
19 //
20 // Example:
21 // fbl::unique_ptr<Snapshot> snapshot;
22 // zx_status_t status = Snapshot::Create(std::move(vmo),
23 //   {.read_attempts = 1024, .skip_consistency_check = false},
24 //   &snapshot);
25 //
26 // Test Example:
27 // zx_status_t status = Snapshot::Create(std::move(vmo),
28 //   {.read_attempts = 1024, .skip_consistency_check = false},
29 //   fbl::make_unique<TestCallback>(),
30 //   &snapshot);
31 class Snapshot final {
32 public:
33     struct Options {
34         // The number of attempts to read a consistent snapshot.
35         // Reading fails if the number of attempts exceeds this number.
36         int read_attempts;
37 
38         // If true, skip checking the buffer for consistency.
39         bool skip_consistency_check;
40     };
41 
42     // Type for observing reads on the VMO.
43     using ReadObserver = fbl::Function<void(uint8_t* buffer, size_t buffer_size)>;
44 
45     // By default, ensure consistency of the incoming Inspect VMO and retry up to
46     // 1024 times.
47     static constexpr Options kDefaultOptions = {.read_attempts = 1024,
48                                                 .skip_consistency_check = false};
49 
50     // Create a new snapshot of the given VMO and default options.
51     static zx_status_t Create(zx::vmo vmo, Snapshot* out_snapshot);
52 
53     // Create a new snapshot of the given VMO and given options.
54     static zx_status_t Create(zx::vmo vmo, Options options, Snapshot* out_snapshot);
55 
56     // Create a new snapshot of the given VMO, given options, and the given read observer
57     // for observing snapshot operations.
58     static zx_status_t Create(zx::vmo vmo, Options options, ReadObserver read_observer,
59                               Snapshot* out_snapshot);
60 
61     Snapshot() = default;
62     ~Snapshot() = default;
63     Snapshot(Snapshot&&) = default;
64     Snapshot& operator=(Snapshot&&) = default;
65 
66     operator bool() const { return buffer_.size() > 0; }
67 
68     // Returns the start of the snapshot data, if valid.
data()69     const uint8_t* data() const { return buffer_.begin(); }
70 
71     // Returns the size of the snapshot, if valid.
size()72     size_t size() const { return buffer_.size(); }
73 
74     // Get a pointer to a block in the buffer by index.
75     // Returns nullptr if the index is out of bounds.
76     internal::Block* GetBlock(internal::BlockIndex index) const;
77 
78 private:
79     // Read from the VMO into a buffer.
80     static zx_status_t Read(zx::vmo& vmo, size_t size, uint8_t* buffer);
81 
82     // Parse the header from a buffer and obtain the generation count.
83     static zx_status_t ParseHeader(uint8_t* buffer, uint64_t* out_generation_count);
84 
85     // Take a new snapshot of the VMO with default options.
86     // If reading fails, the boolean value of the constructed |Snapshot| will be false.
87     explicit Snapshot(fbl::Array<uint8_t> buffer);
88 
89     // The buffer storing the snapshot.
90     fbl::Array<uint8_t> buffer_;
91 };
92 
93 } // namespace inspect
94