Merge "Expose CloseGuard as a public API"
am: 4314616565
Change-Id: I57cbf48bdf2edfbca4ebb377307bb2356cce9398
This commit is contained in:
@@ -48246,6 +48246,13 @@ package android.util {
|
||||
ctor public Base64OutputStream(java.io.OutputStream, int);
|
||||
}
|
||||
|
||||
public final class CloseGuard {
|
||||
ctor public CloseGuard();
|
||||
method public void close();
|
||||
method public void open(@NonNull String);
|
||||
method public void warnIfOpen();
|
||||
}
|
||||
|
||||
@Deprecated public final class Config {
|
||||
field @Deprecated public static final boolean DEBUG = false;
|
||||
field @Deprecated public static final boolean LOGD = true;
|
||||
|
||||
138
core/java/android/util/CloseGuard.java
Normal file
138
core/java/android/util/CloseGuard.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ android_test {
|
||||
],
|
||||
static_libs: [
|
||||
"frameworks-base-testutils",
|
||||
"core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
|
||||
"core-tests-support",
|
||||
"android-common",
|
||||
"frameworks-core-util-lib",
|
||||
|
||||
98
core/tests/coretests/src/android/util/CloseGuardTest.java
Normal file
98
core/tests/coretests/src/android/util/CloseGuardTest.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 libcore.dalvik.system.CloseGuardSupport;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
|
||||
/** Unit tests for {@link android.util.CloseGuard} */
|
||||
public class CloseGuardTest {
|
||||
|
||||
@Rule
|
||||
public final TestRule rule = CloseGuardSupport.getRule();
|
||||
|
||||
@Test
|
||||
public void testEnabled_NotOpen() throws Throwable {
|
||||
ResourceOwner owner = new ResourceOwner();
|
||||
assertUnreleasedResources(owner, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabled_OpenNotClosed() throws Throwable {
|
||||
ResourceOwner owner = new ResourceOwner();
|
||||
owner.open();
|
||||
assertUnreleasedResources(owner, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnabled_OpenThenClosed() throws Throwable {
|
||||
ResourceOwner owner = new ResourceOwner();
|
||||
owner.open();
|
||||
owner.close();
|
||||
assertUnreleasedResources(owner, 0);
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testOpen_withNullMethodName_throwsNPE() throws Throwable {
|
||||
CloseGuard closeGuard = new CloseGuard();
|
||||
closeGuard.open(null);
|
||||
}
|
||||
|
||||
private void assertUnreleasedResources(ResourceOwner owner, int expectedCount)
|
||||
throws Throwable {
|
||||
try {
|
||||
CloseGuardSupport.getFinalizerChecker().accept(owner, expectedCount);
|
||||
} finally {
|
||||
// Close the resource so that CloseGuard does not generate a warning for real when it
|
||||
// is actually finalized.
|
||||
owner.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A test user of {@link CloseGuard}.
|
||||
*/
|
||||
private static class ResourceOwner {
|
||||
|
||||
private final CloseGuard mCloseGuard;
|
||||
|
||||
ResourceOwner() {
|
||||
mCloseGuard = new CloseGuard();
|
||||
}
|
||||
|
||||
public void open() {
|
||||
mCloseGuard.open("close");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mCloseGuard.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make finalize public so that it can be tested directly without relying on garbage
|
||||
* collection to trigger it.
|
||||
*/
|
||||
@Override
|
||||
public void finalize() throws Throwable {
|
||||
mCloseGuard.warnIfOpen();
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user