1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.layoutlib.bridge.impl; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.util.Debug; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.util.SparseWeakArray; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 22476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.util.SparseArray; 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 25fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perezimport java.io.PrintStream; 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.lang.ref.WeakReference; 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.ArrayList; 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.List; 29fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perezimport java.util.concurrent.atomic.AtomicLong; 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Manages native delegates. 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is used in conjunction with layoublib_create: certain Android java classes are mere 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * wrappers around a heavily native based implementation, and we need a way to run these classes 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * in our Eclipse rendering framework without bringing all the native code from the Android 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * platform. 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Thus we instruct layoutlib_create to modify the bytecode of these classes to replace their 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * native methods by "delegate calls". 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * For example, a native method android.graphics.Matrix.init(...) will actually become 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a call to android.graphics.Matrix_Delegate.init(...). 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The Android java classes that use native code uses an int (Java side) to reference native 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * objects. This int is generally directly the pointer to the C structure counterpart. 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Typically a creation method will return such an int, and then this int will be passed later 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * to a Java method to identify the C object to manipulate. 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Since we cannot use the Java object reference as the int directly, DelegateManager manages the 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * int -> Delegate class link. 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Native methods usually always have the int as parameters. The first thing the delegate method 54d77b9ed7dcc42efca33b225c4594a30aab9e709cDeepanshu Gupta * will do is call {@link #getDelegate(long)} to get the Java object matching the int. 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Typical native init methods are returning a new int back to the Java class, so 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link #addNewDelegate(Object)} does the same. 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The JNI references are counted, so we do the same through a {@link WeakReference}. Because 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the Java object needs to count as a reference (even though it only holds an int), we use the 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * following mechanism: 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 63d77b9ed7dcc42efca33b225c4594a30aab9e709cDeepanshu Gupta * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(long)} adds and removes 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the delegate. 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * when nothing references it. This means that any class that holds a delegate (except for the 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Java main class) must not use the int but the Delegate class instead. The integers must 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * only be used in the API between the main Java class and the Delegate. 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param <T> the delegate class to manage 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic final class DelegateManager<T> { 76d77b9ed7dcc42efca33b225c4594a30aab9e709cDeepanshu Gupta @SuppressWarnings("FieldCanBeLocal") 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final Class<T> mClass; 78fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez private static final SparseWeakArray<Object> sDelegates = new SparseWeakArray<>(); 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** list used to store delegates when their main object holds a reference to them. 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @see #addNewDelegate(Object) 82d77b9ed7dcc42efca33b225c4594a30aab9e709cDeepanshu Gupta * @see #removeJavaReferenceFor(long) 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 84fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez private static final List<Object> sJavaReferences = new ArrayList<>(); 85fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez private static final AtomicLong sDelegateCounter = new AtomicLong(1); 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public DelegateManager(Class<T> theClass) { 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mClass = theClass; 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns the delegate from the given native int. 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p> 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If the int is zero, then this will always return null. 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p> 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If the int is non zero and the delegate is not found, this will throw an assert. 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param native_object the native int. 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @return the delegate or null if not found. 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 101d77b9ed7dcc42efca33b225c4594a30aab9e709cDeepanshu Gupta @Nullable 102fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez public T getDelegate(long native_object) { 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (native_object > 0) { 104fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez Object delegate; 105fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez synchronized (DelegateManager.class) { 106fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez delegate = sDelegates.get(native_object); 107fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez } 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (Debug.DEBUG) { 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (delegate == null) { 111511e48728a4b8f8736fcb2ea28dd1ab7cc699972Diego Perez System.err.println("Unknown " + mClass.getSimpleName() + " with int " + 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski native_object); 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski assert delegate != null; 117fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez //noinspection unchecked 118fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez return (T)delegate; 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Adds a delegate to the manager and returns the native int used to identify it. 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param newDelegate the delegate to add 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @return a unique native int to identify the delegate 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 128fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez public long addNewDelegate(T newDelegate) { 129fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez long native_object = sDelegateCounter.getAndIncrement(); 130fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez synchronized (DelegateManager.class) { 131fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez sDelegates.put(native_object, newDelegate); 132fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez assert !sJavaReferences.contains(newDelegate); 133fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez sJavaReferences.add(newDelegate); 134fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez } 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (Debug.DEBUG) { 137511e48728a4b8f8736fcb2ea28dd1ab7cc699972Diego Perez System.out.println( 138511e48728a4b8f8736fcb2ea28dd1ab7cc699972Diego Perez "New " + mClass.getSimpleName() + " " + 139511e48728a4b8f8736fcb2ea28dd1ab7cc699972Diego Perez "with int " + 140511e48728a4b8f8736fcb2ea28dd1ab7cc699972Diego Perez native_object); 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return native_object; 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Removes the main reference on the given delegate. 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param native_object the native integer representing the delegate. 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 150fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez public void removeJavaReferenceFor(long native_object) { 151fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez synchronized (DelegateManager.class) { 152fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez T delegate = getDelegate(native_object); 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 154fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez if (Debug.DEBUG) { 155fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez System.out.println("Removing main Java ref on " + mClass.getSimpleName() + 156fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez " with int " + native_object); 157fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez } 158fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez 159fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez sJavaReferences.remove(delegate); 160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 161fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez } 162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 163fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez public synchronized static void dump(PrintStream out) { 164fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez for (Object reference : sJavaReferences) { 165fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez int idx = sDelegates.indexOfValue(reference); 166fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez out.printf("[%d] %s\n", sDelegates.keyAt(idx), reference.getClass().getSimpleName()); 167fc970ab65ad8c860dd0654d59b70bbe271f95784Diego Perez } 168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 170