diff options
author | Romain Guy <romainguy@google.com> | 2012-04-23 18:22:09 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2012-04-23 20:29:31 -0700 |
commit | ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47 (patch) | |
tree | 04f9b4d5589333970c91e51af6280a5859b78460 | |
parent | 88fffb7a34313d5e94b3974d444d07bd6a4879a4 (diff) | |
download | frameworks_base-ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47.zip frameworks_base-ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47.tar.gz frameworks_base-ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47.tar.bz2 |
Prevent WebView from crashing when detached from the window
Bug #6365056
WebView enqueues a functor in the hardware renderer to handle
animations and this functor is called at a later time by the
hardware renderer. However, the functor was not removed from
the queue when WebView was removed from the window. This could
cause the hardware renderer to attempt to execute an invalid
functor and lead to a crash.
Change-Id: I9d38e80f3fdc5e29d4d0cdfa1e893c251a954508
-rw-r--r-- | core/java/android/os/Handler.java | 16 | ||||
-rw-r--r-- | core/java/android/os/MessageQueue.java | 17 | ||||
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 14 | ||||
-rw-r--r-- | core/java/android/view/HardwareCanvas.java | 22 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 45 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 17 | ||||
-rw-r--r-- | core/java/android/webkit/WebViewClassic.java | 9 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 22 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 52 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 5 |
10 files changed, 183 insertions, 36 deletions
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 610b355..0d562e4 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -550,6 +550,16 @@ public class Handler { return mQueue.hasMessages(this, what, object); } + /** + * Check if there are any pending posts of messages with callback r in + * the message queue. + * + * @hide + */ + public final boolean hasCallbacks(Runnable r) { + return mQueue.hasMessages(this, r, null); + } + // if we can get rid of this method, the handler need not remember its loop // we could instead export a getMessageQueue() method... public final Looper getLooper() { @@ -588,20 +598,20 @@ public class Handler { } } - private final Message getPostMessage(Runnable r) { + private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } - private final Message getPostMessage(Runnable r, Object token) { + private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; } - private final void handleCallback(Message message) { + private static void handleCallback(Message message) { message.callback.run(); } diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index 64027ef..5ad60ec 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -347,6 +347,23 @@ public class MessageQueue { } } + final boolean hasMessages(Handler h, Runnable r, Object object) { + if (h == null) { + return false; + } + + synchronized (this) { + Message p = mMessages; + while (p != null) { + if (p.target == h && p.callback == r && (object == null || p.obj == object)) { + return true; + } + p = p.next; + } + return false; + } + } + final void removeMessages(Handler h, int what, Object object) { if (h == null) { return; diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 7736f57..0bb5f9f 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -266,6 +266,20 @@ class GLES20Canvas extends HardwareCanvas { private static native int nInvokeFunctors(int renderer, Rect dirty); + @Override + public void detachFunctor(int functor) { + nDetachFunctor(mRenderer, functor); + } + + private static native void nDetachFunctor(int renderer, int functor); + + @Override + public void attachFunctor(int functor) { + nAttachFunctor(mRenderer, functor); + } + + private static native void nAttachFunctor(int renderer, int functor); + /////////////////////////////////////////////////////////////////////////// // Memory /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 2f4cd36..ee2dd59 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -107,4 +107,26 @@ public abstract class HardwareCanvas extends Canvas { public int invokeFunctors(Rect dirty) { return DisplayList.STATUS_DONE; } + + /** + * Detaches the specified functor from the current functor execution queue. + * + * @param functor The native functor to remove from the execution queue. + * + * @see #invokeFunctors(android.graphics.Rect) + * @see #callDrawGLFunction(int) + * @see #detachFunctor(int) + */ + abstract void detachFunctor(int functor); + + /** + * Attaches the specified functor to the current functor execution queue. + * + * @param functor The native functor to add to the execution queue. + * + * @see #invokeFunctors(android.graphics.Rect) + * @see #callDrawGLFunction(int) + * @see #detachFunctor(int) + */ + abstract void attachFunctor(int functor); } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 1ec754a..b9295c3 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -437,6 +437,27 @@ public abstract class HardwareRenderer { abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture); /** + * Detaches the specified functor from the current functor execution queue. + * + * @param functor The native functor to remove from the execution queue. + * + * @see HardwareCanvas#callDrawGLFunction(int) + * @see #attachFunctor(android.view.View.AttachInfo, int) + */ + abstract void detachFunctor(int functor); + + /** + * Schedules the specified functor in the functors execution queue. + * + * @param attachInfo AttachInfo tied to this renderer. + * @param functor The native functor to insert in the execution queue. + * + * @see HardwareCanvas#callDrawGLFunction(int) + * @see #detachFunctor(int) + */ + abstract void attachFunctor(View.AttachInfo attachInfo, int functor); + + /** * Initializes the hardware renderer for the specified surface and setup the * renderer for drawing, if needed. This is invoked when the ViewAncestor has * potentially lost the hardware renderer. The hardware renderer should be @@ -1202,13 +1223,33 @@ public abstract class HardwareRenderer { } if ((status & DisplayList.STATUS_INVOKE) != 0) { - attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); - mFunctorsRunnable.attachInfo = attachInfo; + scheduleFunctors(attachInfo); + } + } + + private void scheduleFunctors(View.AttachInfo attachInfo) { + mFunctorsRunnable.attachInfo = attachInfo; + if (!attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) { // delay the functor callback by a few ms so it isn't polled constantly attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY); } } + @Override + void detachFunctor(int functor) { + if (mCanvas != null) { + mCanvas.detachFunctor(functor); + } + } + + @Override + void attachFunctor(View.AttachInfo attachInfo, int functor) { + if (mCanvas != null) { + mCanvas.attachFunctor(functor); + scheduleFunctors(attachInfo); + } + } + /** * Ensures the current EGL context is the one we expect. * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e3681df..59f0917 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -59,7 +59,6 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.TypedValue; -import android.view.KeyCharacterMap.FallbackAction; import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; @@ -669,6 +668,18 @@ public final class ViewRootImpl implements ViewParent, } } + public void attachFunctor(int functor) { + if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor); + } + } + + public void detachFunctor(int functor) { + if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.detachFunctor(functor); + } + } + private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) { mAttachInfo.mHardwareAccelerated = false; mAttachInfo.mHardwareAccelerationRequested = false; @@ -4489,8 +4500,8 @@ public final class ViewRootImpl implements ViewParent, mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); } else { - View newSource = getCommonPredecessor(oldSource, source); - mSendWindowContentChangedAccessibilityEvent.mSource = newSource; + mSendWindowContentChangedAccessibilityEvent.mSource = + getCommonPredecessor(oldSource, source); } } diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 3bd9960..1aa0a52 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -2469,7 +2469,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc /** * Loads the view data from the input stream. See - * {@link #saveViewState(OutputStream)} for more information. + * {@link #saveViewState(java.io.OutputStream, ValueCallback)} for more information. * @param stream The {@link InputStream} to load from */ public void loadViewState(InputStream stream) { @@ -5630,6 +5630,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc removeAccessibilityApisFromJavaScript(); updateHwAccelerated(); + + if (mWebView.isHardwareAccelerated()) { + int drawGLFunction = nativeGetDrawGLFunction(mNativeClass); + if (drawGLFunction != 0) { + mWebView.getViewRootImpl().detachFunctor(drawGLFunction); + } + } } @Override diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index d4d60d3..60929ac 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -158,11 +158,21 @@ static jint android_view_GLES20Canvas_getStencilSize(JNIEnv* env, jobject clazz) // ---------------------------------------------------------------------------- static jint android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz, - OpenGLRenderer* renderer, Functor *functor) { + OpenGLRenderer* renderer, Functor* functor) { android::uirenderer::Rect dirty; return renderer->callDrawGLFunction(functor, dirty); } +static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env, + jobject clazz, OpenGLRenderer* renderer, Functor* functor) { + renderer->detachFunctor(functor); +} + +static void android_view_GLES20Canvas_attachFunctor(JNIEnv* env, + jobject clazz, OpenGLRenderer* renderer, Functor* functor) { + renderer->attachFunctor(functor); +} + static jint android_view_GLES20Canvas_invokeFunctors(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, jobject dirty) { android::uirenderer::Rect bounds; @@ -825,9 +835,9 @@ static JNINativeMethod gMethods[] = { { "nIsAvailable", "()Z", (void*) android_view_GLES20Canvas_isAvailable }, #ifdef USE_OPENGL_RENDERER - { "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches }, - { "nInitCaches", "()V", (void*) android_view_GLES20Canvas_initCaches }, - { "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches }, + { "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches }, + { "nInitCaches", "()V", (void*) android_view_GLES20Canvas_initCaches }, + { "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches }, { "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer }, { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer }, @@ -839,7 +849,9 @@ static JNINativeMethod gMethods[] = { { "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize }, { "nCallDrawGLFunction", "(II)I", (void*) android_view_GLES20Canvas_callDrawGLFunction }, - { "nInvokeFunctors", "(ILandroid/graphics/Rect;)I", + { "nDetachFunctor", "(II)V", (void*) android_view_GLES20Canvas_detachFunctor }, + { "nAttachFunctor", "(II)V", (void*) android_view_GLES20Canvas_attachFunctor }, + { "nInvokeFunctors", "(ILandroid/graphics/Rect;)I", (void*) android_view_GLES20Canvas_invokeFunctors }, { "nSave", "(II)I", (void*) android_view_GLES20Canvas_save }, diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 5edaa46..9f337ff 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -237,33 +237,43 @@ void OpenGLRenderer::resume() { glBlendEquation(GL_FUNC_ADD); } +void OpenGLRenderer::detachFunctor(Functor* functor) { + mFunctors.remove(functor); +} + +void OpenGLRenderer::attachFunctor(Functor* functor) { + mFunctors.add(functor); +} + status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { status_t result = DrawGlInfo::kStatusDone; + size_t count = functors.size(); - Vector<Functor*> functors(mFunctors); - mFunctors.clear(); + if (count > 0) { + SortedVector<Functor*> functors(mFunctors); + mFunctors.clear(); - DrawGlInfo info; - info.clipLeft = 0; - info.clipTop = 0; - info.clipRight = 0; - info.clipBottom = 0; - info.isLayer = false; - info.width = 0; - info.height = 0; - memset(info.transform, 0, sizeof(float) * 16); + DrawGlInfo info; + info.clipLeft = 0; + info.clipTop = 0; + info.clipRight = 0; + info.clipBottom = 0; + info.isLayer = false; + info.width = 0; + info.height = 0; + memset(info.transform, 0, sizeof(float) * 16); - size_t count = functors.size(); - for (size_t i = 0; i < count; i++) { - Functor* f = functors.itemAt(i); - result |= (*f)(DrawGlInfo::kModeProcess, &info); + for (size_t i = 0; i < count; i++) { + Functor* f = functors.itemAt(i); + result |= (*f)(DrawGlInfo::kModeProcess, &info); - if (result != DrawGlInfo::kStatusDone) { - Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom); - dirty.unionWith(localDirty); + if (result != DrawGlInfo::kStatusDone) { + Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom); + dirty.unionWith(localDirty); - if (result & DrawGlInfo::kStatusInvoke) { - mFunctors.push(f); + if (result & DrawGlInfo::kStatusInvoke) { + mFunctors.add(f); + } } } } @@ -305,7 +315,7 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { dirty.unionWith(localDirty); if (result & DrawGlInfo::kStatusInvoke) { - mFunctors.push(functor); + mFunctors.add(functor); } } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 141e22b..18a6923 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -29,6 +29,7 @@ #include <utils/Functor.h> #include <utils/RefBase.h> +#include <utils/SortedVector.h> #include <utils/Vector.h> #include <cutils/compiler.h> @@ -73,6 +74,8 @@ public: virtual void resume(); ANDROID_API status_t invokeFunctors(Rect& dirty); + ANDROID_API void detachFunctor(Functor* functor); + ANDROID_API void attachFunctor(Functor* functor); virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty); ANDROID_API int getSaveCount() const; @@ -612,7 +615,7 @@ private: // List of rectangles to clear after saveLayer() is invoked Vector<Rect*> mLayers; // List of functors to invoke after a frame is drawn - Vector<Functor*> mFunctors; + SortedVector<Functor*> mFunctors; // Indentity matrix const mat4 mIdentity; |