【Android】System.setOut的重定向分析

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”)会调用AndroidPrintStreamprintln方法,继续调用到其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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值