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