Update neuralnetworks HAL to allow collecting execution duration.

Test: VtsHalNeuralnetworksV1_0TargetTest --hal_service_instance=android.hardware.neuralnetworks@1.0::IDevice/sample-all
Test: VtsHalNeuralnetworksV1_1TargetTest --hal_service_instance=android.hardware.neuralnetworks@1.1::IDevice/sample-all
Test: VtsHalNeuralnetworksV1_2TargetTest --hal_service_instance=android.hardware.neuralnetworks@1.2::IDevice/sample-all

Bug: 115390094

Change-Id: If67a5ffe39cfdd78498e01f26251734fdc8e66c7
Merged-In: If67a5ffe39cfdd78498e01f26251734fdc8e66c7
(cherry picked from commit e301349b0597f2cc136703f2aaa182e6a546b50c)
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 1eaea4b..00a7c3e 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -42,6 +42,10 @@
 
 ///////////////////////// UTILITY FUNCTIONS /////////////////////////
 
+static bool badTiming(Timing timing) {
+    return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
+}
+
 static void createPreparedModel(const sp<IDevice>& device, const Model& model,
                                 sp<IPreparedModel>* preparedModel) {
     ASSERT_NE(nullptr, preparedModel);
@@ -98,31 +102,46 @@
                      Request request, const std::function<void(Request*)>& mutation) {
     mutation(&request);
 
+    // We'd like to test both with timing requested and without timing
+    // requested. Rather than running each test both ways, we'll decide whether
+    // to request timing by hashing the message. We do not use std::hash because
+    // it is not guaranteed stable across executions.
+    char hash = 0;
+    for (auto c : message) {
+        hash ^= c;
+    };
+    MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
+
     {
         SCOPED_TRACE(message + " [execute_1_2]");
 
         sp<ExecutionCallback> executionCallback = new ExecutionCallback();
         ASSERT_NE(nullptr, executionCallback.get());
         Return<ErrorStatus> executeLaunchStatus =
-            preparedModel->execute_1_2(request, executionCallback);
+                preparedModel->execute_1_2(request, measure, executionCallback);
         ASSERT_TRUE(executeLaunchStatus.isOk());
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
 
         executionCallback->wait();
         ErrorStatus executionReturnStatus = executionCallback->getStatus();
         const auto& outputShapes = executionCallback->getOutputShapes();
+        Timing timing = executionCallback->getTiming();
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
         ASSERT_EQ(outputShapes.size(), 0);
+        ASSERT_TRUE(badTiming(timing));
     }
 
     {
         SCOPED_TRACE(message + " [executeSynchronously]");
 
         Return<void> executeStatus = preparedModel->executeSynchronously(
-            request, [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes) {
-                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
-                EXPECT_EQ(outputShapes.size(), 0);
-            });
+                request, measure,
+                [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
+                   const Timing& timing) {
+                    ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+                    EXPECT_EQ(outputShapes.size(), 0);
+                    EXPECT_TRUE(badTiming(timing));
+                });
         ASSERT_TRUE(executeStatus.isOk());
     }
 }