Commit c492203d authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

[RenderProcessHost/Desktop] Update process priority on process launch and fix...

[RenderProcessHost/Desktop] Update process priority on process launch and fix navigation priority inversion

This is a second take on
https://chromium-review.googlesource.com/c/chromium/src/+/754299

It's under an experiment to (1) be able to see the side-effects and (2)
make merge to M69 easier. Intentionally kept old (and buggy) behavior
intact under the non-experimental branch for comparison.

This fixes all aspects of crbug.com/560446:
 1) Fixes the OP better than r385608 did.
 2) Fixes the side-effect of r385608 which was to default all tabs
    created backgrounded to run at foreground priority until visiblity
    was toggle on/off again.
 3) Fixes a major priority inversion on foreground navigation which
    could cause them to background their associated renderer while
    navigation (which reintroduced the OP but worse since all background
    tabs were running foregrounded per r385608)...
    See https://crbug.com/560446#c74 for details.

Updated ChildProcessLauncherPriority::is_background() to consistently
reflect backgrounding decision to all callers and renamed
|ChildProcessLauncherPriority::foreground| to
|ChildProcessLauncherPriority::visible| to better reflect that it's a
property but not the resulting foreground/background state.

See in code comment on ShouldBoostPriorityForPendingViews() for more
details.

TBR=haraken@chromium.org (side-effect in third_party/blink)

Bug: 560446
Change-Id: I901b702506a44704b53c007bcdd498fb60824e94
Reviewed-on: https://chromium-review.googlesource.com/1142593
Commit-Queue: Gabriel Charette <gab@chromium.org>
Reviewed-by: default avatarNasko Oskov <nasko@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585918}
parent cdfd0835
...@@ -168,7 +168,11 @@ ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( ...@@ -168,7 +168,11 @@ ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
bool ChildProcessLauncherPriority::operator==( bool ChildProcessLauncherPriority::operator==(
const ChildProcessLauncherPriority& other) const { const ChildProcessLauncherPriority& other) const {
return foreground == other.foreground && // |should_boost_for_pending_views| is temporary and constant for all
// ChildProcessLauncherPriority throughout a session (experiment driven).
DCHECK_EQ(should_boost_for_pending_views,
other.should_boost_for_pending_views);
return visible == other.visible &&
has_media_stream == other.has_media_stream && has_media_stream == other.has_media_stream &&
frame_depth == other.frame_depth && frame_depth == other.frame_depth &&
intersects_viewport == other.intersects_viewport && intersects_viewport == other.intersects_viewport &&
......
...@@ -56,21 +56,23 @@ static_assert(static_cast<int>(LAUNCH_RESULT_START) > ...@@ -56,21 +56,23 @@ static_assert(static_cast<int>(LAUNCH_RESULT_START) >
#endif #endif
struct ChildProcessLauncherPriority { struct ChildProcessLauncherPriority {
ChildProcessLauncherPriority(bool foreground, ChildProcessLauncherPriority(bool visible,
bool has_media_stream, bool has_media_stream,
unsigned int frame_depth, unsigned int frame_depth,
bool intersects_viewport, bool intersects_viewport,
bool boost_for_pending_views bool boost_for_pending_views,
bool should_boost_for_pending_views
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
, ,
ChildProcessImportance importance ChildProcessImportance importance
#endif #endif
) )
: foreground(foreground), : visible(visible),
has_media_stream(has_media_stream), has_media_stream(has_media_stream),
frame_depth(frame_depth), frame_depth(frame_depth),
intersects_viewport(intersects_viewport), intersects_viewport(intersects_viewport),
boost_for_pending_views(boost_for_pending_views) boost_for_pending_views(boost_for_pending_views),
should_boost_for_pending_views(should_boost_for_pending_views)
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
, ,
importance(importance) importance(importance)
...@@ -78,22 +80,59 @@ struct ChildProcessLauncherPriority { ...@@ -78,22 +80,59 @@ struct ChildProcessLauncherPriority {
{ {
} }
bool foreground; // Returns true if the child process is backgrounded.
bool is_background() const {
return !visible && !has_media_stream &&
!(should_boost_for_pending_views && boost_for_pending_views);
}
bool operator==(const ChildProcessLauncherPriority& other) const;
bool operator!=(const ChildProcessLauncherPriority& other) const {
return !(*this == other);
}
// Prefer |is_background()| to inspecting these fields individually (to ensure
// all logic uses the same notion of "backgrounded").
// |visible| is true if the process is responsible for one or more widget(s)
// in foreground tabs. The notion of "visible" is determined by the embedder
// but is ideally a widget in a non-minimized, non-background, non-occluded
// tab (i.e. with pixels visible on the screen).
bool visible;
// |has_media_stream| is true when the process is responsible for "hearable"
// content.
bool has_media_stream; bool has_media_stream;
// |frame_depth| is the depth of the shallowest frame this process is
// responsible for which has |visible| visibility. It only makes sense to
// compare this property for two ChildProcessLauncherPriority instances with
// matching |visible| properties.
unsigned int frame_depth; unsigned int frame_depth;
// |intersects_viewport| is true if this process is responsible for a frame
// which intersects a viewport which has |visible| visibility. It only makes
// sense to compare this property for two ChildProcessLauncherPriority
// instances with matching |visible| properties.
bool intersects_viewport; bool intersects_viewport;
// |boost_for_pending_views| is true if this process is responsible for a
// pending view (this is used to boost priority of a process responsible for
// foreground content which hasn't yet been added as a visible widget -- i.e.
// during navigation).
bool boost_for_pending_views; bool boost_for_pending_views;
// True iff |boost_for_pending_views| should be considered in
// |is_background()|. This needs to be a separate parameter as opposed to
// having the experiment set |boost_for_pending_views == false| when
// |!should_boost_for_pending_views| as that would result in different
// |is_background()| logic than before and defeat the purpose of the
// experiment. TODO(gab): Remove this field when the
// BoostRendererPriorityForPendingViews desktop experiment is over.
bool should_boost_for_pending_views;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
ChildProcessImportance importance; ChildProcessImportance importance;
#endif #endif
// Returns true if the child process is backgrounded.
bool is_background() const { return !foreground && !has_media_stream; }
bool operator==(const ChildProcessLauncherPriority& other) const;
bool operator!=(const ChildProcessLauncherPriority& other) const {
return !(*this == other);
}
}; };
// Launches a process asynchronously and notifies the client of the process // Launches a process asynchronously and notifies the client of the process
......
...@@ -221,7 +221,7 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread( ...@@ -221,7 +221,7 @@ void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread(
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
DCHECK(env); DCHECK(env);
return Java_ChildProcessLauncherHelperImpl_setPriority( return Java_ChildProcessLauncherHelperImpl_setPriority(
env, java_peer_, process.Handle(), priority.foreground, env, java_peer_, process.Handle(), priority.visible,
priority.has_media_stream, priority.frame_depth, priority.has_media_stream, priority.frame_depth,
priority.intersects_viewport, priority.boost_for_pending_views, priority.intersects_viewport, priority.boost_for_pending_views,
static_cast<jint>(priority.importance)); static_cast<jint>(priority.importance));
......
...@@ -136,9 +136,8 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -136,9 +136,8 @@ public final class ChildProcessLauncherHelperImpl {
sLauncherByPid.put(pid, ChildProcessLauncherHelperImpl.this); sLauncherByPid.put(pid, ChildProcessLauncherHelperImpl.this);
if (mRanking != null) { if (mRanking != null) {
mRanking.addConnection(connection, false /* foreground */, mRanking.addConnection(connection, false /* visible */, 1 /* frameDepth */,
1 /* frameDepth */, false /* intersectsViewport */, false /* intersectsViewport */, ChildProcessImportance.MODERATE);
ChildProcessImportance.MODERATE);
} }
// If the connection fails and pid == 0, the Java-side cleanup was already // If the connection fails and pid == 0, the Java-side cleanup was already
...@@ -172,7 +171,7 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -172,7 +171,7 @@ public final class ChildProcessLauncherHelperImpl {
// This is the current computed importance from all the inputs from setPriority. // This is the current computed importance from all the inputs from setPriority.
// The initial value is MODERATE since a newly created connection has moderate bindings. // The initial value is MODERATE since a newly created connection has moderate bindings.
private @ChildProcessImportance int mEffectiveImportance = ChildProcessImportance.MODERATE; private @ChildProcessImportance int mEffectiveImportance = ChildProcessImportance.MODERATE;
private boolean mForeground; private boolean mVisible;
@CalledByNative @CalledByNative
private static FileDescriptorInfo makeFdInfo( private static FileDescriptorInfo makeFdInfo(
...@@ -435,7 +434,7 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -435,7 +434,7 @@ public final class ChildProcessLauncherHelperImpl {
} }
@CalledByNative @CalledByNative
private void setPriority(int pid, boolean foreground, boolean hasMediaStream, long frameDepth, private void setPriority(int pid, boolean visible, boolean hasMediaStream, long frameDepth,
boolean intersectsViewport, boolean boostForPendingViews, boolean intersectsViewport, boolean boostForPendingViews,
@ChildProcessImportance int importance) { @ChildProcessImportance int importance) {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
...@@ -447,7 +446,7 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -447,7 +446,7 @@ public final class ChildProcessLauncherHelperImpl {
ChildProcessConnection connection = mLauncher.getConnection(); ChildProcessConnection connection = mLauncher.getConnection();
if (ChildProcessCreationParamsImpl.getIgnoreVisibilityForImportance()) { if (ChildProcessCreationParamsImpl.getIgnoreVisibilityForImportance()) {
foreground = false; visible = false;
boostForPendingViews = false; boostForPendingViews = false;
} }
...@@ -456,10 +455,10 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -456,10 +455,10 @@ public final class ChildProcessLauncherHelperImpl {
@ChildProcessImportance @ChildProcessImportance
int newEffectiveImportance; int newEffectiveImportance;
if ((foreground && frameDepth == 0) || importance == ChildProcessImportance.IMPORTANT if ((visible && frameDepth == 0) || importance == ChildProcessImportance.IMPORTANT
|| (hasMediaStream && !mediaRendererHasModerate)) { || (hasMediaStream && !mediaRendererHasModerate)) {
newEffectiveImportance = ChildProcessImportance.IMPORTANT; newEffectiveImportance = ChildProcessImportance.IMPORTANT;
} else if ((foreground && frameDepth > 0 && intersectsViewport) || boostForPendingViews } else if ((visible && frameDepth > 0 && intersectsViewport) || boostForPendingViews
|| importance == ChildProcessImportance.MODERATE || importance == ChildProcessImportance.MODERATE
|| (hasMediaStream && mediaRendererHasModerate)) { || (hasMediaStream && mediaRendererHasModerate)) {
newEffectiveImportance = ChildProcessImportance.MODERATE; newEffectiveImportance = ChildProcessImportance.MODERATE;
...@@ -468,13 +467,13 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -468,13 +467,13 @@ public final class ChildProcessLauncherHelperImpl {
} }
// Add first and remove second. // Add first and remove second.
if (foreground && !mForeground) { if (visible && !mVisible) {
BindingManager manager = getBindingManager(); BindingManager manager = getBindingManager();
if (mUseBindingManager && manager != null) { if (mUseBindingManager && manager != null) {
manager.increaseRecency(connection); manager.increaseRecency(connection);
} }
} }
mForeground = foreground; mVisible = visible;
if (mEffectiveImportance != newEffectiveImportance) { if (mEffectiveImportance != newEffectiveImportance) {
switch (newEffectiveImportance) { switch (newEffectiveImportance) {
...@@ -497,7 +496,7 @@ public final class ChildProcessLauncherHelperImpl { ...@@ -497,7 +496,7 @@ public final class ChildProcessLauncherHelperImpl {
if (mRanking != null) { if (mRanking != null) {
mRanking.updateConnection( mRanking.updateConnection(
connection, foreground, frameDepth, intersectsViewport, importance); connection, visible, frameDepth, intersectsViewport, importance);
} }
if (mEffectiveImportance != newEffectiveImportance) { if (mEffectiveImportance != newEffectiveImportance) {
......
...@@ -19,17 +19,17 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> { ...@@ -19,17 +19,17 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> {
public final ChildProcessConnection connection; public final ChildProcessConnection connection;
// Info for ranking a connection. // Info for ranking a connection.
public boolean foreground; public boolean visible;
public long frameDepth; public long frameDepth;
public boolean intersectsViewport; public boolean intersectsViewport;
@ChildProcessImportance @ChildProcessImportance
public int importance; public int importance;
public ConnectionWithRank(ChildProcessConnection connection, boolean foreground, public ConnectionWithRank(ChildProcessConnection connection, boolean visible,
long frameDepth, boolean intersectsViewport, long frameDepth, boolean intersectsViewport,
@ChildProcessImportance int importance) { @ChildProcessImportance int importance) {
this.connection = connection; this.connection = connection;
this.foreground = foreground; this.visible = visible;
this.frameDepth = frameDepth; this.frameDepth = frameDepth;
this.intersectsViewport = intersectsViewport; this.intersectsViewport = intersectsViewport;
this.importance = importance; this.importance = importance;
...@@ -52,16 +52,16 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> { ...@@ -52,16 +52,16 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> {
assert o2 != null; assert o2 != null;
// Ranking order: // Ranking order:
// * foreground or ChildProcessImportance.IMPORTANT // * visible or ChildProcessImportance.IMPORTANT
// * ChildProcessImportance.MODERATE // * ChildProcessImportance.MODERATE
// * intersectsViewport // * intersectsViewport
// * frameDepth (lower value is higher rank) // * frameDepth (lower value is higher rank)
// Note boostForPendingViews is not used for ranking. // Note boostForPendingViews is not used for ranking.
boolean o1IsForeground = boolean o1IsForeground =
o1.foreground || o1.importance == ChildProcessImportance.IMPORTANT; o1.visible || o1.importance == ChildProcessImportance.IMPORTANT;
boolean o2IsForeground = boolean o2IsForeground =
o2.foreground || o2.importance == ChildProcessImportance.IMPORTANT; o2.visible || o2.importance == ChildProcessImportance.IMPORTANT;
if (o1IsForeground && !o2IsForeground) { if (o1IsForeground && !o2IsForeground) {
return -1; return -1;
...@@ -133,13 +133,13 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> { ...@@ -133,13 +133,13 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> {
return new ReverseRankIterator(); return new ReverseRankIterator();
} }
public void addConnection(ChildProcessConnection connection, boolean foreground, public void addConnection(ChildProcessConnection connection, boolean visible, long frameDepth,
long frameDepth, boolean intersectsViewport, @ChildProcessImportance int importance) { boolean intersectsViewport, @ChildProcessImportance int importance) {
assert connection != null; assert connection != null;
assert indexOf(connection) == -1; assert indexOf(connection) == -1;
assert mSize < mRankings.length; assert mSize < mRankings.length;
mRankings[mSize] = new ConnectionWithRank( mRankings[mSize] = new ConnectionWithRank(
connection, foreground, frameDepth, intersectsViewport, importance); connection, visible, frameDepth, intersectsViewport, importance);
mSize++; mSize++;
sort(); sort();
} }
...@@ -156,14 +156,14 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> { ...@@ -156,14 +156,14 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> {
mSize--; mSize--;
} }
public void updateConnection(ChildProcessConnection connection, boolean foreground, public void updateConnection(ChildProcessConnection connection, boolean visible,
long frameDepth, boolean intersectsViewport, @ChildProcessImportance int importance) { long frameDepth, boolean intersectsViewport, @ChildProcessImportance int importance) {
assert connection != null; assert connection != null;
assert mSize > 0; assert mSize > 0;
int i = indexOf(connection); int i = indexOf(connection);
assert i != -1; assert i != -1;
mRankings[i].foreground = foreground; mRankings[i].visible = visible;
mRankings[i].frameDepth = frameDepth; mRankings[i].frameDepth = frameDepth;
mRankings[i].intersectsViewport = intersectsViewport; mRankings[i].intersectsViewport = intersectsViewport;
mRankings[i].importance = importance; mRankings[i].importance = importance;
......
...@@ -15,10 +15,8 @@ namespace blink { ...@@ -15,10 +15,8 @@ namespace blink {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
// This matches Android's ChildProcessConnection state before OnProcessLaunched. // This matches Android's ChildProcessConnection state before OnProcessLaunched.
constexpr bool kLaunchingProcessIsBackgrounded = true; constexpr bool kLaunchingProcessIsBackgrounded = true;
constexpr bool kLaunchingProcessIsBoostedForPendingView = true;
#else #else
constexpr bool kLaunchingProcessIsBackgrounded = false; constexpr bool kLaunchingProcessIsBackgrounded = false;
constexpr bool kLaunchingProcessIsBoostedForPendingView = false;
#endif #endif
} // namespace blink } // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment