xref: /aosp_15_r20/external/pigweed/pw_snapshot/module_usage.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_snapshot-module_usage:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker============
4*61c4878aSAndroid Build Coastguard WorkerModule Usage
5*61c4878aSAndroid Build Coastguard Worker============
6*61c4878aSAndroid Build Coastguard WorkerRight now, pw_snapshot just dictates a *format*. That means there is no provided
7*61c4878aSAndroid Build Coastguard Workersystem information collection integration, underlying storage, or transport
8*61c4878aSAndroid Build Coastguard Workermechanism to fetch a snapshot from a device. These must be set up independently
9*61c4878aSAndroid Build Coastguard Workerby your project.
10*61c4878aSAndroid Build Coastguard Worker
11*61c4878aSAndroid Build Coastguard Worker-------------------
12*61c4878aSAndroid Build Coastguard WorkerBuilding a Snapshot
13*61c4878aSAndroid Build Coastguard Worker-------------------
14*61c4878aSAndroid Build Coastguard WorkerEven though a Snapshot is just a proto message, the potential size of the proto
15*61c4878aSAndroid Build Coastguard Workermakes it important to consider the encoder.
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard WorkerNanopb is a popular encoder for embedded devices, it's impractical to use
18*61c4878aSAndroid Build Coastguard Workerwith the pw_snapshot proto. Nanopb works by generating in-memory structs that
19*61c4878aSAndroid Build Coastguard Workerrepresent the protobuf message. Repeated, optional, and variable-length fields
20*61c4878aSAndroid Build Coastguard Workerincrease the size of the in-memory struct. The struct representation
21*61c4878aSAndroid Build Coastguard Workerof snapshot-like protos can quickly near 10KB in size. Allocating 10KB
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard WorkerPigweed's pw_protobuf is a better choice as its design is centered around
24*61c4878aSAndroid Build Coastguard Workerincrementally writing a proto directly to the final wire format. If you only
25*61c4878aSAndroid Build Coastguard Workerwrite a few fields in a snapshot, you can do so with minimal memory overhead.
26*61c4878aSAndroid Build Coastguard Worker
27*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
28*61c4878aSAndroid Build Coastguard Worker
29*61c4878aSAndroid Build Coastguard Worker   #include "pw_bytes/span.h"
30*61c4878aSAndroid Build Coastguard Worker   #include "pw_protobuf/encoder.h"
31*61c4878aSAndroid Build Coastguard Worker   #include "pw_snapshot_protos/snapshot.pwpb.h"
32*61c4878aSAndroid Build Coastguard Worker   #include "pw_status/status.h"
33*61c4878aSAndroid Build Coastguard Worker   #include "pw_stream/stream.h"
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker   pw::Status EncodeSnapshot(pw::stream::Writer& writer,
36*61c4878aSAndroid Build Coastguard Worker                             pw::ByteSpan submessage_encode_buffer,
37*61c4878aSAndroid Build Coastguard Worker                             const CrashInfo &crash_info) {
38*61c4878aSAndroid Build Coastguard Worker     // Create a snapshot proto encoder.
39*61c4878aSAndroid Build Coastguard Worker     pw::snapshot::Snapshot::StreamEncoder snapshot_encoder(
40*61c4878aSAndroid Build Coastguard Worker         writer, submessage_encode_buffer);
41*61c4878aSAndroid Build Coastguard Worker     {  // This scope is required to handle RAII behavior of the submessage.
42*61c4878aSAndroid Build Coastguard Worker       // Start writing the Metadata submessage.
43*61c4878aSAndroid Build Coastguard Worker       pw::snapshot::Metadata::StreamEncoder metadata_encoder =
44*61c4878aSAndroid Build Coastguard Worker           snapshot_encoder.GetMetadataEncoder();
45*61c4878aSAndroid Build Coastguard Worker       metadata_encoder.WriteReason(EncodeReasonLog(crash_info));
46*61c4878aSAndroid Build Coastguard Worker       metadata_encoder.WriteFatal(true);
47*61c4878aSAndroid Build Coastguard Worker       metadata_encoder.WriteProjectName(pw::as_bytes(pw::span("smart-shoe")));
48*61c4878aSAndroid Build Coastguard Worker       metadata_encoder.WriteDeviceName(
49*61c4878aSAndroid Build Coastguard Worker           pw::as_bytes(pw::span("smart-shoe-p1")));
50*61c4878aSAndroid Build Coastguard Worker     }
51*61c4878aSAndroid Build Coastguard Worker     return proto_encoder.status();
52*61c4878aSAndroid Build Coastguard Worker   }
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard Worker-------------------
55*61c4878aSAndroid Build Coastguard WorkerCustom Project Data
56*61c4878aSAndroid Build Coastguard Worker-------------------
57*61c4878aSAndroid Build Coastguard WorkerThere are two main ways to add custom project-specific data to a snapshot. Tags
58*61c4878aSAndroid Build Coastguard Workerare the simplest way to capture small snippets of information that require
59*61c4878aSAndroid Build Coastguard Workerno or minimal post-processing. For more complex data, it's usually more
60*61c4878aSAndroid Build Coastguard Workerpractical to extend the Snapshot proto.
61*61c4878aSAndroid Build Coastguard Worker
62*61c4878aSAndroid Build Coastguard WorkerTags
63*61c4878aSAndroid Build Coastguard Worker====
64*61c4878aSAndroid Build Coastguard WorkerAdding a key/value pair to the tags map is straightforward when using
65*61c4878aSAndroid Build Coastguard Workerpw_protobuf.
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
68*61c4878aSAndroid Build Coastguard Worker
69*61c4878aSAndroid Build Coastguard Worker   {
70*61c4878aSAndroid Build Coastguard Worker     pw::Snapshot::TagsEntry::StreamEncoder tags_encoder =
71*61c4878aSAndroid Build Coastguard Worker         snapshot_encoder.GetTagsEncoder();
72*61c4878aSAndroid Build Coastguard Worker     tags_encoder.WriteKey("BtState");
73*61c4878aSAndroid Build Coastguard Worker     tags_encoder.WriteValue("connected");
74*61c4878aSAndroid Build Coastguard Worker   }
75*61c4878aSAndroid Build Coastguard Worker
76*61c4878aSAndroid Build Coastguard WorkerExtending the Proto
77*61c4878aSAndroid Build Coastguard Worker===================
78*61c4878aSAndroid Build Coastguard WorkerExtending the Snapshot proto relies on proto behavior details that are explained
79*61c4878aSAndroid Build Coastguard Workerin the :ref:`Snapshot Proto Format<module-pw_snapshot-proto_format>`. Extending
80*61c4878aSAndroid Build Coastguard Workerthe snapshot proto is as simple as defining a proto message that **only**
81*61c4878aSAndroid Build Coastguard Workerdeclares fields with numbers that are reserved by the Snapshot proto for
82*61c4878aSAndroid Build Coastguard Workerdownstream projects. When encoding your snapshot, you can then write both the
83*61c4878aSAndroid Build Coastguard Workerupstream Snapshot proto and your project's custom extension proto message to the
84*61c4878aSAndroid Build Coastguard Workersame proto encoder.
85*61c4878aSAndroid Build Coastguard Worker
86*61c4878aSAndroid Build Coastguard WorkerThe upstream snapshot tooling will ignore any project-specific proto data,
87*61c4878aSAndroid Build Coastguard Workerthe proto data can be decoded a second time using a project-specific proto. At
88*61c4878aSAndroid Build Coastguard Workerthat point, any handling logic of the project-specific data would have to be
89*61c4878aSAndroid Build Coastguard Workerdone as part of project-specific tooling.
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker-------------------
92*61c4878aSAndroid Build Coastguard WorkerAnalyzing Snapshots
93*61c4878aSAndroid Build Coastguard Worker-------------------
94*61c4878aSAndroid Build Coastguard WorkerSnapshots can be processed for analysis using the ``pw_snapshot.process`` python
95*61c4878aSAndroid Build Coastguard Workertool. This tool turns a binary snapshot proto into human readable, actionable
96*61c4878aSAndroid Build Coastguard Workerinformation. As some snapshot fields may optionally be tokenized, a
97*61c4878aSAndroid Build Coastguard Workerpw_tokenizer database or ELF file with embedded pw_tokenizer tokens may
98*61c4878aSAndroid Build Coastguard Workeroptionally be passed to the tool to detokenize applicable fields.
99*61c4878aSAndroid Build Coastguard Worker
100*61c4878aSAndroid Build Coastguard Worker.. code-block:: sh
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard Worker   # Example invocation, which dumps to stdout by default.
103*61c4878aSAndroid Build Coastguard Worker   $ python -m pw_snapshot.processor path/to/serialized_snapshot.bin
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker
106*61c4878aSAndroid Build Coastguard Worker           ____ _       __    _____ _   _____    ____  _____ __  ______  ______
107*61c4878aSAndroid Build Coastguard Worker          / __ \ |     / /   / ___// | / /   |  / __ \/ ___// / / / __ \/_  __/
108*61c4878aSAndroid Build Coastguard Worker         / /_/ / | /| / /    \__ \/  |/ / /| | / /_/ /\__ \/ /_/ / / / / / /
109*61c4878aSAndroid Build Coastguard Worker        / ____/| |/ |/ /    ___/ / /|  / ___ |/ ____/___/ / __  / /_/ / / /
110*61c4878aSAndroid Build Coastguard Worker       /_/     |__/|__/____/____/_/ |_/_/  |_/_/    /____/_/ /_/\____/ /_/
111*61c4878aSAndroid Build Coastguard Worker                     /_____/
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker
114*61c4878aSAndroid Build Coastguard Worker                               ▪▄▄▄ ▄▄▄· ▄▄▄▄▄ ▄▄▄· ▄ ·
115*61c4878aSAndroid Build Coastguard Worker                               █▄▄▄▐█ ▀█ • █▌ ▐█ ▀█ █
116*61c4878aSAndroid Build Coastguard Worker                               █ ▪ ▄█▀▀█   █. ▄█▀▀█ █
117*61c4878aSAndroid Build Coastguard Worker                               ▐▌ .▐█ ▪▐▌ ▪▐▌·▐█ ▪▐▌▐▌
118*61c4878aSAndroid Build Coastguard Worker                               ▀    ▀  ▀ ·  ▀  ▀  ▀ .▀▀
119*61c4878aSAndroid Build Coastguard Worker
120*61c4878aSAndroid Build Coastguard Worker   Device crash cause:
121*61c4878aSAndroid Build Coastguard Worker       ../examples/example_rpc.cc: Assert failed: 1+1 == 42
122*61c4878aSAndroid Build Coastguard Worker
123*61c4878aSAndroid Build Coastguard Worker   Project name:      gShoe
124*61c4878aSAndroid Build Coastguard Worker   Device:            GSHOE-QUANTUM_CORE-REV_0.1
125*61c4878aSAndroid Build Coastguard Worker   Device FW version: QUANTUM_CORE-0.1.325-e4a84b1a
126*61c4878aSAndroid Build Coastguard Worker   FW build UUID:     ad2d39258c1bc487f07ca7e04991a836fdf7d0a0
127*61c4878aSAndroid Build Coastguard Worker   Snapshot UUID:     8481bb12a162164f5c74855f6d94ea1a
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker   Thread State
130*61c4878aSAndroid Build Coastguard Worker     2 threads running, Main Stack (Handler Mode) active at the time of capture.
131*61c4878aSAndroid Build Coastguard Worker                        ~~~~~~~~~~~~~~~~~~~~~~~~~
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard Worker   Thread (INTERRUPT_HANDLER): Main Stack (Handler Mode) <-- [ACTIVE]
134*61c4878aSAndroid Build Coastguard Worker   Est CPU usage: unknown
135*61c4878aSAndroid Build Coastguard Worker   Stack info
136*61c4878aSAndroid Build Coastguard Worker     Stack used:   0x2001b000 - 0x2001ae20 (480 bytes)
137*61c4878aSAndroid Build Coastguard Worker     Stack limits: 0x2001b000 - 0x???????? (size unknown)
138*61c4878aSAndroid Build Coastguard Worker   Raw Stack
139*61c4878aSAndroid Build Coastguard Worker   00caadde
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker   Thread (RUNNING): Idle
143*61c4878aSAndroid Build Coastguard Worker   Est CPU usage: unknown
144*61c4878aSAndroid Build Coastguard Worker   Stack info
145*61c4878aSAndroid Build Coastguard Worker     Stack used:   0x2001ac00 - 0x2001ab0c (244 bytes, 47.66%)
146*61c4878aSAndroid Build Coastguard Worker     Stack limits: 0x2001ac00 - 0x2001aa00 (512 bytes)
147*61c4878aSAndroid Build Coastguard Worker
148*61c4878aSAndroid Build Coastguard Worker---------------------
149*61c4878aSAndroid Build Coastguard WorkerSymbolizing Addresses
150*61c4878aSAndroid Build Coastguard Worker---------------------
151*61c4878aSAndroid Build Coastguard WorkerThe snapshot processor tool has built-in support for symbolization of some data
152*61c4878aSAndroid Build Coastguard Workerembedded into snapshots. Taking advantage of this requires the use of a
153*61c4878aSAndroid Build Coastguard Workerproject-provided ``SymbolizerMatcher`` callback. This is used by the snapshot
154*61c4878aSAndroid Build Coastguard Workerprocessor to understand which ELF file should be used to symbolize which
155*61c4878aSAndroid Build Coastguard Workersnapshot in cases where a snapshot has related snapshots embedded inside of it.
156*61c4878aSAndroid Build Coastguard Worker
157*61c4878aSAndroid Build Coastguard WorkerHere's an example implementation that uses the device name:
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker.. code-block:: py
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard Worker   # Given a firmware bundle directory, determine the ELF file associated with
162*61c4878aSAndroid Build Coastguard Worker   # the provided snapshot.
163*61c4878aSAndroid Build Coastguard Worker   def _snapshot_symbolizer_matcher(fw_bundle_dir: Path,
164*61c4878aSAndroid Build Coastguard Worker                                    snapshot: snapshot_pb2.Snapshot
165*61c4878aSAndroid Build Coastguard Worker       ) -> Symbolizer:
166*61c4878aSAndroid Build Coastguard Worker       metadata = MetadataProcessor(snapshot.metadata, DETOKENIZER)
167*61c4878aSAndroid Build Coastguard Worker       if metadata.device_name().startswith('GSHOE_MAIN_CORE'):
168*61c4878aSAndroid Build Coastguard Worker           return LlvmSymbolizer(fw_bundle_dir / 'main.elf')
169*61c4878aSAndroid Build Coastguard Worker       if metadata.device_name().startswith('GSHOE_SENSOR_CORE'):
170*61c4878aSAndroid Build Coastguard Worker           return LlvmSymbolizer(fw_bundle_dir / 'sensors.elf')
171*61c4878aSAndroid Build Coastguard Worker       return LlvmSymbolizer()
172*61c4878aSAndroid Build Coastguard Worker
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker   # A project specific wrapper to decode snapshots that provides a detokenizer
175*61c4878aSAndroid Build Coastguard Worker   # and ElfMatcher.
176*61c4878aSAndroid Build Coastguard Worker   def decode_snapshots(snapshot: bytes, fw_bundle_dir: Path) -> str:
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker       # This is the actual ElfMatcher, which wraps the helper in a lambda that
179*61c4878aSAndroid Build Coastguard Worker       # captures the passed firmware artifacts directory.
180*61c4878aSAndroid Build Coastguard Worker       matcher: processor.SymbolizerMatcher = (
181*61c4878aSAndroid Build Coastguard Worker           lambda snapshot: _snapshot_symbolizer_matcher(
182*61c4878aSAndroid Build Coastguard Worker               fw_bundle_dir, snapshot))
183*61c4878aSAndroid Build Coastguard Worker       return processor.process_snapshots(snapshot, DETOKENIZER, matcher)
184*61c4878aSAndroid Build Coastguard Worker
185*61c4878aSAndroid Build Coastguard Worker-------------
186*61c4878aSAndroid Build Coastguard WorkerC++ Utilities
187*61c4878aSAndroid Build Coastguard Worker-------------
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard WorkerUUID utilities
190*61c4878aSAndroid Build Coastguard Worker==============
191*61c4878aSAndroid Build Coastguard WorkerSnapshot UUIDs are used to uniquely identify snapshots. Pigweed strongly
192*61c4878aSAndroid Build Coastguard Workerrecommends using randomly generated data as a snapshot UUID. The
193*61c4878aSAndroid Build Coastguard Workermore entropy and random bits, the lower the probability that two devices will
194*61c4878aSAndroid Build Coastguard Workerproduce the same UUID for a snapshot. 16 bytes should be sufficient for most
195*61c4878aSAndroid Build Coastguard Workerprojects, so this module provides ``UuidSpan`` and ``ConstUuidSpan`` types that
196*61c4878aSAndroid Build Coastguard Workercan be helpful for referring to UUID-sized byte spans.
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard WorkerReading a snapshot's UUID
199*61c4878aSAndroid Build Coastguard Worker-------------------------
200*61c4878aSAndroid Build Coastguard WorkerAn in-memory snapshot's UUID may be read using ``ReadUuidFromSnapshot()``.
201*61c4878aSAndroid Build Coastguard Worker
202*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
203*61c4878aSAndroid Build Coastguard Worker
204*61c4878aSAndroid Build Coastguard Worker   void NotifyNewSnapshot(ConstByteSpan snapshot) {
205*61c4878aSAndroid Build Coastguard Worker     std::array<std::byte, pw::snapshot::kUuidSizeBytes> uuid;
206*61c4878aSAndroid Build Coastguard Worker     pw::Result<pw::ConstByteSpan> result =
207*61c4878aSAndroid Build Coastguard Worker         pw::snapshot::ReadUuidFromSnapshot(snapshot, uuid);
208*61c4878aSAndroid Build Coastguard Worker     if (!result.ok()) {
209*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Failed to read UUID from new snapshot, error code %d",
210*61c4878aSAndroid Build Coastguard Worker                    static_cast<int>(result.status().code()));
211*61c4878aSAndroid Build Coastguard Worker       return;
212*61c4878aSAndroid Build Coastguard Worker     }
213*61c4878aSAndroid Build Coastguard Worker     LogNewSnapshotUuid(result.value());
214*61c4878aSAndroid Build Coastguard Worker   }
215