blob: 6ac769623bffcede0b14c05987f971dd034291db [file] [log] [blame]
David Su0c472ad2019-12-06 15:14:17 -08001/*
2 * Copyright (C) 2019 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
17package android.util;
18
19import android.annotation.NonNull;
20
21/**
22 * CloseGuard is a mechanism for flagging implicit finalizer cleanup of
23 * resources that should have been cleaned up by explicit close
24 * methods (aka "explicit termination methods" in Effective Java).
25 * <p>
26 * A simple example: <pre> {@code
27 * class Foo {
28 *
29 * private final CloseGuard guard = CloseGuard.get();
30 *
31 * ...
32 *
33 * public Foo() {
34 * ...;
35 * guard.open("cleanup");
36 * }
37 *
38 * public void cleanup() {
39 * guard.close();
40 * ...;
David Su0def1432019-12-12 18:24:52 -080041 * if (Build.VERSION.SDK_INT >= 28) {
42 * Reference.reachabilityFence(this);
43 * }
44 * // For full correctness in the absence of a close() call, other methods may also need
45 * // reachabilityFence() calls.
David Su0c472ad2019-12-06 15:14:17 -080046 * }
47 *
48 * protected void finalize() throws Throwable {
49 * try {
50 * // Note that guard could be null if the constructor threw.
51 * if (guard != null) {
52 * guard.warnIfOpen();
53 * }
54 * cleanup();
55 * } finally {
56 * super.finalize();
57 * }
58 * }
59 * }
60 * }</pre>
61 *
62 * In usage where the resource to be explicitly cleaned up is
63 * allocated after object construction, CloseGuard protection can
64 * be deferred. For example: <pre> {@code
65 * class Bar {
66 *
67 * private final CloseGuard guard = CloseGuard.get();
68 *
69 * ...
70 *
71 * public Bar() {
72 * ...;
73 * }
74 *
75 * public void connect() {
76 * ...;
77 * guard.open("cleanup");
78 * }
79 *
80 * public void cleanup() {
81 * guard.close();
82 * ...;
David Su0def1432019-12-12 18:24:52 -080083 * if (Build.VERSION.SDK_INT >= 28) {
84 * Reference.reachabilityFence(this);
85 * }
David Su0c472ad2019-12-06 15:14:17 -080086 * // For full correctness in the absence of a close() call, other methods may also need
87 * // reachabilityFence() calls.
88 * }
89 *
90 * protected void finalize() throws Throwable {
91 * try {
92 * // Note that guard could be null if the constructor threw.
93 * if (guard != null) {
94 * guard.warnIfOpen();
95 * }
96 * cleanup();
97 * } finally {
98 * super.finalize();
99 * }
100 * }
101 * }
102 * }</pre>
103 *
104 * When used in a constructor, calls to {@code open} should occur at
105 * the end of the constructor since an exception that would cause
106 * abrupt termination of the constructor will mean that the user will
107 * not have a reference to the object to cleanup explicitly. When used
108 * in a method, the call to {@code open} should occur just after
109 * resource acquisition.
110 */
111public final class CloseGuard {
112 private final dalvik.system.CloseGuard mImpl;
113
114 /**
115 * Constructs a new CloseGuard instance.
116 * {@link #open(String)} can be used to set up the instance to warn on failure to close.
117 */
118 public CloseGuard() {
119 mImpl = dalvik.system.CloseGuard.get();
120 }
121
122 /**
123 * Initializes the instance with a warning that the caller should have explicitly called the
124 * {@code closeMethodName} method instead of relying on finalization.
125 *
126 * @param closeMethodName non-null name of explicit termination method. Printed by warnIfOpen.
127 * @throws NullPointerException if closeMethodName is null.
128 */
129 public void open(@NonNull String closeMethodName) {
130 mImpl.open(closeMethodName);
131 }
132
133 /** Marks this CloseGuard instance as closed to avoid warnings on finalization. */
134 public void close() {
135 mImpl.close();
136 }
137
138 /**
139 * Logs a warning if the caller did not properly cleanup by calling an explicit close method
140 * before finalization.
141 */
142 public void warnIfOpen() {
143 mImpl.warnIfOpen();
144 }
145}