Merge "Expose CloseGuard as a public API"
This commit is contained in:
@@ -48246,6 +48246,13 @@ package android.util {
|
|||||||
ctor public Base64OutputStream(java.io.OutputStream, int);
|
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 {
|
@Deprecated public final class Config {
|
||||||
field @Deprecated public static final boolean DEBUG = false;
|
field @Deprecated public static final boolean DEBUG = false;
|
||||||
field @Deprecated public static final boolean LOGD = true;
|
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: [
|
static_libs: [
|
||||||
"frameworks-base-testutils",
|
"frameworks-base-testutils",
|
||||||
|
"core-test-rules", // for libcore.dalvik.system.CloseGuardSupport
|
||||||
"core-tests-support",
|
"core-tests-support",
|
||||||
"android-common",
|
"android-common",
|
||||||
"frameworks-core-util-lib",
|
"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