NNAPI Usage telemetry

Added basic data collection in the NNAPI runtime in preparation for
statsd and clearcut based telemetry. Added two types of data collection:
one for compilation, and one for execution.

There's missing functionallity that will be addressed in further CLs:

- Extraction of package/binary name from PackageManager.
- Apex version added to atoms.
- Model hash generation
- Execution and compilation time measurements.

Bug: 173392665
Test: mma, run TestTelemetry.*
Change-Id: I6bea18b66ebcd91bc73971912441e42c9c6d6a47
diff --git a/runtime/ExecutionBuilder.cpp b/runtime/ExecutionBuilder.cpp
index f5b74b6..7bbf566 100644
--- a/runtime/ExecutionBuilder.cpp
+++ b/runtime/ExecutionBuilder.cpp
@@ -44,6 +44,7 @@
 #include "Manager.h"
 #include "ModelArgumentInfo.h"
 #include "ModelBuilder.h"
+#include "Telemetry.h"
 #include "TypeManager.h"
 
 namespace android {
@@ -585,12 +586,12 @@
     return mOutputsFullySpecified.value();
 }
 
-int ExecutionBuilder::prepareForCompute(const char* name) {
+int ExecutionBuilder::prepareForCompute(const char* name, ExecutionMode mode) {
     if (!checkAndSetComputationState(name)) {
         return ANEURALNETWORKS_BAD_STATE;
     }
     if (int n = getValidationResultCode(); n != ANEURALNETWORKS_NO_ERROR) {
-        return finishComputation(n, {});
+        return finishComputation(n, {}, mode);
     }
     return ANEURALNETWORKS_NO_ERROR;
 }
@@ -972,7 +973,8 @@
 int ExecutionBuilder::computeFenced(const std::vector<int>& waitFor,
                                     uint64_t timeoutDurationAfterFence, int* syncFence) {
     CHECK(syncFence != nullptr);
-    NN_RETURN_IF_ERROR(prepareForCompute("startComputeWithDependencies"));
+    NN_RETURN_IF_ERROR(
+            prepareForCompute("startComputeWithDependencies", ExecutionMode::ASYNC_WITH_DEPS));
     if (timeoutDurationAfterFence > 0) {
         if (!mCompilation->mExplicitDeviceList || (mCompilation->mDevices.size() != 1)) {
             LOG(ERROR)
@@ -980,13 +982,13 @@
                        "duration on an ANeuralNetworksExecution "
                        "created from an ANeuralNetworksCompilation that was not created by "
                        "ANeuralNetworksCompilation_createForDevices with numDevices = 1";
-            return finishComputation(ANEURALNETWORKS_BAD_DATA, {});
+            return finishComputation(ANEURALNETWORKS_BAD_DATA, {}, ExecutionMode::ASYNC_WITH_DEPS);
         }
     }
     if (!areOutputsFullySpecified()) {
         LOG(ERROR) << "ANeuralNetworksExecution_startComputeWithDependencies"
                       " not all outputs have fully specified dimensions";
-        return finishComputation(ANEURALNETWORKS_BAD_DATA, {});
+        return finishComputation(ANEURALNETWORKS_BAD_DATA, {}, ExecutionMode::ASYNC_WITH_DEPS);
     }
 
     // Unlike ExecutionBuilder::compute, we do not need to reset output dimensions here because
@@ -1002,7 +1004,7 @@
     if (result != ANEURALNETWORKS_NO_ERROR) {
         // TODO(miaowang): support dynamic output shape only with memory domain.
         // For now just return empty output shapes.
-        result = finishComputation(result, {});
+        result = finishComputation(result, {}, ExecutionMode::ASYNC_WITH_DEPS);
     }
     return result;
 }
@@ -1018,7 +1020,10 @@
     }
 
     const char* name = burstBuilder ? "burstCompute" : synchronous ? "compute" : "startCompute";
-    NN_RETURN_IF_ERROR(prepareForCompute(name));
+    const ExecutionMode mode = burstBuilder
+                                       ? ExecutionMode::BURST
+                                       : synchronous ? ExecutionMode::SYNC : ExecutionMode::ASYNC;
+    NN_RETURN_IF_ERROR(prepareForCompute(name, mode));
 
     // Validate input memory dimensions. We need to do the validation in every computation because
     // the memory dimensions may change between computations.
@@ -1026,7 +1031,7 @@
         if (p.state() == ModelArgumentInfo::MEMORY) {
             const RuntimeMemory* memory = mMemories[p.locationAndLength().poolIndex];
             if (!memory->getValidator().validateInputDimensions(p.dimensions())) {
-                return finishComputation(ANEURALNETWORKS_OP_FAILED, {});
+                return finishComputation(ANEURALNETWORKS_OP_FAILED, {}, mode);
             }
         }
     }
@@ -1049,7 +1054,7 @@
         if (mMeasureTiming) {
             mTimingWithoutFencedExecutionCallback = timing;
         }
-        return finishComputation(n, outputShapes);
+        return finishComputation(n, outputShapes, mode);
     } else /* asynchronous */ {
         // TODO: For asynchronous execution, entire plan-based-path should run in an
         // asynchronous thread -- take the asynchronous thread logic out of
@@ -1066,8 +1071,8 @@
         // abstracted in the NN API as an "event".
         auto executionCallback = std::make_shared<ExecutionCallback>();
         executionCallback->setOnFinish(
-                [this](ErrorStatus error, const std::vector<OutputShape>& outputShapes) {
-                    return finishComputation(error, outputShapes);
+                [this, mode](ErrorStatus error, const std::vector<OutputShape>& outputShapes) {
+                    return finishComputation(error, outputShapes, mode);
                 });
         const auto asyncStartCompute = [this, deadline, executionCallback] {
             const auto [n, outputShapes, timing] = computeInternal(deadline, nullptr);
@@ -1149,7 +1154,8 @@
     return true;
 }
 
-int ExecutionBuilder::finishComputation(int result, const std::vector<OutputShape>& outputShapes) {
+int ExecutionBuilder::finishComputation(int result, const std::vector<OutputShape>& outputShapes,
+                                        ExecutionMode mode) {
     const auto status = convertResultCodeToErrorStatus(result);
     if (!updateOutputShapes(status, outputShapes) || !updateMemories()) {
         result = ANEURALNETWORKS_OP_FAILED;
@@ -1178,6 +1184,7 @@
         CHECK(mState != State::COMPLETED) << "ExecutionBuilder::finishComputation is called twice";
         mState = State::COMPLETED;
     }
+    telemetry::onExecutionFinish(this, mode, result);
     return result;
 }