1 /* 2 ** Copyright 2007, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.development; 18 19 import static com.android.internal.util.CharSequences.forAsciiBytes; 20 21 import java.io.DataInputStream; 22 import java.io.IOException; 23 import java.io.FileOutputStream; 24 import java.net.Socket; 25 26 import android.app.Activity; 27 import android.os.Handler; 28 import android.os.Bundle; 29 import android.util.Log; 30 import android.graphics.Typeface; 31 import android.view.Gravity; 32 33 /** 34 * Views the device log. 35 */ 36 public class LogViewer extends Activity { 37 38 static final String TAG = LogViewer.class.getSimpleName(); 39 40 FileOutputStream logger; 41 42 volatile boolean active = true; 43 Handler handler; 44 LogTextBox text; 45 46 @Override onCreate(Bundle icicle)47 protected void onCreate(Bundle icicle) { 48 super.onCreate(icicle); 49 setContentView(R.layout.log_viewer); 50 this.handler = new Handler(); 51 52 text = (LogTextBox) findViewById(R.id.text); 53 54 text.setTextSize(10); 55 text.setHorizontallyScrolling(true); 56 text.setTypeface(Typeface.MONOSPACE); 57 text.setGravity(Gravity.BOTTOM | Gravity.LEFT); 58 59 this.active = true; 60 try { 61 logger = new FileOutputStream("/tmp/logviewer.txt"); 62 new Thread(new LogReader()).start(); 63 } catch (IOException e) { 64 appendThrowable(e); 65 } 66 } 67 appendThrowable(Throwable t)68 private void appendThrowable(Throwable t) { 69 StringBuilder builder = new StringBuilder(); 70 builder.append("Error reading log: "); 71 builder.append(Log.getStackTraceString(t)); 72 text.getText().append(builder); 73 } 74 75 private class LogReader implements Runnable { 76 77 final Socket socket; 78 final DataInputStream in; 79 StringBuilder builder = new StringBuilder(); 80 long lastTime = System.currentTimeMillis(); 81 82 private static final int HEADER_SIZE = 24; 83 LogReader()84 public LogReader() throws IOException { 85 this.socket = new Socket("127.0.0.1", 5040); 86 this.in = new DataInputStream(this.socket.getInputStream()); 87 // Write two newlines to indicate "no reader args" 88 this.socket.getOutputStream().write('\n'); 89 this.socket.getOutputStream().write('\n'); 90 } 91 run()92 public void run() { 93 while (active) { 94 try { 95 while (in.available() > 0) { 96 logger.write("Reading message.\n".getBytes()); 97 98 int length = in.readInt(); 99 byte[] bytes = new byte[length]; 100 in.readFully(bytes); 101 102 int tagEnd = next0(bytes, HEADER_SIZE); 103 int fileEnd = next0(bytes, tagEnd + 1); 104 int messageEnd = next0(bytes, fileEnd + 1); 105 106 CharSequence tag 107 = forAsciiBytes(bytes, HEADER_SIZE, tagEnd); 108 CharSequence message 109 = forAsciiBytes(bytes, fileEnd + 1, messageEnd); 110 111 builder.append(tag) 112 .append(": ") 113 .append(message) 114 .append("\n"); 115 } 116 117 logger.write("Updating UI.\n".getBytes()); 118 handler.post(new AppendCharacters(builder)); 119 builder = new StringBuilder(); 120 121 try { 122 Thread.sleep(1000); 123 } catch (InterruptedException e) {} 124 } catch (final IOException e) { 125 handler.post(new AppendThrowable(e)); 126 } 127 } 128 } 129 } 130 next0(byte[] bytes, int start)131 static int next0(byte[] bytes, int start) { 132 for (int current = start; current < bytes.length; current++) { 133 if (bytes[current] == 0) 134 return current; 135 } 136 return bytes.length; 137 } 138 139 private class AppendThrowable implements Runnable { 140 141 private final Throwable t; 142 AppendThrowable(Throwable t)143 public AppendThrowable(Throwable t) { 144 this.t = t; 145 } 146 run()147 public void run() { 148 appendThrowable(t); 149 } 150 } 151 152 private class AppendCharacters implements Runnable { 153 154 private final CharSequence message; 155 AppendCharacters(CharSequence message)156 public AppendCharacters(CharSequence message) { 157 this.message = message; 158 } 159 run()160 public void run() { 161 text.getText().append(message); 162 // try { 163 // logger.write(builder.toString().getBytes()); 164 // } catch (IOException e) { 165 // appendThrowable(e); 166 // } 167 } 168 } 169 } 170