1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.ref.ReferenceQueue; 18 import java.lang.ref.PhantomReference; 19 import java.util.ArrayList; 20 import java.util.concurrent.CountDownLatch; 21 22 public class Bitmap { 23 String mName; /* for debugging */ 24 int mWidth, mHeight; 25 Bitmap.NativeWrapper mNativeWrapper; 26 27 private static int sSerial = 100; 28 private static ArrayList sPhantomList = new ArrayList<PhantomWrapper>(); 29 private static ReferenceQueue<PhantomWrapper> sPhantomQueue = 30 new ReferenceQueue<PhantomWrapper>(); 31 private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue); 32 static { 33 sWatcher.setDaemon(true); sWatcher.start()34 sWatcher.start(); 35 }; 36 Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData)37 Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData) { 38 mName = name; 39 mWidth = width; 40 mHeight = height; 41 mNativeWrapper = nativeData; 42 43 System.out.println("Created " + this); 44 } 45 toString()46 public String toString() { 47 return "Bitmap " + mName + ": " + mWidth + "x" + mHeight + " (" + 48 mNativeWrapper.mNativeData + ")"; 49 } 50 drawAt(int x, int y)51 public void drawAt(int x, int y) { 52 System.out.println("Drawing " + this); 53 } 54 shutDown()55 public static void shutDown() { 56 sWatcher.shutDown(); 57 try { 58 sWatcher.join(); 59 } catch (InterruptedException ie) { 60 System.out.println("join intr"); 61 } 62 System.out.println("Bitmap has shut down"); 63 } 64 65 /* 66 * Pretend we're allocating native storage. Just returns a unique 67 * serial number. 68 */ allocNativeStorage(int width, int height)69 static Bitmap.NativeWrapper allocNativeStorage(int width, int height) { 70 int nativeData; 71 72 synchronized (Bitmap.class) { 73 nativeData = sSerial++; 74 } 75 76 Bitmap.NativeWrapper wrapper = new Bitmap.NativeWrapper(nativeData); 77 PhantomWrapper phan = new PhantomWrapper(wrapper, sPhantomQueue, 78 nativeData); 79 sPhantomList.add(phan); 80 wrapper.mPhantomWrapper = phan; 81 return wrapper; 82 } 83 freeNativeStorage(int nativeDataPtr, CountDownLatch freeSignal)84 static void freeNativeStorage(int nativeDataPtr, CountDownLatch freeSignal) { 85 System.out.println("freeNativeStorage: " + nativeDataPtr); 86 // Wake up the main thread that is [or will be] blocked until this native data is freed. 87 freeSignal.countDown(); 88 } 89 90 /* 91 * Wraps a native data pointer in an object. When this object is no 92 * longer referenced, we free the native data. 93 */ 94 static class NativeWrapper { NativeWrapper(int nativeDataPtr)95 public NativeWrapper(int nativeDataPtr) { 96 mNativeData = nativeDataPtr; 97 } 98 public int mNativeData; 99 100 // The PhantomWrapper corresponding to this NativeWrapper. 101 public PhantomWrapper mPhantomWrapper; 102 103 /* 104 @Override 105 protected void finalize() throws Throwable { 106 System.out.println("finalized " + mNativeData); 107 } 108 */ 109 } 110 } 111 112 /* 113 * Keep an eye on the native data. 114 * 115 * We keep a copy of the native data pointer value, and set the wrapper 116 * as our referent. We need the copy because you can't get the referred-to 117 * object back out of a PhantomReference. 118 */ 119 class PhantomWrapper extends PhantomReference { PhantomWrapper(Bitmap.NativeWrapper wrapper, ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr)120 PhantomWrapper(Bitmap.NativeWrapper wrapper, 121 ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr) 122 { 123 super(wrapper, queue); 124 mNativeData = nativeDataPtr; 125 } 126 127 public int mNativeData; 128 // This will be signaled once mNativeData has been freed. 129 public CountDownLatch mFreeSignal = new CountDownLatch(1); 130 } 131 132 /* 133 * Thread that watches for un-referenced bitmap data. 134 */ 135 class BitmapWatcher extends Thread { 136 ReferenceQueue<PhantomWrapper> mQueue; 137 BitmapWatcher(ReferenceQueue<PhantomWrapper> queue)138 BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) { 139 mQueue = queue; 140 setName("Bitmap Watcher"); 141 } 142 run()143 public void run() { 144 while (true) { 145 try { 146 PhantomWrapper ref = (PhantomWrapper) mQueue.remove(); 147 //System.out.println("dequeued ref " + ref.mNativeData + 148 // " - " + ref); 149 Bitmap.freeNativeStorage(ref.mNativeData, ref.mFreeSignal); 150 } catch (InterruptedException ie) { 151 System.out.println("intr"); 152 break; 153 } 154 } 155 } 156 shutDown()157 public void shutDown() { 158 interrupt(); 159 } 160 } 161