Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions engine/src/flutter/shell/common/shorebird/snapshots_data_handle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,10 @@

namespace flutter {

static std::unique_ptr<fml::Mapping> DataMapping(const DartSnapshot& snapshot) {
auto ptr = snapshot.GetDataMapping();
return std::make_unique<fml::NonOwnedMapping>(ptr,
Dart_SnapshotDataSize(ptr));
}

static std::unique_ptr<fml::Mapping> InstructionsMapping(
const DartSnapshot& snapshot) {
auto ptr = snapshot.GetInstructionsMapping();
return std::make_unique<fml::NonOwnedMapping>(ptr,
Dart_SnapshotInstrSize(ptr));
static std::unique_ptr<fml::Mapping> RegionMapping(
const uint8_t* region,
const SnapshotsDataHandle::RegionSizer& size) {
return std::make_unique<fml::NonOwnedMapping>(region, size(region));
}

// The size of the snapshot data is the sum of the sizes of the blobs.
Expand Down Expand Up @@ -83,6 +76,16 @@ BlobsIndex SnapshotsDataHandle::IndexForAbsoluteOffset(int64_t offset,

std::unique_ptr<SnapshotsDataHandle> SnapshotsDataHandle::createForSnapshots(
const DartSnapshot& base_snapshot) {
return createForSnapshots(
base_snapshot,
[](const uint8_t* region) { return Dart_SnapshotDataSize(region); },
[](const uint8_t* region) { return Dart_SnapshotInstrSize(region); });
}

std::unique_ptr<SnapshotsDataHandle> SnapshotsDataHandle::createForSnapshots(
const DartSnapshot& base_snapshot,
const RegionSizer& data_size,
const RegionSizer& instructions_size) {
// Order and count must match HandleDumpBlobs in
// runtime/bin/analyze_snapshot.cc, which writes the data region then the
// text region. One snapshot supplies both. The VM isolate's contents were
Expand All @@ -95,8 +98,9 @@ std::unique_ptr<SnapshotsDataHandle> SnapshotsDataHandle::createForSnapshots(
// The caller must pass a snapshot resolved through the VM path. That path is
// patch-blind, and this stream has to be the unpatched base the diff was
// computed against.
auto data = DataMapping(base_snapshot);
auto insns = InstructionsMapping(base_snapshot);
auto data = RegionMapping(base_snapshot.GetDataMapping(), data_size);
auto insns =
RegionMapping(base_snapshot.GetInstructionsMapping(), instructions_size);

// Per-blob observability for the base byte stream the updater is about to
// patch against. Logged at every patch-apply attempt so customer syslogs
Expand Down
16 changes: 16 additions & 0 deletions engine/src/flutter/shell/common/shorebird/snapshots_data_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define FLUTTER_SHELL_COMMON_SHOREBIRD_SNAPSHOTS_DATA_HANDLE_H_

#include <math.h>
#include <functional>
#include "flutter/fml/file.h"
#include "flutter/runtime/dart_snapshot.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
Expand All @@ -25,11 +26,26 @@ class SnapshotsDataHandle {
explicit SnapshotsDataHandle(std::vector<std::unique_ptr<fml::Mapping>> blobs)
: blobs_(std::move(blobs)) {}

// Resolves the byte length of a snapshot region starting at `region`.
//
// Production has to ask the Dart VM. An AOT snapshot's regions arrive as
// fml::SymbolMapping, whose GetSize() is 0 because a dlsym'd symbol address
// carries no extent. Only the snapshot header knows where the region ends.
using RegionSizer = std::function<size_t(const uint8_t* region)>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider passing the size directly here; I think it may be simpler for callers to use something like createForSnapshots(*snapshot, data.size(), instructions.size())


// `base_snapshot` must come from the VM resolve path, which never returns a
// patch. This stream is the base the updater diffs against.
static std::unique_ptr<SnapshotsDataHandle> createForSnapshots(
const DartSnapshot& base_snapshot);

// As above, with the lengths supplied by the caller. A test has no
// serialized snapshot, and the VM's parser dereferences whatever a
// fabricated buffer's header bytes point at.
static std::unique_ptr<SnapshotsDataHandle> createForSnapshots(
const DartSnapshot& base_snapshot,
const RegionSizer& data_size,
const RegionSizer& instructions_size);

uintptr_t Read(uint8_t* buffer, uintptr_t length);
int64_t Seek(int64_t offset, int32_t whence);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ static fml::RefPtr<DartSnapshot> MakeSnapshot(
instructions.size()));
}

// The regions below are fabricated strings, not serialized snapshots.
static SnapshotsDataHandle::RegionSizer SizedAt(size_t size) {
return [size](const uint8_t*) { return size; };
}

// Guards blob count and order, which the Read/Seek tests above never touch
// because they build handles through the public constructor.
//
Expand All @@ -198,7 +203,8 @@ TEST(SnapshotsDataHandle, CreateForSnapshotsEmitsDataThenInstructionsOnce) {
const std::string instructions = "INSTRUCTIONS";
auto snapshot = MakeSnapshot(data, instructions);

auto handle = SnapshotsDataHandle::createForSnapshots(*snapshot);
auto handle = SnapshotsDataHandle::createForSnapshots(
*snapshot, SizedAt(data.size()), SizedAt(instructions.size()));

EXPECT_EQ(handle->FullSize(), data.size() + instructions.size());

Expand All @@ -215,7 +221,8 @@ TEST(SnapshotsDataHandle, CreateForSnapshotsPutsDataBeforeInstructions) {
const std::string instructions = "BB";
auto snapshot = MakeSnapshot(data, instructions);

auto handle = SnapshotsDataHandle::createForSnapshots(*snapshot);
auto handle = SnapshotsDataHandle::createForSnapshots(
*snapshot, SizedAt(data.size()), SizedAt(instructions.size()));

uint8_t first[4] = {0, 0, 0, 0};
EXPECT_EQ(handle->Read(first, 4), 4u);
Expand All @@ -234,7 +241,8 @@ TEST(SnapshotsDataHandle, CreateForSnapshotsKeepsEmptyInstructionsRegion) {
const std::string instructions;
auto snapshot = MakeSnapshot(data, instructions);

auto handle = SnapshotsDataHandle::createForSnapshots(*snapshot);
auto handle = SnapshotsDataHandle::createForSnapshots(
*snapshot, SizedAt(data.size()), SizedAt(instructions.size()));

EXPECT_EQ(handle->FullSize(), data.size());
}
Expand Down
Loading