Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc970ab6 authored by Diego Perez's avatar Diego Perez
Browse files

Implement VirtualRefBasePtr native methods

The VirtualRefBasePtr is used to track the usage of native objects from
the java side by reference counting. Implementing the class delegate to
make sure we dispose the objects correctly.

Change-Id: I3dd4717944b0dbe79f30e49b3083bf65c6e5276d
parent 9a99629e
Loading
Loading
Loading
Loading
+53 −0
Original line number Original line Diff line number Diff line
/*
 * 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);
        }
    }
}
+34 −18
Original line number Original line Diff line number Diff line
@@ -22,9 +22,11 @@ import com.android.layoutlib.bridge.util.SparseWeakArray;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.util.SparseArray;
import android.util.SparseArray;


import java.io.PrintStream;
import java.lang.ref.WeakReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;


/**
/**
 * Manages native delegates.
 * Manages native delegates.
@@ -73,14 +75,14 @@ import java.util.List;
public final class DelegateManager<T> {
public final class DelegateManager<T> {
    @SuppressWarnings("FieldCanBeLocal")
    @SuppressWarnings("FieldCanBeLocal")
    private final Class<T> mClass;
    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.
    /** 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
     * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
     * @see #addNewDelegate(Object)
     * @see #addNewDelegate(Object)
     * @see #removeJavaReferenceFor(long)
     * @see #removeJavaReferenceFor(long)
     */
     */
    private final List<T> mJavaReferences = new ArrayList<T>();
    private static final List<Object> sJavaReferences = new ArrayList<>();
    private int mDelegateCounter = 0;
    private static final AtomicLong sDelegateCounter = new AtomicLong(1);


    public DelegateManager(Class<T> theClass) {
    public DelegateManager(Class<T> theClass) {
        mClass = theClass;
        mClass = theClass;
@@ -97,9 +99,12 @@ public final class DelegateManager<T> {
     * @return the delegate or null if not found.
     * @return the delegate or null if not found.
     */
     */
    @Nullable
    @Nullable
    public synchronized T getDelegate(long native_object) {
    public T getDelegate(long native_object) {
        if (native_object > 0) {
        if (native_object > 0) {
            T delegate = mDelegates.get(native_object);
            Object delegate;
            synchronized (DelegateManager.class) {
                delegate = sDelegates.get(native_object);
            }


            if (Debug.DEBUG) {
            if (Debug.DEBUG) {
                if (delegate == null) {
                if (delegate == null) {
@@ -109,7 +114,8 @@ public final class DelegateManager<T> {
            }
            }


            assert delegate != null;
            assert delegate != null;
            return delegate;
            //noinspection unchecked
            return (T)delegate;
        }
        }
        return null;
        return null;
    }
    }
@@ -119,12 +125,13 @@ public final class DelegateManager<T> {
     * @param newDelegate the delegate to add
     * @param newDelegate the delegate to add
     * @return a unique native int to identify the delegate
     * @return a unique native int to identify the delegate
     */
     */
    public synchronized long addNewDelegate(T newDelegate) {
    public long addNewDelegate(T newDelegate) {
        long native_object = ++mDelegateCounter;
        long native_object = sDelegateCounter.getAndIncrement();

        synchronized (DelegateManager.class) {
        mDelegates.put(native_object, newDelegate);
            sDelegates.put(native_object, newDelegate);
        assert !mJavaReferences.contains(newDelegate);
            assert !sJavaReferences.contains(newDelegate);
        mJavaReferences.add(newDelegate);
            sJavaReferences.add(newDelegate);
        }


        if (Debug.DEBUG) {
        if (Debug.DEBUG) {
            System.out.println(
            System.out.println(
@@ -140,7 +147,8 @@ public final class DelegateManager<T> {
     * Removes the main reference on the given delegate.
     * Removes the main reference on the given delegate.
     * @param native_object the native integer representing the delegate.
     * @param native_object the native integer representing the delegate.
     */
     */
    public synchronized void removeJavaReferenceFor(long native_object) {
    public void removeJavaReferenceFor(long native_object) {
        synchronized (DelegateManager.class) {
            T delegate = getDelegate(native_object);
            T delegate = getDelegate(native_object);


            if (Debug.DEBUG) {
            if (Debug.DEBUG) {
@@ -148,6 +156,14 @@ public final class DelegateManager<T> {
                        " with int " + native_object);
                        " with int " + native_object);
            }
            }


        mJavaReferences.remove(delegate);
            sJavaReferences.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());
        }
    }
    }
}
}
+17 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.io.FolderWrapper;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.RenderAction;
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.ConfigGenerator;
import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
@@ -52,6 +53,7 @@ import android.util.DisplayMetrics;


import java.io.File;
import java.io.File;
import java.io.IOException;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.net.URL;
import java.util.Arrays;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
@@ -298,6 +300,16 @@ public class Main {
        renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
        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
    @AfterClass
    public static void tearDown() {
    public static void tearDown() {
        sLayoutLibLog = null;
        sLayoutLibLog = null;
@@ -305,6 +317,11 @@ public class Main {
        sProjectResources = null;
        sProjectResources = null;
        sLogger = null;
        sLogger = null;
        sBridge = null;
        sBridge = null;

        gc();

        System.out.println("Objects still linked from the DelegateManager:");
        DelegateManager.dump(System.out);
    }
    }


    /** Test expand_layout.xml */
    /** Test expand_layout.xml */
+1 −0
Original line number Original line Diff line number Diff line
@@ -302,6 +302,7 @@ public final class CreateInfo implements ICreateInfo {
        "android.text.StaticLayout",
        "android.text.StaticLayout",
        "android.util.PathParser",
        "android.util.PathParser",
        "android.view.Display",
        "android.view.Display",
        "com.android.internal.util.VirtualRefBasePtr",
        "com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
        "com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
        "libcore.icu.ICU",
        "libcore.icu.ICU",
    };
    };