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