Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 876469ea authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Expose CloseGuard as a public API" am: 43146165 am: 37f8e04d am: 58745b4d

Change-Id: I40a7e24b9e77c27a954ab4394b47ac75a4681760
parents 703c18b1 58745b4d
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -48721,6 +48721,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 −0
Original line number Original line Diff line number Diff line
/*
 * 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();
    }
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 −0
Original line number Original line Diff line number Diff line
/*
 * 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();
        }
    }
}