Implement dynamic output shape in CpuExecutor and Sample Driver.

Create interface for CpuExecutor to report output shapes after
execution.

Add a new ResultCode ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE for
dynamic output shape support.

Let Sample Driver notify output shape after computation.

Bug: 73506513
Test: NeuralNetworksTest_static
Test: VtsHalNeuralnetworksV1_xTargetTest with 1.2 sample driver
Change-Id: I1ee906b7af101e447b479bea96050d8bde7fa6f4
Merged-In: I1ee906b7af101e447b479bea96050d8bde7fa6f4
(cherry picked from commit 8918e6df3f0be871e7db71cb5f331bed3ca15df4)
diff --git a/common/OperationsUtils.cpp b/common/OperationsUtils.cpp
index 6f14fda..d2f2da2 100644
--- a/common/OperationsUtils.cpp
+++ b/common/OperationsUtils.cpp
@@ -78,13 +78,44 @@
 }
 
 bool SetShape(const Shape& in, Shape* out) {
-    if (in.type != out->type || in.dimensions.size() != out->dimensions.size()) {
+    if (in.type != out->type) {
         return false;
     }
     out->dimensions = in.dimensions;
     return true;
 }
 
+bool combineDimensions(const std::vector<uint32_t>& lhs, const std::vector<uint32_t>& rhs,
+                       std::vector<uint32_t>* combined) {
+    if (rhs.empty()) {
+        *combined = lhs;
+        return true;
+    }
+    if (lhs.empty()) {
+        *combined = rhs;
+        return true;
+    }
+    if (lhs.size() != rhs.size()) {
+        return false;
+    }
+    combined->resize(lhs.size());
+    for (uint32_t i = 0; i < lhs.size(); i++) {
+        if (lhs[i] == 0) {
+            (*combined)[i] = rhs[i];
+            continue;
+        }
+        if (rhs[i] == 0) {
+            (*combined)[i] = lhs[i];
+            continue;
+        }
+        if (lhs[i] != rhs[i]) {
+            return false;
+        }
+        (*combined)[i] = lhs[i];
+    }
+    return true;
+}
+
 uint32_t getNumberOfElements(const Shape& shape) {
     uint32_t count = 1;
     for (size_t i = 0; i < shape.dimensions.size(); i++) {