[inspect][dart] Low-level API
Creates the initial Dart Inspect package.
Includes a low-level architecture for VMO access, with an API supporting
creating, modifying, and deleting Nodes, Properties, and Values.
See vmo_writer.dart.
Nothing is implemented yet; placeholder code is trivially wrong.
Test: builds
CF-601 #progress
Change-Id: I6f01377430bfe6340367c39ca37087e365d3863b
diff --git a/packages/tests/dart_unittests b/packages/tests/dart_unittests
index d2c7101..4a99013 100644
--- a/packages/tests/dart_unittests
+++ b/packages/tests/dart_unittests
@@ -12,6 +12,7 @@
"//topaz/lib/setui/settings/common:lib_setui_settings_common_test",
"//topaz/lib/setui/settings/service:lib_setui_service_test",
"//topaz/lib/setui/settings/testing:lib_setui_settings_testing_test",
+ "//topaz/public/dart/fuchsia_inspect:fuchsia_inspect_package_unittests",
"//topaz/public/dart/fuchsia_logger:fuchsia_logger_package_unittests",
"//topaz/public/dart/fuchsia_modular:fuchsia_modular_package_unittests",
"//topaz/public/dart/fuchsia_services:fuchsia_services_package_unittests",
diff --git a/public/dart/fuchsia_inspect/BUILD.gn b/public/dart/fuchsia_inspect/BUILD.gn
new file mode 100644
index 0000000..eb7df06
--- /dev/null
+++ b/public/dart/fuchsia_inspect/BUILD.gn
@@ -0,0 +1,43 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/dart/dart_library.gni")
+import("//topaz/runtime/dart/dart_test.gni")
+
+dart_library("fuchsia_inspect") {
+ package_name = "fuchsia_inspect"
+
+ sdk_category = "partner"
+
+ source_dir = "lib"
+
+ sources = [
+ "inspect.dart",
+ "src/vmo_writer.dart",
+ "src/vmo_heap.dart",
+ "src/inspect.dart",
+ ]
+
+ deps = [
+ "//third_party/dart-pkg/pub/meta",
+ "//topaz/public/dart/fuchsia_services",
+ "//topaz/public/dart/zircon",
+ ]
+}
+
+# Runs these tests using:
+# fx run-host-tests fuchsia_inspect_package_unittests
+
+dart_test("fuchsia_inspect_package_unittests") {
+ sources = [
+ "internal/vmo_state_test.dart",
+ ]
+
+ deps = [
+ ":fuchsia_inspect",
+ "//third_party/dart-pkg/pub/mockito",
+ "//third_party/dart-pkg/pub/test",
+ ]
+}
+
diff --git a/public/dart/fuchsia_inspect/analysis_options.yaml b/public/dart/fuchsia_inspect/analysis_options.yaml
new file mode 100644
index 0000000..bebf512
--- /dev/null
+++ b/public/dart/fuchsia_inspect/analysis_options.yaml
@@ -0,0 +1,5 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include: ../../analysis_options.yaml
diff --git a/public/dart/fuchsia_inspect/lib/inspect.dart b/public/dart/fuchsia_inspect/lib/inspect.dart
new file mode 100644
index 0000000..fe3ebfd
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/inspect.dart
@@ -0,0 +1,6 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// The Inspect API for Dart.
+export 'src/inspect.dart';
diff --git a/public/dart/fuchsia_inspect/lib/src/inspect.dart b/public/dart/fuchsia_inspect/lib/src/inspect.dart
new file mode 100644
index 0000000..0e21806
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/src/inspect.dart
@@ -0,0 +1,18 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'vmo_writer.dart';
+
+const int _defaultVmoSizeBytes = 256 * 1024;
+
+/// Inspect exposes a structured tree of internal component state in a VMO.
+class Inspect {
+ final VmoWriter _vmo;
+
+ /// Initialize the VMO with given or default size.
+ Inspect([vmoSize = _defaultVmoSizeBytes]) : _vmo = VmoWriter(vmoSize);
+
+ /// Placeholder for the upper-level API.
+ bool get valid => _vmo != null;
+}
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo_format.dart b/public/dart/fuchsia_inspect/lib/src/vmo_format.dart
new file mode 100644
index 0000000..3dd4870
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/src/vmo_format.dart
@@ -0,0 +1,70 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'vmo_holder.dart';
+
+/// Types of VMO blocks.
+enum BlockType {
+ /// One block to rule them all. Index 0.
+ header,
+
+ /// Ready to be used.
+ free,
+
+ /// In transition toward being used.
+ reserved,
+
+ /// An entry in the Inspect tree, which may hold child Values: Nodes, Metrics, or Properties.
+ node,
+
+ /// An int Metric.
+ intValue,
+
+ /// A uint Metric.
+ uintValue,
+
+ /// A double Metric.
+ doubleValue,
+
+ /// A property that's been deleted but still has live children.
+ tombstone,
+
+ /// The header of a string (or byte-vector) Property.
+ propertyValue,
+
+ /// The contents of a string Property (in a singly linked list, if necessary).
+ extent,
+
+ /// The name of a Value (Property, Metric, or Node) (must be contained in this one block).
+ name
+}
+
+/// Mirrors a single block in the VMO.
+///
+/// Can be read from VMO and/or modified by code, then written to VMO if desired.
+class Block {
+ /// Order: size = 2^(order+4); order is 1 in this slab allocator.
+ int order = 1;
+
+ /// The VMO-format-defined type of this block.
+ BlockType type;
+
+ /// Index of the block within the VMO.
+ final int index;
+
+ /// Reads the block at this index from the VMO.
+ Block.read(VmoHolder vmo, this.index) {
+ ByteData data = vmo.read(index * 16, 32);
+ int header = data.getUint8(0);
+ // TODO(cphoenix): Replace this with Bitfield64 and less-magic bit locations.
+ type = BlockType.values[header & 0x0F];
+ order = header >> 4;
+ // TODO(cphoenix): Read the rest of the block, depending on type.
+ }
+
+ /// Size of the [Block] in bytes.
+ int get size => 1 << (order + 4);
+}
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo_heap.dart b/public/dart/fuchsia_inspect/lib/src/vmo_heap.dart
new file mode 100644
index 0000000..455f0c7
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/src/vmo_heap.dart
@@ -0,0 +1,50 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'vmo_holder.dart';
+
+const int _blockSize = 32;
+
+/// The base class for which log writers will inherit from.
+///
+/// (The current implementation is a barely-MVP heap: a 32-byte-block slab allocator.)
+class VmoHeap extends VmoHolder {
+ /// Size in bytes of the touched / visited subset of the VMO incorporated in the data structure.
+ int _currentSize;
+
+ /// Max size of the VMO in bytes.
+ final int _maxSize;
+
+ /// Offset of the first block on the freelist.
+ int _freelistHead = 0;
+
+ /// Construct with (initially touched size, maximum available size) of VMO.
+ VmoHeap(this._currentSize, this._maxSize) : super(_maxSize) {
+ _addFreelistBlocks(0, _currentSize);
+ }
+
+ void _addFreelistBlocks(int existingSize, int newSize) {
+ // Placeholder code, not tested, certainly wrong.
+ _freelistHead = existingSize;
+ int i;
+ for (i = existingSize; i < newSize - _blockSize; i += _blockSize) {
+ writeInt64(i, i + _blockSize);
+ }
+ writeInt64(i, _freelistHead);
+ _freelistHead = existingSize;
+ }
+
+ /// Maps more of the VMO.
+ void growVmo(int desiredSize) {
+ if (_currentSize == _maxSize) {
+ return; // Fail silently.
+ }
+ int newSize = desiredSize;
+ if (newSize > _maxSize) {
+ newSize = _maxSize;
+ }
+ _addFreelistBlocks(_currentSize, newSize);
+ _currentSize = newSize;
+ }
+}
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo_holder.dart b/public/dart/fuchsia_inspect/lib/src/vmo_holder.dart
new file mode 100644
index 0000000..13a2d36
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/src/vmo_holder.dart
@@ -0,0 +1,52 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:typed_data';
+import 'package:zircon/zircon.dart';
+
+/// Holder for a VMO with read/write capability.
+class VmoHolder {
+ int _size;
+ Vmo _vmo;
+
+ /// Creates and holds a VMO of desired size.
+ VmoHolder(this._size) {
+ HandleResult result = System.vmoCreate(_size);
+ if (result.status != ZX.OK) {
+ throw new ZxStatusException(
+ result.status, getStringForStatus(result.status));
+ }
+ _vmo = Vmo(result.handle);
+ }
+
+ /// Writes data to VMO at offset (not index).
+ void write(int offset, ByteData data) {
+ int status = _vmo.write(data, offset);
+ if (status != ZX.OK) {
+ throw new ZxStatusException(status, getStringForStatus(status));
+ }
+ }
+
+ /// Reads data from VMO at offset (not index).
+ ByteData read(int offset, int size) {
+ ReadResult result = _vmo.read(size, offset);
+ if (result.status != ZX.OK) {
+ throw new ZxStatusException(
+ result.status, getStringForStatus(result.status));
+ }
+ return result.bytes;
+ }
+
+ /// Writes int64 to VMO.
+ void writeInt64(int offset, int value) {
+ var data = ByteData(8)..setInt64(0, value, Endian.little);
+ write(offset, data);
+ }
+
+ /// Reads int64 from VMO.
+ int readInt64(int offset) {
+ ByteData data = read(8, offset);
+ return data.getInt64(0, Endian.little);
+ }
+}
diff --git a/public/dart/fuchsia_inspect/lib/src/vmo_writer.dart b/public/dart/fuchsia_inspect/lib/src/vmo_writer.dart
new file mode 100644
index 0000000..85cf57b
--- /dev/null
+++ b/public/dart/fuchsia_inspect/lib/src/vmo_writer.dart
@@ -0,0 +1,96 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'vmo_heap.dart';
+
+/// Opaque information referring to a Value (Property, Metric, Node) stored in the VMO.
+///
+/// The user of this API should not care about what's in InspectHandle - just hold it
+/// and pass it back to VmoWriter for further operations on the Value referred to by the handle.
+class InspectHandle {
+ /// First opaque number.
+ int opaque1;
+
+ /// Second opaque number.
+ int opaque2;
+
+ /// Constructor
+ InspectHandle(this.opaque1, this.opaque2);
+}
+
+/// An Inspect-format VMO with accessors.
+///
+/// This holds a VMO, writes Nodes, Metrics, and Properties to
+/// the VMO, modifies them, and deletes them.
+class VmoWriter {
+ final VmoHeap _vmo;
+
+ /// Constructor.
+ ///
+ /// maxSize should be >= 32 bytes and will be rounded up to a multiple of 4K.
+ VmoWriter(int maxSizeBytes) : _vmo = VmoHeap(maxSizeBytes, maxSizeBytes);
+
+ // All the implementations here are trivially wrong placeholders.
+ // For now, just look at the method signature.
+
+ /// Gets the top Node of the Inspect tree.
+ InspectHandle get rootNode => InspectHandle(1, 2);
+
+ /// Creates a new Node inside the tree.
+ InspectHandle createNode(InspectHandle parent, String name) {
+ return parent;
+ }
+
+ /// Frees the Node.
+ void freeNode(InspectHandle node) {
+ _vmo.writeInt64(node.opaque1, 0);
+ }
+
+ /// Adds a named Property to an node.
+ InspectHandle createProperty(InspectHandle parentNode, ByteData name) {
+ _vmo.write(parentNode.opaque1, name);
+ return parentNode;
+ }
+
+ /// Sets a Property's value.
+ void setProperty(InspectHandle property, ByteData value) {
+ _vmo.write(property.opaque1, value);
+ }
+
+ /// Deletes a Property.
+ void freeProperty(InspectHandle property) {
+ _vmo.writeInt64(property.opaque1, 0);
+ }
+
+ // TODO(cphoenix): Convert to generic for Int and Double (not Uint).
+
+ /// Creates and assigns value.
+ InspectHandle createIntMetric(
+ InspectHandle parentNode, String name, int value) {
+ _vmo.writeInt64(parentNode.opaque1, value);
+ return parentNode;
+ }
+
+ /// Sets the metric's value.
+ void setIntMetric(InspectHandle metric, int value) {
+ _vmo.writeInt64(metric.opaque1, value);
+ }
+
+ /// Adds to existing value.
+ void addIntMetric(InspectHandle metric, int value) {
+ _vmo.writeInt64(metric.opaque1, value);
+ }
+
+ /// Subtracts from existing value.
+ void subtractIntMetric(InspectHandle metric, int value) {
+ _vmo.writeInt64(metric.opaque1, value);
+ }
+
+ /// Deletes the Metric.
+ void freeIntMetric(InspectHandle metric) {
+ _vmo.writeInt64(metric.opaque1, 0);
+ }
+}
diff --git a/public/dart/fuchsia_inspect/pubspec.yaml b/public/dart/fuchsia_inspect/pubspec.yaml
new file mode 100644
index 0000000..2d6dba0
--- /dev/null
+++ b/public/dart/fuchsia_inspect/pubspec.yaml
@@ -0,0 +1,7 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+name: fuchsia_inspect
+environment:
+ sdk: '>=2.0.0 <3.0.0'
diff --git a/public/dart/fuchsia_inspect/test/internal/vmo_state_test.dart b/public/dart/fuchsia_inspect/test/internal/vmo_state_test.dart
new file mode 100644
index 0000000..0c345d1
--- /dev/null
+++ b/public/dart/fuchsia_inspect/test/internal/vmo_state_test.dart
@@ -0,0 +1,22 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: implementation_imports, unused_import
+
+// Since we don't have tests yet, import everything to make sure it at least compiles.
+import 'package:test/test.dart';
+import 'package:fuchsia_inspect/inspect.dart';
+import 'package:fuchsia_inspect/src/inspect.dart';
+import 'package:fuchsia_inspect/src/vmo_format.dart';
+import 'package:fuchsia_inspect/src/vmo_heap.dart';
+import 'package:fuchsia_inspect/src/vmo_holder.dart';
+import 'package:fuchsia_inspect/src/vmo_writer.dart';
+
+void main() {
+ group('placeholder for tests', () {
+ test('trivial', () {
+ expect(41, equals(41));
+ });
+ });
+}