Add VTS tests for NNAPI compilation caching.

Add the following tests for compilation caching:
- validation tests
  - Test isCachingSupported
  - Test prepareModelFromCache with invalid numFd and invalid access mode
  - Test saveToCache with invalid numFd, invalid access mode,
    invalid file size, and invalid fd offset
- execution test
  - Save a mobilenet model to cache and then retrieve and run accuracy
    evaluation.
  - The same test but the file offsets for prepareModelFromCache is not at zero.
- security test
  - CompilationCachingSecurityTest.CorruptedSecuritySensitiveCache
    Randomly flip one bit of security-sensitive cache.
  - CompilationCachingSecurityTest.WrongLengthSecuritySensitiveCache
    Randomly append bytes to security-sensitive cache.
  - CompilationCachingSecurityTest.WrongToken
    Randomly flip one bit of cache token.

Bug: 119616526
Test: VtsHalNeuralnetworksV1_xTargetTest with 1.2 sample driver
Test: VtsHalNeuralnetworksV1_xTargetTest with a test driver that can
      read and write cache entries
Change-Id: Iae9211cb28ce972b29572dfedd45d1ade4dfdaf5
Merged-In: Iae9211cb28ce972b29572dfedd45d1ade4dfdaf5
(cherry picked from commit 3405878e5e0eb85549363b69b8dffb3f91c7b8ff)
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
new file mode 100644
index 0000000..454aa1f
--- /dev/null
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "neuralnetworks_hidl_hal_test"
+
+#include "VtsHalNeuralnetworks.h"
+
+#include "Callbacks.h"
+#include "GeneratedTestHarness.h"
+#include "TestHarness.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <cstdio>
+#include <cstdlib>
+#include <random>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace neuralnetworks {
+namespace V1_2 {
+namespace vts {
+namespace functional {
+
+using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
+using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
+using ::android::nn::allocateSharedMemory;
+using ::test_helper::MixedTypedExample;
+
+namespace {
+
+// In frameworks/ml/nn/runtime/tests/generated/, creates a hidl model of mobilenet.
+#include "examples/mobilenet_224_gender_basic_fixed.example.cpp"
+#include "vts_models/mobilenet_224_gender_basic_fixed.model.cpp"
+
+// Prevent the compiler from complaining about an otherwise unused function.
+[[maybe_unused]] auto dummy_createTestModel = createTestModel_dynamic_output_shape;
+[[maybe_unused]] auto dummy_get_examples = get_examples_dynamic_output_shape;
+
+enum class AccessMode { READ_ONLY, WRITE_ONLY };
+
+void createCacheHandle(const std::vector<std::string>& files, AccessMode mode,
+                       hidl_handle* handle) {
+    std::vector<int> fds;
+    for (const auto& file : files) {
+        int fd;
+        if (mode == AccessMode::READ_ONLY) {
+            fd = open(file.c_str(), O_RDONLY);
+        } else if (mode == AccessMode::WRITE_ONLY) {
+            fd = open(file.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+        } else {
+            FAIL();
+        }
+        ASSERT_GE(fd, 0);
+        fds.push_back(fd);
+    }
+    native_handle_t* cacheNativeHandle = native_handle_create(fds.size(), 0);
+    ASSERT_NE(cacheNativeHandle, nullptr);
+    for (uint32_t i = 0; i < fds.size(); i++) {
+        cacheNativeHandle->data[i] = fds[i];
+    }
+    handle->setTo(cacheNativeHandle, /*shouldOwn=*/true);
+}
+
+}  // namespace
+
+// Tag for the compilation caching tests.
+class CompilationCachingTest : public NeuralnetworksHidlTest {
+  protected:
+    void SetUp() override {
+        NeuralnetworksHidlTest::SetUp();
+
+        // Create cache directory.
+        char cacheDirTemp[] = "/data/local/tmp/TestCompilationCachingXXXXXX";
+        char* cacheDir = mkdtemp(cacheDirTemp);
+        ASSERT_NE(cacheDir, nullptr);
+        mCache1 = cacheDir + mCache1;
+        mCache2 = cacheDir + mCache2;
+        mCache3 = cacheDir + mCache3;
+
+        // Check if caching is supported.
+        bool isCachingSupported;
+        Return<void> ret = device->isCachingSupported(
+                [&isCachingSupported](ErrorStatus status, bool supported) {
+                    EXPECT_EQ(ErrorStatus::NONE, status);
+                    isCachingSupported = supported;
+                });
+        EXPECT_TRUE(ret.isOk());
+        if (isCachingSupported) {
+            mIsCachingSupported = true;
+        } else {
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service does not "
+                         "support compilation caching.";
+            std::cout << "[          ]   Early termination of test because vendor service does not "
+                         "support compilation caching."
+                      << std::endl;
+            mIsCachingSupported = false;
+        }
+
+        // Create empty cache files.
+        hidl_handle handle;
+        createCacheHandle({mCache1, mCache2, mCache3}, AccessMode::WRITE_ONLY, &handle);
+    }
+
+    void saveModelToCache(sp<IPreparedModel> preparedModel, const hidl_handle& cache1,
+                          const hidl_handle& cache2, ErrorStatus* status) {
+        // Save IPreparedModel to cache.
+        hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
+        Return<ErrorStatus> saveToCacheStatus =
+                preparedModel->saveToCache(cache1, cache2, cacheToken);
+        ASSERT_TRUE(saveToCacheStatus.isOk());
+        *status = static_cast<ErrorStatus>(saveToCacheStatus);
+    }
+
+    bool checkEarlyTermination(ErrorStatus status) {
+        if (status == ErrorStatus::GENERAL_FAILURE) {
+            LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                         "save the prepared model that it does not support.";
+            std::cout << "[          ]   Early termination of test because vendor service cannot "
+                         "save the prepared model that it does not support."
+                      << std::endl;
+            return true;
+        }
+        return false;
+    }
+
+    void prepareModelFromCache(const hidl_handle& cache1, const hidl_handle& cache2,
+                               sp<IPreparedModel>* preparedModel, ErrorStatus* status) {
+        // Launch prepare model from cache.
+        sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
+        ASSERT_NE(nullptr, preparedModelCallback.get());
+        hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
+        Return<ErrorStatus> prepareLaunchStatus =
+                device->prepareModelFromCache(cache1, cache2, cacheToken, preparedModelCallback);
+        ASSERT_TRUE(prepareLaunchStatus.isOk());
+        if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
+            *preparedModel = nullptr;
+            *status = static_cast<ErrorStatus>(prepareLaunchStatus);
+            return;
+        }
+
+        // Retrieve prepared model.
+        preparedModelCallback->wait();
+        *status = preparedModelCallback->getStatus();
+        *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
+                                 .withDefault(nullptr);
+    }
+
+    std::string mCache1 = "/cache1";
+    std::string mCache2 = "/cache2";
+    std::string mCache3 = "/cache3";
+    uint8_t mToken[static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)] = {};
+    bool mIsCachingSupported;
+};
+
+TEST_F(CompilationCachingTest, CacheSavingAndRetrieval) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (!mIsCachingSupported) {
+            EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        } else {
+            if (checkEarlyTermination(status)) return;
+            ASSERT_EQ(status, ErrorStatus::NONE);
+        }
+    }
+
+    // Retrieve preparedModel from cache.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        if (!mIsCachingSupported) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+            ASSERT_NE(preparedModel, nullptr);
+        }
+    }
+
+    // Execute and verify results.
+    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
+                                           testModel.relaxComputationFloat32toFloat16,
+                                           /*testDynamicOutputShape=*/false);
+}
+
+TEST_F(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (!mIsCachingSupported) {
+            EXPECT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        } else {
+            if (checkEarlyTermination(status)) return;
+            ASSERT_EQ(status, ErrorStatus::NONE);
+        }
+    }
+
+    // Retrieve preparedModel from cache.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        uint8_t dummyByte = 0;
+        // Advance offset by one byte.
+        ASSERT_GE(read(cache1.getNativeHandle()->data[0], &dummyByte, 1), 0);
+        ASSERT_GE(read(cache2.getNativeHandle()->data[0], &dummyByte, 1), 0);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        if (!mIsCachingSupported) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+            ASSERT_EQ(preparedModel, nullptr);
+            return;
+        } else {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+            ASSERT_NE(preparedModel, nullptr);
+        }
+    }
+
+    // Execute and verify results.
+    generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
+                                           testModel.relaxComputationFloat32toFloat16,
+                                           /*testDynamicOutputShape=*/false);
+}
+
+TEST_F(CompilationCachingTest, SaveToCacheInvalidNumFd) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // cache1 with invalid NumFd.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1, mCache3}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+    }
+
+    // cache2 with invalid NumFd.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2, mCache3}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+        }
+    }
+}
+
+TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+        }
+    }
+
+    // cache1 with invalid NumFd.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1, mCache3}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+            ASSERT_EQ(preparedModel, nullptr);
+        }
+    }
+
+    // cache2 with invalid NumFd.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2, mCache3}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
+            ASSERT_EQ(preparedModel, nullptr);
+        }
+    }
+}
+
+TEST_F(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // cache1 with invalid access mode.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+    }
+
+    // cache2 with invalid access mode.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+    }
+}
+
+TEST_F(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (status != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(status, ErrorStatus::NONE);
+        }
+    }
+
+    // cache1 with invalid access mode.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+
+    // cache2 with invalid access mode.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_F(CompilationCachingTest, SaveToCacheInvalidOffset) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // cache1 with invalid file descriptor offset.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        uint8_t dummyByte = 0;
+        // Advance offset by one byte.
+        ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+    }
+
+    // cache2 with invalid file descriptor offset.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        uint8_t dummyByte = 0;
+        // Advance offset by one byte.
+        ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+    }
+}
+
+TEST_F(CompilationCachingTest, SaveToCacheInvalidFileSize) {
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // cache1 with invalid file size.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        uint8_t dummyByte = 0;
+        // Write one byte and seek back to the beginning.
+        ASSERT_EQ(write(cache1.getNativeHandle()->data[0], &dummyByte, 1), 1);
+        ASSERT_EQ(lseek(cache1.getNativeHandle()->data[0], 0, SEEK_SET), 0);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+    }
+
+    // cache2 with invalid file size.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        uint8_t dummyByte = 0;
+        // Write one byte and seek back to the beginning.
+        ASSERT_EQ(write(cache2.getNativeHandle()->data[0], &dummyByte, 1), 1);
+        ASSERT_EQ(lseek(cache2.getNativeHandle()->data[0], 0, SEEK_SET), 0);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+    }
+}
+
+class CompilationCachingSecurityTest : public CompilationCachingTest,
+                                       public ::testing::WithParamInterface<uint32_t> {
+  protected:
+    void SetUp() {
+        CompilationCachingTest::SetUp();
+        generator.seed(kSeed);
+    }
+
+    // Get a random integer within a closed range [lower, upper].
+    template <typename T>
+    T getRandomInt(T lower, T upper) {
+        std::uniform_int_distribution<T> dis(lower, upper);
+        return dis(generator);
+    }
+
+    const uint32_t kSeed = GetParam();
+    std::mt19937 generator;
+};
+
+TEST_P(CompilationCachingSecurityTest, CorruptedSecuritySensitiveCache) {
+    if (!mIsCachingSupported) return;
+
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (checkEarlyTermination(status)) return;
+        ASSERT_EQ(status, ErrorStatus::NONE);
+    }
+
+    // Randomly flip one single bit of the cache entry.
+    FILE* pFile = fopen(mCache1.c_str(), "r+");
+    ASSERT_EQ(fseek(pFile, 0, SEEK_END), 0);
+    long int fileSize = ftell(pFile);
+    ASSERT_GT(fileSize, 0);
+    ASSERT_EQ(fseek(pFile, getRandomInt(0l, fileSize - 1), SEEK_SET), 0);
+    int readByte = fgetc(pFile);
+    ASSERT_NE(readByte, EOF);
+    ASSERT_EQ(fseek(pFile, -1, SEEK_CUR), 0);
+    ASSERT_NE(fputc(static_cast<uint8_t>(readByte) ^ (1U << getRandomInt(0, 7)), pFile), EOF);
+    fclose(pFile);
+
+    // Retrieve preparedModel from cache, expect failure.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongLengthSecuritySensitiveCache) {
+    if (!mIsCachingSupported) return;
+
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (checkEarlyTermination(status)) return;
+        ASSERT_EQ(status, ErrorStatus::NONE);
+    }
+
+    // Randomly append bytes to the cache entry.
+    FILE* pFile = fopen(mCache1.c_str(), "a");
+    uint32_t appendLength = getRandomInt(1, 256);
+    for (uint32_t i = 0; i < appendLength; i++) {
+        ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+    }
+    fclose(pFile);
+
+    // Retrieve preparedModel from cache, expect failure.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+TEST_P(CompilationCachingSecurityTest, WrongToken) {
+    if (!mIsCachingSupported) return;
+
+    // Create test HIDL model and compile.
+    Model testModel = createTestModel();
+    sp<IPreparedModel> preparedModel = nullptr;
+    generated_tests::PrepareModel(device, testModel, &preparedModel);
+    // Terminate early if the driver cannot prepare the model.
+    if (preparedModel == nullptr) return;
+
+    // Save the compilation to cache.
+    {
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::WRITE_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::WRITE_ONLY, &cache2);
+        saveModelToCache(preparedModel, cache1, cache2, &status);
+        if (checkEarlyTermination(status)) return;
+        ASSERT_EQ(status, ErrorStatus::NONE);
+    }
+
+    // Randomly flip one single bit in mToken.
+    uint32_t ind = getRandomInt(0u, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN) - 1);
+    mToken[ind] ^= (1U << getRandomInt(0, 7));
+
+    // Retrieve the preparedModel from cache, expect failure.
+    {
+        preparedModel = nullptr;
+        ErrorStatus status;
+        hidl_handle cache1, cache2;
+        createCacheHandle({mCache1}, AccessMode::READ_ONLY, &cache1);
+        createCacheHandle({mCache2}, AccessMode::READ_ONLY, &cache2);
+        prepareModelFromCache(cache1, cache2, &preparedModel, &status);
+        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        ASSERT_EQ(preparedModel, nullptr);
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
+                        ::testing::Range(0U, 10U));
+
+}  // namespace functional
+}  // namespace vts
+}  // namespace V1_2
+}  // namespace neuralnetworks
+}  // namespace hardware
+}  // namespace android