diff options
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/util/CloseGuard.java | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/core/java/android/util/CloseGuard.java b/core/java/android/util/CloseGuard.java new file mode 100644 index 000000000000..c39a6c9aac93 --- /dev/null +++ b/core/java/android/util/CloseGuard.java @@ -0,0 +1,138 @@ +/* + * 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 = CloseGuard.get(); + * + * ... + * + * public Foo() { + * ...; + * guard.open("cleanup"); + * } + * + * public void cleanup() { + * guard.close(); + * ...; + * } + * + * 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 = CloseGuard.get(); + * + * ... + * + * public Bar() { + * ...; + * } + * + * public void connect() { + * ...; + * guard.open("cleanup"); + * } + * + * public void cleanup() { + * guard.close(); + * ...; + * 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(); + } +} |
