protected void afterDefaultHandling(@NonNull final HeapDump heapDump, @NonNull final AnalysisResult result, @NonNull final String leakInfo) { if (!result.leakFound || result.excludedLeak) { return; } Crashlytics.log("*** Memory Leak ***"); for (final String s : leakInfo.split("\n")) { Crashlytics.log(s); } Crashlytics.log("*** End Of Leak ***"); String name = classSimpleName(result.className); if (!heapDump.referenceName.equals("")) { name += "(" + heapDump.referenceName + ")"; } Crashlytics.logException(new Exception(name + " has leaked")); }
@Override protected void onHandleIntent(Intent intent) { if (intent == null) { CanaryLog.d("HeapAnalyzerService received a null intent, ignoring."); return; } String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA); HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA); HeapAnalyzer heapAnalyzer = new HeapAnalyzer(heapDump.excludedRefs); AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey); AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result); }
@Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) { if (!result.leakFound || result.excludedLeak) { return; } LoggerFactory.getLogger("LeakCanary").warn(leakInfo); }
@Override protected void onHandleIntent(Intent intent) { String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA); HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA); ExcludedRefs androidExcludedDefault = createAndroidDefaults().build(); HeapAnalyzer heapAnalyzer = new HeapAnalyzer(androidExcludedDefault, heapDump.excludedRefs); AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey); AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result); }
Leak(HeapDump heapDump, AnalysisResult result) { this.heapDump = heapDump; this.result = result; }
Leak(HeapDump heapDump, AnalysisResult result, File resultFile) { this.heapDump = heapDump; this.result = result; this.resultFile = resultFile; }
@Override public void run() { final List<Leak> leaks = new ArrayList<>(); File[] files = leakDirectory.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return filename.endsWith(".hprof"); } }); if (files != null) { for (File heapDumpFile : files) { File resultFile = leakResultFile(heapDumpFile); ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream(resultFile)); HeapDump heapDump = (HeapDump) ois.readObject(); AnalysisResult result = (AnalysisResult) ois.readObject(); leaks.add(new Leak(heapDump, result)); } catch (IOException | ClassNotFoundException e) { // Likely a change in the serializable result class. // Let's remove the files, we can't read them anymore. heapDumpFile.delete(); resultFile.delete(); Log.e(TAG, "Could not read result file, deleted result and heap dump:" + heapDumpFile, e); } finally { IOUtils.closeSilently(ois); } } Collections.sort(leaks, new Comparator<Leak>() { @Override public int compare(Leak lhs, Leak rhs) { return Long.valueOf(rhs.heapDump.heapDumpFile.lastModified()) .compareTo(lhs.heapDump.heapDumpFile.lastModified()); } }); } mainHandler.post(new Runnable() { @Override public void run() { inFlight.remove(LoadLeaks.this); if (activityOrNull != null) { activityOrNull.leaks = leaks; activityOrNull.updateUi(); } } }); }
@Override public void run() { final List<Leak> leaks = new ArrayList<>(); List<File> files = leakDirectoryProvider.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return filename.endsWith(".result"); } }); for (File resultFile : files) { FileInputStream fis = null; try { fis = new FileInputStream(resultFile); ObjectInputStream ois = new ObjectInputStream(fis); HeapDump heapDump = (HeapDump) ois.readObject(); AnalysisResult result = (AnalysisResult) ois.readObject(); leaks.add(new Leak(heapDump, result, resultFile)); } catch (IOException | ClassNotFoundException e) { // Likely a change in the serializable result class. // Let's remove the files, we can't read them anymore. boolean deleted = resultFile.delete(); if (deleted) { CanaryLog.d(e, "Could not read result file %s, deleted it.", resultFile); } else { CanaryLog.d(e, "Could not read result file %s, could not delete it either.", resultFile); } } finally { if (fis != null) { try { fis.close(); } catch (IOException ignored) { } } } } Collections.sort(leaks, new Comparator<Leak>() { @Override public int compare(Leak lhs, Leak rhs) { return Long.valueOf(rhs.resultFile.lastModified()) .compareTo(lhs.resultFile.lastModified()); } }); mainHandler.post(new Runnable() { @Override public void run() { inFlight.remove(LoadLeaks.this); if (activityOrNull != null) { activityOrNull.leaks = leaks; activityOrNull.updateUi(); } } }); }