EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.content.common]

COVERAGE SUMMARY FOR SOURCE FILE [CleanupReference.java]

nameclass, %method, %block, %line, %
CleanupReference.java100% (3/3)100% (14/14)84%  (152/181)91%  (44.4/49)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class CleanupReference$1100% (1/1)100% (2/2)67%  (24/36)66%  (5.9/9)
run (): void 100% (1/1)62%  (20/32)61%  (4.9/8)
CleanupReference$1 (String): void 100% (1/1)100% (4/4)100% (1/1)
     
class CleanupReference$2100% (1/1)100% (2/2)70%  (40/57)91%  (14.5/16)
handleMessage (Message): void 100% (1/1)68%  (36/53)90%  (13.5/15)
CleanupReference$2 (Looper): void 100% (1/1)100% (4/4)100% (1/1)
     
class CleanupReference100% (1/1)100% (10/10)100% (88/88)100% (26/26)
<static initializer> 100% (1/1)100% (28/28)100% (7/7)
CleanupReference (Object, Runnable): void 100% (1/1)100% (11/11)100% (4/4)
access$000 (): ReferenceQueue 100% (1/1)100% (2/2)100% (1/1)
access$100 (): Object 100% (1/1)100% (2/2)100% (1/1)
access$200 (): Handler 100% (1/1)100% (2/2)100% (1/1)
access$300 (): Set 100% (1/1)100% (2/2)100% (1/1)
access$400 (CleanupReference): void 100% (1/1)100% (3/3)100% (1/1)
cleanupNow (): void 100% (1/1)100% (4/4)100% (2/2)
handleOnUiThread (int): void 100% (1/1)100% (18/18)100% (6/6)
runCleanupTaskInternal (): void 100% (1/1)100% (16/16)100% (6/6)

1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4 
5package org.chromium.content.common;
6 
7import android.os.Handler;
8import android.os.Looper;
9import android.os.Message;
10import android.util.Log;
11 
12import java.lang.ref.ReferenceQueue;
13import java.lang.ref.WeakReference;
14import java.util.HashSet;
15import java.util.Set;
16 
17/**
18 * Handles running cleanup tasks when an object becomes eligible for GC. Cleanup tasks
19 * are always executed on the main thread. In general, classes should not have
20 * finalizers and likewise should not use this class for the same reasons. The
21 * exception is where public APIs exist that require native side resources to be
22 * cleaned up in response to java side GC of API objects. (Private/internal
23 * interfaces should always favor explicit resource releases / destroy()
24 * protocol for this rather than depend on GC to trigger native cleanup).
25 * NOTE this uses WeakReference rather than PhantomReference, to avoid delaying the
26 * cleanup processing until after finalizers (if any) have run. In general usage of
27 * this class indicates the client does NOT use finalizers anyway (Good), so this should
28 * not be a visible difference in practice.
29 */
30public class CleanupReference extends WeakReference<Object> {
31    private static final String TAG = "CleanupReference";
32 
33    private static final boolean DEBUG = false;  // Always check in as false!
34 
35    // The VM will enqueue CleanupReference instance onto sGcQueue when it becomes eligible for
36    // garbage collection (i.e. when all references to the underlying object are nullified).
37    // |sReaperThread| processes this queue by forwarding the references on to the UI thread
38    // (via REMOVE_REF message) to perform cleanup.
39    private static ReferenceQueue<Object> sGcQueue = new ReferenceQueue<Object>();
40    private static Object sCleanupMonitor = new Object();
41 
42    static private final Thread sReaperThread = new Thread(TAG) {
43        public void run() {
44            while (true) {
45                try {
46                    CleanupReference ref = (CleanupReference) sGcQueue.remove();
47                    if (DEBUG) Log.d(TAG, "removed one ref from GC queue");
48                    synchronized (sCleanupMonitor) {
49                        Message.obtain(sHandler, REMOVE_REF, ref).sendToTarget();
50                        // Give the UI thread chance to run cleanup before looping around and
51                        // taking the next item from the queue, to avoid Message bombing it.
52                        sCleanupMonitor.wait(500);
53                    }
54                } catch (Exception e) {
55                    Log.e(TAG, "Queue remove exception:", e);
56                }
57            }
58        }
59    };
60 
61    static {
62        sReaperThread.setDaemon(true);
63        sReaperThread.start();
64    }
65 
66    // Message's sent in the |what| field to |sHandler|.
67 
68    // Add a new reference to sRefs. |msg.obj| is the CleanupReference to add.
69    private static final int ADD_REF = 1;
70    // Remove reference from sRefs. |msg.obj| is the CleanupReference to remove.
71    private static final int REMOVE_REF = 2;
72 
73    /**
74     * This {@link Handler} polls {@link #sRefs}, looking for cleanup tasks that
75     * are ready to run.
76     */
77    private static Handler sHandler = new Handler(Looper.getMainLooper()) {
78        @Override
79        public void handleMessage(Message msg) {
80            TraceEvent.begin();
81            CleanupReference ref = (CleanupReference) msg.obj;
82            switch (msg.what) {
83                case ADD_REF:
84                    sRefs.add(ref);
85                    break;
86                case REMOVE_REF:
87                    ref.runCleanupTaskInternal();
88                    break;
89                default:
90                    Log.e(TAG, "Bad message=" + msg.what);
91                    break;
92            }
93 
94            if (DEBUG) Log.d(TAG, "will try and cleanup; max = " + sRefs.size());
95 
96            synchronized (sCleanupMonitor) {
97                // Always run the cleanup loop here even when adding or removing refs, to avoid
98                // falling behind on rapid garbage allocation inner loops.
99                while ((ref = (CleanupReference) sGcQueue.poll()) != null) {
100                    ref.runCleanupTaskInternal();
101                }
102                sCleanupMonitor.notifyAll();
103            }
104            TraceEvent.end();
105        }
106    };
107 
108    /**
109     * Keep a strong reference to {@link CleanupReference} so that it will
110     * actually get enqueued.
111     * Only accessed on the UI thread.
112     */
113    private static Set<CleanupReference> sRefs = new HashSet<CleanupReference>();
114 
115    private Runnable mCleanupTask;
116 
117    /**
118     * @param obj the object whose loss of reachability should trigger the
119     *            cleanup task.
120     * @param cleanupTask the task to run once obj loses reachability.
121     */
122    public CleanupReference(Object obj, Runnable cleanupTask) {
123        super(obj, sGcQueue);
124        if (DEBUG) Log.d(TAG, "+++ CREATED ONE REF");
125        mCleanupTask = cleanupTask;
126        handleOnUiThread(ADD_REF);
127    }
128 
129    /**
130     * Clear the cleanup task {@link Runnable} so that nothing will be done
131     * after garbage collection.
132     */
133    public void cleanupNow() {
134        handleOnUiThread(REMOVE_REF);
135    }
136 
137    private void handleOnUiThread(int what) {
138        Message msg = Message.obtain(sHandler, what, this);
139        if (Looper.myLooper() == sHandler.getLooper()) {
140            sHandler.handleMessage(msg);
141            msg.recycle();
142        } else {
143            msg.sendToTarget();
144        }
145    }
146 
147    private void runCleanupTaskInternal() {
148        if (DEBUG) Log.d(TAG, "runCleanupTaskInternal");
149        sRefs.remove(this);
150        if (mCleanupTask != null) {
151            if (DEBUG) Log.i(TAG, "--- CLEANING ONE REF");
152            mCleanupTask.run();
153            mCleanupTask = null;
154        }
155        clear();
156    }
157}

[all classes][org.chromium.content.common]
EMMA 2.0.5312 (C) Vladimir Roubtsov