• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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