From 156a211b21fbaeb6391162a056390b9cd8748fae Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Fri, 3 Jun 2011 17:25:48 -0700 Subject: [PATCH] Cherrypick d1ed33c4 from hc-mr1. do not merge. Fix zombie threads in the Layoutlib. Some widgets can create (indirectly) HandlerThread which are started but never stopped. This patch use the delegate methods to override the thread run method to record which threads are started to be able to call quit() on them after a render. Note that we should really fix layoutlib_create to be able to call the default implementation from a delegate to remove code duplication. Change-Id: Iaf5432623e9704bb3114a8e0583c8553282c205e --- .../src/android/os/HandlerThread_Delegate.java | 80 ++++++++++++++++++++++ .../layoutlib/bridge/impl/RenderAction.java | 5 ++ .../android/tools/layoutlib/create/CreateInfo.java | 1 + 3 files changed, 86 insertions(+) create mode 100644 tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java diff --git a/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java new file mode 100644 index 000000000000..afbe97c06ebb --- /dev/null +++ b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import com.android.layoutlib.bridge.android.BridgeContext; +import com.android.layoutlib.bridge.impl.RenderAction; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Delegate overriding selected methods of android.os.HandlerThread + * + * Through the layoutlib_create tool, selected methods of Handler have been replaced + * by calls to methods of the same name in this delegate class. + * + * + */ +public class HandlerThread_Delegate { + + private static Map> sThreads = + new HashMap>(); + + public static void cleanUp(BridgeContext context) { + List list = sThreads.get(context); + if (list != null) { + for (HandlerThread thread : list) { + thread.quit(); + } + + list.clear(); + sThreads.remove(context); + } + } + + // -------- Delegate methods + + @LayoutlibDelegate + /*package*/ static void run(HandlerThread theThread) { + // record the thread so that it can be quit() on clean up. + BridgeContext context = RenderAction.getCurrentContext(); + List list = sThreads.get(context); + if (list == null) { + list = new ArrayList(); + sThreads.put(context, list); + } + + list.add(theThread); + + // ---- START DEFAULT IMPLEMENTATION. + + theThread.mTid = Process.myTid(); + Looper.prepare(); + synchronized (theThread) { + theThread.mLooper = Looper.myLooper(); + theThread.notifyAll(); + } + Process.setThreadPriority(theThread.mPriority); + theThread.onLooperPrepared(); + Looper.loop(); + theThread.mTid = -1; + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 8e80c2117115..6194f5d757cb 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -29,6 +29,7 @@ import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.resources.ResourceType; +import android.os.HandlerThread_Delegate; import android.util.DisplayMetrics; import java.util.concurrent.TimeUnit; @@ -228,6 +229,10 @@ public abstract class RenderAction extends FrameworkReso private void tearDown() { // Make sure to remove static references, otherwise we could not unload the lib mContext.disposeResources(); + + // quit HandlerThread created during this session. + HandlerThread_Delegate.cleanUp(sCurrentContext); + sCurrentContext = null; Bridge.setLog(null); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 708d8b51b3de..8602782c0c4f 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -98,6 +98,7 @@ public final class CreateInfo implements ICreateInfo { "android.content.res.Resources$Theme#resolveAttribute", "android.graphics.BitmapFactory#finishDecode", "android.os.Handler#sendMessageAtTime", + "android.os.HandlerThread#run", "android.os.Build#getString", "android.view.LayoutInflater#parseInclude", "android.view.View#isInEditMode", -- 2.11.0