Model local.properties as config cache input

When the content of the local.properties file changes, config cache
should be invalidated. The content of an empty local.properties file
should be considered the same as an non-existing local.properties file.

Note we still cannot remove the entry in the "report checker" due to issues
from kgp side. However, we can verify the fix works by removing the
entry and run a test without kgp like CMakeBuildSettingsTest.

Bug: 293321312
Test: CMakeBuildSettingsTest, etc
Change-Id: I1e6177bfd8b56e8bf52f131d667f2d7400cd7699
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkComponents.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkComponents.kt
index e7666a0..0577544 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkComponents.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkComponents.kt
@@ -17,21 +17,16 @@
 package com.android.build.gradle.internal
 
 import com.android.build.gradle.internal.component.ComponentCreationConfig
-import com.android.build.gradle.internal.core.Abi
 import com.android.build.gradle.internal.cxx.configure.NdkLocator
 import com.android.build.gradle.internal.cxx.stripping.SymbolStripExecutableFinder
 import com.android.build.gradle.internal.cxx.stripping.createSymbolStripExecutableFinder
 import com.android.build.gradle.internal.errors.SyncIssueReporterImpl
-import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope
 import com.android.build.gradle.internal.ndk.NdkHandler
 import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope
 import com.android.build.gradle.internal.services.AndroidLocationsBuildService
-import com.android.build.gradle.internal.services.ProjectServices
 import com.android.build.gradle.internal.services.ServiceRegistrationAction
 import com.android.build.gradle.internal.services.getBuildService
-import com.android.build.gradle.internal.tasks.NonIncrementalTask
 import com.android.build.gradle.internal.utils.setDisallowChanges
-import com.android.build.gradle.internal.utils.validatePreviewTargetValue
 import com.android.build.gradle.options.BooleanOption
 import com.android.build.gradle.options.IntegerOption
 import com.android.build.gradle.options.ProjectOptions
@@ -42,7 +37,6 @@
 import com.android.sdklib.AndroidVersion
 import com.android.sdklib.BuildToolInfo
 import com.android.sdklib.OptionalLibrary
-import com.android.tools.analytics.Environment
 import org.gradle.api.DefaultTask
 import org.gradle.api.NonExtensible
 import org.gradle.api.Project
@@ -91,7 +85,7 @@
     }
 
     private val sdkSourceSet: SdkLocationSourceSet by lazy {
-        SdkLocationSourceSet(parameters.projectRootDir.get().asFile)
+        SdkLocationSourceSet(parameters.projectRootDir.get().asFile, providerFactory)
     }
 
     class Environment: SdkLibDataFactory.Environment() {
@@ -218,7 +212,8 @@
             objectFactory.directoryProperty().fileProvider(providerFactory.provider {
                 getSdkDir(
                     parameters.projectRootDir.get().asFile,
-                    parameters.issueReporter.get()
+                    parameters.issueReporter.get(),
+                    providerFactory,
                 )
             })
 
@@ -291,7 +286,7 @@
         ndkLocator: NdkLocator,
         objectFactory: ObjectFactory,
         providerFactory: ProviderFactory
-    ): NdkHandler(ndkLocator) {
+    ): NdkHandler(ndkLocator, providerFactory) {
 
         val ndkDirectoryProvider: Provider<Directory> =
             objectFactory.directoryProperty().fileProvider(providerFactory.provider {
@@ -374,7 +369,8 @@
         objectFactory.directoryProperty().fileProvider(providerFactory.provider {
             getSdkDir(
                 parameters.projectRootDir.get().asFile,
-                parameters.issueReporter.get()
+                parameters.issueReporter.get(),
+                providerFactory,
             )
         })
 
@@ -411,8 +407,8 @@
  * location. This is needed when AGP handles missing [com.android.build.gradle.BaseExtension.compileSdkVersion]
  * and it tries to add highest installed API when invoked from the IDE.
  */
-fun getSdkDir(projectRootDir: File, issueReporter: IssueReporter): File {
-    return SdkLocator.getSdkDirectory(projectRootDir, issueReporter)
+fun getSdkDir(projectRootDir: File, issueReporter: IssueReporter, providers: ProviderFactory): File {
+    return SdkLocator.getSdkDirectory(projectRootDir, issueReporter, providers)
 }
 
 /** This can be used by tasks requiring android.jar as input with [org.gradle.api.tasks.Nested]. */
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkLocator.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkLocator.kt
index a234413..21a764f 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkLocator.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/SdkLocator.kt
@@ -19,10 +19,12 @@
 import com.android.SdkConstants
 import com.android.builder.errors.IssueReporter
 import com.google.common.annotations.VisibleForTesting
-import com.google.common.base.Charsets
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.ProviderFactory
+import org.gradle.api.provider.ValueSource
+import org.gradle.api.provider.ValueSourceParameters
 import java.io.File
-import java.io.FileInputStream
-import java.io.InputStreamReader
+import java.io.StringReader
 import java.util.Properties
 
 /**
@@ -50,7 +52,8 @@
  */
 data class SdkLocationSourceSet(
     val projectRoot: File,
-    internal val localProperties: Properties = GradleLocalPropertiesFactory.get(projectRoot),
+    private val providers: ProviderFactory,
+    internal val localProperties: Properties = GradleLocalPropertiesFactory.get(projectRoot, providers),
     internal val environmentProperties: Properties = EnvironmentVariablesPropertiesFactory.get(),
     internal val systemProperties: Properties = SystemPropertiesFactory.get())
 
@@ -193,8 +196,13 @@
     private var cachedSdkLocation: SdkLocation? = null
 
     @JvmStatic
-    fun getSdkDirectory(projectRootDir: File, issueReporter: IssueReporter): File {
-        val sdkLocation = getSdkLocation(SdkLocationSourceSet(projectRootDir), issueReporter)
+    fun getSdkDirectory(
+        projectRootDir: File,
+        issueReporter: IssueReporter,
+        providers: ProviderFactory
+    ): File {
+        val sdkLocation =
+            getSdkLocation(SdkLocationSourceSet(projectRootDir, providers), issueReporter)
         return if (sdkLocation.type == SdkType.MISSING) {
             // This error should have been reported earlier when SdkLocation was created, so we can
             // just return a dummy file here as it won't be used anyway.
@@ -264,14 +272,15 @@
     val cache = mutableMapOf<File, Properties>()
 
     @Synchronized
-    internal fun get(projectRoot: File): Properties {
+    internal fun get(projectRoot: File, providers: ProviderFactory): Properties {
         val properties = Properties()
-        val localProperties = File(projectRoot, SdkConstants.FN_LOCAL_PROPERTIES)
 
-        if (localProperties.isFile) {
-            InputStreamReader(FileInputStream(localProperties), Charsets.UTF_8).use { reader ->
-                properties.load(reader)
-            }
+        val propertiesContent =
+            providers.of(PropertiesValueSource::class.java) {
+                it.parameters.projectRoot.set(projectRoot)
+            }.get()
+        StringReader(propertiesContent).use { reader ->
+            properties.load(reader)
         }
 
         cache[projectRoot] = properties
@@ -285,6 +294,21 @@
 
 }
 
+abstract class PropertiesValueSource : ValueSource<String, PropertiesValueSource.Params> {
+    interface Params: ValueSourceParameters {
+        val projectRoot: RegularFileProperty
+    }
+
+    override fun obtain(): String {
+        val localPropertiesFile =
+            File(parameters.projectRoot.get().asFile, SdkConstants.FN_LOCAL_PROPERTIES)
+        if (localPropertiesFile.isFile) {
+            return localPropertiesFile.readText()
+        }
+        return ""
+    }
+}
+
 private object EnvironmentVariablesPropertiesFactory {
     internal fun get(): Properties {
         val properties = Properties()
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/CxxCreateGradleTasks.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/CxxCreateGradleTasks.kt
index 62b3593..bb912f3 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/CxxCreateGradleTasks.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/CxxCreateGradleTasks.kt
@@ -88,7 +88,9 @@
         val configurationParameters = variants
                 .mapNotNull { tryCreateConfigurationParameters(
                     projectOptions,
-                    it.variant) }
+                    it.variant,
+                    project.providers,
+                ) }
         if (configurationParameters.isEmpty()) return
         NativeLocationsBuildService.register(project)
 
@@ -332,7 +334,9 @@
         val module =
             createCxxModuleModel(
                 sdkComponents,
-                parameters)
+                parameters,
+                providers,
+            )
         val variant = createCxxVariantModel(parameters, module)
         module.ndkMetaAbiList
             .map { abi -> createCxxAbiModel(sdkComponents, parameters, variant, abi.name)
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/GradleLocalProperties.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/GradleLocalProperties.kt
index d8b0642..9a6be73 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/GradleLocalProperties.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/GradleLocalProperties.kt
@@ -16,26 +16,27 @@
 
 package com.android.build.gradle.internal.cxx.configure
 
-import com.android.SdkConstants.FN_LOCAL_PROPERTIES
-import com.google.common.base.Charsets
+import com.android.build.gradle.internal.PropertiesValueSource
+import org.gradle.api.provider.ProviderFactory
 import java.io.File
-import java.io.FileInputStream
-import java.io.InputStreamReader
+import java.io.StringReader
 import java.util.Properties
 
 /**
  * Retrieve the project local properties if they are available.
  * If there is no local properties file then an empty set of properties is returned.
  */
-fun gradleLocalProperties(projectRootDir : File) : Properties {
+fun gradleLocalProperties(projectRootDir : File, providers: ProviderFactory) : Properties {
     val properties = Properties()
-    val localProperties = File(projectRootDir, FN_LOCAL_PROPERTIES)
+    val propertiesContent =
+        providers.of(PropertiesValueSource::class.java) {
+            it.parameters.projectRoot.set(projectRootDir)
+        }.get()
 
-    if (localProperties.isFile) {
-        InputStreamReader(FileInputStream(localProperties), Charsets.UTF_8).use { reader ->
-            properties.load(reader)
-        }
+    StringReader(propertiesContent).use { reader ->
+        properties.load(reader)
     }
+
     return properties
 }
 
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/NdkLocator.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/NdkLocator.kt
index a964fca..22e959a 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/NdkLocator.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/NdkLocator.kt
@@ -39,6 +39,7 @@
 import com.android.utils.cxx.CxxDiagnosticCode.NDK_VERSION_UNSUPPORTED
 import com.google.common.annotations.VisibleForTesting
 import org.gradle.api.InvalidUserDataException
+import org.gradle.api.provider.ProviderFactory
 import java.io.File
 
 /**
@@ -415,9 +416,9 @@
      * If the user specifies android.ndkVersion in build.gradle then that version must be available
      * or it is an error. If no such version is specified then the default version is used.
      */
-    fun findNdkPath(downloadOkay: Boolean): NdkLocatorRecord? {
-        val properties = gradleLocalProperties(projectDir)
-        val sdkPath = SdkLocator.getSdkDirectory(projectDir, issueReporter)
+    fun findNdkPath(downloadOkay: Boolean, providers: ProviderFactory): NdkLocatorRecord? {
+        val properties = gradleLocalProperties(projectDir, providers)
+        val sdkPath = SdkLocator.getSdkDirectory(projectDir, issueReporter, providers)
         return findNdkPathImpl(
             ndkVersionFromDsl,
             ndkPathFromDsl,
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/gradle/generator/CxxConfigurationModel.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/gradle/generator/CxxConfigurationModel.kt
index d539751..aff38ef 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/gradle/generator/CxxConfigurationModel.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/gradle/generator/CxxConfigurationModel.kt
@@ -65,6 +65,7 @@
 import com.android.utils.cxx.CxxDiagnosticCode.INVALID_EXTERNAL_NATIVE_BUILD_CONFIG
 import com.android.utils.cxx.CxxDiagnosticCode.NINJA_IS_MISSING
 import org.gradle.api.file.FileCollection
+import org.gradle.api.provider.ProviderFactory
 import java.io.File
 import java.util.Locale
 
@@ -188,7 +189,8 @@
  */
 fun tryCreateConfigurationParameters(
     projectOptions: ProjectOptions,
-    variant: VariantCreationConfig
+    variant: VariantCreationConfig,
+    providers: ProviderFactory,
 ): CxxConfigurationParameters? {
     val globalConfig = variant.global
     val projectInfo = variant.services.projectInfo
@@ -212,7 +214,7 @@
      * in Android Studio
      */
     val ndkHandler = globalConfig.versionedNdkHandler
-    val ndkInstall = ndkHandler.getNdkPlatform(downloadOkay = true);
+    val ndkInstall = ndkHandler.getNdkPlatform(downloadOkay = true, providers)
 
     if (!ndkInstall.isConfigured) {
         infoln("Not creating C/C++ model because NDK could not be configured.")
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModel.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModel.kt
index 9412dad..a43415e 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModel.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModel.kt
@@ -30,6 +30,7 @@
 import com.android.build.gradle.tasks.NativeBuildSystem.CMAKE
 import com.android.build.gradle.tasks.NativeBuildSystem.NINJA
 import com.android.utils.FileUtils.join
+import org.gradle.api.provider.ProviderFactory
 import java.io.File
 import java.io.FileReader
 
@@ -39,11 +40,12 @@
 fun createCxxModuleModel(
     sdkComponents : SdkComponentsBuildService,
     configurationParameters: CxxConfigurationParameters,
+    providers: ProviderFactory
 ) : CxxModuleModel {
 
     val cxxFolder = configurationParameters.cxxFolder
-    fun localPropertyFile(property : String) : File? {
-        val path = gradleLocalProperties(configurationParameters.rootDir)
+    fun localPropertyFile(property : String, providers: ProviderFactory) : File? {
+        val path = gradleLocalProperties(configurationParameters.rootDir, providers)
             .getProperty(property) ?: return null
         return File(path)
     }
@@ -54,7 +56,7 @@
     val ndkSymlinkFolder = computeNdkSymLinkFolder(
             ndk.ndkDirectory,
             cxxFolder,
-            localPropertyFile(NDK_SYMLINK_DIR))
+            localPropertyFile(NDK_SYMLINK_DIR, providers))
     val finalNdkFolder = ndkSymlinkFolder ?: ndk.ndkDirectory
     val ndkMetaPlatformsFile = NdkMetaPlatforms.jsonFile(ndk.ndkDirectory)
     val ndkMetaPlatforms = if (ndkMetaPlatformsFile.isFile) {
@@ -88,7 +90,7 @@
     val ndkMetaAbiList = NdkAbiFile(ndkMetaAbisFile(ndk.ndkDirectory)).abiInfoList
     val cmake = if (configurationParameters.buildSystem == CMAKE) {
         CxxCmakeModuleModel(
-            cmakeDirFromPropertiesFile = localPropertyFile(CMAKE_DIR_PROPERTY),
+            cmakeDirFromPropertiesFile = localPropertyFile(CMAKE_DIR_PROPERTY, providers),
             cmakeVersionFromDsl = configurationParameters.cmakeVersion,
             cmakeExe = File(NDK_MODULE_CMAKE_EXECUTABLE.configurationPlaceholder)
         )
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ndk/NdkHandler.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ndk/NdkHandler.kt
index 982f874..da6fd2e 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ndk/NdkHandler.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ndk/NdkHandler.kt
@@ -22,6 +22,7 @@
 import com.android.build.gradle.internal.ndk.NdkInstallStatus.NotInstalled
 import com.android.build.gradle.internal.ndk.NdkInstallStatus.Valid
 import org.gradle.api.InvalidUserDataException
+import org.gradle.api.provider.ProviderFactory
 
 sealed class NdkInstallStatus {
     /**
@@ -67,7 +68,8 @@
  * Handles NDK related information.
  */
 open class NdkHandler(
-    private val ndkLocator: NdkLocator
+    private val ndkLocator: NdkLocator,
+    private val providers: ProviderFactory,
 ) {
     private var ndkInstallStatus: NdkInstallStatus? = null
 
@@ -81,8 +83,8 @@
         else -> DefaultNdkInfo(ndk.ndk)
     }
 
-    private fun getNdkStatus(downloadOkay: Boolean): NdkInstallStatus {
-        val ndk = ndkLocator.findNdkPath(downloadOkay)
+    private fun getNdkStatus(downloadOkay: Boolean, providers: ProviderFactory): NdkInstallStatus {
+        val ndk = ndkLocator.findNdkPath(downloadOkay, providers)
             ?: return NotInstalled
         val ndkInfo = getNdkInfo(ndk)
         val error = ndkInfo.validate()
@@ -90,16 +92,16 @@
         return Valid(NdkPlatform(ndk.ndk, ndkInfo, ndk.revision))
     }
 
-    fun getNdkPlatform(downloadOkay: Boolean) : NdkInstallStatus {
+    fun getNdkPlatform(downloadOkay: Boolean, providers: ProviderFactory) : NdkInstallStatus {
         if (ndkInstallStatus == null ||
             (downloadOkay && ndkInstallStatus == NotInstalled)) {
             // Calculate NDK platform if that hadn't been done before or if it's
             // okay to download now.
-            ndkInstallStatus = getNdkStatus(downloadOkay)
+            ndkInstallStatus = getNdkStatus(downloadOkay, providers)
         }
         return ndkInstallStatus!!
     }
 
     val ndkPlatform: NdkInstallStatus
-        get() = getNdkPlatform(downloadOkay = false)
+        get() = getNdkPlatform(downloadOkay = false, providers)
 }
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/BasePlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/BasePlugin.kt
index af896d3..798ab9d 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/BasePlugin.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/BasePlugin.kt
@@ -798,7 +798,7 @@
     private fun findHighestSdkInstalled(): String? {
         var highestSdk: String? = null
         val folder = withProject("findHighestSdkInstalled") { project ->
-            File(getSdkDir(project.rootDir, syncIssueReporter), "platforms")
+            File(getSdkDir(project.rootDir, syncIssueReporter, project.providers), "platforms")
         }
         val listOfFiles = folder.listFiles()
         if (listOfFiles != null) {
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLoadingStrategyTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLoadingStrategyTest.kt
index 3559e46..4c2b712 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLoadingStrategyTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLoadingStrategyTest.kt
@@ -18,6 +18,7 @@
 
 import com.android.SdkConstants
 import com.android.SdkConstants.FN_CORE_FOR_SYSTEM_MODULES
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.build.gradle.internal.fixtures.FakeSyncIssueReporter
 import com.android.builder.core.ToolsRevisionUtils
 import com.android.builder.internal.compiler.RenderScriptProcessor
@@ -401,6 +402,7 @@
         sdkLocationSourceSet =
             SdkLocationSourceSet(
                 projectRootDir,
+                FakeProviderFactory.factory,
                 localProperties = Properties(),
                 environmentProperties = Properties(),
                 systemProperties = Properties()
@@ -748,7 +750,7 @@
         platformHash: String = "android-28",
         buildTools: String = SdkConstants.CURRENT_BUILD_TOOLS_VERSION): SdkDirectLoadingStrategy {
         return SdkDirectLoadingStrategy(
-            SdkLocationSourceSet(testFolder.root, Properties(), Properties(), Properties()),
+            SdkLocationSourceSet(testFolder.root, FakeProviderFactory.factory, Properties(), Properties(), Properties()),
             platformHash,
             Revision.parseRevision(buildTools),
             true,
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLocatorTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLocatorTest.kt
index 7531f24..4c93a33 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLocatorTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/SdkLocatorTest.kt
@@ -17,6 +17,7 @@
 package com.android.build.gradle.internal
 
 import com.android.SdkConstants
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.build.gradle.internal.fixtures.FakeSyncIssueReporter
 import com.google.common.base.Charsets
 import com.google.common.truth.Truth.assertThat
@@ -350,7 +351,7 @@
         val systemProperties = Properties()
         systemAndroidHome?.let { systemProperties.setProperty(SdkLocator.ANDROID_HOME_SYSTEM_PROPERTY, systemAndroidHome) }
 
-        return SdkLocationSourceSet(projectRootDir, localProperties, envProperties, systemProperties)
+        return SdkLocationSourceSet(projectRootDir, FakeProviderFactory.factory, localProperties, envProperties, systemProperties)
     }
 
     private fun writeLocalPropertiesFile(properties: Properties) {
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicCmakeMock.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicCmakeMock.kt
index 89fd411..ca2029c 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicCmakeMock.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicCmakeMock.kt
@@ -16,6 +16,7 @@
 
 package com.android.build.gradle.internal.cxx.model
 
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.utils.FileUtils.join
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.SetProperty
@@ -31,7 +32,8 @@
     val module by lazy {
         createCxxModuleModel(
             sdkComponents,
-            configurationParameters
+            configurationParameters,
+            FakeProviderFactory.factory,
         )
     }
     val variant by lazy { createCxxVariantModel(configurationParameters, module) }
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicModuleModelMock.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicModuleModelMock.kt
index a8adceb..2f8d6b6 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicModuleModelMock.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicModuleModelMock.kt
@@ -39,9 +39,10 @@
 import com.android.build.gradle.internal.dsl.Splits
 import com.android.build.gradle.internal.fixtures.FakeGradleDirectory
 import com.android.build.gradle.internal.fixtures.FakeGradleProvider
+import com.android.build.gradle.internal.fixtures.FakeProjectLayout
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.build.gradle.internal.ndk.NdkInstallStatus
 import com.android.build.gradle.internal.ndk.NdkPlatform
-import com.android.build.gradle.internal.ndk.NdkR19Info
 import com.android.build.gradle.internal.ndk.NdkR25Info
 import com.android.build.gradle.internal.publishing.AndroidArtifacts
 import com.android.build.gradle.internal.scope.BuildFeatureValues
@@ -60,12 +61,9 @@
 import org.gradle.api.file.Directory
 import org.gradle.api.file.FileCollection
 import org.gradle.api.file.FileContents
-import org.gradle.api.file.ProjectLayout
-import org.gradle.api.file.RegularFile
 import org.gradle.api.invocation.Gradle
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.SetProperty
-import org.mockito.ArgumentMatchers
 import org.mockito.Mockito
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
@@ -75,7 +73,6 @@
 import java.io.File
 import java.io.InputStreamReader
 import java.util.Locale
-import java.util.concurrent.Callable
 
 /**
  * Set up up a mock for constructing [CxxModuleModel]. It takes a lot of plumbing so this can
@@ -276,16 +273,17 @@
         Gradle::class.java
     )
 
-    val providers = mock(org.gradle.api.provider.ProviderFactory::class.java, throwUnmocked)
+    val providers = FakeProviderFactory(FakeProviderFactory.factory, emptyMap())
 
-    val layout = mock(ProjectLayout::class.java, throwUnmocked)
+    val layout = FakeProjectLayout()
 
-    val fileContents = mock(FileContents::class.java, throwUnmocked)
+    lateinit var fileContents : FileContents
 
     val configurationParameters by lazy {
         tryCreateConfigurationParameters(
             projectOptions,
-            variantImpl
+            variantImpl,
+            FakeProviderFactory.factory,
         )!!
     }
 
@@ -365,12 +363,6 @@
         doReturn(false).`when`(abiSplitOptions).isUniversalApk
         doReturn(":$appName").`when`(project).path
 
-        val fileProvider = FakeGradleProvider(File::class.java)
-        doReturn(fileProvider).`when`(providers).provider(ArgumentMatchers.any(Callable::class.java))
-        val regularFileProvider = FakeGradleProvider(mock(RegularFile::class.java))
-        doReturn(regularFileProvider).`when`(layout).file(ArgumentMatchers.any())
-        doReturn(fileContents).`when`(providers).fileContents(regularFileProvider)
-
         return appFolder
     }
 
@@ -446,7 +438,7 @@
         )
         doReturn(ndkHandler).`when`(globalConfig).versionedNdkHandler
         doReturn(ndkInstallStatus).`when`(ndkHandler).ndkPlatform
-        doReturn(ndkInstallStatus).`when`(ndkHandler).getNdkPlatform(true)
+        doReturn(ndkInstallStatus).`when`(ndkHandler).getNdkPlatform(true, FakeProviderFactory.factory)
         doReturn(true).`when`(variantImpl).debuggable
 
         val ndkInfo = NdkR25Info(ndkFolder)
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicNdkBuildMock.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicNdkBuildMock.kt
index 7c271b0..12ca78a 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicNdkBuildMock.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/BasicNdkBuildMock.kt
@@ -17,6 +17,7 @@
 package com.android.build.gradle.internal.cxx.model
 
 import com.android.build.gradle.internal.core.Abi
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.utils.FileUtils
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.SetProperty
@@ -31,7 +32,8 @@
     val module by lazy {
         createCxxModuleModel(
             sdkComponents,
-            configurationParameters
+            configurationParameters,
+            FakeProviderFactory.factory,
         )
     }
     val variant by lazy { createCxxVariantModel(configurationParameters, module) }
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CmakeSettingsMock.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CmakeSettingsMock.kt
index 8715077..fc8d718 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CmakeSettingsMock.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CmakeSettingsMock.kt
@@ -16,10 +16,10 @@
 
 package com.android.build.gradle.internal.cxx.model
 
-import com.android.build.gradle.internal.core.Abi
 import com.android.build.gradle.internal.cxx.configure.CmakeProperty
 import com.android.build.gradle.internal.cxx.settings.Macro
-import com.android.build.gradle.internal.fixtures.FakeGradleProvider
+import com.android.build.gradle.internal.fixtures.FakeFileContents
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.utils.FileUtils.join
 import org.gradle.api.provider.ListProperty
 import org.gradle.api.provider.SetProperty
@@ -38,7 +38,8 @@
     val module by lazy {
         createCxxModuleModel(
             sdkComponents,
-            configurationParameters
+            configurationParameters,
+            FakeProviderFactory.factory,
         )
     }
     val variant by lazy { createCxxVariantModel(configurationParameters, module) }
@@ -91,7 +92,7 @@
                     "buildRoot": "project-build-root/${Macro.NDK_ABI.ref}"
                 } ]
             }""".trimIndent())
-        doReturn(FakeGradleProvider(cmakeSettingsJson.readText())).`when`(fileContents).asText
+        fileContents = FakeFileContents(cmakeSettingsJson)
         doReturn(makefile).`when`(cmake).path
         projectRootDir.mkdirs()
         makefile.writeText("# written by ${BasicCmakeMock::class}")
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModelTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModelTest.kt
index 72b20f4..1a8bbdd 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModelTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModelTest.kt
@@ -18,6 +18,7 @@
 
 import com.android.build.gradle.internal.cxx.RandomInstanceGenerator
 import com.android.build.gradle.internal.cxx.logging.PassThroughRecordingLoggingEnvironment
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
@@ -28,7 +29,8 @@
         BasicCmakeMock().let {
             val module = createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters
+                it.configurationParameters,
+                FakeProviderFactory.factory,
             )
             val variant = createCxxVariantModel(
                 it.configurationParameters,
@@ -48,7 +50,8 @@
         BasicCmakeMock().let {
             val module = createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters
+                it.configurationParameters,
+                FakeProviderFactory.factory,
             )
             val variant = createCxxVariantModel(
                 it.configurationParameters,
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModelTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModelTest.kt
index 9f1b333..bb9cc0a 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModelTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxModuleModelTest.kt
@@ -19,6 +19,7 @@
 import com.android.build.gradle.internal.cxx.RandomInstanceGenerator
 import com.android.build.gradle.internal.cxx.gradle.generator.tryCreateConfigurationParameters
 import com.android.build.gradle.internal.cxx.logging.PassThroughRecordingLoggingEnvironment
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.utils.FileUtils.join
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -33,7 +34,8 @@
             assertThat(
             tryCreateConfigurationParameters(
                 it.projectOptions,
-                it.variantImpl
+                it.variantImpl,
+                FakeProviderFactory.factory,
             )
             ).isNull()
         }
@@ -45,7 +47,9 @@
             doReturn(File("./CMakeLists.txt")).`when`(it.cmake).path
             assertThat(createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters)).isNotNull()
+                it.configurationParameters,
+                FakeProviderFactory.factory,
+            )).isNotNull()
         }
     }
 
@@ -55,7 +59,8 @@
             doReturn(File("./Android.mk")).`when`(it.ndkBuild).path
             assertThat(createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters
+                it.configurationParameters,
+                FakeProviderFactory.factory,
             )).isNotNull()
         }
     }
@@ -68,7 +73,8 @@
                 assertThat(
                     tryCreateConfigurationParameters(
                             it.projectOptions,
-                            it.variantImpl
+                            it.variantImpl,
+                            FakeProviderFactory.factory,
                     )
                 ).isNull()
                 assertThat(logEnvironment.errors).hasSize(1)
@@ -86,11 +92,13 @@
                 val componentModel =
                     tryCreateConfigurationParameters(
                             it.projectOptions,
-                            it.variantImpl
+                            it.variantImpl,
+                            FakeProviderFactory.factory,
                     )!!
                 val module = createCxxModuleModel(
                     it.sdkComponents,
-                    it.configurationParameters
+                    it.configurationParameters,
+                    FakeProviderFactory.factory,
                 )
                 val finalStagingDir = module.cxxFolder
                 assertThat(logEnvironment.errors).hasSize(0)
@@ -107,10 +115,13 @@
                     .`when`(it.cmake).buildStagingDirectory
                 val configurationParameters = tryCreateConfigurationParameters(
                         it.projectOptions,
-                        it.variantImpl)!!
+                        it.variantImpl,
+                        FakeProviderFactory.factory,
+                )!!
                 val module = createCxxModuleModel(
                     it.sdkComponents,
-                    configurationParameters
+                    configurationParameters,
+                    FakeProviderFactory.factory,
                 )
                 val finalStagingDir = module.cxxFolder
                 assertThat(logEnvironment.warnings).hasSize(1)
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxVariantModelTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxVariantModelTest.kt
index d1c0e3b..11bce27 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxVariantModelTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/model/CreateCxxVariantModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.build.gradle.internal.cxx.model
 
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import org.junit.Test
 
 class CreateCxxVariantModelTest {
@@ -25,7 +26,8 @@
         BasicCmakeMock().let {
             val module = createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters
+                it.configurationParameters,
+                FakeProviderFactory.factory,
             )
             createCxxVariantModel(
                 it.configurationParameters,
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/BuiltInSettingsJsonKtTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/BuiltInSettingsJsonKtTest.kt
index 7ce39dc..509de23 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/BuiltInSettingsJsonKtTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/BuiltInSettingsJsonKtTest.kt
@@ -22,6 +22,7 @@
 import com.android.build.gradle.internal.cxx.model.createCxxAbiModel
 import com.android.build.gradle.internal.cxx.model.createCxxModuleModel
 import com.android.build.gradle.internal.cxx.model.createCxxVariantModel
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import org.junit.Test
 
 class BuiltInSettingsJsonKtTest {
@@ -31,7 +32,9 @@
         BasicCmakeMock().let {
             val module = createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters)
+                it.configurationParameters,
+                FakeProviderFactory.factory,
+            )
             val variant = createCxxVariantModel(
                 it.configurationParameters,
                 module)
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/LookupSettingFromModelKtTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/LookupSettingFromModelKtTest.kt
index e08e6f8..3d6678e 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/LookupSettingFromModelKtTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/LookupSettingFromModelKtTest.kt
@@ -27,6 +27,7 @@
 import com.android.build.gradle.internal.cxx.model.name
 import com.android.build.gradle.internal.cxx.settings.Token.LiteralToken
 import com.android.build.gradle.internal.cxx.settings.Token.MacroToken
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.build.gradle.tasks.NativeBuildSystem
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -47,7 +48,9 @@
             // Walk all vals in the model and invoke them
             val module = createCxxModuleModel(
                 it.sdkComponents,
-                it.configurationParameters)
+                it.configurationParameters,
+                FakeProviderFactory.factory,
+            )
             val variant = createCxxVariantModel(
                 it.configurationParameters,
                 module)
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/SettingsConfigurationRewriterKtTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/SettingsConfigurationRewriterKtTest.kt
index 56bb97d..f5783fb 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/SettingsConfigurationRewriterKtTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/cxx/settings/SettingsConfigurationRewriterKtTest.kt
@@ -44,7 +44,8 @@
 import com.android.build.gradle.internal.cxx.settings.Macro.NDK_CONFIGURATION_HASH
 import com.android.build.gradle.internal.cxx.settings.Macro.NDK_FULL_CONFIGURATION_HASH
 import com.android.build.gradle.internal.cxx.settings.Macro.NDK_MODULE_NDK_DIR
-import com.android.build.gradle.internal.fixtures.FakeGradleProvider
+import com.android.build.gradle.internal.fixtures.FakeFileContents
+import com.android.build.gradle.internal.fixtures.FakeProviderFactory
 import com.android.build.gradle.options.ProjectOptions
 import com.android.build.gradle.tasks.NativeBuildSystem
 import com.android.utils.FileUtils
@@ -79,7 +80,7 @@
                       }]
                     }
                 """.trimIndent())
-                Mockito.doReturn(FakeGradleProvider(cmakeSettingsFile.readText())).`when`(fileContents).asText
+                fileContents = FakeFileContents(cmakeSettingsFile)
                 abi.toJsonString() // Force lazy fields to evaluate
                 val rewritten = abi.calculateConfigurationArguments(providers, layout)
                 rewritten.toJsonString() // Force lazy fields to evaluate
@@ -393,12 +394,14 @@
                 }]
                 }""".trimIndent()
             )
-            Mockito.doReturn(FakeGradleProvider(settings.readText())).`when`(fileContents).asText
+            fileContents = FakeFileContents(settings)
             setup(this, 1)
 
             val configurationModel1 = tryCreateConfigurationParameters(
                     Mockito.mock(ProjectOptions::class.java),
-                    variantImpl)!!
+                    variantImpl,
+                    FakeProviderFactory.factory,
+            )!!
             val variant1 = createCxxVariantModel(configurationModel1, module)
             val result1 = createCxxAbiModel(
                 sdkComponents, configurationModel1,
@@ -408,7 +411,9 @@
             setup(this, 2)
             val configurationModel2 = tryCreateConfigurationParameters(
                 Mockito.mock(ProjectOptions::class.java),
-                variantImpl)!!
+                variantImpl,
+                FakeProviderFactory.factory,
+            )!!
             val variant2 = createCxxVariantModel(configurationModel2, module)
             val result2 = createCxxAbiModel(
                 sdkComponents, configurationModel2,
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeFileContents.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeFileContents.kt
new file mode 100644
index 0000000..e3dbb7b
--- /dev/null
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeFileContents.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.build.gradle.internal.fixtures
+
+import org.gradle.api.file.FileContents
+import org.gradle.api.provider.Provider
+import java.io.File
+
+class FakeFileContents(private val file: File) : FileContents {
+
+    override fun getAsText(): Provider<String> {
+        return FakeGradleProvider(file.readText())
+    }
+
+    override fun getAsBytes(): Provider<ByteArray> {
+        TODO("Not yet implemented")
+    }
+}
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProjectLayout.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProjectLayout.kt
new file mode 100644
index 0000000..c6eaf84
--- /dev/null
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProjectLayout.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.build.gradle.internal.fixtures
+
+import org.gradle.api.file.Directory
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.FileCollection
+import org.gradle.api.file.ProjectLayout
+import org.gradle.api.file.RegularFile
+import org.gradle.api.provider.Provider
+import java.io.File
+
+class FakeProjectLayout : ProjectLayout {
+
+    override fun getProjectDirectory(): Directory {
+        TODO("Not yet implemented")
+    }
+
+    override fun getBuildDirectory(): DirectoryProperty {
+        TODO("Not yet implemented")
+    }
+
+    override fun file(file: Provider<File>): Provider<RegularFile> {
+        return FakeGradleProvider(FakeGradleRegularFile(file.get()))
+    }
+
+    override fun dir(file: Provider<File>): Provider<Directory> {
+        TODO("Not yet implemented")
+    }
+
+    override fun files(vararg paths: Any?): FileCollection {
+        TODO("Not yet implemented")
+    }
+}
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProviderFactory.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProviderFactory.kt
index a01ddaa..794f372 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProviderFactory.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeProviderFactory.kt
@@ -16,6 +16,8 @@
 
 package com.android.build.gradle.internal.fixtures
 
+import org.gradle.api.file.FileContents
+import org.gradle.api.file.RegularFile
 import org.gradle.api.provider.Provider
 import org.gradle.api.provider.ProviderFactory
 
@@ -32,10 +34,14 @@
         }
     }
 
+    override fun fileContents(file: Provider<RegularFile>): FileContents {
+        return FakeFileContents(file.get().asFile)
+    }
+
     companion object {
         @JvmStatic
         val factory: ProviderFactory by lazy {
             ProjectFactory.project.providers
         }
     }
-}
\ No newline at end of file
+}