Allow compilations in TOCTOU tests to fail with GENERAL_FAILURE. am: 0b617ae022

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1351583

Change-Id: I2b8d60a749f39823cb8daa2735dd8e4f6c7cfd2f
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 449b8f3..16b313a 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -315,7 +315,8 @@
 
     void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
                           const hidl_vec<hidl_handle>& dataCache,
-                          sp<IPreparedModel>* preparedModel = nullptr) {
+                          sp<IPreparedModel>* preparedModel = nullptr,
+                          bool allowGeneralFailure = false) {
         if (preparedModel != nullptr) *preparedModel = nullptr;
 
         // Launch prepare model.
@@ -329,7 +330,10 @@
 
         // Retrieve prepared model.
         preparedModelCallback->wait();
-        ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+        const auto prepareCallbackStatus = preparedModelCallback->getStatus();
+        if (!allowGeneralFailure || prepareCallbackStatus != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(prepareCallbackStatus, ErrorStatus::NONE);
+        }
         if (preparedModel != nullptr) {
             *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
                                      .withDefault(nullptr);
@@ -1022,7 +1026,8 @@
 
 // Number of operations in the large test model.
 constexpr uint32_t kLargeModelSize = 100;
-constexpr uint32_t kNumIterationsTOCTOU = 100;
+constexpr uint32_t kNumSuccessfulIterationsTOCTOU = 100;
+constexpr uint32_t kMaxNumFailedIterationsTOCTOU = 100;
 
 TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
     if (!mIsCachingSupported) return;
@@ -1050,18 +1055,30 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
 
+            sp<IPreparedModel> preparedModel = nullptr;
             // Spawn a thread to copy the cache content concurrently while saving to cache.
             std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
             thread.join();
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
@@ -1112,14 +1129,26 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            sp<IPreparedModel> preparedModel = nullptr;
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index ac18c8f..382fc76 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -318,7 +318,8 @@
 
     void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
                           const hidl_vec<hidl_handle>& dataCache,
-                          sp<IPreparedModel>* preparedModel = nullptr) {
+                          sp<IPreparedModel>* preparedModel = nullptr,
+                          bool allowGeneralFailure = false) {
         if (preparedModel != nullptr) *preparedModel = nullptr;
 
         // Launch prepare model.
@@ -332,7 +333,10 @@
 
         // Retrieve prepared model.
         preparedModelCallback->wait();
-        ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+        const auto prepareCallbackStatus = preparedModelCallback->getStatus();
+        if (!allowGeneralFailure || prepareCallbackStatus != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(prepareCallbackStatus, ErrorStatus::NONE);
+        }
         if (preparedModel != nullptr) {
             *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
                                      .withDefault(nullptr);
@@ -1013,7 +1017,8 @@
 
 // Number of operations in the large test model.
 constexpr uint32_t kLargeModelSize = 100;
-constexpr uint32_t kNumIterationsTOCTOU = 100;
+constexpr uint32_t kNumSuccessfulIterationsTOCTOU = 100;
+constexpr uint32_t kMaxNumFailedIterationsTOCTOU = 100;
 
 TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
     if (!mIsCachingSupported) return;
@@ -1041,18 +1046,30 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
 
+            sp<IPreparedModel> preparedModel = nullptr;
             // Spawn a thread to copy the cache content concurrently while saving to cache.
             std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
             thread.join();
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
@@ -1103,14 +1120,26 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            sp<IPreparedModel> preparedModel = nullptr;
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.