diff options
4 files changed, 105 insertions, 18 deletions
diff --git a/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java new file mode 100644 index 000000000000..01fe45d2644c --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 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 com.android.internal.util; + +import com.android.layoutlib.bridge.impl.DelegateManager; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import android.util.LongSparseLongArray; + +/** + * Delegate used to provide new implementation the native methods of {@link VirtualRefBasePtr} + * + * Through the layoutlib_create tool, the original native methods of VirtualRefBasePtr have been + * replaced by calls to methods of the same name in this delegate class. + * + */ +@SuppressWarnings("unused") +public class VirtualRefBasePtr_Delegate { + private static final DelegateManager<Object> sManager = new DelegateManager<>(Object.class); + private static final LongSparseLongArray sRefCount = new LongSparseLongArray(); + + @LayoutlibDelegate + /*package*/ static synchronized void nIncStrong(long ptr) { + long counter = sRefCount.get(ptr); + sRefCount.put(ptr, ++counter); + } + + @LayoutlibDelegate + /*package*/ static synchronized void nDecStrong(long ptr) { + long counter = sRefCount.get(ptr); + + if (counter > 1) { + sRefCount.put(ptr, --counter); + } else { + sRefCount.delete(ptr); + sManager.removeJavaReferenceFor(ptr); + } + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java index baf2e2e11564..c59b1a66bb02 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java @@ -22,9 +22,11 @@ import com.android.layoutlib.bridge.util.SparseWeakArray; import android.annotation.Nullable; import android.util.SparseArray; +import java.io.PrintStream; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; /** * Manages native delegates. @@ -73,14 +75,14 @@ import java.util.List; public final class DelegateManager<T> { @SuppressWarnings("FieldCanBeLocal") private final Class<T> mClass; - private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>(); + private static final SparseWeakArray<Object> sDelegates = new SparseWeakArray<>(); /** list used to store delegates when their main object holds a reference to them. * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed * @see #addNewDelegate(Object) * @see #removeJavaReferenceFor(long) */ - private final List<T> mJavaReferences = new ArrayList<T>(); - private int mDelegateCounter = 0; + private static final List<Object> sJavaReferences = new ArrayList<>(); + private static final AtomicLong sDelegateCounter = new AtomicLong(1); public DelegateManager(Class<T> theClass) { mClass = theClass; @@ -97,9 +99,12 @@ public final class DelegateManager<T> { * @return the delegate or null if not found. */ @Nullable - public synchronized T getDelegate(long native_object) { + public T getDelegate(long native_object) { if (native_object > 0) { - T delegate = mDelegates.get(native_object); + Object delegate; + synchronized (DelegateManager.class) { + delegate = sDelegates.get(native_object); + } if (Debug.DEBUG) { if (delegate == null) { @@ -109,7 +114,8 @@ public final class DelegateManager<T> { } assert delegate != null; - return delegate; + //noinspection unchecked + return (T)delegate; } return null; } @@ -119,12 +125,13 @@ public final class DelegateManager<T> { * @param newDelegate the delegate to add * @return a unique native int to identify the delegate */ - public synchronized long addNewDelegate(T newDelegate) { - long native_object = ++mDelegateCounter; - - mDelegates.put(native_object, newDelegate); - assert !mJavaReferences.contains(newDelegate); - mJavaReferences.add(newDelegate); + public long addNewDelegate(T newDelegate) { + long native_object = sDelegateCounter.getAndIncrement(); + synchronized (DelegateManager.class) { + sDelegates.put(native_object, newDelegate); + assert !sJavaReferences.contains(newDelegate); + sJavaReferences.add(newDelegate); + } if (Debug.DEBUG) { System.out.println( @@ -140,14 +147,23 @@ public final class DelegateManager<T> { * Removes the main reference on the given delegate. * @param native_object the native integer representing the delegate. */ - public synchronized void removeJavaReferenceFor(long native_object) { - T delegate = getDelegate(native_object); + public void removeJavaReferenceFor(long native_object) { + synchronized (DelegateManager.class) { + T delegate = getDelegate(native_object); - if (Debug.DEBUG) { - System.out.println("Removing main Java ref on " + mClass.getSimpleName() + - " with int " + native_object); + if (Debug.DEBUG) { + System.out.println("Removing main Java ref on " + mClass.getSimpleName() + + " with int " + native_object); + } + + sJavaReferences.remove(delegate); } + } - mJavaReferences.remove(delegate); + public synchronized static void dump(PrintStream out) { + for (Object reference : sJavaReferences) { + int idx = sDelegates.indexOfValue(reference); + out.printf("[%d] %s\n", sDelegates.keyAt(idx), reference.getClass().getSimpleName()); + } } } diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index a5561fab953c..09dd5f078b9a 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -31,6 +31,7 @@ import com.android.io.FolderWrapper; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.impl.RenderAction; +import com.android.layoutlib.bridge.impl.DelegateManager; import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback; import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; @@ -52,6 +53,7 @@ import android.util.DisplayMetrics; import java.io.File; import java.io.IOException; +import java.lang.ref.WeakReference; import java.net.URL; import java.util.Arrays; import java.util.concurrent.TimeUnit; @@ -298,6 +300,16 @@ public class Main { renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012); } + private static void gc() { + // See RuntimeUtil#gc in jlibs (http://jlibs.in/) + Object obj = new Object(); + WeakReference ref = new WeakReference<Object>(obj); + obj = null; + while(ref.get() != null) { + System.gc(); + } + } + @AfterClass public static void tearDown() { sLayoutLibLog = null; @@ -305,6 +317,11 @@ public class Main { sProjectResources = null; sLogger = null; sBridge = null; + + gc(); + + System.out.println("Objects still linked from the DelegateManager:"); + DelegateManager.dump(System.out); } /** Test expand_layout.xml */ 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 1a00cc942c42..483bddc21859 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 @@ -302,6 +302,7 @@ public final class CreateInfo implements ICreateInfo { "android.text.StaticLayout", "android.util.PathParser", "android.view.Display", + "com.android.internal.util.VirtualRefBasePtr", "com.android.internal.view.animation.NativeInterpolatorFactoryHelper", "libcore.icu.ICU", }; |