拦截 System.out 以及 System.err

本文介绍了一种方法,通过拦截System.out和System.err,将打印信息输出到指定的文件中,实现日志文件记录。

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

针对System.out 以及 System.err 进行拦截 比如将打印信息 输出到指定的文件:
不如 拦截 Jdk logger 的 ConsoleHandler 或者 logj4j的 ConsoleAppender 时
一下是 demo 代码:

============================================================
package com.bes.graphics;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;

public class SystemErrInterceptor {

private SystemErrInterceptor(){
System.setErr(new SelfPrintStream());
System.setOut(new SelfPrintStream());
}

private static final SystemErrInterceptor instance = new SystemErrInterceptor();

public static final SystemErrInterceptor getInstance(){
return instance;
}


private static class SelfPrintStream extends PrintStream{

public SelfPrintStream(){
super(new SelfOutputStream());
}

@Override
public void print(boolean b) {
log(String.valueOf(b));
}

@Override
public void print(char c) {
log(String.valueOf(c));
}

@Override
public void print(char[] s) {
log(new String(s));
}

@Override
public void print(double d) {
log(String.valueOf(d));
}

@Override
public void print(float f) {
log(String.valueOf(f));
}

@Override
public void print(int i) {
log(String.valueOf(i));
}

@Override
public void print(long l) {
log(String.valueOf(l));
}

@Override
public void print(Object obj) {
log(String.valueOf(obj));
}

@Override
public void print(String s) {
log(s);
}

@Override
public void println() {
log("\n");
}

@Override
public void println(boolean x) {
log(x + "\n");
}

@Override
public void println(char x) {
log(x + "\n");
}

@Override
public void println(char[] x) {
log(new String(x) + "\n");
}

@Override
public void println(double x) {
log(x + "\n");
}

@Override
public void println(float x) {
log(x + "\n");
}

@Override
public void println(int x) {
log(x + "\n");
}

@Override
public void println(long x) {
log(x + "\n");
}

@Override
public void println(Object x) {
log(x + "\n");
}

@Override
public void println(String x) {
log(x + "\n");
}



}


private static class SelfOutputStream extends ByteArrayOutputStream{

@Override
public synchronized void write(byte[] b, int off, int len) {
log(String.valueOf(b));
}

@Override
public synchronized void write(int b) {
log(String.valueOf(b));
}

@Override
public void write(byte[] b) throws IOException {
log(String.valueOf(b));
}

}


/**
* @param obj
*/
private static void log(Object obj){
try{
File f = new File("c:/a.log");
if(!f.exists()){
f.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(f, "rw");
raf.seek(raf.length());
String msg = obj + "\r\n";
raf.write(msg.getBytes("utf-8"));
}catch(Exception ex){
ex.printStackTrace();
}

}

}
03-12 19:05:45.149904 29300 29389 W System.err: java.lang.SecurityException: Not allowed to start service Intent { act=onetrack.action.TRACK_EVENT flg=0x2 pkg=com.miui.analytics (has extras) } without permission com.miui.analytics.onetrack.TRACK_EVENT 03-12 19:05:45.149965 29300 29389 W System.err: at android.app.ContextImpl.startServiceCommon(ContextImpl.java:2041) 03-12 19:05:45.149971 29300 29389 W System.err: at android.app.ContextImpl.startService(ContextImpl.java:2002) 03-12 19:05:45.149992 29300 29389 W System.err: at android.content.ContextWrapper.startService(ContextWrapper.java:866) 03-12 19:05:45.150001 29300 29389 W System.err: at com.android.bluetooth.util.OneTrackInterfaceUtil.track(OneTrackInterfaceUtil.java:212) 03-12 19:05:45.150008 29300 29389 W System.err: at com.android.bluetooth.util.OneTrackInterfaceUtil.trackTwsHeadset(OneTrackInterfaceUtil.java:1380) 03-12 19:05:45.150013 29300 29389 W System.err: at com.android.bluetooth.hfp.HeadsetService.onConnectionStateChangedFromStateMachine(HeadsetService.java:3419) 03-12 19:05:45.150018 29300 29389 W System.err: at com.android.bluetooth.hfp.HeadsetStateMachine$HeadsetStateBase.broadcastConnectionState(HeadsetStateMachine.java:972) 03-12 19:05:45.150023 29300 29389 W System.err: at com.android.bluetooth.hfp.HeadsetStateMachine$HeadsetStateBase.broadcastStateTransitions(HeadsetStateMachine.java:954) 03-12 19:05:45.150030 29300 29389 W System.err: at com.android.bluetooth.hfp.HeadsetStateMachine$Connected.enter(HeadsetStateMachine.java:2035) 03-12 19:05:45.150035 29300 29389 W System.err: at com.android.bluetooth.x.com.android.internal.util.StateMachine$SmHandler.invokeEnterMethods(StateMachine.java:1043) 03-12 19:05:45.150040 29300 29389 W System.err: at com.android.bluetooth.x.com.android.internal.util.StateMachine$SmHandler.performTransitions(StateMachine.java:889) 03-12 19:05:45.150044 29300 29389 W System.err: at com.android.bluetooth.x.com.android.internal.util.StateMachine$SmHandler.handleMessage(StateMachine.java:829) 03-12 19:05:45.150050 29300 29389 W System.err: at android.os.Handler.dispatchMessage(Handler.java:109) 03-12 19:05:45.150056 29300 29389 W System.err: at android.os.Looper.loopOnce(Looper.java:249) 03-12 19:05:45.150061 29300 29389 W System.err: at android.os.Looper.loop(Looper.java:337) 03-12 19:05:45.150065 29300 29389 W System.err: at android.os.HandlerThread.run(HandlerThread.java:85) 03-12 19:05:45.150167 29300 29300 D SilenceDeviceManager: handleMessage: 11解释下这段日志
最新发布
04-09
<think>嗯,我现在需要解释用户提供的这段Android日志。首先,我得仔细看一下日志内容,理解发生了什么事情。用户给出的日志中有一个SecurityException,提示没有权限启动某个服务。让我先分解一下日志的各个部分。 日志开头是时间戳和进程ID,29300和29389,看起来是系统错误信息。然后第一行错误信息是SecurityException,指出不允许启动一个Intent,这个Intent的动作是onetrack.action.TRACK_EVENT,包名是com.miui.analytics,缺少com.miui.analytics.onetrack.TRACK_EVENT权限。 接下来是调用栈,显示从ContextImpl的startServiceCommon方法开始,经过一系列的调用,最终在HeadsetService的onConnectionStateChangedFromStateMachine方法里触发。看起来是蓝牙模块在处理连接状态变化时,尝试通过OneTrackInterfaceUtil发送跟踪事件,但因为没有相应权限被拒绝。 我需要确定这个错误的根本原因。可能的几点是:应用没有声明需要的权限,或者权限属于系统或签名级别,普通应用无法获取。com.miui.analytics可能是小米的统计分析服务,需要特定权限才能调用。而调用方是蓝牙模块的一部分,可能属于系统应用,但可能没有正确声明或获取权限。 另外,这个错误是否会影响用户体验?比如蓝牙连接是否因此失败,还是只是无法记录分析事件?根据调用栈,错误发生在蓝牙服务处理连接状态变化时,但错误可能被捕获处理,可能不会导致功能失效,但会影响数据分析。 解决方案可能需要检查权限声明,或者调用方是否有权限。但如果是系统应用的问题,可能需要厂商修复。普通开发者可能需要避免调用需要特定权限的服务,或者使用其他方法记录事件。 现在需要把这些分析组织成用户能理解的步骤,解释错误原因、涉及组件、可能的影响和解决方法。同时注意使用中文,结构清晰,分点说明。</think>以下是对该Android系统日志的逐步分析: 1. **错误类型定位** 日志核心报错:`java.lang.SecurityException: Not allowed to start service... without permission com.miui.analytics.onetrack.TRACK_EVENT` - 这是一个**权限缺失导致的服务启动失败**问题 - 触发场景:尝试通过隐式Intent启动小米分析服务(`com.miui.analytics`)的追踪事件服务 2. **调用链路还原** 通过堆栈跟踪可还原调用流程: $$ \begin{aligned} &\text{蓝牙服务} \rightarrow \text{HeadsetService} \rightarrow \text{连接状态变更} \\ &\downarrow \\ &\text{OneTrackInterfaceUtil.trackTwsHeadset()} \quad (\text{蓝牙设备事件追踪}) \\ &\downarrow \\ &\text{尝试启动} \quad \text{com.miui.analytics} \quad \text{的TRACK\_EVENT服务} \\ &\downarrow \\ &\text{系统拦截:缺少TRACK\_EVENT权限} \end{aligned} $$ 3. **关键组件解析** | 组件名称 | 作用 | |---------|------| | `com.miui.analytics` | 小米系统级数据分析服务 | | `com.android.bluetooth.hfp` | 蓝牙Hands-Free Profile实现模块 | | `OneTrackInterfaceUtil` | 蓝牙模块与数据分析服务的桥梁类 | 4. **可能原因分析** - **权限声明缺失**:调用方未在AndroidManifest.xml中声明`<uses-permission android:name="com.miui.analytics.onetrack.TRACK_EVENT"/>` - **权限级别限制**:该权限可能被定义为`signature`或`system`级别,普通APP无法获取 - **服务调用方式错误**:尝试通过隐式Intent(`act=onetrack.action.TRACK_EVENT`)启动受保护服务 5. **影响范围评估** - **功能层面**:蓝牙连接状态监控可能缺失部分数据分析,但基础蓝牙功能应正常 - **系统层面**:属于非致命异常,通过`W System.err`警告级别输出 - **用户体验**:普通用户无感知,开发者需关注潜在的数据统计缺失 6. **解决方案建议** - **系统开发者**: 1. 检查小米分析服务的权限声明方式 2. 改用显式Intent绑定服务(若服务允许外部绑定) 3. 申请系统签名使用`signature`级别权限 - **应用开发者**: 1. 避免直接调用系统私有服务 2. 使用官方提供的SDK进行事件追踪 3. 增加异常捕获机制: ```java try { context.startService(intent); } catch (SecurityException e) { Log.w(TAG, "Analytics service unavailable"); } ``` **附加说明**:该错误常见于小米定制系统开发场景,反映系统服务权限管理机制的运行状态。普通应用开发如遇到类似问题,建议优先检查权限声明清单和第三方SDK集成规范。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值