diff options
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); + } + } +} |