1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
import android.annotation.NonNull;
/**
* CloseGuard is a mechanism for flagging implicit finalizer cleanup of
* resources that should have been cleaned up by explicit close
* methods (aka "explicit termination methods" in Effective Java).
* <p>
* A simple example: <pre> {@code
* class Foo {
*
* private final CloseGuard guard = new CloseGuard();
*
* ...
*
* public Foo() {
* ...;
* guard.open("cleanup");
* }
*
* public void cleanup() {
* guard.close();
* ...;
* if (Build.VERSION.SDK_INT >= 28) {
* Reference.reachabilityFence(this);
* }
* // For full correctness in the absence of a close() call, other methods may also need
* // reachabilityFence() calls.
* }
*
* protected void finalize() throws Throwable {
* try {
* // Note that guard could be null if the constructor threw.
* if (guard != null) {
* guard.warnIfOpen();
* }
* cleanup();
* } finally {
* super.finalize();
* }
* }
* }
* }</pre>
*
* In usage where the resource to be explicitly cleaned up is
* allocated after object construction, CloseGuard protection can
* be deferred. For example: <pre> {@code
* class Bar {
*
* private final CloseGuard guard = new CloseGuard();
*
* ...
*
* public Bar() {
* ...;
* }
*
* public void connect() {
* ...;
* guard.open("cleanup");
* }
*
* public void cleanup() {
* guard.close();
* ...;
* if (Build.VERSION.SDK_INT >= 28) {
* Reference.reachabilityFence(this);
* }
* // For full correctness in the absence of a close() call, other methods may also need
* // reachabilityFence() calls.
* }
*
* protected void finalize() throws Throwable {
* try {
* // Note that guard could be null if the constructor threw.
* if (guard != null) {
* guard.warnIfOpen();
* }
* cleanup();
* } finally {
* super.finalize();
* }
* }
* }
* }</pre>
*
* When used in a constructor, calls to {@code open} should occur at
* the end of the constructor since an exception that would cause
* abrupt termination of the constructor will mean that the user will
* not have a reference to the object to cleanup explicitly. When used
* in a method, the call to {@code open} should occur just after
* resource acquisition.
*/
public final class CloseGuard {
private final dalvik.system.CloseGuard mImpl;
/**
* Constructs a new CloseGuard instance.
* {@link #open(String)} can be used to set up the instance to warn on failure to close.
*/
public CloseGuard() {
mImpl = dalvik.system.CloseGuard.get();
}
/**
* Initializes the instance with a warning that the caller should have explicitly called the
* {@code closeMethodName} method instead of relying on finalization.
*
* @param closeMethodName non-null name of explicit termination method. Printed by warnIfOpen.
* @throws NullPointerException if closeMethodName is null.
*/
public void open(@NonNull String closeMethodName) {
mImpl.open(closeMethodName);
}
/** Marks this CloseGuard instance as closed to avoid warnings on finalization. */
public void close() {
mImpl.close();
}
/**
* Logs a warning if the caller did not properly cleanup by calling an explicit close method
* before finalization.
*/
public void warnIfOpen() {
mImpl.warnIfOpen();
}
}
|