Add configuration option to not filter out inlines

Original implementation of XProcessing always excluded methods that
receive value classes as parameters because they cannot be called from
java source. This is also what KAPT does when generating stubs.

This configuration allows room to not do the filtering, which increases
get declared methods performance ~100x.
Note that this does not help with collecting all methods as that still
requires type resolution. That being said, we can possibly slightly
improve it by avoiding some overrides checks (e.g. we can group by
parameter count or check for override modifier for kotlin sources).

Room still uses the slow configuration. We can followup with another
CL to see if we can make Room benefit from it.

stats:
GetMethodsScenarioTest > filterOutInline_declaredMethods STANDARD_OUT
    Stats(min=92.546784ms, max=152.486889ms, avg=120.771651ms, mean=145.828504ms)

GetMethodsScenarioTest > keepInline_declaredMethods STANDARD_OUT
    Stats(min=946.523us, max=1.731635ms, avg=1.301860ms, mean=1.441747ms)

GetMethodsScenarioTest > filterOutInline_enclosedElements STANDARD_OUT
    Stats(min=81.061261ms, max=410.522507ms, avg=140.475732ms, mean=271.770458ms)

GetMethodsScenarioTest > keepInline_enclosedElements STANDARD_OUT
    Stats(min=1.046700ms, max=1.678441ms, avg=1.308582ms, mean=1.192400ms)

Fixes: 204913321
Fixes: 206517658
Test: InternalModifierTest
Change-Id: I41c5d51db0981e1cf163e92a7e8405a83915a688
(cherry picked from commit cedb2ecd5806502ef5fff6f36907c06a138a68b1)
Merged-In:I41c5d51db0981e1cf163e92a7e8405a83915a688
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt
index 600520d..5230095 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XMethodElement.kt
@@ -16,6 +16,8 @@
 
 package androidx.room.compiler.processing
 
+import androidx.room.compiler.processing.util.isValidJavaSourceName
+
 /**
  * Represents a method in a class / interface.
  *
@@ -39,6 +41,8 @@
      * The name of the method in JVM.
      * Use this properly when you need to generate code accessing this method.
      *
+     * Note that accessing this property requires resolving jvmName for Kotlin sources, which is an
+     * expensive operation that includes type resolution (in KSP).
      * @see name
      */
     val jvmName: String
@@ -124,4 +128,24 @@
      * Creates a new [XMethodElement] where containing element is replaced with [newContainer].
      */
     fun copyTo(newContainer: XTypeElement): XMethodElement
-}
\ No newline at end of file
+
+    /**
+     * If true, this method can be invoked from Java sources. This is especially important for
+     * Kotlin functions that receive value class as a parameter as they cannot be called from Java
+     * sources.
+     *
+     * Note that calling this method requires resolving jvmName for Kotlin sources, which is an
+     * expensive operation that includes type resolution (in KSP).
+     */
+    fun hasValidJvmSourceName() = jvmName.isValidJavaSourceName()
+}
+
+internal fun <T : XMethodElement> List<T>.filterMethodsByConfig(
+    env: XProcessingEnv
+): List<T> = if (env.config.excludeMethodsWithInvalidJvmSourceNames) {
+    filter {
+        it.hasValidJvmSourceName()
+    }
+} else {
+    this
+}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt
index 52a6070..6677e68 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt
@@ -32,7 +32,7 @@
 @Suppress("SyntheticAccessor", "DataClassPrivateConstructor")
 data class XProcessingEnvConfig private constructor(
     /**
-     * TODO: not implemented yet.
+     * @see [Builder.excludeMethodsWithInvalidJvmSourceNames] for docs.
      */
     val excludeMethodsWithInvalidJvmSourceNames: Boolean = false
 ) {
@@ -43,6 +43,17 @@
     ) {
         private var instance = baseline
 
+        /**
+         * When set to `true`, XProcessingEnv will hide all methods that have invalid source names
+         * in Java (i.e. cannot be called from generated Java sources).
+         *
+         * Doing this resolution is expensive (requires type resolution) hence it is set to `false`
+         * by default.
+         *
+         * Note that, due to KAPT stubs, this is not 100% consistent between KAPT and KSP when set
+         * to `false`. Since KAPT generates stubs, it automatically removes methods that have
+         * invalid JVM names.
+         */
         fun excludeMethodsWithInvalidJvmSourceNames(value: Boolean) = apply {
             instance = instance.copy(
                 excludeMethodsWithInvalidJvmSourceNames = value
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
index 4263bf5..9bc64f8 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
@@ -21,6 +21,7 @@
 import androidx.room.compiler.processing.XFieldElement
 import androidx.room.compiler.processing.XHasModifiers
 import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.filterMethodsByConfig
 import androidx.room.compiler.processing.javac.kotlin.KotlinMetadataElement
 import com.google.auto.common.MoreElements
 import com.google.auto.common.MoreTypes
@@ -111,7 +112,7 @@
                 containing = this,
                 element = it
             )
-        }
+        }.filterMethodsByConfig(env)
     }
 
     override fun getDeclaredMethods(): List<JavacMethodElement> {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 0ff48a5..942fd38 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -25,6 +25,7 @@
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.filterMethodsByConfig
 import androidx.room.compiler.processing.ksp.KspAnnotated.UseSiteFilter.Companion.NO_USE_SITE
 import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticPropertyMethodElement
 import androidx.room.compiler.processing.tryBox
@@ -144,11 +145,6 @@
     private val syntheticGetterSetterMethods: List<XMethodElement> by lazy {
         _declaredProperties.flatMap { field ->
             when {
-                field.type.ksType.isInline() -> {
-                    // KAPT does not generate getters/setters for inlines, we'll hide them as well
-                    // until room generates kotlin code
-                    emptyList()
-                }
                 field.declaration.hasJvmFieldAnnotation() -> {
                     // jvm fields cannot have accessors but KSP generates synthetic accessors for
                     // them. We check for JVM field first before checking the getter
@@ -183,7 +179,7 @@
                             )
                         }.toList()
             }
-        }
+        }.filterMethodsByConfig(env)
     }
 
     override fun isNested(): Boolean {
@@ -260,12 +256,6 @@
             .filterNot {
                 // filter out constructors
                 it.simpleName.asString() == name
-            }.filterNot {
-                // if it receives or returns inline, drop it.
-                // we can re-enable these once room generates kotlin code
-                it.parameters.any {
-                    it.type.resolve().isInline()
-                } || it.returnType?.resolve()?.isInline() == true
             }.map {
                 KspMethodElement.create(
                     env = env,
@@ -273,6 +263,7 @@
                     declaration = it
                 )
             }.toList()
+            .filterMethodsByConfig(env)
         KspClassFileUtility.orderMethods(declaration, declaredMethods) +
             syntheticGetterSetterMethods
     }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/util/NamingUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/util/NamingUtils.kt
index 7889069..dff43f4 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/util/NamingUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/util/NamingUtils.kt
@@ -28,4 +28,9 @@
     this
 } else {
     "p$argIndex"
-}
\ No newline at end of file
+}
+
+/**
+ * Returns true if the given name can be used in generated java sources.
+ */
+internal fun String.isValidJavaSourceName() = SourceVersion.isName(this)
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/InternalModifierTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/InternalModifierTest.kt
index 3a0bff2b..ba80257 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/InternalModifierTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/InternalModifierTest.kt
@@ -18,23 +18,64 @@
 
 import androidx.room.compiler.processing.util.CompilationTestCapabilities
 import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.compileFiles
 import androidx.room.compiler.processing.util.runKaptTest
 import androidx.room.compiler.processing.util.runKspTest
-import com.google.common.truth.Truth.assertWithMessage
+import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
 class InternalModifierTest {
-    @OptIn(ExperimentalStdlibApi::class)
     @Test
-    fun testInternalsAndInlines() {
+    fun testInternalsAndInlines_excludeInlines() {
+        val signatures = buildSignatures(
+            XProcessingEnvConfig.DEFAULT.copy(
+                excludeMethodsWithInvalidJvmSourceNames = true,
+            )
+        )
+        assertThat(signatures.ksp).containsExactlyElementsIn(signatures.kapt)
+    }
+
+    @Test
+    fun testInternalsAndInlines_includeInlines() {
+        val signatures = buildSignatures(
+            XProcessingEnvConfig.DEFAULT.copy(
+                excludeMethodsWithInvalidJvmSourceNames = false
+            )
+        )
+        // KAPT will always remove methods with invalid java source names when generating stubs
+        // so we need to assert them manually.
+        val nonJvmSourceSignatures = signatures.ksp.filter {
+            it.startsWith("main.") && it.contains("-")
+        }
+        assertThat(
+            signatures.ksp - nonJvmSourceSignatures
+        ).containsExactlyElementsIn(signatures.kapt)
+        assertThat(
+            nonJvmSourceSignatures.map {
+                it.substringBefore("-")
+            }
+        ).containsExactly(
+            "main.Subject.getInlineProp",
+            "main.Subject.getInternalInlineProp",
+            "main.Subject.inlineReceivingFun",
+            "main.Subject.inlineReturningFun",
+            "main.Subject.internalInlineReceivingFun",
+            "main.Subject.internalInlineReturningFun",
+            "main.Subject.setInlineProp",
+            "main.Subject.setInternalInlineProp"
+        )
+    }
+
+    @OptIn(ExperimentalStdlibApi::class)
+    private fun buildSignatures(config: XProcessingEnvConfig): Signatures {
         CompilationTestCapabilities.assumeKspIsEnabled()
         /**
          * parse same file w/ kapt and KSP and ensure results are the same.
          */
-        val source = Source.kotlin(
+        fun buildSource(pkg: String) = Source.kotlin(
             "Subject.kt",
             """
-            package mainPackage;
+            package $pkg;
             internal class InternalClass(val value: String)
             inline class InlineClass(val value:String)
             abstract class Subject {
@@ -62,9 +103,14 @@
 
         fun XType.toSignature() = this.typeName.toString()
 
-        fun XFieldElement.toSignature() = "$name : ${type.toSignature()}"
+        fun XMemberContainer.toSignature() = className.toString()
+
+        fun XFieldElement.toSignature() =
+            "${enclosingElement.toSignature()}.$name : ${type.toSignature()}"
 
         fun XMethodElement.toSignature() = buildString {
+            append(enclosingElement.toSignature())
+            append(".")
             append(jvmName)
             append("(")
             parameters.forEach {
@@ -75,32 +121,50 @@
             append(returnType.toSignature())
         }
 
-        fun traverse(env: XProcessingEnv) = buildList<String> {
-            val subject = env.requireTypeElement("mainPackage.Subject")
-            add(subject.name)
-            add(subject.qualifiedName)
-            subject.getDeclaredMethods().forEach {
-                add(it.toSignature())
+        fun traverse(env: XProcessingEnv) = buildList {
+            listOf(
+                "main.Subject",
+                "lib.Subject"
+            ).flatMap {
+                val subject = env.requireTypeElement(it)
+                add(subject.name)
+                add(subject.qualifiedName)
+                subject.getDeclaredMethods().forEach {
+                    add(it.toSignature())
+                }
+                subject.getAllFieldsIncludingPrivateSupers().map {
+                    add(it.toSignature())
+                }
             }
-            subject.getAllFieldsIncludingPrivateSupers().map {
-                add(it.toSignature())
-            }
-        }.sorted().joinToString("\n")
+        }.sorted()
 
-        var kaptResult: String = "pending"
-        var kspResult: String = "pending"
+        var kaptResult: List<String>? = null
+        var kspResult: List<String>? = null
+        val source = buildSource("main")
+        val classpath = compileFiles(sources = listOf(buildSource("lib")))
         runKaptTest(
-            sources = listOf(source)
+            sources = listOf(source),
+            classpath = classpath,
+            config = config,
         ) { invocation ->
             kaptResult = traverse(invocation.processingEnv)
         }
 
         runKspTest(
-            sources = listOf(source)
+            sources = listOf(source),
+            classpath = classpath,
+            config = config,
         ) { invocation ->
             kspResult = traverse(invocation.processingEnv)
         }
-        assertWithMessage("$kspResult\n--\n$kaptResult")
-            .that(kspResult).isEqualTo(kaptResult)
+        return Signatures(
+            ksp = checkNotNull(kspResult),
+            kapt = checkNotNull(kaptResult)
+        )
     }
+
+    private data class Signatures(
+        val ksp: List<String>,
+        val kapt: List<String>
+    )
 }
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/GetMethodsScenarioTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/GetMethodsScenarioTest.kt
new file mode 100644
index 0000000..595c81b
--- /dev/null
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/GetMethodsScenarioTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2021 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 androidx.room.compiler.processing.profiling
+
+import androidx.room.compiler.processing.XProcessingEnvConfig
+import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.runKspTest
+import org.junit.Rule
+import org.junit.Test
+
+class GetMethodsScenarioTest {
+    @get:Rule
+    val profileRule = ProfileRule()
+
+    @Test
+    fun keepInline_declaredMethods() {
+        profileDeclaredMethods(
+            XProcessingEnvConfig.DEFAULT.copy(
+                excludeMethodsWithInvalidJvmSourceNames = false
+            )
+        )
+    }
+
+    @Test
+    fun filterOutInline_declaredMethods() {
+        profileDeclaredMethods(
+            XProcessingEnvConfig.DEFAULT.copy(
+                excludeMethodsWithInvalidJvmSourceNames = true
+            )
+        )
+    }
+
+    @Test
+    fun keepInline_enclosedElements() {
+        profileEnclosedElements(
+            XProcessingEnvConfig.DEFAULT.copy(
+                excludeMethodsWithInvalidJvmSourceNames = false
+            )
+        )
+    }
+
+    @Test
+    fun filterOutInline_enclosedElements() {
+        profileEnclosedElements(
+            XProcessingEnvConfig.DEFAULT.copy(
+                excludeMethodsWithInvalidJvmSourceNames = true
+            )
+        )
+    }
+
+    private fun profileDeclaredMethods(processingConfig: XProcessingEnvConfig) {
+        profile(processingConfig) {
+            getDeclaredMethods().toList()
+        }
+    }
+
+    private fun profileEnclosedElements(processingConfig: XProcessingEnvConfig) {
+        profile(processingConfig) {
+            getEnclosedElements().toList()
+        }
+    }
+
+    fun profile(processingConfig: XProcessingEnvConfig, block: XTypeElement.() -> Unit) {
+        val methodCount = 1000
+        val contents = buildString {
+            appendLine("class Subject {")
+            repeat(methodCount) { index ->
+                appendLine("fun method_$index(param1:Int, param2:String):String { TODO() }")
+            }
+            appendLine("}")
+        }
+        val sources = Source.kotlin("Subject.kt", contents)
+        profileRule.runRepeated(
+            warmUps = 5,
+            repeat = 10
+        ) { profileScope ->
+            runKspTest(
+                sources = listOf(sources),
+                config = processingConfig
+            ) { invocation ->
+                val subject = invocation.processingEnv.requireTypeElement(
+                    "Subject"
+                )
+                profileScope.trace {
+                    subject.block()
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/ProfileRule.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/ProfileRule.kt
index c30c894..03bc13c 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/ProfileRule.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/profiling/ProfileRule.kt
@@ -20,6 +20,10 @@
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.nanoseconds
+import kotlin.time.DurationUnit
+import kotlin.time.ExperimentalTime
 
 /**
  * Helper rule to run profiling tests.
@@ -29,6 +33,7 @@
  *
  * If this rule is applied outside a profiling session, it will ignore the test.
  */
+@OptIn(ExperimentalTime::class)
 class ProfileRule : TestRule {
     /**
      * Runs the given block, repeatedly :).
@@ -50,6 +55,26 @@
         repeat(repeat) {
             block(realProfileScope)
         }
+        println(buildReport(realProfileScope.measurements).toString())
+    }
+
+    private fun buildReport(measurements: List<Duration>): Stats {
+        check(measurements.isNotEmpty())
+        val min = measurements.minByOrNull { it.toLong(DurationUnit.NANOSECONDS) }!!
+        val max = measurements.maxByOrNull { it.toLong(DurationUnit.NANOSECONDS) }!!
+        val avg = measurements.fold(Duration.ZERO) { acc, next -> acc + next } / measurements.size
+        val mean = if (measurements.size % 2 == 0) {
+            (measurements[measurements.size / 2] + measurements[measurements.size / 2 - 1]) / 2
+        } else {
+            measurements[measurements.size / 2]
+        }
+        return Stats(
+            allMeasurements = measurements,
+            min = min,
+            max = max,
+            avg = avg,
+            mean = mean
+        )
     }
 
     override fun apply(base: Statement, description: Description): Statement {
@@ -78,11 +103,23 @@
     }
 
     private class RealProfileScope : ProfileScope {
+        private val _measurements = mutableListOf<Duration>()
+        val measurements: List<Duration>
+            get() = _measurements
+        @OptIn(ExperimentalTime::class)
         override fun trace(block: () -> Unit) {
             // this doesn't do anything but profile.sh trace profiler checks
             // this class while filtering stacktraces
-            block()
+            val start = now()
+            try {
+                block()
+            } finally {
+                val end = now()
+                _measurements.add(end - start)
+            }
         }
+
+        private fun now() = System.nanoTime().nanoseconds
     }
 
     private class WarmUpProfileScope : ProfileScope {
@@ -91,6 +128,14 @@
         }
     }
 
+    data class Stats(
+        val min: Duration,
+        val max: Duration,
+        val avg: Duration,
+        val mean: Duration,
+        val allMeasurements: List<Duration>,
+    )
+
     companion object {
         val isProfilingEnabled by lazy {
             // set by profile.sh
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt b/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt
index e33227f..f2d5486 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt
@@ -18,6 +18,7 @@
 
 import androidx.room.compiler.processing.XElement
 import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.XProcessingEnvConfig
 import androidx.room.compiler.processing.XProcessingStep
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.log.RLog
@@ -57,6 +58,10 @@
         elementsByAnnotation: Map<String, Set<XElement>>,
         isProcessingOver: Boolean
     ): Set<XTypeElement> {
+        check(env.config == ENV_CONFIG) {
+            "Room Processor expected $ENV_CONFIG but was invoked with a different configuration:" +
+                "${env.config}"
+        }
         val context = Context(env)
 
         val rejectedElements = mutableSetOf<XTypeElement>()
@@ -173,4 +178,10 @@
                 }
             }
     }
+
+    companion object {
+        internal val ENV_CONFIG = XProcessingEnvConfig.DEFAULT.copy(
+            excludeMethodsWithInvalidJvmSourceNames = true
+        )
+    }
 }
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
index 073351788..3c3080d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
@@ -16,6 +16,7 @@
 
 package androidx.room
 
+import androidx.room.DatabaseProcessingStep.Companion.ENV_CONFIG
 import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor
 import androidx.room.processor.Context.BooleanProcessorOptions.USE_NULL_AWARE_CONVERTER
 import androidx.room.processor.ProcessorErrors
@@ -29,7 +30,7 @@
  */
 class RoomKspProcessor(
     environment: SymbolProcessorEnvironment
-) : KspBasicAnnotationProcessor(environment) {
+) : KspBasicAnnotationProcessor(environment, ENV_CONFIG) {
     init {
         // print a warning if null aware converter is disabled because we'll remove that ability
         // soon.
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
index 7a14cc2..e230b3e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
@@ -16,6 +16,7 @@
 
 package androidx.room
 
+import androidx.room.DatabaseProcessingStep.Companion.ENV_CONFIG
 import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor
 import androidx.room.processor.Context
 import androidx.room.processor.ProcessorErrors
@@ -32,7 +33,9 @@
 /**
  * The annotation processor for Room.
  */
-class RoomProcessor : JavacBasicAnnotationProcessor() {
+class RoomProcessor : JavacBasicAnnotationProcessor({
+    ENV_CONFIG
+}) {
 
     /** Helper variable to avoid reporting the warning twice. */
     private var jdkVersionHasBugReported = false
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/RoomTestEnvConfigProvider.kt b/room/room-compiler/src/test/kotlin/androidx/room/RoomTestEnvConfigProvider.kt
new file mode 100644
index 0000000..addefbc
--- /dev/null
+++ b/room/room-compiler/src/test/kotlin/androidx/room/RoomTestEnvConfigProvider.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 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 androidx.room
+
+import androidx.room.compiler.processing.XProcessingEnvConfig
+import androidx.room.compiler.processing.XProcessingEnvironmentTestConfigProvider
+
+class RoomTestEnvConfigProvider : XProcessingEnvironmentTestConfigProvider {
+    override fun configure(options: Map<String, String>): XProcessingEnvConfig {
+        return DatabaseProcessingStep.ENV_CONFIG
+    }
+}
\ No newline at end of file
diff --git a/room/room-compiler/src/test/resources/META-INF/services/androidx.room.compiler.processing.XProcessingEnvironmentTestConfigProvider b/room/room-compiler/src/test/resources/META-INF/services/androidx.room.compiler.processing.XProcessingEnvironmentTestConfigProvider
new file mode 100644
index 0000000..08ae40f
--- /dev/null
+++ b/room/room-compiler/src/test/resources/META-INF/services/androidx.room.compiler.processing.XProcessingEnvironmentTestConfigProvider
@@ -0,0 +1,16 @@
+#
+# Copyright 2022 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.
+#
+androidx.room.RoomTestEnvConfigProvider
\ No newline at end of file
diff --git a/room/scripts/ksp-kapt-comparison.sh b/room/scripts/ksp-kapt-comparison.sh
index f3ac843..2e19578 100755
--- a/room/scripts/ksp-kapt-comparison.sh
+++ b/room/scripts/ksp-kapt-comparison.sh
@@ -54,9 +54,10 @@
     fi
     local cmd="./gradlew --init-script \
         $SCRIPT_DIR/rerun-requested-task-init-script.gradle \
+        --no-configuration-cache
         --profile $task"
     log "Executing $cmd"
-    local profileFile=`$cmd|grep -v "buildSrc"|awk '/profiling report at:/ {print $6}'`
+    local profileFile=`$cmd|grep "room"|awk '/profiling report at:/ {print $6}'`
     log "result: $profileFile"
     parseTimes $profileFile $type
 }
diff --git a/room/scripts/profile.sh b/room/scripts/profile.sh
index a412414..e8c912e 100755
--- a/room/scripts/profile.sh
+++ b/room/scripts/profile.sh
@@ -156,7 +156,14 @@
         # wait until file is written
         sleep 2
         if test -f "$1"; then
-            google-chrome $1
+            case "`uname`" in
+                Darwin* )
+                    open $1
+                    ;;
+                Linux* )
+                    google-chrome $1
+                    ;;
+            esac
             return 0
         fi
     done