diff options
author | Dianne Hackborn <hackbod@google.com> | 2013-06-21 23:49:07 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-06-21 23:49:08 +0000 |
commit | 142dd91583f429db43017ada2497d0ecfdc2b392 (patch) | |
tree | 6976ddef55d58eebb7ffbdee4a0269b1e13ca29e | |
parent | 35c70f94ef86e076cd0287954d4f224c0019905e (diff) | |
parent | db4e33f1f1d766afa3218a6bbdbb561e7962c854 (diff) | |
download | frameworks_base-142dd91583f429db43017ada2497d0ecfdc2b392.zip frameworks_base-142dd91583f429db43017ada2497d0ecfdc2b392.tar.gz frameworks_base-142dd91583f429db43017ada2497d0ecfdc2b392.tar.bz2 |
Merge "Faster PrintWriter."
-rw-r--r-- | core/java/android/os/Binder.java | 5 | ||||
-rw-r--r-- | core/java/com/android/internal/util/FastPrintWriter.java | 478 |
2 files changed, 481 insertions, 2 deletions
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 7ffd30b..7b91418 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -17,6 +17,7 @@ package android.os; import android.util.Log; +import com.android.internal.util.FastPrintWriter; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -288,7 +289,7 @@ public class Binder implements IBinder { */ public void dump(FileDescriptor fd, String[] args) { FileOutputStream fout = new FileOutputStream(fd); - PrintWriter pw = new PrintWriter(fout); + PrintWriter pw = new FastPrintWriter(fout); try { final String disabled; synchronized (Binder.class) { @@ -310,7 +311,7 @@ public class Binder implements IBinder { */ public void dumpAsync(final FileDescriptor fd, final String[] args) { final FileOutputStream fout = new FileOutputStream(fd); - final PrintWriter pw = new PrintWriter(fout); + final PrintWriter pw = new FastPrintWriter(fout); Thread thr = new Thread("Binder.dumpAsync") { public void run() { try { diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java new file mode 100644 index 0000000..6ad8e66 --- /dev/null +++ b/core/java/com/android/internal/util/FastPrintWriter.java @@ -0,0 +1,478 @@ +package com.android.internal.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +public class FastPrintWriter extends PrintWriter { + private static final int BUFFER_LEN = 8192; + + private final char[] mText = new char[BUFFER_LEN]; + private int mPos; + + final private OutputStream mOutputStream; + private CharsetEncoder mCharset; + final private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN); + + /** + * Constructs a new {@code PrintWriter} with {@code out} as its target + * stream. By default, the new print writer does not automatically flush its + * contents to the target stream when a newline is encountered. + * + * @param out + * the target output stream. + * @throws NullPointerException + * if {@code out} is {@code null}. + */ + public FastPrintWriter(OutputStream out) { + super(out); + mOutputStream = out; + initDefaultEncoder(); + } + + /** + * Constructs a new {@code PrintWriter} with {@code out} as its target + * stream. The parameter {@code autoFlush} determines if the print writer + * automatically flushes its contents to the target stream when a newline is + * encountered. + * + * @param out + * the target output stream. + * @param autoFlush + * indicates whether contents are flushed upon encountering a + * newline sequence. + * @throws NullPointerException + * if {@code out} is {@code null}. + */ + public FastPrintWriter(OutputStream out, boolean autoFlush) { + super(out, autoFlush); + mOutputStream = out; + initDefaultEncoder(); + } + + /** + * Constructs a new {@code PrintWriter} with {@code wr} as its target + * writer. By default, the new print writer does not automatically flush its + * contents to the target writer when a newline is encountered. + * + * @param wr + * the target writer. + * @throws NullPointerException + * if {@code wr} is {@code null}. + */ + public FastPrintWriter(Writer wr) { + super(wr); + mOutputStream = null; + initDefaultEncoder(); + } + + /** + * Constructs a new {@code PrintWriter} with {@code out} as its target + * writer. The parameter {@code autoFlush} determines if the print writer + * automatically flushes its contents to the target writer when a newline is + * encountered. + * + * @param wr + * the target writer. + * @param autoFlush + * indicates whether to flush contents upon encountering a + * newline sequence. + * @throws NullPointerException + * if {@code out} is {@code null}. + */ + public FastPrintWriter(Writer wr, boolean autoFlush) { + super(wr, autoFlush); + mOutputStream = null; + initDefaultEncoder(); + } + + /** + * Constructs a new {@code PrintWriter} with {@code file} as its target. The + * VM's default character set is used for character encoding. + * The print writer does not automatically flush its contents to the target + * file when a newline is encountered. The output to the file is buffered. + * + * @param file + * the target file. If the file already exists, its contents are + * removed, otherwise a new file is created. + * @throws java.io.FileNotFoundException + * if an error occurs while opening or creating the target file. + */ + public FastPrintWriter(File file) throws FileNotFoundException { + super(file); + mOutputStream = null; + initDefaultEncoder(); + } + + /** + * Constructs a new {@code PrintWriter} with {@code file} as its target. The + * character set named {@code csn} is used for character encoding. + * The print writer does not automatically flush its contents to the target + * file when a newline is encountered. The output to the file is buffered. + * + * @param file + * the target file. If the file already exists, its contents are + * removed, otherwise a new file is created. + * @param csn + * the name of the character set used for character encoding. + * @throws FileNotFoundException + * if an error occurs while opening or creating the target file. + * @throws NullPointerException + * if {@code csn} is {@code null}. + * @throws java.io.UnsupportedEncodingException + * if the encoding specified by {@code csn} is not supported. + */ + public FastPrintWriter(File file, String csn) throws FileNotFoundException, + UnsupportedEncodingException { + super(file, csn); + mOutputStream = null; + initEncoder(csn); + } + + /** + * Constructs a new {@code PrintWriter} with the file identified by {@code + * fileName} as its target. The VM's default character set is + * used for character encoding. The print writer does not automatically + * flush its contents to the target file when a newline is encountered. The + * output to the file is buffered. + * + * @param fileName + * the target file's name. If the file already exists, its + * contents are removed, otherwise a new file is created. + * @throws FileNotFoundException + * if an error occurs while opening or creating the target file. + */ + public FastPrintWriter(String fileName) throws FileNotFoundException { + super(fileName); + mOutputStream = null; + initDefaultEncoder(); + } + + /** + * Constructs a new {@code PrintWriter} with the file identified by {@code + * fileName} as its target. The character set named {@code csn} is used for + * character encoding. The print writer does not automatically flush its + * contents to the target file when a newline is encountered. The output to + * the file is buffered. + * + * @param fileName + * the target file's name. If the file already exists, its + * contents are removed, otherwise a new file is created. + * @param csn + * the name of the character set used for character encoding. + * @throws FileNotFoundException + * if an error occurs while opening or creating the target file. + * @throws NullPointerException + * if {@code csn} is {@code null}. + * @throws UnsupportedEncodingException + * if the encoding specified by {@code csn} is not supported. + */ + public FastPrintWriter(String fileName, String csn) + throws FileNotFoundException, UnsupportedEncodingException { + super(fileName, csn); + mOutputStream = null; + initEncoder(csn); + } + + private final void initEncoder(String csn) throws UnsupportedEncodingException { + try { + mCharset = Charset.forName(csn).newEncoder(); + } catch (Exception e) { + throw new UnsupportedEncodingException(csn); + } + mCharset.onMalformedInput(CodingErrorAction.REPLACE); + mCharset.onUnmappableCharacter(CodingErrorAction.REPLACE); + } + + private final void initDefaultEncoder() { + mCharset = Charset.defaultCharset().newEncoder(); + mCharset.onMalformedInput(CodingErrorAction.REPLACE); + mCharset.onUnmappableCharacter(CodingErrorAction.REPLACE); + } + + private void appendInner(char c) throws IOException { + int pos = mPos; + if (pos >= (BUFFER_LEN-1)) { + flush(); + pos = mPos; + } + mText[pos] = c; + mPos = pos+1; + } + + private void appendInner(String str, int i, final int length) throws IOException { + if (length > BUFFER_LEN) { + final int end = i + length; + while (i < end) { + int next = i + BUFFER_LEN; + appendInner(str, i, next<end ? BUFFER_LEN : (end-i)); + i = next; + } + return; + } + int pos = mPos; + if ((pos+length) > BUFFER_LEN) { + flush(); + pos = mPos; + } + str.getChars(i, i + length, mText, pos); + mPos = pos + length; + } + + private void appendInner(char[] buf, int i, final int length) throws IOException { + if (length > BUFFER_LEN) { + final int end = i + length; + while (i < end) { + int next = i + BUFFER_LEN; + appendInner(buf, i, next < end ? BUFFER_LEN : (end - i)); + i = next; + } + return; + } + int pos = mPos; + if ((pos+length) > BUFFER_LEN) { + flush(); + pos = mPos; + } + System.arraycopy(buf, i, mText, pos, length); + mPos = pos + length; + } + + private void flushBytesInner() throws IOException { + int position; + if ((position = mBytes.position()) > 0) { + mBytes.flip(); + mOutputStream.write(mBytes.array(), 0, position); + mBytes.clear(); + } + } + + private void flushInner() throws IOException { + //Log.i("PackageManager", "flush mPos=" + mPos); + if (mPos > 0) { + if (mOutputStream != null) { + CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos); + CoderResult result = mCharset.encode(charBuffer, mBytes, true); + while (true) { + if (result.isError()) { + throw new IOException(result.toString()); + } else if (result.isOverflow()) { + flushBytesInner(); + result = mCharset.encode(charBuffer, mBytes, true); + continue; + } + break; + } + flushBytesInner(); + mOutputStream.flush(); + } else { + out.write(mText, 0, mPos); + out.flush(); + } + mPos = 0; + } + } + + /** + * Ensures that all pending data is sent out to the target. It also + * flushes the target. If an I/O error occurs, this writer's error + * state is set to {@code true}. + */ + @Override + public void flush() { + try { + flushInner(); + } catch (IOException e) { + } + super.flush(); + } + + /** + * Prints the string representation of the specified character array + * to the target. + * + * @param charArray + * the character array to print to the target. + * @see #print(String) + */ + public void print(char[] charArray) { + try { + appendInner(charArray, 0, charArray.length); + } catch (IOException e) { + } + } + + /** + * Prints the string representation of the specified character to the + * target. + * + * @param ch + * the character to print to the target. + * @see #print(String) + */ + public void print(char ch) { + try { + appendInner(ch); + } catch (IOException e) { + } + } + + /** + * Prints a string to the target. The string is converted to an array of + * bytes using the encoding chosen during the construction of this writer. + * The bytes are then written to the target with {@code write(int)}. + * <p> + * If an I/O error occurs, this writer's error flag is set to {@code true}. + * + * @param str + * the string to print to the target. + * @see #write(int) + */ + public void print(String str) { + if (str == null) { + str = String.valueOf((Object) null); + } + try { + appendInner(str, 0, str.length()); + } catch (IOException e) { + } + } + + /** + * Prints the string representation of the character array {@code chars} followed by a newline. + * Flushes this writer if the autoFlush flag is set to {@code true}. + */ + public void println(char[] chars) { + print(chars); + println(); + } + + /** + * Prints the string representation of the char {@code c} followed by a newline. + * Flushes this writer if the autoFlush flag is set to {@code true}. + */ + public void println(char c) { + print(c); + println(); + } + + /** + * Writes {@code count} characters from {@code buffer} starting at {@code + * offset} to the target. + * <p> + * This writer's error flag is set to {@code true} if this writer is closed + * or an I/O error occurs. + * + * @param buf + * the buffer to write to the target. + * @param offset + * the index of the first character in {@code buffer} to write. + * @param count + * the number of characters in {@code buffer} to write. + * @throws IndexOutOfBoundsException + * if {@code offset < 0} or {@code count < 0}, or if {@code + * offset + count} is greater than the length of {@code buf}. + */ + @Override + public void write(char[] buf, int offset, int count) { + try { + appendInner(buf, offset, count); + } catch (IOException e) { + } + } + + /** + * Writes one character to the target. Only the two least significant bytes + * of the integer {@code oneChar} are written. + * <p> + * This writer's error flag is set to {@code true} if this writer is closed + * or an I/O error occurs. + * + * @param oneChar + * the character to write to the target. + */ + @Override + public void write(int oneChar) { + try { + appendInner((char) oneChar); + } catch (IOException e) { + } + } + + /** + * Writes the characters from the specified string to the target. + * + * @param str + * the non-null string containing the characters to write. + */ + @Override + public void write(String str) { + try { + appendInner(str, 0, str.length()); + } catch (IOException e) { + } + } + + /** + * Writes {@code count} characters from {@code str} starting at {@code + * offset} to the target. + * + * @param str + * the non-null string containing the characters to write. + * @param offset + * the index of the first character in {@code str} to write. + * @param count + * the number of characters from {@code str} to write. + * @throws IndexOutOfBoundsException + * if {@code offset < 0} or {@code count < 0}, or if {@code + * offset + count} is greater than the length of {@code str}. + */ + @Override + public void write(String str, int offset, int count) { + try { + appendInner(str, offset, count); + } catch (IOException e) { + } + } + + /** + * Appends a subsequence of the character sequence {@code csq} to the + * target. This method works the same way as {@code + * PrintWriter.print(csq.subsequence(start, end).toString())}. If {@code + * csq} is {@code null}, then the specified subsequence of the string "null" + * will be written to the target. + * + * @param csq + * the character sequence appended to the target. + * @param start + * the index of the first char in the character sequence appended + * to the target. + * @param end + * the index of the character following the last character of the + * subsequence appended to the target. + * @return this writer. + * @throws StringIndexOutOfBoundsException + * if {@code start > end}, {@code start < 0}, {@code end < 0} or + * either {@code start} or {@code end} are greater or equal than + * the length of {@code csq}. + */ + @Override + public PrintWriter append(CharSequence csq, int start, int end) { + if (csq == null) { + csq = "null"; + } + String output = csq.subSequence(start, end).toString(); + write(output, 0, output.length()); + return this; + } +} |