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

本文解析了Android系统中system_server启动过程中的日志重定向实现。通过重写System.out和System.err,利用AndroidPrintStream将输出重定向到Log中。此方法改进了日志记录流程,提升了系统的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

Application: ASD880.exe CoreCLR Version: 9.0.24.52809 .NET Version: 9.0.0 Description: The process was terminated due to an unhandled exception. Exception Info: System.UnauthorizedAccessException: Access to the path is denied. at ASD880.View.SerialPortCommunication.SendDataAsync(Byte[] data) in C:\Users\asd\Desktop\充电头网PD31\ASD880\Page Navigation App\View\Communication.xaml.cs:line 59 at ASD880.View.BatteryMode.executePipeline(JArray jsonArray, Boolean PipeResult, Int32 frequency) in C:\Users\asd\Desktop\充电头网PD31\ASD880\Page Navigation App\View\BatteryMode.xaml.cs:line 1407 at ASD880.View.BatteryMode.ProjectStart_Click(Object sender, RoutedEventArgs e) in C:\Users\asd\Desktop\充电头网PD31\ASD880\Page Navigation App\View\BatteryMode.xaml.cs:line 890 at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.DispatcherOperation.InvokeImpl() at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Threading.DispatcherOperation.Invoke() at System.Windows.Threading.Dispatcher.ProcessQueue() at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at ASD880.App.Main() 分析错误
06-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值