Bug 1927595 - Open GeckoViewTest Priority Tests for Isolated Processes r=geckoview-reviewers,m_kato

Issue was `getContentProcessesOomScore` was attempting to read other process's oom scores.

This patch:
* Adjusts `getContentProcessesOomScore` to read the oom score through the test privileged `uiAutomation`
* Opens tests in `GeckoViewTest` gated by isolated process
* Runs ktlint on `GeckoViewTest`

Differential Revision: https://phabricator.services.mozilla.com/D246355
This commit is contained in:
Olivia Hall
2025-04-29 13:54:13 +00:00
parent 99c30c384e
commit 84b42d3f2a

View File

@@ -1,3 +1,5 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package org.mozilla.geckoview.test
import android.content.Context
@@ -5,6 +7,7 @@ import android.graphics.Matrix
import android.os.Build
import android.os.Bundle
import android.os.LocaleList
import android.os.ParcelFileDescriptor
import android.util.Pair
import android.util.SparseArray
import android.view.View
@@ -15,11 +18,11 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import org.hamcrest.Matchers.equalTo
import org.junit.* // ktlint-disable no-wildcard-imports
import org.junit.*
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Assume.assumeThat
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import org.mozilla.geckoview.Autofill
@@ -27,12 +30,12 @@ import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.GeckoView
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.NullDelegate
import org.mozilla.geckoview.test.util.UiThreadUtils
import java.io.File
@RunWith(AndroidJUnit4::class)
@LargeTest
class GeckoViewTest : BaseSessionTest() {
val activityRule = ActivityScenarioRule(GeckoViewTestActivity::class.java)
private val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
@get:Rule
override val rules = RuleChain.outerRule(activityRule).around(sessionRule)
@@ -95,13 +98,19 @@ class GeckoViewTest : BaseSessionTest() {
}
}
private fun waitUntilContentProcessPriority(high: List<GeckoSession>, low: List<GeckoSession>) {
private fun waitUntilContentProcessPriority(
high: List<GeckoSession>,
low: List<GeckoSession>,
) {
val highPids = high.map { sessionRule.getSessionPid(it) }.toSet()
val lowPids = low.map { sessionRule.getSessionPid(it) }.toSet()
waitUntilContentProcessPriorityByPid(highPids = highPids, lowPids = lowPids)
}
private fun waitUntilContentProcessPriorityByPid(highPids: Collection<Int>, lowPids: Collection<Int>) {
private fun waitUntilContentProcessPriorityByPid(
highPids: Collection<Int>,
lowPids: Collection<Int>,
) {
UiThreadUtils.waitForCondition({
val shouldBeHighPri = getContentProcessesOomScore(highPids)
val shouldBeLowPri = getContentProcessesOomScore(lowPids)
@@ -111,11 +120,17 @@ class GeckoViewTest : BaseSessionTest() {
}, env.defaultTimeoutMillis)
}
fun getContentProcessesOomScore(pids: Collection<Int>): List<Int> {
return pids.map { pid ->
File("/proc/$pid/oom_score").readText(Charsets.UTF_8).trim().toInt()
fun getContentProcessesOomScore(pids: Collection<Int>): List<Int> =
pids.map { pid ->
val shellCommand = uiAutomation.executeShellCommand("cat /proc/$pid/oom_score")
ParcelFileDescriptor.AutoCloseInputStream(shellCommand).use { inputStream ->
inputStream
.bufferedReader(Charsets.UTF_8)
.readText()
.trim()
.toInt()
}
}
}
fun setupPriorityTest(): GeckoSession {
// This makes the test a little bit faster
@@ -152,8 +167,6 @@ class GeckoViewTest : BaseSessionTest() {
@Test
@NullDelegate(Autofill.Delegate::class)
fun setTabActiveKeepsTabAtHighPriority() {
// Bug 1927595
assumeThat(env.isIsolatedProcess, equalTo(false))
activityRule.scenario.onActivity {
val otherSession = setupPriorityTest()
@@ -180,8 +193,6 @@ class GeckoViewTest : BaseSessionTest() {
@Test
@NullDelegate(Autofill.Delegate::class)
fun processPriorityTest() {
// Bug 1927595
assumeThat(env.isIsolatedProcess, equalTo(false))
activityRule.scenario.onActivity {
val otherSession = setupPriorityTest()
@@ -221,8 +232,6 @@ class GeckoViewTest : BaseSessionTest() {
@Test
@NullDelegate(Autofill.Delegate::class)
fun setPriorityHint() {
// Bug 1927595
assumeThat(env.isIsolatedProcess, equalTo(false))
val otherSession = setupPriorityTest()
// Setting priorityHint to PRIORITY_HIGH raises priority
@@ -245,9 +254,6 @@ class GeckoViewTest : BaseSessionTest() {
@Test
@NullDelegate(Autofill.Delegate::class)
fun setActiveProcessPriorityTest() {
// Bug 1927595
assumeThat(env.isIsolatedProcess, equalTo(false))
sessionRule.setPrefsUntilTestEnd(
mapOf(
"dom.ipc.processPriorityManager.backgroundGracePeriodMS" to 0,
@@ -295,7 +301,10 @@ class GeckoViewTest : BaseSessionTest() {
}
}
private fun visit(node: MockViewStructure, callback: (MockViewStructure) -> Unit) {
private fun visit(
node: MockViewStructure,
callback: (MockViewStructure) -> Unit,
) {
callback(node)
for (child in node.children) {
@@ -312,22 +321,24 @@ class GeckoViewTest : BaseSessionTest() {
mainSession.loadTestPath(FORMS_XORIGIN_HTML_PATH)
mainSession.waitForPageStop()
val autofills = mapOf(
"#user1" to "username@example.com",
"#user2" to "username@example.com",
"#pass1" to "test-password",
"#pass2" to "test-password",
)
val autofills =
mapOf(
"#user1" to "username@example.com",
"#user2" to "username@example.com",
"#pass1" to "test-password",
"#pass2" to "test-password",
)
// Set up promises to monitor the values changing.
val promises = autofills.map { entry ->
// Repeat each test with both the top document and the iframe document.
mainSession.evaluatePromiseJS(
"""
val promises =
autofills.map { entry ->
// Repeat each test with both the top document and the iframe document.
mainSession.evaluatePromiseJS(
"""
window.getDataForAllFrames('${entry.key}', '${entry.value}')
""",
)
}
)
}
activityRule.scenario.onActivity {
val root = MockViewStructure(View.NO_ID)
@@ -385,14 +396,22 @@ class GeckoViewTest : BaseSessionTest() {
}
}
class MockViewStructure(var id: Int, var parent: MockViewStructure? = null) : ViewStructure() {
class MockViewStructure(
var id: Int,
var parent: MockViewStructure? = null,
) : ViewStructure() {
private var enabled: Boolean = false
private var inputType = 0
var children = Array<MockViewStructure?>(0, { null })
var childIndex = 0
var hints: Array<out String>? = null
override fun setId(p0: Int, p1: String?, p2: String?, p3: String?) {
override fun setId(
p0: Int,
p1: String?,
p2: String?,
p3: String?,
) {
id = p0
}
@@ -404,9 +423,7 @@ class GeckoViewTest : BaseSessionTest() {
children = Array(p0, { null })
}
override fun getChildCount(): Int {
return children.size
}
override fun getChildCount(): Int = children.size
override fun newChild(p0: Int): ViewStructure {
val child = MockViewStructure(p0, this)
@@ -414,17 +431,13 @@ class GeckoViewTest : BaseSessionTest() {
return child
}
override fun asyncNewChild(p0: Int): ViewStructure {
return newChild(p0)
}
override fun asyncNewChild(p0: Int): ViewStructure = newChild(p0)
override fun setInputType(p0: Int) {
inputType = p0
}
fun getInputType(): Int {
return inputType
}
fun getInputType(): Int = inputType
override fun setAutofillHints(p0: Array<out String>?) {
hints = p0
@@ -434,76 +447,119 @@ class GeckoViewTest : BaseSessionTest() {
TODO()
}
override fun setDimens(p0: Int, p1: Int, p2: Int, p3: Int, p4: Int, p5: Int) {}
override fun setTransformation(p0: Matrix?) {}
override fun setElevation(p0: Float) {}
override fun setAlpha(p0: Float) {}
override fun setVisibility(p0: Int) {}
override fun setClickable(p0: Boolean) {}
override fun setLongClickable(p0: Boolean) {}
override fun setContextClickable(p0: Boolean) {}
override fun setFocusable(p0: Boolean) {}
override fun setFocused(p0: Boolean) {}
override fun setAccessibilityFocused(p0: Boolean) {}
override fun setCheckable(p0: Boolean) {}
override fun setChecked(p0: Boolean) {}
override fun setSelected(p0: Boolean) {}
override fun setActivated(p0: Boolean) {}
override fun setOpaque(p0: Boolean) {}
override fun setClassName(p0: String?) {}
override fun setContentDescription(p0: CharSequence?) {}
override fun setText(p0: CharSequence?) {}
override fun setText(p0: CharSequence?, p1: Int, p2: Int) {}
override fun setTextStyle(p0: Float, p1: Int, p2: Int, p3: Int) {}
override fun setTextLines(p0: IntArray?, p1: IntArray?) {}
override fun setHint(p0: CharSequence?) {}
override fun getText(): CharSequence {
return ""
}
override fun getTextSelectionStart(): Int {
return 0
}
override fun getTextSelectionEnd(): Int {
return 0
}
override fun getHint(): CharSequence {
return ""
}
override fun getExtras(): Bundle {
return Bundle()
}
override fun hasExtras(): Boolean {
return false
}
override fun setDimens(
p0: Int,
p1: Int,
p2: Int,
p3: Int,
p4: Int,
p5: Int,
) {}
override fun setTransformation(p0: Matrix?) {}
override fun setElevation(p0: Float) {}
override fun setAlpha(p0: Float) {}
override fun setVisibility(p0: Int) {}
override fun setClickable(p0: Boolean) {}
override fun setLongClickable(p0: Boolean) {}
override fun setContextClickable(p0: Boolean) {}
override fun setFocusable(p0: Boolean) {}
override fun setFocused(p0: Boolean) {}
override fun setAccessibilityFocused(p0: Boolean) {}
override fun setCheckable(p0: Boolean) {}
override fun setChecked(p0: Boolean) {}
override fun setSelected(p0: Boolean) {}
override fun setActivated(p0: Boolean) {}
override fun setOpaque(p0: Boolean) {}
override fun setClassName(p0: String?) {}
override fun setContentDescription(p0: CharSequence?) {}
override fun setText(p0: CharSequence?) {}
override fun setText(
p0: CharSequence?,
p1: Int,
p2: Int,
) {}
override fun setTextStyle(
p0: Float,
p1: Int,
p2: Int,
p3: Int,
) {}
override fun setTextLines(
p0: IntArray?,
p1: IntArray?,
) {}
override fun setHint(p0: CharSequence?) {}
override fun getText(): CharSequence = ""
override fun getTextSelectionStart(): Int = 0
override fun getTextSelectionEnd(): Int = 0
override fun getHint(): CharSequence = ""
override fun getExtras(): Bundle = Bundle()
override fun hasExtras(): Boolean = false
override fun getAutofillId(): AutofillId? = null
override fun getAutofillId(): AutofillId? {
return null
}
override fun setAutofillId(p0: AutofillId) {}
override fun setAutofillId(p0: AutofillId, p1: Int) {}
override fun setAutofillId(
p0: AutofillId,
p1: Int,
) {}
override fun setAutofillType(p0: Int) {}
override fun setAutofillValue(p0: AutofillValue?) {}
override fun setAutofillOptions(p0: Array<out CharSequence>?) {}
override fun setDataIsSensitive(p0: Boolean) {}
override fun asyncCommit() {}
override fun setWebDomain(p0: String?) {}
override fun setLocaleList(p0: LocaleList?) {}
override fun newHtmlInfoBuilder(p0: String): HtmlInfo.Builder {
return MockHtmlInfoBuilder()
}
override fun newHtmlInfoBuilder(p0: String): HtmlInfo.Builder = MockHtmlInfoBuilder()
override fun setHtmlInfo(p0: HtmlInfo) {
}
}
class MockHtmlInfoBuilder : ViewStructure.HtmlInfo.Builder() {
override fun addAttribute(p0: String, p1: String): ViewStructure.HtmlInfo.Builder {
return this
}
override fun addAttribute(
p0: String,
p1: String,
): ViewStructure.HtmlInfo.Builder = this
override fun build(): ViewStructure.HtmlInfo {
return MockHtmlInfo()
}
override fun build(): ViewStructure.HtmlInfo = MockHtmlInfo()
}
class MockHtmlInfo : ViewStructure.HtmlInfo() {