public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
        != PackageManager.PERMISSION_GRANTED) {
      pw.println("Permission Denial: Can't dump DropBoxManagerService");
      return;
    }

    try {
      init();
    } catch (IOException e) {
      pw.println("Can't initialize: " + e);
      Slog.e(TAG, "Can't init", e);
      return;
    }

    if (PROFILE_DUMP) Debug.startMethodTracing("/data/trace/dropbox.dump");

    StringBuilder out = new StringBuilder();
    boolean doPrint = false, doFile = false;
    ArrayList<String> searchArgs = new ArrayList<String>();
    for (int i = 0; args != null && i < args.length; i++) {
      if (args[i].equals("-p") || args[i].equals("--print")) {
        doPrint = true;
      } else if (args[i].equals("-f") || args[i].equals("--file")) {
        doFile = true;
      } else if (args[i].startsWith("-")) {
        out.append("Unknown argument: ").append(args[i]).append("\n");
      } else {
        searchArgs.add(args[i]);
      }
    }

    out.append("Drop box contents: ").append(mAllFiles.contents.size()).append(" entries\n");

    if (!searchArgs.isEmpty()) {
      out.append("Searching for:");
      for (String a : searchArgs) out.append(" ").append(a);
      out.append("\n");
    }

    int numFound = 0, numArgs = searchArgs.size();
    Time time = new Time();
    out.append("\n");
    for (EntryFile entry : mAllFiles.contents) {
      time.set(entry.timestampMillis);
      String date = time.format("%Y-%m-%d %H:%M:%S");
      boolean match = true;
      for (int i = 0; i < numArgs && match; i++) {
        String arg = searchArgs.get(i);
        match = (date.contains(arg) || arg.equals(entry.tag));
      }
      if (!match) continue;

      numFound++;
      if (doPrint) out.append("========================================\n");
      out.append(date).append(" ").append(entry.tag == null ? "(no tag)" : entry.tag);
      if (entry.file == null) {
        out.append(" (no file)\n");
        continue;
      } else if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
        out.append(" (contents lost)\n");
        continue;
      } else {
        out.append(" (");
        if ((entry.flags & DropBoxManager.IS_GZIPPED) != 0) out.append("compressed ");
        out.append((entry.flags & DropBoxManager.IS_TEXT) != 0 ? "text" : "data");
        out.append(", ").append(entry.file.length()).append(" bytes)\n");
      }

      if (doFile || (doPrint && (entry.flags & DropBoxManager.IS_TEXT) == 0)) {
        if (!doPrint) out.append("    ");
        out.append(entry.file.getPath()).append("\n");
      }

      if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
        DropBoxManager.Entry dbe = null;
        InputStreamReader isr = null;
        try {
          dbe = new DropBoxManager.Entry(entry.tag, entry.timestampMillis, entry.file, entry.flags);

          if (doPrint) {
            isr = new InputStreamReader(dbe.getInputStream());
            char[] buf = new char[4096];
            boolean newline = false;
            for (; ; ) {
              int n = isr.read(buf);
              if (n <= 0) break;
              out.append(buf, 0, n);
              newline = (buf[n - 1] == '\n');

              // Flush periodically when printing to avoid out-of-memory.
              if (out.length() > 65536) {
                pw.write(out.toString());
                out.setLength(0);
              }
            }
            if (!newline) out.append("\n");
          } else {
            String text = dbe.getText(70);
            out.append("    ");
            if (text == null) {
              out.append("[null]");
            } else {
              boolean truncated = (text.length() == 70);
              out.append(text.trim().replace('\n', '/'));
              if (truncated) out.append(" ...");
            }
            out.append("\n");
          }
        } catch (IOException e) {
          out.append("*** ").append(e.toString()).append("\n");
          Slog.e(TAG, "Can't read: " + entry.file, e);
        } finally {
          if (dbe != null) dbe.close();
          if (isr != null) {
            try {
              isr.close();
            } catch (IOException unused) {
            }
          }
        }
      }

      if (doPrint) out.append("\n");
    }

    if (numFound == 0) out.append("(No entries found.)\n");

    if (args == null || args.length == 0) {
      if (!doPrint) out.append("\n");
      out.append("Usage: dumpsys dropbox [--print|--file] [YYYY-mm-dd] [HH:MM:SS] [tag]\n");
    }

    pw.write(out.toString());
    if (PROFILE_DUMP) Debug.stopMethodTracing();
  }
  @Override
  public void add(DropBoxManager.Entry entry) {
    File temp = null;
    OutputStream output = null;
    final String tag = entry.getTag();
    try {
      int flags = entry.getFlags();
      if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();

      init();
      if (!isTagEnabled(tag)) return;
      long max = trimToFit();
      long lastTrim = System.currentTimeMillis();

      byte[] buffer = new byte[mBlockSize];
      InputStream input = entry.getInputStream();

      // First, accumulate up to one block worth of data in memory before
      // deciding whether to compress the data or not.

      int read = 0;
      while (read < buffer.length) {
        int n = input.read(buffer, read, buffer.length - read);
        if (n <= 0) break;
        read += n;
      }

      // If we have at least one block, compress it -- otherwise, just write
      // the data in uncompressed form.

      temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp");
      int bufferSize = mBlockSize;
      if (bufferSize > 4096) bufferSize = 4096;
      if (bufferSize < 512) bufferSize = 512;
      FileOutputStream foutput = new FileOutputStream(temp);
      output = new BufferedOutputStream(foutput, bufferSize);
      if (read == buffer.length && ((flags & DropBoxManager.IS_GZIPPED) == 0)) {
        output = new GZIPOutputStream(output);
        flags = flags | DropBoxManager.IS_GZIPPED;
      }

      do {
        output.write(buffer, 0, read);

        long now = System.currentTimeMillis();
        if (now - lastTrim > 30 * 1000) {
          max = trimToFit(); // In case data dribbles in slowly
          lastTrim = now;
        }

        read = input.read(buffer);
        if (read <= 0) {
          FileUtils.sync(foutput);
          output.close(); // Get a final size measurement
          output = null;
        } else {
          output.flush(); // So the size measurement is pseudo-reasonable
        }

        long len = temp.length();
        if (len > max) {
          Slog.w(TAG, "Dropping: " + tag + " (" + temp.length() + " > " + max + " bytes)");
          temp.delete();
          temp = null; // Pass temp = null to createEntry() to leave a tombstone
          break;
        }
      } while (read > 0);

      long time = createEntry(temp, tag, flags);
      temp = null;

      final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
      dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
      dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
      if (!mBooted) {
        dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
      }
      // Call sendBroadcast after returning from this call to avoid deadlock. In particular
      // the caller may be holding the WindowManagerService lock but sendBroadcast requires a
      // lock in ActivityManagerService. ActivityManagerService has been caught holding that
      // very lock while waiting for the WindowManagerService lock.
      mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent));
    } catch (IOException e) {
      Slog.e(TAG, "Can't write: " + tag, e);
    } finally {
      try {
        if (output != null) output.close();
      } catch (IOException e) {
      }
      entry.close();
      if (temp != null) temp.delete();
    }
  }