/** * Called when there was an error saving or loading the analysis result. This will be called from * a background intent service thread. */ protected void onAnalysisResultFailure(String failureMessage) { CanaryLog.d(failureMessage); } }
@Override public void run() { File heapDumpFile = visibleLeak.heapDump.heapDumpFile; File resultFile = visibleLeak.selfFile; boolean resultDeleted = resultFile.delete(); if (!resultDeleted) { CanaryLog.d("Could not delete result file %s", resultFile.getPath()); } boolean heapDumpDeleted = heapDumpFile.delete(); if (!heapDumpDeleted) { CanaryLog.d("Could not delete heap dump file %s", heapDumpFile.getPath()); } } });
@Override public void clearLeakDirectory() { List<File> allFilesExceptPending = listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return !filename.endsWith(PENDING_HEAPDUMP_SUFFIX); } }); for (File file : allFilesExceptPending) { boolean deleted = file.delete(); if (!deleted) { CanaryLog.d("Could not delete file %s", file.getPath()); } } }
private HeapDump renameHeapdump(HeapDump heapDump) { String fileName = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_SSS'.hprof'", Locale.US).format(new Date()); File newFile = new File(heapDump.heapDumpFile.getParent(), fileName); boolean renamed = heapDump.heapDumpFile.renameTo(newFile); if (!renamed) { CanaryLog.d("Could not rename heap dump file %s to %s", heapDump.heapDumpFile.getPath(), newFile.getPath()); } return heapDump.buildUpon().heapDumpFile(newFile).build(); }
private void cleanupOldHeapDumps() { List<File> hprofFiles = listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { return filename.endsWith(HPROF_SUFFIX); } }); int filesToRemove = hprofFiles.size() - maxStoredHeapDumps; if (filesToRemove > 0) { CanaryLog.d("Removing %d heap dumps", filesToRemove); // Sort with oldest modified first. Collections.sort(hprofFiles, new Comparator<File>() { @Override public int compare(File lhs, File rhs) { return Long.valueOf(lhs.lastModified()).compareTo(rhs.lastModified()); } }); for (int i = 0; i < filesToRemove; i++) { boolean deleted = hprofFiles.get(i).delete(); if (!deleted) { CanaryLog.d("Could not delete old hprof file %s", hprofFiles.get(i).getPath()); } } } } }
@Nullable public static File save(@NonNull HeapDump heapDump, @NonNull AnalysisResult result) { File analyzedHeapfile = new File(heapDump.heapDumpFile.getParentFile(), heapDump.heapDumpFile.getName() + ".result"); FileOutputStream fos = null; try { fos = new FileOutputStream(analyzedHeapfile); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(heapDump); oos.writeObject(result); return analyzedHeapfile; } catch (IOException e) { CanaryLog.d(e, "Could not save leak analysis result to disk."); } finally { if (fos != null) { try { fos.close(); } catch (IOException ignored) { } } } return null; }
@Nullable public static AnalyzedHeap load(@NonNull File resultFile) { FileInputStream fis = null; try { fis = new FileInputStream(resultFile); ObjectInputStream ois = new ObjectInputStream(fis); HeapDump heapDump = (HeapDump) ois.readObject(); AnalysisResult result = (AnalysisResult) ois.readObject(); return new AnalyzedHeap(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) { } } } return null; }
packageInfo = packageManager.getPackageInfo(context.getPackageName(), GET_SERVICES); } catch (Exception e) { CanaryLog.d(e, "Could not get package info for %s", context.getPackageName()); return false; CanaryLog.d("Did not expect service %s to run in main process %s", serviceClass, mainProcess); } catch (SecurityException exception) { CanaryLog.d("Could not get running app processes %d", exception); return false; CanaryLog.d("Could not find running process for %d", myPid); return false;
@Override protected void onHandleIntentInForeground(@Nullable 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, this, heapDump.reachabilityInspectorClasses); AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey, heapDump.computeRetainedHeapSize); AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result); }
@Override public void onProgressUpdate(Step step) { int percent = (int) ((100f * step.ordinal()) / Step.values().length); CanaryLog.d("Analysis in progress, working on: %s", step.name()); String lowercase = step.name().replace("_", " ").toLowerCase(); String message = lowercase.substring(0, 1).toUpperCase() + lowercase.substring(1); showForegroundNotification(100, percent, false, message); } }
CanaryLog.d("Could not dump heap, previous analysis still is in progress."); return RETRY_LATER; if (!directoryWritableAfterMkdirs(storageDirectory)) { if (!hasStoragePermission()) { CanaryLog.d("WRITE_EXTERNAL_STORAGE permission not granted"); requestWritePermissionNotification(); } else { String state = Environment.getExternalStorageState(); if (!Environment.MEDIA_MOUNTED.equals(state)) { CanaryLog.d("External storage not mounted, state: %s", state); } else { CanaryLog.d("Could not create heap dump directory in external storage: [%s]", storageDirectory.getAbsolutePath()); CanaryLog.d("Could not create heap dump directory in app storage: [%s]", storageDirectory.getAbsolutePath()); return RETRY_LATER;
private void detectLeaks() { if (skipLeakDetectionReason != null) { CanaryLog.d("Skipping leak detection because the test %s", skipLeakDetectionReason); skipLeakDetectionReason = null; return; } InstrumentationLeakDetector leakDetector = new InstrumentationLeakDetector(); InstrumentationLeakResults results = leakDetector.detectLeaks(); reportLeaks(results); }
@Override protected final void onHandleIntentInForeground(@Nullable Intent intent) { if (intent == null) { CanaryLog.d("AbstractAnalysisResultService received a null intent, ignoring."); return; } if (!intent.hasExtra(ANALYZED_HEAP_PATH_EXTRA)) { onAnalysisResultFailure(getString(R.string.leak_canary_result_failure_no_disk_space)); return; } File analyzedHeapFile = new File(intent.getStringExtra(ANALYZED_HEAP_PATH_EXTRA)); AnalyzedHeap analyzedHeap = AnalyzedHeap.load(analyzedHeapFile); if (analyzedHeap == null) { onAnalysisResultFailure(getString(R.string.leak_canary_result_failure_no_file)); return; } try { onHeapAnalyzed(analyzedHeap); } finally { //noinspection ResultOfMethodCallIgnored analyzedHeap.heapDump.heapDumpFile.delete(); //noinspection ResultOfMethodCallIgnored analyzedHeap.selfFile.delete(); } }
CanaryLog.d("%s", leakInfo);