监控android binder size
我们知道binder是android中跨进程通信的一大亮点,但binder通信时如果待传数据较大,可能会出现binder call失败,那怎么才能监控传输多大的size呢。
frameworks/base/core/java/android/os/Binder.java#661687 private boolean execTransact(int code, long dataObj, long replyObj,688 int flags) {689 Parcel data = Parcel.obtain(dataObj);690 Parcel reply = Parcel.obtain(replyObj);......702 res = onTransact(code, data, reply, flags);......723 checkParcel(this, code, reply, "Unreasonably large binder reply buffer");724 reply.recycle();725 data.recycle();
看到binder服务端里面有个checkParcel,这个就是关键,每次java层面收到的binder call 都会调用此方法,无论成功还是失败,那么接收端也是同理,其code如下,发送请求之前就会调用checkParcel
frameworks/base/core/java/android/os/Binder.java#750749 public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {750 Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
既然发送和接收都会调用checkParcel,那么问题就归一了,看下其实现
658 static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {660 if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {663 StringBuilder sb = new StringBuilder();664 sb.append(msg);665 sb.append(": on ");......679 Slog.wtfStack(TAG, sb.toString());680 }
只是一个if条件,然后封装字符串,输出wtf的log。如此而已,那么,手机厂商们就可以修改这个if条件了。随你怎么造。
例如:
1,设置版本控制,例如debug版本开、release版本关闭;
2,通过属性动态设置care的size,如将persist属性的值赋值给CHECK_PARCEL_SIZE,就可以完成动态监控;
到此就了解完毕了。
下面简单说下WTF log的输出,只是调用了Log.wtf,而且指定了输出到system
frameworks/base/core/java/android/util/Slog.java22public final class Slog {......97 public static int wtfStack(String tag, String msg) {98 return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true); //可见log是输出到system log99 }
继续看下源码
frameworks/base/core/java/android/util/Log.java301 static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack,302 boolean system) {303 TerribleFailure what = new TerribleFailure(msg, tr);304 // Only mark this as ERROR, do not use ASSERT since that should be305 // reserved for cases where the system is guaranteed to abort.306 // The onTerribleFailure call does not always cause a crash.307 int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr); //类的一个静态方法,输出到system log308 sWtfHandler.onTerribleFailure(tag, what, system); //通知系统309 return bytes;310 }
先看下printlns的方法
393 public static int printlns(int bufID, int priority, String tag, String msg,394 Throwable tr) {395 ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);396 // Acceptable buffer size. Get the native buffer size, subtract two zero terminators,397 // and the length of the tag.398 // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It399 // is too expensive to compute that ahead of time.400 int bufferSize = PreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD // Base.401 - 2 // Two terminators.402 - (tag != null ? tag.length() : 0) // Tag length.403 - 32; // Some slack.404 // At least assume you can print *some* characters (tag is not too large).405 bufferSize = Math.max(bufferSize, 100);406407 LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize);408409 lbbw.println(msg);410411 if (tr != null) {412 // This is to reduce the amount of log spew that apps do in the non-error413 // condition of the network being unavailable.414 Throwable t = tr;415 while (t != null) {416 if (t instanceof UnknownHostException) {417 break;418 }419 if (t instanceof DeadSystemException) {420 lbbw.println("DeadSystemException: The system died; "421 + "earlier logs will point to the root cause");422 break;423 }424 t = t.getCause();425 }426 if (t == null) {427 tr.printStackTrace(lbbw);428 }429 }430431 lbbw.flush();432433 return logWriter.getWritten();434 }
在了解下sWtfHandler,这是一个匿名内部类
108 private static TerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {109 public void onTerribleFailure(String tag, TerribleFailure what, boolean system) {110 RuntimeInit.wtf(tag, what, system);111 }
又回到了RuntimeInit,真是麻烦啊
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java332 public static void wtf(String tag, Throwable t, boolean system) {333 try {334 if (ActivityManager.getService().handleApplicationWtf(335 mApplicationObject, tag, system,336 new ApplicationErrorReport.ParcelableCrashInfo(t))) {337 // The Activity Manager has already written us off -- now exit.338 Process.killProcess(Process.myPid());339 System.exit(10);340 }
我的天呢,一个简单的wtf log,还会binder call到AMS,调用了AMS的handleApplicationWtf,而且如果返回值为true,还好kill掉当前进程。
简单说下ApplicationErrorReport.ParcelableCrashInfo(t),其继承了Parcel,所以可以通过binder 传输
frameworks/base/core/java/android/app/ApplicationErrorReport.java464 public static class ParcelableCrashInfo extends CrashInfo implements Parcelable {.....474 public ParcelableCrashInfo(Throwable tr) {475 super(tr);476 }
还是看handleApplicationWtf吧
15078 public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system,15079 final ApplicationErrorReport.ParcelableCrashInfo crashInfo) {15080 final int callingUid = Binder.getCallingUid();15081 final int callingPid = Binder.getCallingPid();1508215083 if (system) {15084 // If this is coming from the system, we could very well have low-level15085 // system locks held, so we want to do this all asynchronously. And we15086 // never want this to become fatal, so there is that too. //如果来自系统,则跑消息给主线程执行15087 mHandler.post(new Runnable() {15088 @Override public void run() {15089 handleApplicationWtfInner(callingUid, callingPid, app, tag, crashInfo);15090 }15091 }); //返回false,所以wtf log后,一般不会进程退出15092 return false;15093 }15094 //非系统的话,直接binder线程执行15095 final ProcessRecord r = handleApplicationWtfInner(callingUid, callingPid, app, tag,15096 crashInfo);1509715098 final boolean isFatal = Build.IS_ENG || Settings.Global15099 .getInt(mContext.getContentResolver(), Settings.Global.WTF_IS_FATAL, 0) != 0;15100 final boolean isSystem = (r == null) || r.persistent;1510115102 if (isFatal && !isSystem) { //只有这一种情况wtf log会导致进程挂掉,即非系统报的wtf,且不是工程版本,设置中也未设置wtf15103 mAppErrors.crashApplication(r, crashInfo);15104 return true;15105 } else {15106 return false;15107 }15108 }
通过handleApplicationWtfInner,可以看到dropbox中有log输出,而且event也有一行输出。
15110 ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, IBinder app, String tag,15111 final ApplicationErrorReport.CrashInfo crashInfo) {15112 final ProcessRecord r = findAppProcess(app, "WTF");15113 final String processName = app == null ? "system_server"15114 : (r == null ? "unknown" : r.processName);15115 //event log有一行输出15116 EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,15117 processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);15118 //将wtf写入dropbox15119 addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);1512015121 return r;15122 }
event log类似如下:
08-01 13:24:25.717 1000 1268 1302 I am_wtf : [0,1268,system_server,-1,PackageManager.DexOptimizer,Well this is awkward; package com.xgame.app.XgameApplication had UID -1]
dropbox log路径:data/system/dropbox,文件名称格式:system_server_wtf@×××××××.txt
完毕。
更多相关文章
- Android夜间模式实现(系统自带)
- Android 获取应用的icon、名字、版本号
- 在Android Service中弹出系统全屏对话框
- 【笔记】Android高版本Apache HTTPClient变更兼容和HTTP请求
- Android系统开发—对View的clipChildren,clipToPadding,importan
- Android系统信息获取