1 /* 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 17 package android.util; 18 19 import 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 = new CloseGuard(); 30 * 31 * ... 32 * 33 * public Foo() { 34 * ...; 35 * guard.open("cleanup"); 36 * } 37 * 38 * public void cleanup() { 39 * guard.close(); 40 * ...; 41 * 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. 46 * } 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 = new CloseGuard(); 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 * ...; 83 * if (Build.VERSION.SDK_INT >= 28) { 84 * Reference.reachabilityFence(this); 85 * } 86 * // 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 */ 111 public 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 */ CloseGuard()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 */ open(@onNull String closeMethodName)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. */ close()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 */ warnIfOpen()142 public void warnIfOpen() { 143 mImpl.warnIfOpen(); 144 } 145 } 146