Add NNAPI loop timeout API

Bug: 145906499
Bug: 136735929
Test: NNT_static
Change-Id: Ie40c248b174964676985403f9f1a5127b408a00a
diff --git a/current.txt b/current.txt
index 29e95fe..67e2818 100644
--- a/current.txt
+++ b/current.txt
@@ -674,9 +674,9 @@
 9db064ee44268a876be0367ff771e618362d39ec603b6ecab17e1575725fcd87 android.hardware.neuralnetworks@1.3::IDevice
 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
 2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
-237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel
+43088ffc71945b463a7279262cfe2e290f6ed2f15d3fd6032798a3be299fb08f android.hardware.neuralnetworks@1.3::IPreparedModel
 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-5e2a14b40dc11da9d478185838f4401b652739922d14cecea0a0ce4c1359fe21 android.hardware.neuralnetworks@1.3::types
+306fda32ac969fd51d75d066352cadcb769944ec4823be4cdd3f86fdb9e97511 android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
 2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index d645de7..4ce3691 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -92,6 +92,17 @@
      * @param deadline The time by which the execution must complete. If the
      *                 execution cannot be finished by the deadline, the
      *                 execution must be aborted.
+     * @param loopTimeoutDuration The maximum amount of time that should be spent
+     *                            executing a {@link OperationType::WHILE}
+     *                            operation. If a loop condition model does not
+     *                            output false within this duration, the
+     *                            execution must be aborted. If the model
+     *                            contains a {@link OperationType::WHILE}
+     *                            operation and no loop timeout duration is
+     *                            provided, the maximum amount of time is {@link
+     *                            LoopTimeoutDurationNs::DEFAULT}. When
+     *                            provided, the duration must not exceed {@link
+     *                            LoopTimeoutDurationNs::MAXIMUM}.
      * @param callback A callback object used to return the error status of
      *                 the execution, shape information of model output operands, and
      *                 duration of execution. The callback object's notify function must
@@ -111,7 +122,7 @@
      *                  driver
      */
     execute_1_3(Request request, MeasureTiming measure, OptionalTimePoint deadline,
-                IExecutionCallback callback)
+                OptionalTimeoutDuration loopTimeoutDuration, IExecutionCallback callback)
         generates (ErrorStatus status);
 
     /**
@@ -163,6 +174,17 @@
      * @param deadline The time by which the execution must complete. If the
      *                 execution cannot be finished by the deadline, the
      *                 execution must be aborted.
+     * @param loopTimeoutDuration The maximum amount of time that should be spent
+     *                            executing a {@link OperationType::WHILE}
+     *                            operation. If a loop condition model does not
+     *                            output false within this duration, the
+     *                            execution must be aborted. If the model
+     *                            contains a {@link OperationType::WHILE}
+     *                            operation and no loop timeout duration is
+     *                            provided, the maximum amount of time is {@link
+     *                            LoopTimeoutDurationNs::DEFAULT}. When
+     *                            provided, the duration must not exceed {@link
+     *                            LoopTimeoutDurationNs::MAXIMUM}.
      * @return status Error status of the execution, must be:
      *                - NONE if execution is performed successfully
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
@@ -187,7 +209,8 @@
      *                measurement is not available.
      */
     executeSynchronously_1_3(Request request, MeasureTiming measure,
-                             OptionalTimePoint deadline)
+                             OptionalTimePoint deadline,
+                             OptionalTimeoutDuration loopTimeoutDuration)
                   generates (ErrorStatus status, vec<OutputShape> outputShapes,
                              Timing timing);
 
@@ -243,6 +266,17 @@
      * @param deadline The time by which the execution must complete. If the
      *                 execution cannot be finished by the deadline, the
      *                 execution must be aborted.
+     * @param loopTimeoutDuration The maximum amount of time that should be spent
+     *                            executing a {@link OperationType::WHILE}
+     *                            operation. If a loop condition model does not
+     *                            output false within this duration, the
+     *                            execution must be aborted. If the model
+     *                            contains a {@link OperationType::WHILE}
+     *                            operation and no loop timeout duration is
+     *                            provided, the maximum amount of time is {@link
+     *                            LoopTimeoutDurationNs::DEFAULT}. When
+     *                            provided, the duration must not exceed {@link
+     *                            LoopTimeoutDurationNs::MAXIMUM}.
      * @param duration The length of time within which the execution must
      *                 complete after all sync fences in waitFor are signaled. If the
      *                 execution cannot be finished within the duration, the execution
@@ -264,6 +298,7 @@
      *                  and error status when the execution is completed.
      */
     executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure,
-                  OptionalTimePoint deadline, OptionalTimeoutDuration duration)
+                  OptionalTimePoint deadline, OptionalTimeoutDuration loopTimeoutDuration,
+                  OptionalTimeoutDuration duration)
         generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback);
 };
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 8ee867c..a808a2e 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -5671,3 +5671,14 @@
      */
     RESOURCE_EXHAUSTED_PERSISTENT,
 };
+
+/**
+ * Each {@link OperationType::WHILE} operation in the model has an implicit
+ * execution timeout duration associated with it ("loop timeout duration").
+ * This duration is configurable on a per-execution basis and must not exceed
+ * 15 seconds. The default value is 2 seconds.
+ */
+enum LoopTimeoutDurationNs : uint64_t {
+    DEFAULT = 2000000000,
+    MAXIMUM = 15000000000,
+};
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index c663a60..0a6e45e 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -598,3 +598,14 @@
      */
     RESOURCE_EXHAUSTED_PERSISTENT,
 };
+
+/**
+ * Each {@link OperationType::WHILE} operation in the model has an implicit
+ * execution timeout duration associated with it ("loop timeout duration").
+ * This duration is configurable on a per-execution basis and must not exceed
+ * 15 seconds. The default value is 2 seconds.
+ */
+enum LoopTimeoutDurationNs : uint64_t {
+    DEFAULT = 2000000000,
+    MAXIMUM = 15000000000,
+};
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 404c2a1..89edfb7 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -496,7 +496,7 @@
 static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
                                                 const Request& request, MeasureTiming measure,
                                                 sp<ExecutionCallback>& callback) {
-    return preparedModel->execute_1_3(request, measure, {}, callback);
+    return preparedModel->execute_1_3(request, measure, {}, {}, callback);
 }
 static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
                                                 const Request& request, MeasureTiming measure,
@@ -504,7 +504,7 @@
                                                 Timing* timing) {
     ErrorStatus result;
     Return<void> ret = preparedModel->executeSynchronously_1_3(
-            request, measure, {},
+            request, measure, {}, {},
             [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
                                             const Timing& time) {
                 result = error;
@@ -612,7 +612,7 @@
             hidl_handle syncFenceHandle;
             sp<IFencedExecutionCallback> fencedCallback;
             Return<void> ret = preparedModel->executeFenced(
-                    request, {}, testConfig.measureTiming, {}, {},
+                    request, {}, testConfig.measureTiming, {}, {}, {},
                     [&result, &syncFenceHandle, &fencedCallback](
                             ErrorStatus error, const hidl_handle& handle,
                             const sp<IFencedExecutionCallback>& callback) {
diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
index 8271135..fccc612 100644
--- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
@@ -171,7 +171,7 @@
 
     // launch execution
     const sp<ExecutionCallback> callback = new ExecutionCallback();
-    Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, callback);
+    Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, {}, callback);
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE));
     if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt;
@@ -198,7 +198,7 @@
 
     // run execution
     const Return<void> ret =
-            preparedModel->executeSynchronously_1_3(request, measure, deadline, cb);
+            preparedModel->executeSynchronously_1_3(request, measure, deadline, {}, cb);
     EXPECT_TRUE(ret.isOk());
     if (!ret.isOk()) return std::nullopt;
 
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 2a4269f..20f4fe2 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -70,7 +70,7 @@
 
         sp<ExecutionCallback> executionCallback = new ExecutionCallback();
         Return<ErrorStatus> executeLaunchStatus =
-                preparedModel->execute_1_3(request, measure, deadline, executionCallback);
+                preparedModel->execute_1_3(request, measure, deadline, {}, executionCallback);
         ASSERT_TRUE(executeLaunchStatus.isOk());
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
 
@@ -88,7 +88,7 @@
         SCOPED_TRACE(message + " [executeSynchronously_1_3]");
 
         Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
-                request, measure, deadline,
+                request, measure, deadline, {},
                 [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
                    const Timing& timing) {
                     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -143,7 +143,7 @@
     {
         SCOPED_TRACE(message + " [executeFenced]");
         Return<void> ret =
-                preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {},
+                preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, {},
                                              [](ErrorStatus error, const hidl_handle& handle,
                                                 const sp<IFencedExecutionCallback>& callback) {
                                                  ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -196,7 +196,7 @@
 void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
     SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]");
     Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
-            request, MeasureTiming::NO, {},
+            request, MeasureTiming::NO, {}, {},
             [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
                 ASSERT_NE(ErrorStatus::NONE, error);
                 EXPECT_EQ(outputShapes.size(), 0);
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 9a87569..16341da 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -137,7 +137,7 @@
 void validateExecuteFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
     SCOPED_TRACE("Expecting request to fail [executeFenced]");
     Return<void> ret_null = preparedModel->executeFenced(
-            request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {},
+            request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, {},
             [](ErrorStatus error, const hidl_handle& handle,
                const sp<IFencedExecutionCallback>& callback) {
                 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);