在system_server启动的过程中,系统对System.out进行了重定向,以便于让其输出到log中,这个是怎么实现的呢?
在ZygoteInit.java中有
/*
* Pass the remaining arguments to SystemServer.
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
里面调用到redirectLogStreams方法
public static void redirectLogStreams() {
System.out.close();
System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
System.err.close();
System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
}
查看AndroidPrintStream
class AndroidPrintStream extends LoggingPrintStream {
private final int priority;
private final String tag;
/**
* Constructs a new logging print stream.
*
* @param priority from {@link android.util.Log}
* @param tag to log
*/
public AndroidPrintStream(int priority, String tag) {
if (tag == null) {
throw new NullPointerException("tag");
}
this.priority = priority;
this.tag = tag;
}
protected void log(String line) {
Log.println(priority, tag, line);
}
再查看LoggingPrintStream
里面定义了很多print方法
@Override
public synchronized void print(String str) {
builder.append(str);
flush(false);
}
@Override
public synchronized void print(boolean bool) {
builder.append(bool);
}
@Override
public synchronized void println() {
flush(true);
}
@Override
public synchronized void println(char[] charArray) {
builder.append(charArray);
flush(true);
}
@Override
public synchronized void println(char ch) {
builder.append(ch);
flush(true);
}
@Override
public synchronized void println(double dnum) {
builder.append(dnum);
flush(true);
}
@Override
public synchronized void println(float fnum) {
builder.append(fnum);
flush(true);
}
调用flush方法进行输出,
private void flush(boolean completely) {
int length = builder.length();
int start = 0;
int nextBreak;
// Log one line for each line break.
while (start < length
&& (nextBreak = builder.indexOf("\n", start)) != -1) {
log(builder.substring(start, nextBreak));
start = nextBreak + 1;
}
if (completely) {
// Log the remainder of the buffer.
if (start < length) {
log(builder.substring(start));
}
builder.setLength(0);
} else {
// Delete characters leading up to the next starting point.
builder.delete(0, start);
}
}
关键写log的地方是log方法
protected abstract void log(String line);
在重定向之后,由于有System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
System.out.println(“hello”)会调用AndroidPrintStream的println方法,继续调用到其log方法,
protected void log(String line) {
Log.println(priority, tag, line);
}
这里成功的调用到了Log类的println方法来写log了。这是一种李代桃僵的方法。
Log.java中有
public static int println(int priority, String tag, String msg) {
return println_native(LOG_ID_MAIN, priority, tag, msg);
}
System.out的类设计很灵活,扩展性好,所以就可以采用这样的方式来进行替换式的重定向了。
而命令logwrapper则是从底层进行重定向实现来把输出写到log中