Add 1.2 NN HAL interface for dynamic output shape.

Let notify_1_2() notify output shapes.

Document unspecified dimensions and rank.

Bug: 73506513
Bug: 77234888
Test: NeuralNetworksTest_static
Test: VtsHalNeuralnetworksV1_xTargetTest with 1.2 sample driver
Change-Id: I01108913212d9f4aa47daf2f293ea19259925865
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 3b4eb21..b5a8607 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -89,13 +89,24 @@
                                                 sp<ExecutionCallback>& callback) {
     return preparedModel->execute_1_2(request, callback);
 }
-static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&) {
+static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&,
+                                                hidl_vec<OutputShape>*) {
     ADD_FAILURE() << "asking for synchronous execution at V1_0";
     return ErrorStatus::GENERAL_FAILURE;
 }
 static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
-                                                const Request& request) {
-    return preparedModel->executeSynchronously(request);
+                                                const Request& request,
+                                                hidl_vec<OutputShape>* outputShapes) {
+    ErrorStatus result;
+    Return<void> ret = preparedModel->executeSynchronously(
+        request, [&result, &outputShapes](ErrorStatus error, const hidl_vec<OutputShape>& shapes) {
+            result = error;
+            *outputShapes = shapes;
+        });
+    if (!ret.isOk()) {
+        return ErrorStatus::GENERAL_FAILURE;
+    }
+    return result;
 }
 enum class Synchronously { NO, YES };
 const float kDefaultAtol = 1e-5f;
@@ -197,6 +208,8 @@
         inputMemory->commit();
         outputMemory->commit();
 
+        ErrorStatus executionStatus;
+        hidl_vec<OutputShape> outputShapes;
         if (sync == Synchronously::NO) {
             SCOPED_TRACE("asynchronous");
 
@@ -211,18 +224,24 @@
 
             // retrieve execution status
             executionCallback->wait();
-            ErrorStatus executionReturnStatus = executionCallback->getStatus();
-            EXPECT_EQ(ErrorStatus::NONE, executionReturnStatus);
+            executionStatus = executionCallback->getStatus();
+            outputShapes = executionCallback->getOutputShapes();
         } else {
             SCOPED_TRACE("synchronous");
 
             // execute
-            Return<ErrorStatus> executionStatus = ExecutePreparedModel(
-                preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
-            ASSERT_TRUE(executionStatus.isOk());
-            EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionStatus));
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                preparedModel, {.inputs = inputs_info, .outputs = outputs_info, .pools = pools},
+                &outputShapes);
+            ASSERT_TRUE(executionReturnStatus.isOk());
+            executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
         }
 
+        ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+        // TODO(xusongw): Check if the returned output shapes match with expectation once the
+        //                sample driver implementation of dynamic output shape is finished.
+        ASSERT_EQ(outputShapes.size(), 0);
+
         // validate results
         outputMemory->read();
         copy_back(&test, outputs_info, outputPtr);