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 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.util.SparseArray; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.lang.ref.WeakReference; 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.ArrayList; 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.List; 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Manages native delegates. 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is used in conjunction with layoublib_create: certain Android java classes are mere 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * wrappers around a heavily native based implementation, and we need a way to run these classes 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * in our Eclipse rendering framework without bringing all the native code from the Android 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * platform. 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Thus we instruct layoutlib_create to modify the bytecode of these classes to replace their 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * native methods by "delegate calls". 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * For example, a native method android.graphics.Matrix.init(...) will actually become 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a call to android.graphics.Matrix_Delegate.init(...). 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The Android java classes that use native code uses an int (Java side) to reference native 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * objects. This int is generally directly the pointer to the C structure counterpart. 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Typically a creation method will return such an int, and then this int will be passed later 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * to a Java method to identify the C object to manipulate. 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Since we cannot use the Java object reference as the int directly, DelegateManager manages the 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * int -> Delegate class link. 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Native methods usually always have the int as parameters. The first thing the delegate method 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * will do is call {@link #getDelegate(int)} to get the Java object matching the int. 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Typical native init methods are returning a new int back to the Java class, so 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link #addNewDelegate(Object)} does the same. 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The JNI references are counted, so we do the same through a {@link WeakReference}. Because 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the Java object needs to count as a reference (even though it only holds an int), we use the 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * following mechanism: 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the delegate. 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * when nothing references it. This means that any class that holds a delegate (except for the 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Java main class) must not use the int but the Delegate class instead. The integers must 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * only be used in the API between the main Java class and the Delegate. 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param <T> the delegate class to manage 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic final class DelegateManager<T> { 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final Class<T> mClass; 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>(); 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** list used to store delegates when their main object holds a reference to them. 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @see #addNewDelegate(Object) 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @see #removeJavaReferenceFor(int) 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final List<T> mJavaReferences = new ArrayList<T>(); 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private int mDelegateCounter = 0; 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public DelegateManager(Class<T> theClass) { 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mClass = theClass; 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns the delegate from the given native int. 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p> 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If the int is zero, then this will always return null. 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p> 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * If the int is non zero and the delegate is not found, this will throw an assert. 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param native_object the native int. 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @return the delegate or null if not found. 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 9788a8364c386c694f7ad56662ef89713dbf7c9d63Narayan Kamath public T getDelegate(long native_object) { 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (native_object > 0) { 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski T delegate = mDelegates.get(native_object); 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (Debug.DEBUG) { 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (delegate == null) { 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println("Unknown " + mClass.getSimpleName() + " with int " + 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski native_object); 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski assert delegate != null; 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return delegate; 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Adds a delegate to the manager and returns the native int used to identify it. 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param newDelegate the delegate to add 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @return a unique native int to identify the delegate 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 11988a8364c386c694f7ad56662ef89713dbf7c9d63Narayan Kamath public long addNewDelegate(T newDelegate) { 12088a8364c386c694f7ad56662ef89713dbf7c9d63Narayan Kamath long native_object = ++mDelegateCounter; 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mDelegates.put(native_object, newDelegate); 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski assert !mJavaReferences.contains(newDelegate); 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mJavaReferences.add(newDelegate); 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (Debug.DEBUG) { 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println("New " + mClass.getSimpleName() + " with int " + native_object); 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return native_object; 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Removes the main reference on the given delegate. 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param native_object the native integer representing the delegate. 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 13688a8364c386c694f7ad56662ef89713dbf7c9d63Narayan Kamath public void removeJavaReferenceFor(long native_object) { 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski T delegate = getDelegate(native_object); 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (Debug.DEBUG) { 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println("Removing main Java ref on " + mClass.getSimpleName() + 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski " with int " + native_object); 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mJavaReferences.remove(delegate); 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 147