public File dumpHeap() { if (!LeakCanaryInternals.isExternalStorageWritable()) { Log.d(TAG, "Could not dump heap, external storage not mounted."); } File heapDumpFile = getHeapDumpFile(); if (heapDumpFile.exists()) { Log.d(TAG, "Could not dump heap, previous analysis still is in progress."); return NO_DUMP; } FutureResult<Toast> waitingForToast = new FutureResult(); showToast(waitingForToast); if (waitingForToast.wait(5, TimeUnit.SECONDS)) { Toast toast = (Toast) waitingForToast.get(); try { Debug.dumpHprofData(heapDumpFile.getAbsolutePath()); cancelToast(toast); return heapDumpFile; } catch (IOException e) { cleanup(); Log.e(TAG, "Could not perform heap dump", e); return NO_DUMP; } } Log.d(TAG, "Did not dump heap, too much time waiting for Toast."); return NO_DUMP; }
private void showToast(final FutureResult<Toast> waitingForToast) { this.mainHandler.post(new Runnable() { public void run() { final Toast toast = new Toast(AndroidHeapDumper.this.context); toast.setGravity(16, 0, 0); toast.setDuration(1); toast.setView(LayoutInflater.from(AndroidHeapDumper.this.context).inflate(R .layout.__leak_canary_heap_dump_toast, null)); toast.show(); Looper.myQueue().addIdleHandler(new IdleHandler() { public boolean queueIdle() { waitingForToast.set(toast); return false; } }); } }); }
private void showToast(final FutureResult<Toast> waitingForToast) { mainHandler.post(new Runnable() { @Override public void run() { final Toast toast = new Toast(context); toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); toast.setDuration(Toast.LENGTH_LONG); LayoutInflater inflater = LayoutInflater.from(context); toast.setView(inflater.inflate(R.layout.leak_canary_heap_dump_toast, null)); toast.setDuration(Toast.LENGTH_LONG); toast.show(); // Waiting for Idle to make sure Toast gets rendered. Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { waitingForToast.set(toast); return false; } }); } }); }
private void showToast(final FutureResult<Toast> waitingForToast) { mainHandler.post(new Runnable() { @Override public void run() { final Toast toast = new Toast(context); toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); toast.setDuration(Toast.LENGTH_LONG); LayoutInflater inflater = LayoutInflater.from(context); toast.setView(inflater.inflate(R.layout.leak_canary_heap_dump_toast, null)); toast.show(); // Waiting for Idle to make sure Toast gets rendered. Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { waitingForToast.set(toast); return false; } }); } }); }
@SuppressWarnings("ReferenceEquality") // Explicitly checking for named null. @Override public File dumpHeap() { File heapDumpFile = leakDirectoryProvider.newHeapDumpFile(); if (heapDumpFile == RETRY_LATER) { return RETRY_LATER; } FutureResult<Toast> waitingForToast = new FutureResult<>(); showToast(waitingForToast); if (!waitingForToast.wait(5, SECONDS)) { CanaryLog.d("Did not dump heap, too much time waiting for Toast."); return RETRY_LATER; } Toast toast = waitingForToast.get(); try { Debug.dumpHprofData(heapDumpFile.getAbsolutePath()); cancelToast(toast); return heapDumpFile; } catch (Exception e) { CanaryLog.d(e, "Could not dump heap"); // Abort heap dump return RETRY_LATER; } }