Add 'Flog' formatted logging to mojo/services
Introduces service definitions for 'Flog' (formatting logging) and
associated C++ library for adding log generation to services and
applications. No logging service is implemented yet, just the stuff
needed to annotate code that needs to generate log messages.

R=kulakowski@chromium.org

Review URL: https://codereview.chromium.org/2008553006 .
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/flog/flog.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/flog/flog.mojom.dart
new file mode 100644
index 0000000..738b2fc
--- /dev/null
+++ b/mojo/dart/packages/mojo_services/lib/mojo/flog/flog.mojom.dart
@@ -0,0 +1,2164 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library flog_mojom;
+import 'dart:async';
+import 'package:mojo/bindings.dart' as bindings;
+import 'package:mojo/core.dart' as core;
+import 'package:mojo/mojo/bindings/types/service_describer.mojom.dart' as service_describer;
+
+
+
+class FlogDescription extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(48, 0)
+  ];
+  String label = null;
+  int logId = 0;
+  int entryCount = 0;
+  int startTimeUs = 0;
+  int stopTimeUs = 0;
+  bool open = false;
+
+  FlogDescription() : super(kVersions.last.size);
+
+  static FlogDescription deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static FlogDescription decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    FlogDescription result = new FlogDescription();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.label = decoder0.decodeString(8, false);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.logId = decoder0.decodeUint32(16);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.entryCount = decoder0.decodeUint32(20);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.startTimeUs = decoder0.decodeInt64(24);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.stopTimeUs = decoder0.decodeInt64(32);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.open = decoder0.decodeBool(40, 0);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeString(label, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "label of struct FlogDescription: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(logId, 16);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "logId of struct FlogDescription: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(entryCount, 20);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "entryCount of struct FlogDescription: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeInt64(startTimeUs, 24);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "startTimeUs of struct FlogDescription: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeInt64(stopTimeUs, 32);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "stopTimeUs of struct FlogDescription: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeBool(open, 40, 0);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "open of struct FlogDescription: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "FlogDescription("
+           "label: $label" ", "
+           "logId: $logId" ", "
+           "entryCount: $entryCount" ", "
+           "startTimeUs: $startTimeUs" ", "
+           "stopTimeUs: $stopTimeUs" ", "
+           "open: $open" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["label"] = label;
+    map["logId"] = logId;
+    map["entryCount"] = entryCount;
+    map["startTimeUs"] = startTimeUs;
+    map["stopTimeUs"] = stopTimeUs;
+    map["open"] = open;
+    return map;
+  }
+}
+
+
+class FlogEntry extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(40, 0)
+  ];
+  int timeUs = 0;
+  int logId = 0;
+  int channelId = 0;
+  FlogEntryDetails details = null;
+
+  FlogEntry() : super(kVersions.last.size);
+
+  static FlogEntry deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static FlogEntry decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    FlogEntry result = new FlogEntry();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.timeUs = decoder0.decodeInt64(8);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.logId = decoder0.decodeUint32(16);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.channelId = decoder0.decodeUint32(20);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+        result.details = FlogEntryDetails.decode(decoder0, 24);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInt64(timeUs, 8);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "timeUs of struct FlogEntry: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(logId, 16);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "logId of struct FlogEntry: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(channelId, 20);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "channelId of struct FlogEntry: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUnion(details, 24, true);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "details of struct FlogEntry: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "FlogEntry("
+           "timeUs: $timeUs" ", "
+           "logId: $logId" ", "
+           "channelId: $channelId" ", "
+           "details: $details" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["timeUs"] = timeUs;
+    map["logId"] = logId;
+    map["channelId"] = channelId;
+    map["details"] = details;
+    return map;
+  }
+}
+
+
+class FlogChannelCreationEntryDetails extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  String typeName = null;
+
+  FlogChannelCreationEntryDetails() : super(kVersions.last.size);
+
+  static FlogChannelCreationEntryDetails deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static FlogChannelCreationEntryDetails decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    FlogChannelCreationEntryDetails result = new FlogChannelCreationEntryDetails();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.typeName = decoder0.decodeString(8, false);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeString(typeName, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "typeName of struct FlogChannelCreationEntryDetails: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "FlogChannelCreationEntryDetails("
+           "typeName: $typeName" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["typeName"] = typeName;
+    return map;
+  }
+}
+
+
+class FlogChannelMessageEntryDetails extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  List<int> data = null;
+
+  FlogChannelMessageEntryDetails() : super(kVersions.last.size);
+
+  static FlogChannelMessageEntryDetails deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static FlogChannelMessageEntryDetails decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    FlogChannelMessageEntryDetails result = new FlogChannelMessageEntryDetails();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.data = decoder0.decodeUint8Array(8, bindings.kNothingNullable, bindings.kUnspecifiedArrayLength);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeUint8Array(data, 8, bindings.kNothingNullable, bindings.kUnspecifiedArrayLength);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "data of struct FlogChannelMessageEntryDetails: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "FlogChannelMessageEntryDetails("
+           "data: $data" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["data"] = data;
+    return map;
+  }
+}
+
+
+class _FlogServiceCreateLoggerParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(24, 0)
+  ];
+  FlogLoggerInterfaceRequest logger = null;
+  String label = null;
+
+  _FlogServiceCreateLoggerParams() : super(kVersions.last.size);
+
+  static _FlogServiceCreateLoggerParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogServiceCreateLoggerParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogServiceCreateLoggerParams result = new _FlogServiceCreateLoggerParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.logger = decoder0.decodeInterfaceRequest(8, false, FlogLoggerStub.newFromEndpoint);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.label = decoder0.decodeString(16, false);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInterfaceRequest(logger, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "logger of struct _FlogServiceCreateLoggerParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeString(label, 16, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "label of struct _FlogServiceCreateLoggerParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "_FlogServiceCreateLoggerParams("
+           "logger: $logger" ", "
+           "label: $label" ")";
+  }
+
+  Map toJson() {
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
+  }
+}
+
+
+class _FlogServiceGetLogDescriptionsParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(8, 0)
+  ];
+
+  _FlogServiceGetLogDescriptionsParams() : super(kVersions.last.size);
+
+  static _FlogServiceGetLogDescriptionsParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogServiceGetLogDescriptionsParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogServiceGetLogDescriptionsParams result = new _FlogServiceGetLogDescriptionsParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    encoder.getStructEncoderAtOffset(kVersions.last);
+  }
+
+  String toString() {
+    return "_FlogServiceGetLogDescriptionsParams("")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    return map;
+  }
+}
+
+
+class FlogServiceGetLogDescriptionsResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  List<FlogDescription> descriptions = null;
+
+  FlogServiceGetLogDescriptionsResponseParams() : super(kVersions.last.size);
+
+  static FlogServiceGetLogDescriptionsResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static FlogServiceGetLogDescriptionsResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    FlogServiceGetLogDescriptionsResponseParams result = new FlogServiceGetLogDescriptionsResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, false);
+      {
+        var si1 = decoder1.decodeDataHeaderForPointerArray(bindings.kUnspecifiedArrayLength);
+        result.descriptions = new List<FlogDescription>(si1.numElements);
+        for (int i1 = 0; i1 < si1.numElements; ++i1) {
+          
+          var decoder2 = decoder1.decodePointer(bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i1, false);
+          result.descriptions[i1] = FlogDescription.decode(decoder2);
+        }
+      }
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      if (descriptions == null) {
+        encoder0.encodeNullPointer(8, false);
+      } else {
+        var encoder1 = encoder0.encodePointerArray(descriptions.length, 8, bindings.kUnspecifiedArrayLength);
+        for (int i0 = 0; i0 < descriptions.length; ++i0) {
+          encoder1.encodeStruct(descriptions[i0], bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i0, false);
+        }
+      }
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "descriptions of struct FlogServiceGetLogDescriptionsResponseParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "FlogServiceGetLogDescriptionsResponseParams("
+           "descriptions: $descriptions" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["descriptions"] = descriptions;
+    return map;
+  }
+}
+
+
+class _FlogServiceCreateReaderParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  FlogReaderInterfaceRequest reader = null;
+  int logId = 0;
+
+  _FlogServiceCreateReaderParams() : super(kVersions.last.size);
+
+  static _FlogServiceCreateReaderParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogServiceCreateReaderParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogServiceCreateReaderParams result = new _FlogServiceCreateReaderParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.reader = decoder0.decodeInterfaceRequest(8, false, FlogReaderStub.newFromEndpoint);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.logId = decoder0.decodeUint32(12);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInterfaceRequest(reader, 8, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "reader of struct _FlogServiceCreateReaderParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(logId, 12);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "logId of struct _FlogServiceCreateReaderParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "_FlogServiceCreateReaderParams("
+           "reader: $reader" ", "
+           "logId: $logId" ")";
+  }
+
+  Map toJson() {
+    throw new bindings.MojoCodecError(
+        'Object containing handles cannot be encoded to JSON.');
+  }
+}
+
+
+class _FlogLoggerLogChannelCreationParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(32, 0)
+  ];
+  int timeUs = 0;
+  int channelId = 0;
+  String typeName = null;
+
+  _FlogLoggerLogChannelCreationParams() : super(kVersions.last.size);
+
+  static _FlogLoggerLogChannelCreationParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogLoggerLogChannelCreationParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogLoggerLogChannelCreationParams result = new _FlogLoggerLogChannelCreationParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.timeUs = decoder0.decodeInt64(8);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.channelId = decoder0.decodeUint32(16);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.typeName = decoder0.decodeString(24, false);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInt64(timeUs, 8);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "timeUs of struct _FlogLoggerLogChannelCreationParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(channelId, 16);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "channelId of struct _FlogLoggerLogChannelCreationParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeString(typeName, 24, false);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "typeName of struct _FlogLoggerLogChannelCreationParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "_FlogLoggerLogChannelCreationParams("
+           "timeUs: $timeUs" ", "
+           "channelId: $channelId" ", "
+           "typeName: $typeName" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["timeUs"] = timeUs;
+    map["channelId"] = channelId;
+    map["typeName"] = typeName;
+    return map;
+  }
+}
+
+
+class _FlogLoggerLogChannelMessageParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(32, 0)
+  ];
+  int timeUs = 0;
+  int channelId = 0;
+  List<int> data = null;
+
+  _FlogLoggerLogChannelMessageParams() : super(kVersions.last.size);
+
+  static _FlogLoggerLogChannelMessageParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogLoggerLogChannelMessageParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogLoggerLogChannelMessageParams result = new _FlogLoggerLogChannelMessageParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.timeUs = decoder0.decodeInt64(8);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.channelId = decoder0.decodeUint32(16);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.data = decoder0.decodeUint8Array(24, bindings.kNothingNullable, bindings.kUnspecifiedArrayLength);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInt64(timeUs, 8);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "timeUs of struct _FlogLoggerLogChannelMessageParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(channelId, 16);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "channelId of struct _FlogLoggerLogChannelMessageParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint8Array(data, 24, bindings.kNothingNullable, bindings.kUnspecifiedArrayLength);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "data of struct _FlogLoggerLogChannelMessageParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "_FlogLoggerLogChannelMessageParams("
+           "timeUs: $timeUs" ", "
+           "channelId: $channelId" ", "
+           "data: $data" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["timeUs"] = timeUs;
+    map["channelId"] = channelId;
+    map["data"] = data;
+    return map;
+  }
+}
+
+
+class _FlogLoggerLogChannelDeletionParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(24, 0)
+  ];
+  int timeUs = 0;
+  int channelId = 0;
+
+  _FlogLoggerLogChannelDeletionParams() : super(kVersions.last.size);
+
+  static _FlogLoggerLogChannelDeletionParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogLoggerLogChannelDeletionParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogLoggerLogChannelDeletionParams result = new _FlogLoggerLogChannelDeletionParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.timeUs = decoder0.decodeInt64(8);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.channelId = decoder0.decodeUint32(16);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeInt64(timeUs, 8);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "timeUs of struct _FlogLoggerLogChannelDeletionParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(channelId, 16);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "channelId of struct _FlogLoggerLogChannelDeletionParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "_FlogLoggerLogChannelDeletionParams("
+           "timeUs: $timeUs" ", "
+           "channelId: $channelId" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["timeUs"] = timeUs;
+    map["channelId"] = channelId;
+    return map;
+  }
+}
+
+
+class _FlogReaderGetEntriesParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  int startIndex = 0;
+  int maxCount = 0;
+
+  _FlogReaderGetEntriesParams() : super(kVersions.last.size);
+
+  static _FlogReaderGetEntriesParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static _FlogReaderGetEntriesParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    _FlogReaderGetEntriesParams result = new _FlogReaderGetEntriesParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.startIndex = decoder0.decodeUint32(8);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.maxCount = decoder0.decodeUint32(12);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      encoder0.encodeUint32(startIndex, 8);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "startIndex of struct _FlogReaderGetEntriesParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(maxCount, 12);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "maxCount of struct _FlogReaderGetEntriesParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "_FlogReaderGetEntriesParams("
+           "startIndex: $startIndex" ", "
+           "maxCount: $maxCount" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["startIndex"] = startIndex;
+    map["maxCount"] = maxCount;
+    return map;
+  }
+}
+
+
+class FlogReaderGetEntriesResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(24, 0)
+  ];
+  List<FlogEntry> entries = null;
+  int entryCount = 0;
+  bool open = false;
+
+  FlogReaderGetEntriesResponseParams() : super(kVersions.last.size);
+
+  static FlogReaderGetEntriesResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static FlogReaderGetEntriesResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    FlogReaderGetEntriesResponseParams result = new FlogReaderGetEntriesResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, false);
+      {
+        var si1 = decoder1.decodeDataHeaderForPointerArray(bindings.kUnspecifiedArrayLength);
+        result.entries = new List<FlogEntry>(si1.numElements);
+        for (int i1 = 0; i1 < si1.numElements; ++i1) {
+          
+          var decoder2 = decoder1.decodePointer(bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i1, false);
+          result.entries[i1] = FlogEntry.decode(decoder2);
+        }
+      }
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.entryCount = decoder0.decodeUint32(16);
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      result.open = decoder0.decodeBool(20, 0);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    try {
+      if (entries == null) {
+        encoder0.encodeNullPointer(8, false);
+      } else {
+        var encoder1 = encoder0.encodePointerArray(entries.length, 8, bindings.kUnspecifiedArrayLength);
+        for (int i0 = 0; i0 < entries.length; ++i0) {
+          encoder1.encodeStruct(entries[i0], bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i0, false);
+        }
+      }
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "entries of struct FlogReaderGetEntriesResponseParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeUint32(entryCount, 16);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "entryCount of struct FlogReaderGetEntriesResponseParams: $e";
+      rethrow;
+    }
+    try {
+      encoder0.encodeBool(open, 20, 0);
+    } on bindings.MojoCodecError catch(e) {
+      e.message = "Error encountered while encoding field "
+          "open of struct FlogReaderGetEntriesResponseParams: $e";
+      rethrow;
+    }
+  }
+
+  String toString() {
+    return "FlogReaderGetEntriesResponseParams("
+           "entries: $entries" ", "
+           "entryCount: $entryCount" ", "
+           "open: $open" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["entries"] = entries;
+    map["entryCount"] = entryCount;
+    map["open"] = open;
+    return map;
+  }
+}
+
+
+
+enum FlogEntryDetailsTag {
+  channelCreation,
+  channelMessage,
+  unknown
+}
+
+class FlogEntryDetails extends bindings.Union {
+  static final _tagToInt = const {
+    FlogEntryDetailsTag.channelCreation: 0,
+    FlogEntryDetailsTag.channelMessage: 1,
+  };
+
+  static final _intToTag = const {
+    0: FlogEntryDetailsTag.channelCreation,
+    1: FlogEntryDetailsTag.channelMessage,
+  };
+
+  var _data;
+  FlogEntryDetailsTag _tag = FlogEntryDetailsTag.unknown;
+
+  FlogEntryDetailsTag get tag => _tag;
+  FlogChannelCreationEntryDetails get channelCreation {
+    if (_tag != FlogEntryDetailsTag.channelCreation) {
+      throw new bindings.UnsetUnionTagError(_tag, FlogEntryDetailsTag.channelCreation);
+    }
+    return _data;
+  }
+
+  set channelCreation(FlogChannelCreationEntryDetails value) {
+    _tag = FlogEntryDetailsTag.channelCreation;
+    _data = value;
+  }
+  FlogChannelMessageEntryDetails get channelMessage {
+    if (_tag != FlogEntryDetailsTag.channelMessage) {
+      throw new bindings.UnsetUnionTagError(_tag, FlogEntryDetailsTag.channelMessage);
+    }
+    return _data;
+  }
+
+  set channelMessage(FlogChannelMessageEntryDetails value) {
+    _tag = FlogEntryDetailsTag.channelMessage;
+    _data = value;
+  }
+
+  static FlogEntryDetails decode(bindings.Decoder decoder0, int offset) {
+    int size = decoder0.decodeUint32(offset);
+    if (size == 0) {
+      return null;
+    }
+    FlogEntryDetails result = new FlogEntryDetails();
+
+    
+    FlogEntryDetailsTag tag = _intToTag[decoder0.decodeUint32(offset + 4)];
+    switch (tag) {
+      case FlogEntryDetailsTag.channelCreation:
+        
+        var decoder1 = decoder0.decodePointer(offset + 8, false);
+        result.channelCreation = FlogChannelCreationEntryDetails.decode(decoder1);
+        break;
+      case FlogEntryDetailsTag.channelMessage:
+        
+        var decoder1 = decoder0.decodePointer(offset + 8, false);
+        result.channelMessage = FlogChannelMessageEntryDetails.decode(decoder1);
+        break;
+      default:
+        throw new bindings.MojoCodecError("Bad union tag: $tag");
+    }
+
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder0, int offset) {
+    
+    encoder0.encodeUint32(16, offset);
+    encoder0.encodeUint32(_tagToInt[_tag], offset + 4);
+    switch (_tag) {
+      case FlogEntryDetailsTag.channelCreation:
+        encoder0.encodeStruct(channelCreation, offset + 8, false);
+        break;
+      case FlogEntryDetailsTag.channelMessage:
+        encoder0.encodeStruct(channelMessage, offset + 8, false);
+        break;
+      default:
+        throw new bindings.MojoCodecError("Bad union tag: $_tag");
+    }
+  }
+
+  String toString() {
+    String result = "FlogEntryDetails(";
+    switch (_tag) {
+      case FlogEntryDetailsTag.channelCreation:
+        result += "channelCreation";
+        break;
+      case FlogEntryDetailsTag.channelMessage:
+        result += "channelMessage";
+        break;
+      default:
+        result += "unknown";
+    }
+    result += ": $_data)";
+    return result;
+  }
+}
+const int _flogServiceMethodCreateLoggerName = 0;
+const int _flogServiceMethodGetLogDescriptionsName = 1;
+const int _flogServiceMethodCreateReaderName = 2;
+
+class _FlogServiceServiceDescription implements service_describer.ServiceDescription {
+  dynamic getTopLevelInterface([Function responseFactory]) =>
+      responseFactory(null);
+
+  dynamic getTypeDefinition(String typeKey, [Function responseFactory]) =>
+      responseFactory(null);
+
+  dynamic getAllTypeDefinitions([Function responseFactory]) =>
+      responseFactory(null);
+}
+
+abstract class FlogService {
+  static const String serviceName = "mojo::flog::FlogService";
+
+  static service_describer.ServiceDescription _cachedServiceDescription;
+  static service_describer.ServiceDescription get serviceDescription {
+    if (_cachedServiceDescription == null) {
+      _cachedServiceDescription = new _FlogServiceServiceDescription();
+    }
+    return _cachedServiceDescription;
+  }
+
+  static FlogServiceProxy connectToService(
+      bindings.ServiceConnector s, String url, [String serviceName]) {
+    FlogServiceProxy p = new FlogServiceProxy.unbound();
+    String name = serviceName ?? FlogService.serviceName;
+    if ((name == null) || name.isEmpty) {
+      throw new core.MojoApiError(
+          "If an interface has no ServiceName, then one must be provided.");
+    }
+    s.connectToService(url, p, name);
+    return p;
+  }
+  void createLogger(FlogLoggerInterfaceRequest logger, String label);
+  dynamic getLogDescriptions([Function responseFactory = null]);
+  void createReader(FlogReaderInterfaceRequest reader, int logId);
+}
+
+abstract class FlogServiceInterface
+    implements bindings.MojoInterface<FlogService>,
+               FlogService {
+  factory FlogServiceInterface([FlogService impl]) =>
+      new FlogServiceStub.unbound(impl);
+  factory FlogServiceInterface.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint,
+      [FlogService impl]) =>
+      new FlogServiceStub.fromEndpoint(endpoint, impl);
+}
+
+abstract class FlogServiceInterfaceRequest
+    implements bindings.MojoInterface<FlogService>,
+               FlogService {
+  factory FlogServiceInterfaceRequest() =>
+      new FlogServiceProxy.unbound();
+}
+
+class _FlogServiceProxyControl
+    extends bindings.ProxyMessageHandler
+    implements bindings.ProxyControl<FlogService> {
+  _FlogServiceProxyControl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
+
+  _FlogServiceProxyControl.fromHandle(
+      core.MojoHandle handle) : super.fromHandle(handle);
+
+  _FlogServiceProxyControl.unbound() : super.unbound();
+
+  String get serviceName => FlogService.serviceName;
+
+  void handleResponse(bindings.ServiceMessage message) {
+    switch (message.header.type) {
+      case _flogServiceMethodGetLogDescriptionsName:
+        var r = FlogServiceGetLogDescriptionsResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
+      default:
+        proxyError("Unexpected message type: ${message.header.type}");
+        close(immediate: true);
+        break;
+    }
+  }
+
+  FlogService get impl => null;
+  set impl(FlogService _) {
+    throw new core.MojoApiError("The impl of a Proxy cannot be set.");
+  }
+
+  @override
+  String toString() {
+    var superString = super.toString();
+    return "_FlogServiceProxyControl($superString)";
+  }
+}
+
+class FlogServiceProxy
+    extends bindings.Proxy<FlogService>
+    implements FlogService,
+               FlogServiceInterface,
+               FlogServiceInterfaceRequest {
+  FlogServiceProxy.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint)
+      : super(new _FlogServiceProxyControl.fromEndpoint(endpoint));
+
+  FlogServiceProxy.fromHandle(core.MojoHandle handle)
+      : super(new _FlogServiceProxyControl.fromHandle(handle));
+
+  FlogServiceProxy.unbound()
+      : super(new _FlogServiceProxyControl.unbound());
+
+  static FlogServiceProxy newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For FlogServiceProxy"));
+    return new FlogServiceProxy.fromEndpoint(endpoint);
+  }
+
+
+  void createLogger(FlogLoggerInterfaceRequest logger, String label) {
+    if (!ctrl.isBound) {
+      ctrl.proxyError("The Proxy is closed.");
+      return;
+    }
+    var params = new _FlogServiceCreateLoggerParams();
+    params.logger = logger;
+    params.label = label;
+    ctrl.sendMessage(params,
+        _flogServiceMethodCreateLoggerName);
+  }
+  dynamic getLogDescriptions([Function responseFactory = null]) {
+    var params = new _FlogServiceGetLogDescriptionsParams();
+    return ctrl.sendMessageWithRequestId(
+        params,
+        _flogServiceMethodGetLogDescriptionsName,
+        -1,
+        bindings.MessageHeader.kMessageExpectsResponse);
+  }
+  void createReader(FlogReaderInterfaceRequest reader, int logId) {
+    if (!ctrl.isBound) {
+      ctrl.proxyError("The Proxy is closed.");
+      return;
+    }
+    var params = new _FlogServiceCreateReaderParams();
+    params.reader = reader;
+    params.logId = logId;
+    ctrl.sendMessage(params,
+        _flogServiceMethodCreateReaderName);
+  }
+}
+
+class _FlogServiceStubControl
+    extends bindings.StubMessageHandler
+    implements bindings.StubControl<FlogService> {
+  FlogService _impl;
+
+  _FlogServiceStubControl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [FlogService impl])
+      : super.fromEndpoint(endpoint, autoBegin: impl != null) {
+    _impl = impl;
+  }
+
+  _FlogServiceStubControl.fromHandle(
+      core.MojoHandle handle, [FlogService impl])
+      : super.fromHandle(handle, autoBegin: impl != null) {
+    _impl = impl;
+  }
+
+  _FlogServiceStubControl.unbound([this._impl]) : super.unbound();
+
+  String get serviceName => FlogService.serviceName;
+
+
+  FlogServiceGetLogDescriptionsResponseParams _flogServiceGetLogDescriptionsResponseParamsFactory(List<FlogDescription> descriptions) {
+    var result = new FlogServiceGetLogDescriptionsResponseParams();
+    result.descriptions = descriptions;
+    return result;
+  }
+
+  dynamic handleMessage(bindings.ServiceMessage message) {
+    if (bindings.ControlMessageHandler.isControlMessage(message)) {
+      return bindings.ControlMessageHandler.handleMessage(this,
+                                                          0,
+                                                          message);
+    }
+    if (_impl == null) {
+      throw new core.MojoApiError("$this has no implementation set");
+    }
+    switch (message.header.type) {
+      case _flogServiceMethodCreateLoggerName:
+        var params = _FlogServiceCreateLoggerParams.deserialize(
+            message.payload);
+        _impl.createLogger(params.logger, params.label);
+        break;
+      case _flogServiceMethodGetLogDescriptionsName:
+        var response = _impl.getLogDescriptions(_flogServiceGetLogDescriptionsResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  _flogServiceMethodGetLogDescriptionsName,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              _flogServiceMethodGetLogDescriptionsName,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
+        break;
+      case _flogServiceMethodCreateReaderName:
+        var params = _FlogServiceCreateReaderParams.deserialize(
+            message.payload);
+        _impl.createReader(params.reader, params.logId);
+        break;
+      default:
+        throw new bindings.MojoCodecError("Unexpected message name");
+        break;
+    }
+    return null;
+  }
+
+  FlogService get impl => _impl;
+  set impl(FlogService d) {
+    if (d == null) {
+      throw new core.MojoApiError("$this: Cannot set a null implementation");
+    }
+    if (isBound && (_impl == null)) {
+      beginHandlingEvents();
+    }
+    _impl = d;
+  }
+
+  @override
+  void bind(core.MojoMessagePipeEndpoint endpoint) {
+    super.bind(endpoint);
+    if (!isOpen && (_impl != null)) {
+      beginHandlingEvents();
+    }
+  }
+
+  @override
+  String toString() {
+    var superString = super.toString();
+    return "_FlogServiceStubControl($superString)";
+  }
+
+  int get version => 0;
+}
+
+class FlogServiceStub
+    extends bindings.Stub<FlogService>
+    implements FlogService,
+               FlogServiceInterface,
+               FlogServiceInterfaceRequest {
+  FlogServiceStub.unbound([FlogService impl])
+      : super(new _FlogServiceStubControl.unbound(impl));
+
+  FlogServiceStub.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [FlogService impl])
+      : super(new _FlogServiceStubControl.fromEndpoint(endpoint, impl));
+
+  FlogServiceStub.fromHandle(
+      core.MojoHandle handle, [FlogService impl])
+      : super(new _FlogServiceStubControl.fromHandle(handle, impl));
+
+  static FlogServiceStub newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For FlogServiceStub"));
+    return new FlogServiceStub.fromEndpoint(endpoint);
+  }
+
+
+  void createLogger(FlogLoggerInterfaceRequest logger, String label) {
+    return impl.createLogger(logger, label);
+  }
+  dynamic getLogDescriptions([Function responseFactory = null]) {
+    return impl.getLogDescriptions(responseFactory);
+  }
+  void createReader(FlogReaderInterfaceRequest reader, int logId) {
+    return impl.createReader(reader, logId);
+  }
+}
+
+const int _flogLoggerMethodLogChannelCreationName = 0;
+const int _flogLoggerMethodLogChannelMessageName = 1;
+const int _flogLoggerMethodLogChannelDeletionName = 2;
+
+class _FlogLoggerServiceDescription implements service_describer.ServiceDescription {
+  dynamic getTopLevelInterface([Function responseFactory]) =>
+      responseFactory(null);
+
+  dynamic getTypeDefinition(String typeKey, [Function responseFactory]) =>
+      responseFactory(null);
+
+  dynamic getAllTypeDefinitions([Function responseFactory]) =>
+      responseFactory(null);
+}
+
+abstract class FlogLogger {
+  static const String serviceName = null;
+
+  static service_describer.ServiceDescription _cachedServiceDescription;
+  static service_describer.ServiceDescription get serviceDescription {
+    if (_cachedServiceDescription == null) {
+      _cachedServiceDescription = new _FlogLoggerServiceDescription();
+    }
+    return _cachedServiceDescription;
+  }
+
+  static FlogLoggerProxy connectToService(
+      bindings.ServiceConnector s, String url, [String serviceName]) {
+    FlogLoggerProxy p = new FlogLoggerProxy.unbound();
+    String name = serviceName ?? FlogLogger.serviceName;
+    if ((name == null) || name.isEmpty) {
+      throw new core.MojoApiError(
+          "If an interface has no ServiceName, then one must be provided.");
+    }
+    s.connectToService(url, p, name);
+    return p;
+  }
+  void logChannelCreation(int timeUs, int channelId, String typeName);
+  void logChannelMessage(int timeUs, int channelId, List<int> data);
+  void logChannelDeletion(int timeUs, int channelId);
+}
+
+abstract class FlogLoggerInterface
+    implements bindings.MojoInterface<FlogLogger>,
+               FlogLogger {
+  factory FlogLoggerInterface([FlogLogger impl]) =>
+      new FlogLoggerStub.unbound(impl);
+  factory FlogLoggerInterface.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint,
+      [FlogLogger impl]) =>
+      new FlogLoggerStub.fromEndpoint(endpoint, impl);
+}
+
+abstract class FlogLoggerInterfaceRequest
+    implements bindings.MojoInterface<FlogLogger>,
+               FlogLogger {
+  factory FlogLoggerInterfaceRequest() =>
+      new FlogLoggerProxy.unbound();
+}
+
+class _FlogLoggerProxyControl
+    extends bindings.ProxyMessageHandler
+    implements bindings.ProxyControl<FlogLogger> {
+  _FlogLoggerProxyControl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
+
+  _FlogLoggerProxyControl.fromHandle(
+      core.MojoHandle handle) : super.fromHandle(handle);
+
+  _FlogLoggerProxyControl.unbound() : super.unbound();
+
+  String get serviceName => FlogLogger.serviceName;
+
+  void handleResponse(bindings.ServiceMessage message) {
+    switch (message.header.type) {
+      default:
+        proxyError("Unexpected message type: ${message.header.type}");
+        close(immediate: true);
+        break;
+    }
+  }
+
+  FlogLogger get impl => null;
+  set impl(FlogLogger _) {
+    throw new core.MojoApiError("The impl of a Proxy cannot be set.");
+  }
+
+  @override
+  String toString() {
+    var superString = super.toString();
+    return "_FlogLoggerProxyControl($superString)";
+  }
+}
+
+class FlogLoggerProxy
+    extends bindings.Proxy<FlogLogger>
+    implements FlogLogger,
+               FlogLoggerInterface,
+               FlogLoggerInterfaceRequest {
+  FlogLoggerProxy.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint)
+      : super(new _FlogLoggerProxyControl.fromEndpoint(endpoint));
+
+  FlogLoggerProxy.fromHandle(core.MojoHandle handle)
+      : super(new _FlogLoggerProxyControl.fromHandle(handle));
+
+  FlogLoggerProxy.unbound()
+      : super(new _FlogLoggerProxyControl.unbound());
+
+  static FlogLoggerProxy newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For FlogLoggerProxy"));
+    return new FlogLoggerProxy.fromEndpoint(endpoint);
+  }
+
+
+  void logChannelCreation(int timeUs, int channelId, String typeName) {
+    if (!ctrl.isBound) {
+      ctrl.proxyError("The Proxy is closed.");
+      return;
+    }
+    var params = new _FlogLoggerLogChannelCreationParams();
+    params.timeUs = timeUs;
+    params.channelId = channelId;
+    params.typeName = typeName;
+    ctrl.sendMessage(params,
+        _flogLoggerMethodLogChannelCreationName);
+  }
+  void logChannelMessage(int timeUs, int channelId, List<int> data) {
+    if (!ctrl.isBound) {
+      ctrl.proxyError("The Proxy is closed.");
+      return;
+    }
+    var params = new _FlogLoggerLogChannelMessageParams();
+    params.timeUs = timeUs;
+    params.channelId = channelId;
+    params.data = data;
+    ctrl.sendMessage(params,
+        _flogLoggerMethodLogChannelMessageName);
+  }
+  void logChannelDeletion(int timeUs, int channelId) {
+    if (!ctrl.isBound) {
+      ctrl.proxyError("The Proxy is closed.");
+      return;
+    }
+    var params = new _FlogLoggerLogChannelDeletionParams();
+    params.timeUs = timeUs;
+    params.channelId = channelId;
+    ctrl.sendMessage(params,
+        _flogLoggerMethodLogChannelDeletionName);
+  }
+}
+
+class _FlogLoggerStubControl
+    extends bindings.StubMessageHandler
+    implements bindings.StubControl<FlogLogger> {
+  FlogLogger _impl;
+
+  _FlogLoggerStubControl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [FlogLogger impl])
+      : super.fromEndpoint(endpoint, autoBegin: impl != null) {
+    _impl = impl;
+  }
+
+  _FlogLoggerStubControl.fromHandle(
+      core.MojoHandle handle, [FlogLogger impl])
+      : super.fromHandle(handle, autoBegin: impl != null) {
+    _impl = impl;
+  }
+
+  _FlogLoggerStubControl.unbound([this._impl]) : super.unbound();
+
+  String get serviceName => FlogLogger.serviceName;
+
+
+
+  dynamic handleMessage(bindings.ServiceMessage message) {
+    if (bindings.ControlMessageHandler.isControlMessage(message)) {
+      return bindings.ControlMessageHandler.handleMessage(this,
+                                                          0,
+                                                          message);
+    }
+    if (_impl == null) {
+      throw new core.MojoApiError("$this has no implementation set");
+    }
+    switch (message.header.type) {
+      case _flogLoggerMethodLogChannelCreationName:
+        var params = _FlogLoggerLogChannelCreationParams.deserialize(
+            message.payload);
+        _impl.logChannelCreation(params.timeUs, params.channelId, params.typeName);
+        break;
+      case _flogLoggerMethodLogChannelMessageName:
+        var params = _FlogLoggerLogChannelMessageParams.deserialize(
+            message.payload);
+        _impl.logChannelMessage(params.timeUs, params.channelId, params.data);
+        break;
+      case _flogLoggerMethodLogChannelDeletionName:
+        var params = _FlogLoggerLogChannelDeletionParams.deserialize(
+            message.payload);
+        _impl.logChannelDeletion(params.timeUs, params.channelId);
+        break;
+      default:
+        throw new bindings.MojoCodecError("Unexpected message name");
+        break;
+    }
+    return null;
+  }
+
+  FlogLogger get impl => _impl;
+  set impl(FlogLogger d) {
+    if (d == null) {
+      throw new core.MojoApiError("$this: Cannot set a null implementation");
+    }
+    if (isBound && (_impl == null)) {
+      beginHandlingEvents();
+    }
+    _impl = d;
+  }
+
+  @override
+  void bind(core.MojoMessagePipeEndpoint endpoint) {
+    super.bind(endpoint);
+    if (!isOpen && (_impl != null)) {
+      beginHandlingEvents();
+    }
+  }
+
+  @override
+  String toString() {
+    var superString = super.toString();
+    return "_FlogLoggerStubControl($superString)";
+  }
+
+  int get version => 0;
+}
+
+class FlogLoggerStub
+    extends bindings.Stub<FlogLogger>
+    implements FlogLogger,
+               FlogLoggerInterface,
+               FlogLoggerInterfaceRequest {
+  FlogLoggerStub.unbound([FlogLogger impl])
+      : super(new _FlogLoggerStubControl.unbound(impl));
+
+  FlogLoggerStub.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [FlogLogger impl])
+      : super(new _FlogLoggerStubControl.fromEndpoint(endpoint, impl));
+
+  FlogLoggerStub.fromHandle(
+      core.MojoHandle handle, [FlogLogger impl])
+      : super(new _FlogLoggerStubControl.fromHandle(handle, impl));
+
+  static FlogLoggerStub newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For FlogLoggerStub"));
+    return new FlogLoggerStub.fromEndpoint(endpoint);
+  }
+
+
+  void logChannelCreation(int timeUs, int channelId, String typeName) {
+    return impl.logChannelCreation(timeUs, channelId, typeName);
+  }
+  void logChannelMessage(int timeUs, int channelId, List<int> data) {
+    return impl.logChannelMessage(timeUs, channelId, data);
+  }
+  void logChannelDeletion(int timeUs, int channelId) {
+    return impl.logChannelDeletion(timeUs, channelId);
+  }
+}
+
+const int _flogReaderMethodGetEntriesName = 0;
+
+class _FlogReaderServiceDescription implements service_describer.ServiceDescription {
+  dynamic getTopLevelInterface([Function responseFactory]) =>
+      responseFactory(null);
+
+  dynamic getTypeDefinition(String typeKey, [Function responseFactory]) =>
+      responseFactory(null);
+
+  dynamic getAllTypeDefinitions([Function responseFactory]) =>
+      responseFactory(null);
+}
+
+abstract class FlogReader {
+  static const String serviceName = null;
+
+  static service_describer.ServiceDescription _cachedServiceDescription;
+  static service_describer.ServiceDescription get serviceDescription {
+    if (_cachedServiceDescription == null) {
+      _cachedServiceDescription = new _FlogReaderServiceDescription();
+    }
+    return _cachedServiceDescription;
+  }
+
+  static FlogReaderProxy connectToService(
+      bindings.ServiceConnector s, String url, [String serviceName]) {
+    FlogReaderProxy p = new FlogReaderProxy.unbound();
+    String name = serviceName ?? FlogReader.serviceName;
+    if ((name == null) || name.isEmpty) {
+      throw new core.MojoApiError(
+          "If an interface has no ServiceName, then one must be provided.");
+    }
+    s.connectToService(url, p, name);
+    return p;
+  }
+  dynamic getEntries(int startIndex,int maxCount,[Function responseFactory = null]);
+}
+
+abstract class FlogReaderInterface
+    implements bindings.MojoInterface<FlogReader>,
+               FlogReader {
+  factory FlogReaderInterface([FlogReader impl]) =>
+      new FlogReaderStub.unbound(impl);
+  factory FlogReaderInterface.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint,
+      [FlogReader impl]) =>
+      new FlogReaderStub.fromEndpoint(endpoint, impl);
+}
+
+abstract class FlogReaderInterfaceRequest
+    implements bindings.MojoInterface<FlogReader>,
+               FlogReader {
+  factory FlogReaderInterfaceRequest() =>
+      new FlogReaderProxy.unbound();
+}
+
+class _FlogReaderProxyControl
+    extends bindings.ProxyMessageHandler
+    implements bindings.ProxyControl<FlogReader> {
+  _FlogReaderProxyControl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) : super.fromEndpoint(endpoint);
+
+  _FlogReaderProxyControl.fromHandle(
+      core.MojoHandle handle) : super.fromHandle(handle);
+
+  _FlogReaderProxyControl.unbound() : super.unbound();
+
+  String get serviceName => FlogReader.serviceName;
+
+  void handleResponse(bindings.ServiceMessage message) {
+    switch (message.header.type) {
+      case _flogReaderMethodGetEntriesName:
+        var r = FlogReaderGetEntriesResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
+      default:
+        proxyError("Unexpected message type: ${message.header.type}");
+        close(immediate: true);
+        break;
+    }
+  }
+
+  FlogReader get impl => null;
+  set impl(FlogReader _) {
+    throw new core.MojoApiError("The impl of a Proxy cannot be set.");
+  }
+
+  @override
+  String toString() {
+    var superString = super.toString();
+    return "_FlogReaderProxyControl($superString)";
+  }
+}
+
+class FlogReaderProxy
+    extends bindings.Proxy<FlogReader>
+    implements FlogReader,
+               FlogReaderInterface,
+               FlogReaderInterfaceRequest {
+  FlogReaderProxy.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint)
+      : super(new _FlogReaderProxyControl.fromEndpoint(endpoint));
+
+  FlogReaderProxy.fromHandle(core.MojoHandle handle)
+      : super(new _FlogReaderProxyControl.fromHandle(handle));
+
+  FlogReaderProxy.unbound()
+      : super(new _FlogReaderProxyControl.unbound());
+
+  static FlogReaderProxy newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For FlogReaderProxy"));
+    return new FlogReaderProxy.fromEndpoint(endpoint);
+  }
+
+
+  dynamic getEntries(int startIndex,int maxCount,[Function responseFactory = null]) {
+    var params = new _FlogReaderGetEntriesParams();
+    params.startIndex = startIndex;
+    params.maxCount = maxCount;
+    return ctrl.sendMessageWithRequestId(
+        params,
+        _flogReaderMethodGetEntriesName,
+        -1,
+        bindings.MessageHeader.kMessageExpectsResponse);
+  }
+}
+
+class _FlogReaderStubControl
+    extends bindings.StubMessageHandler
+    implements bindings.StubControl<FlogReader> {
+  FlogReader _impl;
+
+  _FlogReaderStubControl.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [FlogReader impl])
+      : super.fromEndpoint(endpoint, autoBegin: impl != null) {
+    _impl = impl;
+  }
+
+  _FlogReaderStubControl.fromHandle(
+      core.MojoHandle handle, [FlogReader impl])
+      : super.fromHandle(handle, autoBegin: impl != null) {
+    _impl = impl;
+  }
+
+  _FlogReaderStubControl.unbound([this._impl]) : super.unbound();
+
+  String get serviceName => FlogReader.serviceName;
+
+
+  FlogReaderGetEntriesResponseParams _flogReaderGetEntriesResponseParamsFactory(List<FlogEntry> entries, int entryCount, bool open) {
+    var result = new FlogReaderGetEntriesResponseParams();
+    result.entries = entries;
+    result.entryCount = entryCount;
+    result.open = open;
+    return result;
+  }
+
+  dynamic handleMessage(bindings.ServiceMessage message) {
+    if (bindings.ControlMessageHandler.isControlMessage(message)) {
+      return bindings.ControlMessageHandler.handleMessage(this,
+                                                          0,
+                                                          message);
+    }
+    if (_impl == null) {
+      throw new core.MojoApiError("$this has no implementation set");
+    }
+    switch (message.header.type) {
+      case _flogReaderMethodGetEntriesName:
+        var params = _FlogReaderGetEntriesParams.deserialize(
+            message.payload);
+        var response = _impl.getEntries(params.startIndex,params.maxCount,_flogReaderGetEntriesResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  _flogReaderMethodGetEntriesName,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              _flogReaderMethodGetEntriesName,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
+        break;
+      default:
+        throw new bindings.MojoCodecError("Unexpected message name");
+        break;
+    }
+    return null;
+  }
+
+  FlogReader get impl => _impl;
+  set impl(FlogReader d) {
+    if (d == null) {
+      throw new core.MojoApiError("$this: Cannot set a null implementation");
+    }
+    if (isBound && (_impl == null)) {
+      beginHandlingEvents();
+    }
+    _impl = d;
+  }
+
+  @override
+  void bind(core.MojoMessagePipeEndpoint endpoint) {
+    super.bind(endpoint);
+    if (!isOpen && (_impl != null)) {
+      beginHandlingEvents();
+    }
+  }
+
+  @override
+  String toString() {
+    var superString = super.toString();
+    return "_FlogReaderStubControl($superString)";
+  }
+
+  int get version => 0;
+}
+
+class FlogReaderStub
+    extends bindings.Stub<FlogReader>
+    implements FlogReader,
+               FlogReaderInterface,
+               FlogReaderInterfaceRequest {
+  FlogReaderStub.unbound([FlogReader impl])
+      : super(new _FlogReaderStubControl.unbound(impl));
+
+  FlogReaderStub.fromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint, [FlogReader impl])
+      : super(new _FlogReaderStubControl.fromEndpoint(endpoint, impl));
+
+  FlogReaderStub.fromHandle(
+      core.MojoHandle handle, [FlogReader impl])
+      : super(new _FlogReaderStubControl.fromHandle(handle, impl));
+
+  static FlogReaderStub newFromEndpoint(
+      core.MojoMessagePipeEndpoint endpoint) {
+    assert(endpoint.setDescription("For FlogReaderStub"));
+    return new FlogReaderStub.fromEndpoint(endpoint);
+  }
+
+
+  dynamic getEntries(int startIndex,int maxCount,[Function responseFactory = null]) {
+    return impl.getEntries(startIndex,maxCount,responseFactory);
+  }
+}
+
+
+
diff --git a/mojo/services/flog/cpp/BUILD.gn b/mojo/services/flog/cpp/BUILD.gn
new file mode 100644
index 0000000..dafae11
--- /dev/null
+++ b/mojo/services/flog/cpp/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2016 The Chromium 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/module_args/mojo.gni")
+import("$mojo_sdk_root/mojo/public/mojo_sdk.gni")
+
+mojo_sdk_source_set("cpp") {
+  sources = [
+    "flog.cc",
+    "flog.h",
+  ]
+
+  deps = [
+    "$mojo_sdk_root/mojo/public/cpp/application",
+    "$mojo_sdk_root/mojo/public/cpp/bindings",
+    "$mojo_sdk_root/mojo/public/cpp/environment",
+    "$mojo_sdk_root/mojo/services/flog/interfaces",
+  ]
+}
diff --git a/mojo/services/flog/cpp/flog.cc b/mojo/services/flog/cpp/flog.cc
new file mode 100644
index 0000000..3493682
--- /dev/null
+++ b/mojo/services/flog/cpp/flog.cc
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium 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 "mojo/services/flog/cpp/flog.h"
+
+namespace mojo {
+namespace flog {
+
+// static
+std::atomic_ulong Flog::last_allocated_channel_id_;
+
+// static
+FlogLoggerPtr Flog::logger_;
+
+FlogChannel::FlogChannel(const char* channel_type_name)
+    : id_(Flog::AllocateChannelId()) {
+  Flog::LogChannelCreation(id_, channel_type_name);
+}
+
+FlogChannel::~FlogChannel() {
+  Flog::LogChannelDeletion(id_);
+}
+
+bool FlogChannel::Accept(Message* message) {
+  Flog::LogChannelMessage(id_, message);
+  return true;
+}
+
+bool FlogChannel::AcceptWithResponder(Message* message,
+                                      MessageReceiver* responder) {
+  MOJO_DCHECK(false) << "Flog doesn't support messages with responses";
+  abort();
+}
+
+}  // namespace flog
+}  // namespace mojo
diff --git a/mojo/services/flog/cpp/flog.h b/mojo/services/flog/cpp/flog.h
new file mode 100644
index 0000000..5badda1
--- /dev/null
+++ b/mojo/services/flog/cpp/flog.h
@@ -0,0 +1,197 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_SERVICES_FLOG_CPP_FLOG_H_
+#define MOJO_SERVICES_FLOG_CPP_FLOG_H_
+
+#include <atomic>
+#include <memory>
+
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/environment/logging.h"
+#include "mojo/public/cpp/system/time.h"
+#include "mojo/services/flog/interfaces/flog.mojom.h"
+
+namespace mojo {
+namespace flog {
+
+//
+// FORMATTED LOGGING
+//
+// The Flog class and associated macros provide a means of logging 'formatted'
+// log messages serialized by Mojo. Flog uses an instance of FlogLogger to
+// log events to the FlogService. Messages pulled from the FlogService can be
+// deserialized using Mojo on behalf of log visualization and analysis tools.
+//
+// Message logging is performed using a 'channel', which is bound to a Mojo
+// proxy for a particular interface. Mojo interfaces used for this purpose must
+// be request-only, meaning the constituent methods must not have responses.
+//
+// Assume that we've defined the following interface:
+//
+//     [ServiceName="my_namespace::MyFlogChannelInterface"]
+//     interface MyFlogChannelInterface {
+//       Thing1(int64 a, int32 b);
+//       Thing2(string c);
+//     };
+//
+// Note that the ServiceName annotation is required.
+//
+// A channel instance may be defined, typically as a member of a class, as
+// follows:
+//
+//     FLOG_CHANNEL(MyFlogChannelInterface, my_flog_channel_instance_);
+//
+// If NDEBUG is defined, this compiles to nothing. Otherwise, it declares and
+// initializes my_flog_channel_instance, which can be used via the FLOG macro:
+//
+//     FLOG(my_flog_channel_instance_, Thing1(1234, 5678));
+//     FLOG(my_flog_channel_instance_, Thing2("To the lifeboats!"));
+//
+// These invocations compile to nothing if NDEBUG is defined. Otherwise, they
+// log messages to the channel represented by my_flog_channel_instance.
+//
+// FLOG_CHANNEL_DECL produces only a declaration for cases in which a channel
+// must be declared but not defined (e.g. as a static class member).
+//
+// Logging to a channel does nothing unless the Flog class has been initialized
+// with a call to Flog::Initialize. Flog::Initialize provides a FlogLogger
+// implementation to be used for logging. Typically, this implementation would
+// be acquired from the FlogService using CreateLogger.
+//
+
+#if defined(NDEBUG)
+
+#define FLOG_INITIALIZE(app_or_logger, label) ((void)0)
+#define FLOG_DESTROY() ((void)0)
+#define FLOG_CHANNEL(channel_type, channel_name)
+#define FLOG_CHANNEL_DECL(channel_type, channel_name)
+#define FLOG(channel_name, call) ((void)0)
+#define FLOG_ID(channel_name) 0
+
+#else
+
+#define FLOG_INITIALIZE(app_or_logger, label) \
+  mojo::flog::Flog::Initialize(app_or_logger, label)
+
+#define FLOG_DESTROY() mojo::flog::Flog::Destroy()
+
+#define FLOG_CHANNEL(channel_type, channel_name)                      \
+  std::unique_ptr<mojo::flog::FlogProxy<channel_type>> channel_name = \
+      mojo::flog::FlogProxy<channel_type>::Create()
+
+#define FLOG_CHANNEL_DECL(channel_type, channel_name) \
+  std::unique_ptr<mojo::flog::FlogProxy<channel_type>> channel_name
+
+#define FLOG(channel_name, call) channel_name->call
+
+#define FLOG_ID(channel_name) channel_name->channel()->id()
+
+#endif
+
+// Thread-safe logger for all channels in a given process.
+class Flog {
+ public:
+  static void Initialize(ApplicationImpl* app, const std::string& label) {
+    MOJO_DCHECK(!logger_);
+    FlogServicePtr flog_service;
+    FlogLoggerPtr flog_logger;
+    ConnectToService(app->shell(), "mojo:flog", GetProxy(&flog_service));
+    flog_service->CreateLogger(GetProxy(&flog_logger), label);
+    logger_ = flog_logger.Pass();
+  }
+
+  // Sets the flog logger singleton.
+  static void Initialize(FlogLoggerPtr flog_logger) {
+    MOJO_DCHECK(!logger_);
+    logger_ = flog_logger.Pass();
+  }
+
+  // Deletes the flog logger singleton.
+  static void Destroy() {
+    MOJO_DCHECK(logger_);
+    logger_.reset();
+  }
+
+  // Allocates a unique id for a new channel. Never returns 0.
+  static uint32_t AllocateChannelId() { return ++last_allocated_channel_id_; }
+
+  // Logs the creation of a channel.
+  static void LogChannelCreation(uint32_t channel_id,
+                                 const char* channel_type_name) {
+    if (!logger_) {
+      return;
+    }
+
+    logger_->LogChannelCreation(GetTimeTicksNow(), channel_id,
+                                channel_type_name);
+  }
+
+  // Logs a channel message.
+  static void LogChannelMessage(uint32_t channel_id, Message* message) {
+    if (!logger_) {
+      return;
+    }
+
+    Array<uint8_t> array = Array<uint8_t>::New(message->data_num_bytes());
+    memcpy(array.data(), message->data(), message->data_num_bytes());
+    logger_->LogChannelMessage(GetTimeTicksNow(), channel_id, array.Pass());
+  }
+
+  // Logs the deletion of a channel.
+  static void LogChannelDeletion(uint32_t channel_id) {
+    if (!logger_) {
+      return;
+    }
+
+    logger_->LogChannelDeletion(GetTimeTicksNow(), channel_id);
+  }
+
+ private:
+  static std::atomic_ulong last_allocated_channel_id_;
+  static FlogLoggerPtr logger_;
+};
+
+// Channel backing a FlogProxy.
+class FlogChannel : public MessageReceiverWithResponder {
+ public:
+  FlogChannel(const char* channel_type_name);
+
+  ~FlogChannel() override;
+
+  // Returns the channel id.
+  uint32_t id() const { return id_; }
+
+  // MessageReceiverWithResponder implementation.
+  bool Accept(Message* message) override;
+
+  bool AcceptWithResponder(Message* message,
+                           MessageReceiver* responder) override;
+
+ private:
+  uint32_t id_ = 0;
+};
+
+template <typename T>
+class FlogProxy : public T::Proxy_ {
+ public:
+  static std::unique_ptr<FlogProxy<T>> Create() {
+    return std::unique_ptr<FlogProxy<T>>(new FlogProxy<T>());
+  }
+
+  FlogChannel* channel() {
+    return reinterpret_cast<FlogChannel*>(this->receiver_);
+  }
+
+ private:
+  explicit FlogProxy() : T::Proxy_(new FlogChannel(T::Name_)) {}
+};
+
+}  // namespace flog
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_FLOG_CPP_FLOG_H_
diff --git a/mojo/services/flog/interfaces/BUILD.gn b/mojo/services/flog/interfaces/BUILD.gn
new file mode 100644
index 0000000..623c356
--- /dev/null
+++ b/mojo/services/flog/interfaces/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2016 The Chromium 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/module_args/mojo.gni")
+import("$mojo_sdk_root/mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "flog.mojom",
+  ]
+}
diff --git a/mojo/services/flog/interfaces/flog.mojom b/mojo/services/flog/interfaces/flog.mojom
new file mode 100644
index 0000000..0c6f171
--- /dev/null
+++ b/mojo/services/flog/interfaces/flog.mojom
@@ -0,0 +1,75 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[DartPackage="mojo_services"]
+module mojo.flog;
+
+// TODO(dalesat): Move out of media to somewhere more generic.
+
+// Exposed by the log service to enable creation and consumption of logs.
+[ServiceName="mojo::flog::FlogService"]
+interface FlogService {
+  // Creates a new logger.
+  CreateLogger(FlogLogger& logger, string label);
+
+  // Gets the descriptions of all logs.
+  GetLogDescriptions() => (array<FlogDescription> descriptions);
+
+  // Gets a reader for the specified log.
+  CreateReader(FlogReader& reader, uint32 log_id);
+};
+
+// A logger that logs messages regarding multiple channels.
+interface FlogLogger {
+  // Logs the creation of a channel.
+  LogChannelCreation(int64 time_us, uint32 channel_id, string type_name);
+
+  // Logs a message sent to an existing channel.
+  LogChannelMessage(int64 time_us, uint32 channel_id, array<uint8> data);
+
+  // Logs the deletion of a channel.
+  LogChannelDeletion(int64 time_us, uint32 channel_id);
+};
+
+// A reader that reads messages from one or more logs.
+interface FlogReader {
+  // Gets entries from the log starting and the specified index (entries are
+  // indexed starting at 0). If the log is open, the callback will be called
+  // when max_count entries are avaiable starting at start_index. If the log
+  // is closed, the callback will be called immediately with as many entries
+  // as are available starting at start_index and not exceeding max_count
+  // entries. entry_count and open refer to the entire log at the time the
+  // callback occurred.
+  GetEntries(uint32 start_index, uint32 max_count) =>
+      (array<FlogEntry> entries, uint32 entry_count, bool open);
+};
+
+struct FlogDescription {
+  string label;
+  uint32 log_id;
+  uint32 entry_count;
+  int64 start_time_us;
+  int64 stop_time_us;
+  bool open;
+};
+
+struct FlogEntry {
+  int64 time_us;
+  uint32 log_id;
+  uint32 channel_id;
+  FlogEntryDetails? details;
+};
+
+union FlogEntryDetails {
+  FlogChannelCreationEntryDetails channel_creation;
+  FlogChannelMessageEntryDetails channel_message;
+};
+
+struct FlogChannelCreationEntryDetails {
+  string type_name;
+};
+
+struct FlogChannelMessageEntryDetails {
+  array<uint8> data;
+};
diff --git a/mojo/services/mojo_services.gni b/mojo/services/mojo_services.gni
index dc6e0ec..cb2b814 100644
--- a/mojo/services/mojo_services.gni
+++ b/mojo/services/mojo_services.gni
@@ -18,6 +18,7 @@
   "//mojo/services/content_handler/interfaces",
   "//mojo/services/device_info/interfaces",
   "//mojo/services/files/interfaces",
+  "//mojo/services/flog/interfaces",
   "//mojo/services/geometry/interfaces",
   "//mojo/services/gfx/composition/interfaces",
   "//mojo/services/gpu/interfaces",