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 
21 public class Bitmap {
22     String mName;           /* for debugging */
23     int mWidth, mHeight;
24     Bitmap.NativeWrapper mNativeWrapper;
25 
26     private static int sSerial = 100;
27     private static ArrayList sPhantomList = new ArrayList<PhantomWrapper>();
28     private static ReferenceQueue<PhantomWrapper> sPhantomQueue =
29             new ReferenceQueue<PhantomWrapper>();
30     private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue);
31     static {
32         sWatcher.setDaemon(true);
sWatcher.start()33         sWatcher.start();
34     };
35 
Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData)36     Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData) {
37         mName = name;
38         mWidth = width;
39         mHeight = height;
40         mNativeWrapper = nativeData;
41 
42         System.out.println("Created " + this);
43     }
44 
toString()45     public String toString() {
46         return "Bitmap " + mName + ": " + mWidth + "x" + mHeight + " (" +
47                 mNativeWrapper.mNativeData + ")";
48     }
49 
drawAt(int x, int y)50     public void drawAt(int x, int y) {
51         System.out.println("Drawing " + this);
52     }
53 
shutDown()54     public static void shutDown() {
55         sWatcher.shutDown();
56         try {
57             sWatcher.join();
58         } catch (InterruptedException ie) {
59             System.out.println("join intr");
60         }
61         System.out.println("Bitmap has shut down");
62     }
63 
64     /*
65      * Pretend we're allocating native storage.  Just returns a unique
66      * serial number.
67      */
allocNativeStorage(int width, int height)68     static Bitmap.NativeWrapper allocNativeStorage(int width, int height) {
69         int nativeData;
70 
71         synchronized (Bitmap.class) {
72             nativeData = sSerial++;
73         }
74 
75         Bitmap.NativeWrapper wrapper = new Bitmap.NativeWrapper(nativeData);
76         PhantomWrapper phan = new PhantomWrapper(wrapper, sPhantomQueue,
77                 nativeData);
78         sPhantomList.add(phan);
79         return wrapper;
80     }
81 
freeNativeStorage(int nativeDataPtr)82     static void freeNativeStorage(int nativeDataPtr) {
83         System.out.println("freeNativeStorage: " + nativeDataPtr);
84     }
85 
86     /*
87      * Wraps a native data pointer in an object.  When this object is no
88      * longer referenced, we free the native data.
89      */
90     static class NativeWrapper {
NativeWrapper(int nativeDataPtr)91         public NativeWrapper(int nativeDataPtr) {
92             mNativeData = nativeDataPtr;
93         }
94         public int mNativeData;
95 
96         /*
97         @Override
98         protected void finalize() throws Throwable {
99             System.out.println("finalized " + mNativeData);
100         }
101         */
102     }
103 }
104 
105 /*
106  * Keep an eye on the native data.
107  *
108  * We keep a copy of the native data pointer value, and set the wrapper
109  * as our referent.  We need the copy because you can't get the referred-to
110  * object back out of a PhantomReference.
111  */
112 class PhantomWrapper extends PhantomReference {
PhantomWrapper(Bitmap.NativeWrapper wrapper, ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr)113     PhantomWrapper(Bitmap.NativeWrapper wrapper,
114         ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr)
115     {
116         super(wrapper, queue);
117         mNativeData = nativeDataPtr;
118     }
119 
120     public int mNativeData;
121 }
122 
123 /*
124  * Thread that watches for un-referenced bitmap data.
125  */
126 class BitmapWatcher extends Thread {
127     ReferenceQueue<PhantomWrapper> mQueue;
128     volatile boolean mQuit = false;
129 
BitmapWatcher(ReferenceQueue<PhantomWrapper> queue)130     BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) {
131         mQueue = queue;
132         setName("Bitmap Watcher");
133     }
134 
run()135     public void run() {
136         while (!mQuit) {
137             try {
138                 PhantomWrapper ref = (PhantomWrapper) mQueue.remove();
139                 //System.out.println("dequeued ref " + ref.mNativeData +
140                 //    " - " + ref);
141                 Bitmap.freeNativeStorage(ref.mNativeData);
142                 //ref.clear();
143             } catch (InterruptedException ie) {
144                 System.out.println("intr");
145             }
146         }
147     }
148 
shutDown()149     public void shutDown() {
150         mQuit = true;
151         interrupt();
152     }
153 }
154