Android SurfaceViewRenderer: Fix deadlock
Deadlock caused by two methods grabbing two locks in the opposite order:
renderFrame():
handlerLock
layoutLock
onMeasure():
layoutLock
handlerLock
This CL removs the nested locking to fix the deadlock and make it less
error prone for the future.
BUG=webrtc:6003
R=sakal@webrtc.org
Review URL: https://codereview.webrtc.org/2111933002 .
Cr-Original-Commit-Position: refs/heads/master@{#13364}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 897d932e0b0b81b81393316692d8687e5975a62a
diff --git a/api/android/java/src/org/webrtc/SurfaceViewRenderer.java b/api/android/java/src/org/webrtc/SurfaceViewRenderer.java
index c37d247..4b79fe4 100644
--- a/api/android/java/src/org/webrtc/SurfaceViewRenderer.java
+++ b/api/android/java/src/org/webrtc/SurfaceViewRenderer.java
@@ -295,7 +295,6 @@
VideoRenderer.renderFrameDone(pendingFrame);
}
pendingFrame = frame;
- updateFrameDimensionsAndReportEvents(frame);
renderThreadHandler.post(renderFrameRunnable);
}
}
@@ -321,23 +320,26 @@
// View layout interface.
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
+ final boolean isNewSize;
synchronized (layoutLock) {
if (frameWidth == 0 || frameHeight == 0) {
super.onMeasure(widthSpec, heightSpec);
return;
}
desiredLayoutSize = getDesiredLayoutSize(widthSpec, heightSpec);
- if (desiredLayoutSize.x != getMeasuredWidth() || desiredLayoutSize.y != getMeasuredHeight()) {
- // Clear the surface asap before the layout change to avoid stretched video and other
- // render artifacs. Don't wait for it to finish because the IO thread should never be
- // blocked, so it's a best-effort attempt.
- synchronized (handlerLock) {
- if (renderThreadHandler != null) {
- renderThreadHandler.postAtFrontOfQueue(makeBlackRunnable);
- }
+ isNewSize = (desiredLayoutSize.x != getMeasuredWidth()
+ || desiredLayoutSize.y != getMeasuredHeight());
+ setMeasuredDimension(desiredLayoutSize.x, desiredLayoutSize.y);
+ }
+ if (isNewSize) {
+ // Clear the surface asap before the layout change to avoid stretched video and other
+ // render artifacs. Don't wait for it to finish because the IO thread should never be
+ // blocked, so it's a best-effort attempt.
+ synchronized (handlerLock) {
+ if (renderThreadHandler != null) {
+ renderThreadHandler.postAtFrontOfQueue(makeBlackRunnable);
}
}
- setMeasuredDimension(desiredLayoutSize.x, desiredLayoutSize.y);
}
}
@@ -446,6 +448,7 @@
frame = pendingFrame;
pendingFrame = null;
}
+ updateFrameDimensionsAndReportEvents(frame);
if (eglBase == null || !eglBase.hasSurface()) {
Logging.d(TAG, getResourceName() + "No surface to draw on");
VideoRenderer.renderFrameDone(frame);