Преглед на файлове

[Sessions] Add Sessions SDK nanopb and proto (#10351)

Sam Edson преди 3 години
родител
ревизия
bb4c6382cd

+ 79 - 0
FirebaseSessions/ProtoSupport/Protos/clientanalytics.proto

@@ -0,0 +1,79 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+syntax = "proto2";
+
+// This is in a separate file so it can be used as proto2.
+
+// To describe the network connectivity of the client.
+// Copied from android/play/playlog/proto/clientanalytics.proto
+// Next tag: 3
+message NetworkConnectionInfo {
+  enum NetworkType {
+    NONE = -1;
+    MOBILE = 0;
+    WIFI = 1;
+    MOBILE_MMS = 2;
+    MOBILE_SUPL = 3;
+    MOBILE_DUN = 4;
+    MOBILE_HIPRI = 5;
+    WIMAX = 6;
+    BLUETOOTH = 7;
+    DUMMY = 8;
+    ETHERNET = 9;
+    MOBILE_FOTA = 10;
+    MOBILE_IMS = 11;
+    MOBILE_CBS = 12;
+    WIFI_P2P = 13;
+    MOBILE_IA = 14;
+    MOBILE_EMERGENCY = 15;
+    PROXY = 16;
+    VPN = 17;
+  }
+
+  enum MobileSubtype {
+    UNKNOWN_MOBILE_SUBTYPE = 0;
+    GPRS = 1;
+    EDGE = 2;
+    UMTS = 3;
+    CDMA = 4;
+    EVDO_0 = 5;
+    EVDO_A = 6;
+    RTT = 7;
+    HSDPA = 8;
+    HSUPA = 9;
+    HSPA = 10;
+    IDEN = 11;
+    EVDO_B = 12;
+    LTE = 13;
+    EHRPD = 14;
+    HSPAP = 15;
+    GSM = 16;
+    TD_SCDMA = 17;
+    IWLAN = 18;
+    LTE_CA = 19;
+
+    // COMBINED has value -1 in NetworkIdentity.java, but is given the value
+    // 100 here to save (disk) space. The value -1 takes up the full 10 bytes in
+    // a varint for enums, but the value 100 only takes up 1 byte.
+    COMBINED = 100;
+  }
+
+  // The current network connectivity type when the event was logged in the
+  // client
+  optional NetworkType network_type = 1 [default = NONE];
+
+  // The current mobile connectivity subtype when the event was logged in the
+  // client
+  optional MobileSubtype mobile_subtype = 2 [default = UNKNOWN_MOBILE_SUBTYPE];
+}

+ 36 - 0
FirebaseSessions/ProtoSupport/Protos/sessions.options

@@ -0,0 +1,36 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Options for sessions.proto
+#
+# Important: Any strings or repeated fields should be speficied in this file as
+# type:FT_POINTER
+#
+# Eg: `# google_crashlytics.Report.sdk_version type:FT_POINTER`
+#
+
+firebase.appquality.sessions.SessionInfo.session_id type:FT_POINTER
+firebase.appquality.sessions.SessionInfo.previous_session_id type:FT_POINTER
+firebase.appquality.sessions.SessionInfo.firebase_installation_id type:FT_POINTER
+firebase.appquality.sessions.ApplicationInfo.app_id type:FT_POINTER
+firebase.appquality.sessions.ApplicationInfo.device_model type:FT_POINTER
+firebase.appquality.sessions.ApplicationInfo.development_platform_name type:FT_POINTER
+firebase.appquality.sessions.ApplicationInfo.development_platform_version type:FT_POINTER
+firebase.appquality.sessions.AndroidApplicationInfo.package_name type:FT_POINTER
+firebase.appquality.sessions.AndroidApplicationInfo.sdk_version type:FT_POINTER
+firebase.appquality.sessions.AndroidApplicationInfo.version_name type:FT_POINTER
+firebase.appquality.sessions.AppleApplicationInfo.bundle_short_version type:FT_POINTER
+firebase.appquality.sessions.AppleApplicationInfo.sdk_version type:FT_POINTER

+ 160 - 0
FirebaseSessions/ProtoSupport/Protos/sessions.proto

@@ -0,0 +1,160 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+// Instructions for updating this file:
+//
+// 1. Get the session_event.proto from the backend
+// 2. Copy everything below the options, and past it here below the package
+//    declaraction.
+// 3. Remove all the datapol.semantic_type tags
+// 4. Remove "wireless_android_play_playlog." from
+//    "wireless_android_play_playlog.NetworkConnectionInfo"
+// 5. Any new proto fields of type string, repeated, or bytes must be specified
+//    in the sessions.options file as "type:FT_POINTER"
+//
+
+syntax = "proto3";
+
+import "clientanalytics.proto";
+
+package firebase.appquality.sessions;
+
+// Contains the relevant information around an App Quality Session.
+// See go/app-quality-unified-session-definition for more details.
+message SessionEvent {
+  // The type of event being reported.
+  EventType event_type = 1;
+  // Information about the session triggering the event.
+  SessionInfo session_data = 2;
+  // Information about the running application.
+  ApplicationInfo application_info = 3;
+}
+
+// Enum denoting all possible session event types.
+enum EventType {
+  EVENT_UNKNOWN = 0;
+  // This event type is fired as soon as a new session begins.
+  EVENT_SESSION_START = 1;
+}
+
+// Contains session-specific information relating to the event being uploaded.
+message SessionInfo {
+  // A globally unique identifier for the session.
+  string session_id = 1;
+  // The unique identifier for the session that preceded this one on the device.
+  // This will be the empty string if there was no previous session.
+  string previous_session_id = 2;
+  // Identifies a unique device+app installation: go/firebase-installations
+  string firebase_installation_id = 3;
+  // The device-reported timestamp at which the event occurred.
+  int64 event_timestamp_us = 4;
+  // Any sampling rate being applied to these events on device.
+  // 1.0 implies no sampling.
+  float sampling_rate = 5;
+  // The data collection status for each related SDK.
+  DataCollectionStatus data_collection_status = 6;
+}
+
+// Contains the data collection status for each related SDK.
+message DataCollectionStatus {
+  // The collection status of the FirePerf SDK.
+  DataCollectionState performance = 1;
+  // The collection status for the Crashlytics SDK.
+  DataCollectionState crashlytics = 2;
+}
+
+// Enum denoting all possible states for SDK data collection.
+enum DataCollectionState {
+  COLLECTION_UNKNOWN = 0;
+  // This product SDK is not present in this version of the app.
+  COLLECTION_SDK_NOT_INSTALLED = 1;
+  // The product SDK is present and collecting all product-level events.
+  COLLECTION_ENABLED = 2;
+  // The product SDK is present but data collection for it has been locally
+  // disabled.
+  COLLECTION_DISABLED = 3;
+  // The product SDK is present but data collection has been remotely disabled.
+  COLLECTION_DISABLED_REMOTE = 4;
+  // Indicates that the product SDK is present, but session data is being
+  // collected, but the product-level events are not being uploaded.
+  COLLECTION_SAMPLED = 5;
+}
+
+// App-level information collected from the device.
+message ApplicationInfo {
+  // Commonly known as the GMP App Id
+  string app_id = 1;
+  // The manufacturer supplied device model name. Eg. 'N5502L'
+  string device_model = 2;
+  // The development platform used by the app. Eg. 'Unity', 'Flutter'
+  string development_platform_name = 3;
+  // The version of the development platform in use by the app. Eg. 2020.3.33f1
+  string development_platform_version = 4;
+
+  oneof platform_info {
+    // App info relevant only to Android apps
+    AndroidApplicationInfo android_app_info = 5;
+    // App info relevant only to Apple apps
+    AppleApplicationInfo apple_app_info = 6;
+  }
+}
+
+// Android-specific app information
+// In addition to these fields, the Firelog SDK also collects:
+// - application_build
+// - mcc_mnc
+// - sdk_version(app's build version)
+// - manufacturer
+// - model
+// - country
+// - network_connection_info
+message AndroidApplicationInfo {
+  // The applications package name. Eg. com.google.search
+  string package_name = 1;
+  // The version of the Android Firebase-Sessions SDK in use
+  string sdk_version = 2;
+  // The version name as specified in the app's manifest
+  // https://developer.android.com/guide/topics/manifest/manifest-element#vname
+  string version_name = 3;
+}
+
+// Apple-specific app information
+// In addition to these fields, the Firelog SDK also collects:
+// - application_build
+// - application_version
+// - os_full_version
+// - model
+// - country
+message AppleApplicationInfo {
+  // The application's bundle id. Eg. com.google.search
+  string bundle_short_version = 1;
+  // The version of the Apple Firebase-Sessions SDK in use
+  string sdk_version = 2;
+  // Describes the network connectivity of the device
+  NetworkConnectionInfo network_connection_info = 3;
+  // Collects the OS running. Eg. iOS, iPadOs, tvOS, etc.
+  OsName os_name = 4;
+}
+
+// The name of the operating system on which the application is running.
+// Currently Apple only.
+enum OsName {
+  OS_NAME_UNKNOWN = 0;
+  OS_NAME_IOS = 1;
+  OS_NAME_IPAD_OS = 2;
+  OS_NAME_MAC_OS = 3;
+  OS_NAME_TV_OS = 4;
+  OS_NAME_WATCH_OS = 5;
+}

+ 64 - 0
FirebaseSessions/ProtoSupport/generate_protos.sh

@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Example usage:
+# ./build_protos <path to nanopb>
+
+# Dependencies: git, protobuf, python-protobuf, pyinstaller
+
+readonly DIR="$( git rev-parse --show-toplevel )"
+
+# Current release of nanopb being used  to build the CCT protos
+readonly NANOPB_VERSION="0.3.9.8"
+readonly NANOPB_TEMPDIR="${DIR}/FirebaseSessions/nanopb_temp"
+
+readonly LIBRARY_DIR="${DIR}/FirebaseSessions/Sources/"
+readonly PROTO_DIR="${DIR}/FirebaseSessions/ProtoSupport/Protos/"
+readonly PROTOGEN_DIR="${DIR}/FirebaseSessions/Protogen/"
+
+rm -rf "${NANOPB_TEMPDIR}"
+
+echo "Downloading nanopb..."
+git clone --branch "${NANOPB_VERSION}" https://github.com/nanopb/nanopb.git "${NANOPB_TEMPDIR}"
+
+echo "Building nanopb..."
+pushd "${NANOPB_TEMPDIR}"
+./tools/make_mac_package.sh
+GIT_DESCRIPTION=`git describe --always`-macosx-x86
+NANOPB_BIN_DIR="dist/${GIT_DESCRIPTION}"
+popd
+
+echo "Removing existing protos..."
+rm -rf "${PROTOGEN_DIR}/*"
+
+echo "Generating protos..."
+python "${DIR}/FirebaseSessions/ProtoSupport/proto_generator.py" \
+  --nanopb \
+  --protos_dir="${PROTO_DIR}" \
+  --pythonpath="${NANOPB_TEMPDIR}/${NANOPB_BIN_DIR}/generator" \
+  --output_dir="${PROTOGEN_DIR}" \
+  --include="${PROTO_DIR}"
+
+rm -rf "${NANOPB_TEMPDIR}"
+
+RED='\033[0;31m'
+NC='\033[0m'
+echo ""
+echo ""
+echo -e "${RED}Important: Any new proto fields of type string, repeated, or bytes must be specified in the sessions.options file${NC}"
+echo ""
+echo ""

+ 221 - 0
FirebaseSessions/ProtoSupport/nanopb_objc_generator.py

@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Generates and massages protocol buffer outputs.
+"""
+
+from __future__ import print_function
+
+import sys
+
+import io
+import nanopb_generator as nanopb
+import os
+import os.path
+import shlex
+
+from google.protobuf.descriptor_pb2 import FieldDescriptorProto
+
+# The plugin_pb2 package loads descriptors on import, but doesn't defend
+# against multiple imports. Reuse the plugin package as loaded by the
+# nanopb_generator.
+plugin_pb2 = nanopb.plugin_pb2
+nanopb_pb2 = nanopb.nanopb_pb2
+
+
+def main():
+  # Parse request
+  data = io.open(sys.stdin.fileno(), 'rb').read()
+  request = plugin_pb2.CodeGeneratorRequest.FromString(data)
+
+  # Preprocess inputs, changing types and nanopb defaults
+  options = nanopb_parse_options(request)
+  use_anonymous_oneof(request)
+  use_bytes_for_strings(request)
+
+  # Generate code
+  parsed_files = nanopb_parse_files(request, options)
+  results = nanopb_generate(request, options, parsed_files)
+  response = nanopb_write(results)
+
+  # Write to stdout
+  io.open(sys.stdout.fileno(), 'wb').write(response.SerializeToString())
+
+
+def use_anonymous_oneof(request):
+  """Use anonymous unions for oneofs if they're the only one in a message.
+
+  Equivalent to setting this option on messages where it applies:
+
+    option (nanopb).anonymous_oneof = true;
+
+  Args:
+    request: A CodeGeneratorRequest from protoc. The descriptors are modified
+      in place.
+  """
+  for _, message_type in iterate_messages(request):
+    if len(message_type.oneof_decl) == 1:
+      ext = message_type.options.Extensions[nanopb_pb2.nanopb_msgopt]
+      ext.anonymous_oneof = True
+
+
+def use_bytes_for_strings(request):
+  """Always use the bytes type instead of string.
+
+  By default, nanopb renders proto strings as having the C type char* and does
+  not include a separate size field, getting the length of the string via
+  strlen(). Unfortunately this prevents using strings with embedded nulls,
+  which is something the wire format supports.
+
+  Fortunately, string and bytes proto fields are identical on the wire and
+  nanopb's bytes representation does have an explicit length, so this function
+  changes the types of all string fields to bytes. The generated code will now
+  contain pb_bytes_array_t.
+
+  There's no nanopb or proto option to control this behavior. The equivalent
+  would be to hand edit all the .proto files :-(.
+
+  Args:
+    request: A CodeGeneratorRequest from protoc. The descriptors are modified
+      in place.
+  """
+  for names, message_type in iterate_messages(request):
+    for field in message_type.field:
+      if field.type == FieldDescriptorProto.TYPE_STRING:
+        field.type = FieldDescriptorProto.TYPE_BYTES
+
+
+def iterate_messages(request):
+  """Iterates over all messages in all files in the request.
+
+  Args:
+    request: A CodeGeneratorRequest passed by protoc.
+
+  Yields:
+    names: a nanopb.Names object giving a qualified name for the message
+    message_type: a DescriptorProto for the message.
+  """
+  for fdesc in request.proto_file:
+    for names, message_type in nanopb.iterate_messages(fdesc):
+      yield names, message_type
+
+
+def nanopb_parse_options(request):
+  """Parses nanopb_generator command-line options from the given request.
+
+  Args:
+    request: A CodeGeneratorRequest passed by protoc.
+
+  Returns:
+    Nanopb's options object, obtained via optparser.
+  """
+  # Parse options the same as nanopb_generator.main_plugin() does.
+  args = shlex.split(request.parameter)
+  options, _ = nanopb.optparser.parse_args(args)
+
+  # Force certain options
+  options.extension = '.nanopb'
+  options.verbose = True
+
+  # Replicate options setup from nanopb_generator.main_plugin.
+  nanopb.Globals.verbose_options = options.verbose
+
+  # Google's protoc does not currently indicate the full path of proto files.
+  # Instead always add the main file path to the search dirs, that works for
+  # the common case.
+  options.options_path.append(os.path.dirname(request.file_to_generate[0]))
+  return options
+
+
+def nanopb_parse_files(request, options):
+  """Parses the files in the given request into nanopb ProtoFile objects.
+
+  Args:
+    request: A CodeGeneratorRequest, as passed by protoc.
+    options: The command-line options from nanopb_parse_options.
+
+  Returns:
+    A dictionary of filename to nanopb.ProtoFile objects, each one representing
+    the parsed form of a FileDescriptor in the request.
+  """
+  # Process any include files first, in order to have them
+  # available as dependencies
+  parsed_files = {}
+  for fdesc in request.proto_file:
+    parsed_files[fdesc.name] = nanopb.parse_file(fdesc.name, fdesc, options)
+
+  return parsed_files
+
+
+def nanopb_generate(request, options, parsed_files):
+  """Generates C sources from the given parsed files.
+
+  Args:
+    request: A CodeGeneratorRequest, as passed by protoc.
+    options: The command-line options from nanopb_parse_options.
+    parsed_files: A dictionary of filename to nanopb.ProtoFile, as returned by
+      nanopb_parse_files().
+
+  Returns:
+    A list of nanopb output dictionaries, each one representing the code
+    generation result for each file to generate. The output dictionaries have
+    the following form:
+
+        {
+          'headername': Name of header file, ending in .h,
+          'headerdata': Contents of the header file,
+          'sourcename': Name of the source code file, ending in .c,
+          'sourcedata': Contents of the source code file
+        }
+  """
+  output = []
+
+  for filename in request.file_to_generate:
+    for fdesc in request.proto_file:
+      if fdesc.name == filename:
+        results = nanopb.process_file(filename, fdesc, options, parsed_files)
+        output.append(results)
+
+  return output
+
+
+def nanopb_write(results):
+  """Translates nanopb output dictionaries to a CodeGeneratorResponse.
+
+  Args:
+    results: A list of generated source dictionaries, as returned by
+      nanopb_generate().
+
+  Returns:
+    A CodeGeneratorResponse describing the result of the code generation
+    process to protoc.
+  """
+  response = plugin_pb2.CodeGeneratorResponse()
+
+  for result in results:
+    f = response.file.add()
+    f.name = result['headername']
+    f.content = result['headerdata']
+
+    f = response.file.add()
+    f.name = result['sourcename']
+    f.content = result['sourcedata']
+
+  return response
+
+
+if __name__ == '__main__':
+  main()

+ 323 - 0
FirebaseSessions/ProtoSupport/proto_generator.py

@@ -0,0 +1,323 @@
+#! /usr/bin/env python
+
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Generates and massages protocol buffer outputs.
+
+Example usage:
+
+python Crashlytics/ProtoSupport/build_protos.py \
+  --nanopb \
+  --protos_dir=Crashlytics/Classes/Protos/ \
+  --pythonpath=~/Downloads/nanopb-0.3.9.2-macosx-x86/generator/ \
+  --output_dir=Crashlytics/Protogen/
+"""
+
+from __future__ import print_function
+
+import sys
+
+import argparse
+import os
+import os.path
+import re
+import subprocess
+
+OBJC_GENERATOR='nanopb_objc_generator.py'
+
+COPYRIGHT_NOTICE = '''
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+'''.lstrip()
+
+
+def main():
+  parser = argparse.ArgumentParser(
+      description='Generates proto messages.')
+  parser.add_argument(
+      '--nanopb', action='store_true',
+      help='Generates nanopb messages.')
+  parser.add_argument(
+      '--objc', action='store_true',
+      help='Generates Objective-C messages.')
+  parser.add_argument(
+      '--protos_dir',
+      help='Source directory containing .proto files.')
+  parser.add_argument(
+      '--output_dir', '-d',
+      help='Directory to write files; subdirectories will be created.')
+  parser.add_argument(
+      '--protoc', default='protoc',
+      help='Location of the protoc executable')
+  parser.add_argument(
+      '--pythonpath',
+      help='Location of the protoc python library.')
+  parser.add_argument(
+      '--include', '-I', action='append', default=[],
+      help='Adds INCLUDE to the proto path.')
+
+
+  args = parser.parse_args()
+  if args.nanopb is None and args.objc is None:
+    parser.print_help()
+    sys.exit(1)
+
+  if args.protos_dir is None:
+    root_dir = os.path.abspath(os.path.dirname(__file__))
+    args.protos_dir = os.path.join(root_dir, 'protos')
+
+  if args.output_dir is None:
+    root_dir = os.path.abspath(os.path.dirname(__file__))
+    args.output_dir = os.path.join(root_dir, 'protogen-please-supply-an-outputdir')
+
+  all_proto_files = collect_files(args.protos_dir, '.proto')
+  if args.nanopb:
+    NanopbGenerator(args, all_proto_files).run()
+
+  proto_files = remove_well_known_protos(all_proto_files)
+
+  if args.objc:
+    ObjcProtobufGenerator(args, proto_files).run()
+
+
+class NanopbGenerator(object):
+  """Builds and runs the nanopb plugin to protoc."""
+
+  def __init__(self, args, proto_files):
+    self.args = args
+    self.proto_files = proto_files
+
+  def run(self):
+    """Performs the action of the generator."""
+
+    nanopb_out = os.path.join(self.args.output_dir, 'nanopb')
+    mkdir(nanopb_out)
+
+    self.__run_generator(nanopb_out)
+
+    sources = collect_files(nanopb_out, '.nanopb.h', '.nanopb.c')
+    post_process_files(
+        sources,
+        add_copyright,
+        nanopb_remove_extern_c,
+        nanopb_rename_delete,
+        nanopb_use_module_import
+    )
+
+  def __run_generator(self, out_dir):
+    """Invokes protoc using the nanopb plugin."""
+    cmd = protoc_command(self.args)
+
+    gen = os.path.join(os.path.dirname(__file__), OBJC_GENERATOR)
+    cmd.append('--plugin=protoc-gen-nanopb=%s' % gen)
+
+    nanopb_flags = [
+        '--extension=.nanopb',
+        '--source-extension=.c',
+        '--no-timestamp'
+    ]
+    nanopb_flags.extend(['-I%s' % path for path in self.args.include])
+    cmd.append('--nanopb_out=%s:%s' % (' '.join(nanopb_flags), out_dir))
+
+    cmd.extend(self.proto_files)
+    run_protoc(self.args, cmd)
+
+
+def protoc_command(args):
+  """Composes the initial protoc command-line including its include path."""
+  cmd = [args.protoc]
+  if args.include is not None:
+    cmd.extend(['-I=%s' % path for path in args.include])
+  return cmd
+
+
+def run_protoc(args, cmd):
+  """Actually runs the given protoc command.
+
+  Args:
+    args: The command-line args (including pythonpath)
+    cmd: The command to run expressed as a list of strings
+  """
+
+  kwargs = {}
+  if args.pythonpath:
+    env = os.environ.copy()
+    old_path = env.get('PYTHONPATH')
+    env['PYTHONPATH'] = os.path.expanduser(args.pythonpath)
+    if old_path is not None:
+      env['PYTHONPATH'] += os.pathsep + old_path
+    kwargs['env'] = env
+
+  try:
+    print(subprocess.check_output(cmd, stderr=subprocess.STDOUT, **kwargs))
+  except subprocess.CalledProcessError as error:
+    print('command failed: ', ' '.join(cmd), '\nerror: ', error.output)
+
+
+def remove_well_known_protos(filenames):
+  """Remove "well-known" protos for objc.
+
+  On those platforms we get these for free as a part of the protobuf runtime.
+  We only need them for nanopb.
+
+  Args:
+    filenames: A list of filenames, each naming a .proto file.
+
+  Returns:
+    The filenames with members of google/protobuf removed.
+  """
+
+  return [f for f in filenames if 'protos/google/protobuf/' not in f]
+
+
+def post_process_files(filenames, *processors):
+  for filename in filenames:
+    lines = []
+    with open(filename, 'r') as fd:
+      lines = fd.readlines()
+
+    for processor in processors:
+      lines = processor(lines)
+
+    write_file(filename, lines)
+
+
+def write_file(filename, lines):
+  mkdir(os.path.dirname(filename))
+  with open(filename, 'w') as fd:
+    fd.write(''.join(lines))
+
+
+def add_copyright(lines):
+  """Adds a copyright notice to the lines."""
+  result = [COPYRIGHT_NOTICE, '\n']
+  result.extend(lines)
+  return result
+
+
+def nanopb_remove_extern_c(lines):
+  """Removes extern "C" directives from nanopb code.
+
+  Args:
+    lines: A nanobp-generated source file, split into lines.
+  Returns:
+    A list of strings, similar to the input but modified to remove extern "C".
+  """
+  result = []
+  state = 'initial'
+  for line in lines:
+    if state == 'initial':
+      if '#ifdef __cplusplus' in line:
+        state = 'in-ifdef'
+        continue
+
+      result.append(line)
+
+    elif state == 'in-ifdef':
+      if '#endif' in line:
+        state = 'initial'
+
+  return result
+
+
+def nanopb_rename_delete(lines):
+  """Renames a delete symbol to delete_.
+
+  If a proto uses a field named 'delete', nanopb happily uses that in the
+  message definition. Works fine for C; not so much for C++.
+
+  Args:
+    lines: The lines to fix.
+
+  Returns:
+    The lines, fixed.
+  """
+  delete_keyword = re.compile(r'\bdelete\b')
+  return [delete_keyword.sub('delete_', line) for line in lines]
+
+
+def nanopb_use_module_import(lines):
+  """Changes #include <pb.h> to include <nanopb/pb.h>""" # Don't let Copybara alter these lines.
+  return [line.replace('#include <pb.h>', '{}include <nanopb/pb.h>'.format("#")) for line in lines]
+
+
+def strip_trailing_whitespace(lines):
+  """Removes trailing whitespace from the given lines."""
+  return [line.rstrip() + '\n' for line in lines]
+
+
+def objc_flatten_imports(lines):
+  """Flattens the import statements for compatibility with CocoaPods."""
+
+  long_import = re.compile(r'#import ".*/')
+  return [long_import.sub('#import "', line) for line in lines]
+
+
+def objc_strip_extension_registry(lines):
+  """Removes extensionRegistry methods from the classes."""
+  skip = False
+  result = []
+  for line in lines:
+    if '+ (GPBExtensionRegistry*)extensionRegistry {' in line:
+      skip = True
+    if not skip:
+      result.append(line)
+    elif line == '}\n':
+      skip = False
+
+  return result
+
+
+def collect_files(root_dir, *extensions):
+  """Finds files with the given extensions in the root_dir.
+
+  Args:
+    root_dir: The directory from which to start traversing.
+    *extensions: Filename extensions (including the leading dot) to find.
+
+  Returns:
+    A list of filenames, all starting with root_dir, that have one of the given
+    extensions.
+  """
+  result = []
+  for root, _, files in os.walk(root_dir):
+    for basename in files:
+      for ext in extensions:
+        if basename.endswith(ext):
+          filename = os.path.join(root, basename)
+          result.append(filename)
+  return result
+
+
+def mkdir(dirname):
+  if not os.path.isdir(dirname):
+    os.makedirs(dirname)
+
+
+if __name__ == '__main__':
+  main()

+ 40 - 0
FirebaseSessions/Protogen/nanopb/clientanalytics.nanopb.c

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.9.8 */
+
+#include "clientanalytics.nanopb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+const NetworkConnectionInfo_NetworkType NetworkConnectionInfo_network_type_default = NetworkConnectionInfo_NetworkType_NONE;
+const NetworkConnectionInfo_MobileSubtype NetworkConnectionInfo_mobile_subtype_default = NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE;
+
+
+const pb_field_t NetworkConnectionInfo_fields[3] = {
+    PB_FIELD(  1, ENUM    , OPTIONAL, STATIC  , FIRST, NetworkConnectionInfo, network_type, network_type, &NetworkConnectionInfo_network_type_default),
+    PB_FIELD(  2, UENUM   , OPTIONAL, STATIC  , OTHER, NetworkConnectionInfo, mobile_subtype, network_type, &NetworkConnectionInfo_mobile_subtype_default),
+    PB_LAST_FIELD
+};
+
+
+
+
+/* @@protoc_insertion_point(eof) */

+ 120 - 0
FirebaseSessions/Protogen/nanopb/clientanalytics.nanopb.h

@@ -0,0 +1,120 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.9.8 */
+
+#ifndef PB_CLIENTANALYTICS_NANOPB_H_INCLUDED
+#define PB_CLIENTANALYTICS_NANOPB_H_INCLUDED
+#include <nanopb/pb.h>
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+/* Enum definitions */
+typedef enum _NetworkConnectionInfo_NetworkType {
+    NetworkConnectionInfo_NetworkType_NONE = -1,
+    NetworkConnectionInfo_NetworkType_MOBILE = 0,
+    NetworkConnectionInfo_NetworkType_WIFI = 1,
+    NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2,
+    NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3,
+    NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4,
+    NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5,
+    NetworkConnectionInfo_NetworkType_WIMAX = 6,
+    NetworkConnectionInfo_NetworkType_BLUETOOTH = 7,
+    NetworkConnectionInfo_NetworkType_DUMMY = 8,
+    NetworkConnectionInfo_NetworkType_ETHERNET = 9,
+    NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10,
+    NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11,
+    NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12,
+    NetworkConnectionInfo_NetworkType_WIFI_P2P = 13,
+    NetworkConnectionInfo_NetworkType_MOBILE_IA = 14,
+    NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15,
+    NetworkConnectionInfo_NetworkType_PROXY = 16,
+    NetworkConnectionInfo_NetworkType_VPN = 17
+} NetworkConnectionInfo_NetworkType;
+#define _NetworkConnectionInfo_NetworkType_MIN NetworkConnectionInfo_NetworkType_NONE
+#define _NetworkConnectionInfo_NetworkType_MAX NetworkConnectionInfo_NetworkType_VPN
+#define _NetworkConnectionInfo_NetworkType_ARRAYSIZE ((NetworkConnectionInfo_NetworkType)(NetworkConnectionInfo_NetworkType_VPN+1))
+
+typedef enum _NetworkConnectionInfo_MobileSubtype {
+    NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0,
+    NetworkConnectionInfo_MobileSubtype_GPRS = 1,
+    NetworkConnectionInfo_MobileSubtype_EDGE = 2,
+    NetworkConnectionInfo_MobileSubtype_UMTS = 3,
+    NetworkConnectionInfo_MobileSubtype_CDMA = 4,
+    NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5,
+    NetworkConnectionInfo_MobileSubtype_EVDO_A = 6,
+    NetworkConnectionInfo_MobileSubtype_RTT = 7,
+    NetworkConnectionInfo_MobileSubtype_HSDPA = 8,
+    NetworkConnectionInfo_MobileSubtype_HSUPA = 9,
+    NetworkConnectionInfo_MobileSubtype_HSPA = 10,
+    NetworkConnectionInfo_MobileSubtype_IDEN = 11,
+    NetworkConnectionInfo_MobileSubtype_EVDO_B = 12,
+    NetworkConnectionInfo_MobileSubtype_LTE = 13,
+    NetworkConnectionInfo_MobileSubtype_EHRPD = 14,
+    NetworkConnectionInfo_MobileSubtype_HSPAP = 15,
+    NetworkConnectionInfo_MobileSubtype_GSM = 16,
+    NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17,
+    NetworkConnectionInfo_MobileSubtype_IWLAN = 18,
+    NetworkConnectionInfo_MobileSubtype_LTE_CA = 19,
+    NetworkConnectionInfo_MobileSubtype_COMBINED = 100
+} NetworkConnectionInfo_MobileSubtype;
+#define _NetworkConnectionInfo_MobileSubtype_MIN NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+#define _NetworkConnectionInfo_MobileSubtype_MAX NetworkConnectionInfo_MobileSubtype_COMBINED
+#define _NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((NetworkConnectionInfo_MobileSubtype)(NetworkConnectionInfo_MobileSubtype_COMBINED+1))
+
+/* Struct definitions */
+typedef struct _NetworkConnectionInfo {
+    bool has_network_type;
+    NetworkConnectionInfo_NetworkType network_type;
+    bool has_mobile_subtype;
+    NetworkConnectionInfo_MobileSubtype mobile_subtype;
+/* @@protoc_insertion_point(struct:NetworkConnectionInfo) */
+} NetworkConnectionInfo;
+
+/* Default values for struct fields */
+extern const NetworkConnectionInfo_NetworkType NetworkConnectionInfo_network_type_default;
+extern const NetworkConnectionInfo_MobileSubtype NetworkConnectionInfo_mobile_subtype_default;
+
+/* Initializer values for message structs */
+#define NetworkConnectionInfo_init_default       {false, NetworkConnectionInfo_NetworkType_NONE, false, NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE}
+#define NetworkConnectionInfo_init_zero          {false, _NetworkConnectionInfo_NetworkType_MIN, false, _NetworkConnectionInfo_MobileSubtype_MIN}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define NetworkConnectionInfo_network_type_tag   1
+#define NetworkConnectionInfo_mobile_subtype_tag 2
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t NetworkConnectionInfo_fields[3];
+
+/* Maximum encoded size of messages (where known) */
+#define NetworkConnectionInfo_size               13
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define CLIENTANALYTICS_MESSAGES \
+
+
+#endif
+
+/* @@protoc_insertion_point(eof) */
+
+#endif

+ 105 - 0
FirebaseSessions/Protogen/nanopb/sessions.nanopb.c

@@ -0,0 +1,105 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.9.8 */
+
+#include "sessions.nanopb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t firebase_appquality_sessions_SessionEvent_fields[4] = {
+    PB_FIELD(  1, UENUM   , SINGULAR, STATIC  , FIRST, firebase_appquality_sessions_SessionEvent, event_type, event_type, 0),
+    PB_FIELD(  2, MESSAGE , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_SessionEvent, session_data, event_type, &firebase_appquality_sessions_SessionInfo_fields),
+    PB_FIELD(  3, MESSAGE , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_SessionEvent, application_info, session_data, &firebase_appquality_sessions_ApplicationInfo_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t firebase_appquality_sessions_SessionInfo_fields[7] = {
+    PB_FIELD(  1, BYTES   , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_SessionInfo, session_id, session_id, 0),
+    PB_FIELD(  2, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_SessionInfo, previous_session_id, session_id, 0),
+    PB_FIELD(  3, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_SessionInfo, firebase_installation_id, previous_session_id, 0),
+    PB_FIELD(  4, INT64   , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_SessionInfo, event_timestamp_us, firebase_installation_id, 0),
+    PB_FIELD(  5, FLOAT   , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_SessionInfo, sampling_rate, event_timestamp_us, 0),
+    PB_FIELD(  6, MESSAGE , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_SessionInfo, data_collection_status, sampling_rate, &firebase_appquality_sessions_DataCollectionStatus_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t firebase_appquality_sessions_DataCollectionStatus_fields[3] = {
+    PB_FIELD(  1, UENUM   , SINGULAR, STATIC  , FIRST, firebase_appquality_sessions_DataCollectionStatus, performance, performance, 0),
+    PB_FIELD(  2, UENUM   , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_DataCollectionStatus, crashlytics, performance, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t firebase_appquality_sessions_ApplicationInfo_fields[7] = {
+    PB_FIELD(  1, BYTES   , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_ApplicationInfo, app_id, app_id, 0),
+    PB_FIELD(  2, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, device_model, app_id, 0),
+    PB_FIELD(  3, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, development_platform_name, device_model, 0),
+    PB_FIELD(  4, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, development_platform_version, development_platform_name, 0),
+    PB_ANONYMOUS_ONEOF_FIELD(platform_info,   5, MESSAGE , ONEOF, STATIC  , OTHER, firebase_appquality_sessions_ApplicationInfo, android_app_info, development_platform_version, &firebase_appquality_sessions_AndroidApplicationInfo_fields),
+    PB_ANONYMOUS_ONEOF_FIELD(platform_info,   6, MESSAGE , ONEOF, STATIC  , UNION, firebase_appquality_sessions_ApplicationInfo, apple_app_info, development_platform_version, &firebase_appquality_sessions_AppleApplicationInfo_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t firebase_appquality_sessions_AndroidApplicationInfo_fields[4] = {
+    PB_FIELD(  1, BYTES   , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_AndroidApplicationInfo, package_name, package_name, 0),
+    PB_FIELD(  2, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_AndroidApplicationInfo, sdk_version, package_name, 0),
+    PB_FIELD(  3, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_AndroidApplicationInfo, version_name, sdk_version, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t firebase_appquality_sessions_AppleApplicationInfo_fields[5] = {
+    PB_FIELD(  1, BYTES   , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_AppleApplicationInfo, bundle_short_version, bundle_short_version, 0),
+    PB_FIELD(  2, BYTES   , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_AppleApplicationInfo, sdk_version, bundle_short_version, 0),
+    PB_FIELD(  3, MESSAGE , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_AppleApplicationInfo, network_connection_info, sdk_version, &NetworkConnectionInfo_fields),
+    PB_FIELD(  4, UENUM   , SINGULAR, STATIC  , OTHER, firebase_appquality_sessions_AppleApplicationInfo, os_name, network_connection_info, 0),
+    PB_LAST_FIELD
+};
+
+
+
+
+
+/* Check that field information fits in pb_field_t */
+#if !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_32BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ *
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in 8 or 16 bit
+ * field descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(firebase_appquality_sessions_SessionEvent, session_data) < 65536 && pb_membersize(firebase_appquality_sessions_SessionEvent, application_info) < 65536 && pb_membersize(firebase_appquality_sessions_SessionInfo, data_collection_status) < 65536 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, android_app_info) < 65536 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, apple_app_info) < 65536 && pb_membersize(firebase_appquality_sessions_AppleApplicationInfo, network_connection_info) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_firebase_appquality_sessions_SessionEvent_firebase_appquality_sessions_SessionInfo_firebase_appquality_sessions_DataCollectionStatus_firebase_appquality_sessions_ApplicationInfo_firebase_appquality_sessions_AndroidApplicationInfo_firebase_appquality_sessions_AppleApplicationInfo)
+#endif
+
+#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_16BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ *
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in the default
+ * 8 bit descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(firebase_appquality_sessions_SessionEvent, session_data) < 256 && pb_membersize(firebase_appquality_sessions_SessionEvent, application_info) < 256 && pb_membersize(firebase_appquality_sessions_SessionInfo, data_collection_status) < 256 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, android_app_info) < 256 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, apple_app_info) < 256 && pb_membersize(firebase_appquality_sessions_AppleApplicationInfo, network_connection_info) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_firebase_appquality_sessions_SessionEvent_firebase_appquality_sessions_SessionInfo_firebase_appquality_sessions_DataCollectionStatus_firebase_appquality_sessions_ApplicationInfo_firebase_appquality_sessions_AndroidApplicationInfo_firebase_appquality_sessions_AppleApplicationInfo)
+#endif
+
+
+/* @@protoc_insertion_point(eof) */

+ 185 - 0
FirebaseSessions/Protogen/nanopb/sessions.nanopb.h

@@ -0,0 +1,185 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.9.8 */
+
+#ifndef PB_FIREBASE_APPQUALITY_SESSIONS_SESSIONS_NANOPB_H_INCLUDED
+#define PB_FIREBASE_APPQUALITY_SESSIONS_SESSIONS_NANOPB_H_INCLUDED
+#include <nanopb/pb.h>
+
+#include "clientanalytics.nanopb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+/* Enum definitions */
+typedef enum _firebase_appquality_sessions_EventType {
+    firebase_appquality_sessions_EventType_EVENT_UNKNOWN = 0,
+    firebase_appquality_sessions_EventType_EVENT_SESSION_START = 1
+} firebase_appquality_sessions_EventType;
+#define _firebase_appquality_sessions_EventType_MIN firebase_appquality_sessions_EventType_EVENT_UNKNOWN
+#define _firebase_appquality_sessions_EventType_MAX firebase_appquality_sessions_EventType_EVENT_SESSION_START
+#define _firebase_appquality_sessions_EventType_ARRAYSIZE ((firebase_appquality_sessions_EventType)(firebase_appquality_sessions_EventType_EVENT_SESSION_START+1))
+
+typedef enum _firebase_appquality_sessions_DataCollectionState {
+    firebase_appquality_sessions_DataCollectionState_COLLECTION_UNKNOWN = 0,
+    firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED = 1,
+    firebase_appquality_sessions_DataCollectionState_COLLECTION_ENABLED = 2,
+    firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED = 3,
+    firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED_REMOTE = 4,
+    firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED = 5
+} firebase_appquality_sessions_DataCollectionState;
+#define _firebase_appquality_sessions_DataCollectionState_MIN firebase_appquality_sessions_DataCollectionState_COLLECTION_UNKNOWN
+#define _firebase_appquality_sessions_DataCollectionState_MAX firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED
+#define _firebase_appquality_sessions_DataCollectionState_ARRAYSIZE ((firebase_appquality_sessions_DataCollectionState)(firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED+1))
+
+typedef enum _firebase_appquality_sessions_OsName {
+    firebase_appquality_sessions_OsName_OS_NAME_UNKNOWN = 0,
+    firebase_appquality_sessions_OsName_OS_NAME_IOS = 1,
+    firebase_appquality_sessions_OsName_OS_NAME_IPAD_OS = 2,
+    firebase_appquality_sessions_OsName_OS_NAME_MAC_OS = 3,
+    firebase_appquality_sessions_OsName_OS_NAME_TV_OS = 4,
+    firebase_appquality_sessions_OsName_OS_NAME_WATCH_OS = 5
+} firebase_appquality_sessions_OsName;
+#define _firebase_appquality_sessions_OsName_MIN firebase_appquality_sessions_OsName_OS_NAME_UNKNOWN
+#define _firebase_appquality_sessions_OsName_MAX firebase_appquality_sessions_OsName_OS_NAME_WATCH_OS
+#define _firebase_appquality_sessions_OsName_ARRAYSIZE ((firebase_appquality_sessions_OsName)(firebase_appquality_sessions_OsName_OS_NAME_WATCH_OS+1))
+
+/* Struct definitions */
+typedef struct _firebase_appquality_sessions_AndroidApplicationInfo {
+    pb_bytes_array_t *package_name;
+    pb_bytes_array_t *sdk_version;
+    pb_bytes_array_t *version_name;
+/* @@protoc_insertion_point(struct:firebase_appquality_sessions_AndroidApplicationInfo) */
+} firebase_appquality_sessions_AndroidApplicationInfo;
+
+typedef struct _firebase_appquality_sessions_AppleApplicationInfo {
+    pb_bytes_array_t *bundle_short_version;
+    pb_bytes_array_t *sdk_version;
+    NetworkConnectionInfo network_connection_info;
+    firebase_appquality_sessions_OsName os_name;
+/* @@protoc_insertion_point(struct:firebase_appquality_sessions_AppleApplicationInfo) */
+} firebase_appquality_sessions_AppleApplicationInfo;
+
+typedef struct _firebase_appquality_sessions_DataCollectionStatus {
+    firebase_appquality_sessions_DataCollectionState performance;
+    firebase_appquality_sessions_DataCollectionState crashlytics;
+/* @@protoc_insertion_point(struct:firebase_appquality_sessions_DataCollectionStatus) */
+} firebase_appquality_sessions_DataCollectionStatus;
+
+typedef struct _firebase_appquality_sessions_ApplicationInfo {
+    pb_bytes_array_t *app_id;
+    pb_bytes_array_t *device_model;
+    pb_bytes_array_t *development_platform_name;
+    pb_bytes_array_t *development_platform_version;
+    pb_size_t which_platform_info;
+    union {
+        firebase_appquality_sessions_AndroidApplicationInfo android_app_info;
+        firebase_appquality_sessions_AppleApplicationInfo apple_app_info;
+    };
+/* @@protoc_insertion_point(struct:firebase_appquality_sessions_ApplicationInfo) */
+} firebase_appquality_sessions_ApplicationInfo;
+
+typedef struct _firebase_appquality_sessions_SessionInfo {
+    pb_bytes_array_t *session_id;
+    pb_bytes_array_t *previous_session_id;
+    pb_bytes_array_t *firebase_installation_id;
+    int64_t event_timestamp_us;
+    float sampling_rate;
+    firebase_appquality_sessions_DataCollectionStatus data_collection_status;
+/* @@protoc_insertion_point(struct:firebase_appquality_sessions_SessionInfo) */
+} firebase_appquality_sessions_SessionInfo;
+
+typedef struct _firebase_appquality_sessions_SessionEvent {
+    firebase_appquality_sessions_EventType event_type;
+    firebase_appquality_sessions_SessionInfo session_data;
+    firebase_appquality_sessions_ApplicationInfo application_info;
+/* @@protoc_insertion_point(struct:firebase_appquality_sessions_SessionEvent) */
+} firebase_appquality_sessions_SessionEvent;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define firebase_appquality_sessions_SessionEvent_init_default {_firebase_appquality_sessions_EventType_MIN, firebase_appquality_sessions_SessionInfo_init_default, firebase_appquality_sessions_ApplicationInfo_init_default}
+#define firebase_appquality_sessions_SessionInfo_init_default {NULL, NULL, NULL, 0, 0, firebase_appquality_sessions_DataCollectionStatus_init_default}
+#define firebase_appquality_sessions_DataCollectionStatus_init_default {_firebase_appquality_sessions_DataCollectionState_MIN, _firebase_appquality_sessions_DataCollectionState_MIN}
+#define firebase_appquality_sessions_ApplicationInfo_init_default {NULL, NULL, NULL, NULL, 0, {firebase_appquality_sessions_AndroidApplicationInfo_init_default}}
+#define firebase_appquality_sessions_AndroidApplicationInfo_init_default {NULL, NULL, NULL}
+#define firebase_appquality_sessions_AppleApplicationInfo_init_default {NULL, NULL, NetworkConnectionInfo_init_default, _firebase_appquality_sessions_OsName_MIN}
+#define firebase_appquality_sessions_SessionEvent_init_zero {_firebase_appquality_sessions_EventType_MIN, firebase_appquality_sessions_SessionInfo_init_zero, firebase_appquality_sessions_ApplicationInfo_init_zero}
+#define firebase_appquality_sessions_SessionInfo_init_zero {NULL, NULL, NULL, 0, 0, firebase_appquality_sessions_DataCollectionStatus_init_zero}
+#define firebase_appquality_sessions_DataCollectionStatus_init_zero {_firebase_appquality_sessions_DataCollectionState_MIN, _firebase_appquality_sessions_DataCollectionState_MIN}
+#define firebase_appquality_sessions_ApplicationInfo_init_zero {NULL, NULL, NULL, NULL, 0, {firebase_appquality_sessions_AndroidApplicationInfo_init_zero}}
+#define firebase_appquality_sessions_AndroidApplicationInfo_init_zero {NULL, NULL, NULL}
+#define firebase_appquality_sessions_AppleApplicationInfo_init_zero {NULL, NULL, NetworkConnectionInfo_init_zero, _firebase_appquality_sessions_OsName_MIN}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define firebase_appquality_sessions_AndroidApplicationInfo_package_name_tag 1
+#define firebase_appquality_sessions_AndroidApplicationInfo_sdk_version_tag 2
+#define firebase_appquality_sessions_AndroidApplicationInfo_version_name_tag 3
+#define firebase_appquality_sessions_AppleApplicationInfo_bundle_short_version_tag 1
+#define firebase_appquality_sessions_AppleApplicationInfo_sdk_version_tag 2
+#define firebase_appquality_sessions_AppleApplicationInfo_network_connection_info_tag 3
+#define firebase_appquality_sessions_AppleApplicationInfo_os_name_tag 4
+#define firebase_appquality_sessions_DataCollectionStatus_performance_tag 1
+#define firebase_appquality_sessions_DataCollectionStatus_crashlytics_tag 2
+#define firebase_appquality_sessions_ApplicationInfo_android_app_info_tag 5
+#define firebase_appquality_sessions_ApplicationInfo_apple_app_info_tag 6
+#define firebase_appquality_sessions_ApplicationInfo_app_id_tag 1
+#define firebase_appquality_sessions_ApplicationInfo_device_model_tag 2
+#define firebase_appquality_sessions_ApplicationInfo_development_platform_name_tag 3
+#define firebase_appquality_sessions_ApplicationInfo_development_platform_version_tag 4
+#define firebase_appquality_sessions_SessionInfo_session_id_tag 1
+#define firebase_appquality_sessions_SessionInfo_previous_session_id_tag 2
+#define firebase_appquality_sessions_SessionInfo_firebase_installation_id_tag 3
+#define firebase_appquality_sessions_SessionInfo_event_timestamp_us_tag 4
+#define firebase_appquality_sessions_SessionInfo_sampling_rate_tag 5
+#define firebase_appquality_sessions_SessionInfo_data_collection_status_tag 6
+#define firebase_appquality_sessions_SessionEvent_event_type_tag 1
+#define firebase_appquality_sessions_SessionEvent_session_data_tag 2
+#define firebase_appquality_sessions_SessionEvent_application_info_tag 3
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t firebase_appquality_sessions_SessionEvent_fields[4];
+extern const pb_field_t firebase_appquality_sessions_SessionInfo_fields[7];
+extern const pb_field_t firebase_appquality_sessions_DataCollectionStatus_fields[3];
+extern const pb_field_t firebase_appquality_sessions_ApplicationInfo_fields[7];
+extern const pb_field_t firebase_appquality_sessions_AndroidApplicationInfo_fields[4];
+extern const pb_field_t firebase_appquality_sessions_AppleApplicationInfo_fields[5];
+
+/* Maximum encoded size of messages (where known) */
+/* firebase_appquality_sessions_SessionEvent_size depends on runtime parameters */
+/* firebase_appquality_sessions_SessionInfo_size depends on runtime parameters */
+#define firebase_appquality_sessions_DataCollectionStatus_size 4
+/* firebase_appquality_sessions_ApplicationInfo_size depends on runtime parameters */
+/* firebase_appquality_sessions_AndroidApplicationInfo_size depends on runtime parameters */
+/* firebase_appquality_sessions_AppleApplicationInfo_size depends on runtime parameters */
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define SESSIONS_MESSAGES \
+
+
+#endif
+
+/* @@protoc_insertion_point(eof) */
+
+#endif

+ 15 - 0
FirebaseSessions/README.md

@@ -0,0 +1,15 @@
+# Firebase Sessions SDK
+
+## Prerequisites
+
+To update the Sessions Proto, Protobuf is required. To install run:
+
+```
+brew install protobuf
+```
+
+## Updating the Proto
+
+ 1. Follow the directions in `sessions.proto` for updating it
+ 1. Run the following to regenerate the nanopb source files: `./FirebaseSessions/ProtoSupport/generate_protos.sh`
+ 1. Update the SDK to use the new proto fields

+ 1 - 0
scripts/check_imports.swift

@@ -34,6 +34,7 @@ let skipDirPatterns = ["/Sample/", "/Pods/",
   [
     "CoreOnly/Sources", // Skip Firebase.h.
     "SwiftPMTests", // The SwiftPM imports test module imports.
+    "FirebaseSessions/Protogen/", // Generated nanopb code with imports
   ] +
 
   // The following are temporary skips pending working through a first pass of the repo: