Validate FULLY_CONNECTED outputScale > inputScale * weightsScale below v1.2

FULLY_CONNECTED's constraint "outputScale > inputScale * weightsScale" was
relaxed for HAL v1.2, but the appropriate version checks were not put in
place. For more information about this check, refer to the description
of the output operand for FULLY_CONNECTED in NeuralNetworks.h.

Bug: 130169097
Test: NeuralNetworkTest_static
Change-Id: Id8baa985efbf2978f88b7cfc732ae6d0c68a5a33
Merged-In: Id8baa985efbf2978f88b7cfc732ae6d0c68a5a33
(cherry picked from commit 0a0f75e852a87d2cb99ea590a08e6a34dcd31802)
diff --git a/common/operations/FullyConnected.cpp b/common/operations/FullyConnected.cpp
index 14cd431..542fb53 100644
--- a/common/operations/FullyConnected.cpp
+++ b/common/operations/FullyConnected.cpp
@@ -161,7 +161,20 @@
                 OperandType::INT32,
         };
     } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
-        NN_RET_CHECK(validateHalVersion(context, HalVersion::V1_0));
+        // NeuralNetworks.h specifies that ANEURALNETWORKS_FULLY_CONNECTED's output must
+        // meet "outputScale > inputScale * weightsScale" for the operand type
+        // ANEURALNETWORKS_TENSOR_QUANT8_ASYMM before API level 29.
+        const float inputScale = context->getInputShape(kInputTensor).scale;
+        const float weightsScale = context->getInputShape(kWeightsTensor).scale;
+        const float outputScale = context->getOutputShape(kOutputTensor).scale;
+        bool meetsQuantizedScaleConstraintBeforeV1_2 = (outputScale > inputScale * weightsScale);
+
+        if (!meetsQuantizedScaleConstraintBeforeV1_2) {
+            NN_RET_CHECK(validateHalVersion(context, HalVersion::V1_2));
+        } else {
+            NN_RET_CHECK(validateHalVersion(context, HalVersion::V1_0));
+        }
+
         inExpectedTypes = {
                 OperandType::TENSOR_QUANT8_ASYMM,
                 OperandType::TENSOR_QUANT8_ASYMM,
diff --git a/runtime/test/TestCompliance.cpp b/runtime/test/TestCompliance.cpp
index 85df3d0..47700bf 100644
--- a/runtime/test/TestCompliance.cpp
+++ b/runtime/test/TestCompliance.cpp
@@ -74,6 +74,7 @@
 TEST_AVAILABLE_SINCE_V1_2(sub_v1_2, quant8)
 TEST_AVAILABLE_SINCE_V1_2(conv2d_v1_2, nchw)
 TEST_AVAILABLE_SINCE_V1_2(conv2d_v1_2, quant_output_multiplier_gt_1)
+TEST_AVAILABLE_SINCE_V1_2(fully_connected_v1_2, quant8_mult_gt_1)
 TEST_AVAILABLE_SINCE_V1_2(depthwise_conv2d_v1_2, nchw)
 TEST_AVAILABLE_SINCE_V1_2(depthwise_conv2d_v1_2, quant_output_multiplier_gt_1)
 TEST_AVAILABLE_SINCE_V1_2(avg_pool_v1_2, nchw)