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