diff options
author | Paul Duffin <paulduffin@google.com> | 2014-02-28 16:43:15 +0000 |
---|---|---|
committer | Paul Duffin <paulduffin@google.com> | 2014-05-01 16:06:57 +0100 |
commit | a6f350c645dbb66d68cc2b03afb8f2eeaa88fbba (patch) | |
tree | 3625ee2813edb10bdb706e263408f744a16cccbd /dalvik | |
parent | 8ccb6f5b798aa991cccf7bba6ddb21ee8affecac (diff) | |
download | libcore-a6f350c645dbb66d68cc2b03afb8f2eeaa88fbba.zip libcore-a6f350c645dbb66d68cc2b03afb8f2eeaa88fbba.tar.gz libcore-a6f350c645dbb66d68cc2b03afb8f2eeaa88fbba.tar.bz2 |
Improve detection of CloseGuard protected resource leakage
* Add CloseGuardMonitor to intercept and collate CloseGuard reports and if
necessary throw an exception listing the resource leaks.
* Add ResourceLeakageDetector to abstract away the CloseGuardMonitor which will
not work on RI.
* Add AbstractResourceLeakageDetectorTestCase as a base class for tests
that need to detect resource leaks, in future this could be handled by
modifications to Cts and Vogar test runners.
* Remove CloseGuardTester and its sole usage in ProcessBuilderTest.
* Remove CloseGuardGuard from within URLConnectionTest
* Change ZipFileTest, ProcessBuilderTest, URLConnectionTest to use new
mechanism, fix issues that are identified and do some cleanup/remove
duplicated code.
Bug: https://code.google.com/p/android/issues/detail?id=66383
Change-Id: Id026dbb6bc66091a15f07329e6371cd0d1f32cf5
Diffstat (limited to 'dalvik')
-rw-r--r-- | dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java b/dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java new file mode 100644 index 0000000..b5bf380 --- /dev/null +++ b/dalvik/src/test/java/dalvik/system/CloseGuardMonitor.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2014 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 dalvik.system; + +import dalvik.system.CloseGuard.Reporter; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Provides support for detecting issues found by {@link CloseGuard} from within tests. + * + * <p>This is a best effort as it relies on both {@link CloseGuard} being enabled and being able to + * force a GC and finalization, none of which are directly controllable by this. + * + * <p>This is loaded using reflection by the AbstractResourceLeakageDetectorTestCase class as that + * class needs to run on the reference implementation which does not have this class. It implements + * {@link Runnable} because that is simpler than trying to manage a specialized interface. + * + * @hide + */ +public class CloseGuardMonitor implements Runnable { + /** + * The {@link Reporter} instance used to receive warnings from {@link CloseGuard}. + */ + private final Reporter closeGuardReporter; + + /** + * The list of allocation sites that {@link CloseGuard} has reported as not being released. + * + * <p>Is thread safe as this will be called during finalization and so there are no guarantees + * as to whether it will be called concurrently or not. + */ + private final List<Throwable> closeGuardAllocationSites = new CopyOnWriteArrayList<>(); + + /** + * Default constructor required for reflection. + */ + public CloseGuardMonitor() { + System.logI("Creating CloseGuard monitor"); + + // Save current reporter. + closeGuardReporter = CloseGuard.getReporter(); + + // Override the reporter with our own which collates the allocation sites. + CloseGuard.setReporter(new Reporter() { + @Override + public void report(String message, Throwable allocationSite) { + // Ignore message as it's always the same. + closeGuardAllocationSites.add(allocationSite); + } + }); + } + + /** + * Check to see whether any resources monitored by {@link CloseGuard} were not released before + * they were garbage collected. + */ + @Override + public void run() { + // Create a weak reference to an object so that we can detect when it is garbage collected. + WeakReference<Object> reference = new WeakReference<>(new Object()); + + try { + // 'Force' a GC and finalize to cause CloseGuards to report warnings. Doesn't loop + // forever as there are no guarantees that the following code does anything at all so + // don't want a potential infinite loop. + Runtime runtime = Runtime.getRuntime(); + for (int i = 0; i < 20; ++i) { + runtime.gc(); + System.runFinalization(); + try { + Thread.sleep(1); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + + // Check to see if the weak reference has been garbage collected. + if (reference.get() == null) { + System.logI("Sentry object has been freed so assuming CloseGuards have reported" + + " any resource leakages"); + break; + } + } + } finally { + // Restore the reporter. + CloseGuard.setReporter(closeGuardReporter); + } + + if (!closeGuardAllocationSites.isEmpty()) { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + int i = 0; + for (Throwable allocationSite : closeGuardAllocationSites) { + printWriter.print(++i); + printWriter.print(") "); + allocationSite.printStackTrace(printWriter); + printWriter.println(" --------------------------------"); + } + throw new AssertionError("Potential resource leakage detected:\n" + writer); + } + } +} |