Android开发这么久你竟然还不知道Dropbox?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/conconbenben/article/details/102550977

Android DropBox 是 Android 用来持续化存储系统数据的一个管理类,主要用于记录 Android 运行过程中, 内核, 系统进程, 用户进程等出现严重问题时的 log, 可以认为这是一个可持续存储的系统级别的 logcat。

本文主要从以下几个方面阐述Android Dropbox。

1.什么是Android Dropbox

Android Dropbox 是 Android 在 Froyo(API level 8) 引入的用来持续化存储系统数据的机制。主要用于记录 Android 运行过程中, 内核, 系统进程, 用户进程等出现严重问题时的 log, 可以认为这是一个可持续存储的系统级别的 logcat。

相关文件记录存储目录:/data/system/dropbox

2.Dropbox源码

主要源码(基于N版本代码:http://androidxref.com/7.0.0_r1/):

/frameworks/base/core/java/android/os/DropBoxManager.java

/frameworks/base/services/core/java/com/android/server/DropBoxManagerService.java

接下来对源码进行初步分析。(备注:因为篇幅原因,源码中...是我省略无关代码)

a.Dropbox的启动流程

作为android系统服务,其启动方式和其他android服务基本一致。

系统启动过程中SystemServer.java中的startOtherServices()方法中启动
private void startOtherServices() {...    mSystemServiceManager.startService(DropBoxManagerService.class);...}

DropBoxManagerService的构造函数:

public DropBoxManagerService(final Context context) {    this(context, new File("/data/system/dropbox"));}

可以看出dropbox文件存储的目录是:/data/system/dropbox

再就是需要关注DropBoxManagerService中add和dump方法:

      private final IDropBoxManagerService.Stub mStub = new IDropBoxManagerService.Stub() {          @Override          public void add(DropBoxManager.Entry entry) {              DropBoxManagerService.this.add(entry);          }        ...          @Override          public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {              DropBoxManagerService.this.dump(fd, pw, args);          }      };

DropBoxManager进程通讯时写数据都是通过这个add方法将数据写入到存储目录,通过dump来采集记录数据的。

这里重点提下add方法:

public void add(DropBoxManager.Entry entry) {      ...          final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);          dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);          dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);          if (!mBooted) {              dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);          }          // Call sendBroadcast after returning from this call to avoid deadlock. In particular          // the caller may be holding the WindowManagerService lock but sendBroadcast requires a          // lock in ActivityManagerService. ActivityManagerService has been caught holding that          // very lock while waiting for the WindowManagerService lock.          mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent));      ...}

可以发现:在dropbox在日志存储时会发送系统广播:

DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED

所以我们可以针对这个做一些系统定制,如获取dropbox中的日志以确认相关问题。

另外,DropBoxManagerService中数据dump和add的一些控制数据需了解下:

private static final int DEFAULT_AGE_SECONDS = 3 * 86400;private static final int DEFAULT_MAX_FILES = 1000;private static final int DEFAULT_QUOTA_KB = 5 * 1024;private static final int DEFAULT_QUOTA_PERCENT = 10;private static final int DEFAULT_RESERVE_PERCENT = 10;private static final int QUOTA_RESCAN_MILLIS = 5000;

DEFAULT_AGE_SECONDS = 3 * 86400:文件最长可存活时长为3天 

DEFAULT_MAX_FILES = 1000:最大dropbox文件个数为1000 

DEFAULT_QUOTA_KB = 5 * 1024:分配dropbox空间的最大值5M

DEFAULT_QUOTA_PERCENT = 10:是指dropbox目录最多可占用空间比例10% 

DEFAULT_RESERVE_PERCENT = 10:是指dropbox不可使用的存储空间比例10% 

QUOTA_RESCAN_MILLIS = 5000:重新扫描retrim时长为5s

上面这些都是默认值,完全可以通过设置content://settings/global数据库对应项来修改。

DropBoxManager是可以供其系统服务直接调用的类。

final DropBoxManager dbox = (DropBoxManager)mContext.getSystemService(Context.DROPBOX_SERVICE);

例如,拿ActivityManagerService中,设备应用出现crash时,报错信息栈就会记录到dropbox目录,下面详细介绍下应用出现crash后日志记录到dropbox的过程。

首先:应用在crash后,ActivityManagerService会处理对应的消息:

HANDLE_APPLICATION_CRASH_TRANSACTION

      case HANDLE_APPLICATION_CRASH_TRANSACTION: {          data.enforceInterface(IActivityManager.descriptor);          IBinder app = data.readStrongBinder();          ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);          handleApplicationCrash(app, ci);          reply.writeNoException();          return true;      }

handleApplicationCrash实现了处理appcrash的流程:

可以看到 addErrorToDropBox方法:

public void addErrorToDropBox(String eventType,         ProcessRecord process, String processName, ActivityRecord activity,         ActivityRecord parent, String subject,         final String report, final File dataFile,         final ApplicationErrorReport.CrashInfo crashInfo) {        ...             dbox.addText(dropboxTag, sb.toString());        ...}

代码:dbox.addText(dropboxTag, sb.toString()); 就是调用的DropBoxManager中的addText方法

public void addText(String tag, String data) {    try {        mService.add(new Entry(tag, 0, data));    } catch (RemoteException e) {        if (e instanceof TransactionTooLargeException                && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {            Log.e(TAG, "App sent too much data, so it was ignored", e);            return;        }        throw e.rethrowFromSystemServer();    }}

addText实际是调用DropBoxManagerService中add方法最终将crash的trace信息写入dropbox目录。

3.dropbox中记录的文件有哪些呢?

下图是项目中从dropbox目录pull出来的一个目录截图:

可以看到每个文件格式命名都是:processClass _ eventType@时间戳[.txt|txt.gz].

processClass列举:system_server, system_app, data_app; 

eventType列举:分为crash anr watchdog wtf strict_mode lowmem

netstats_error Kernel Panic SYSTEM_BOOT SYSTEM_RESTART 

BATTERY_DISCHARGE_INFO SYSTEM_TOMBSTONE;

其中@前面部分及dropbox写入的tag。

如列举部分tag含义: 

system_app_anr:系统app无响应 

system_app_crash:系统app进程崩溃 

system_server_native_crash system进程native出现崩溃 

system_server_wtf:system进程发生严重错误 

system_server_lowmem:system进程内存不足 

4.如何利用DropboxManager

a.利用 DropBoxManager 来记录需要相对持久化存储的错误日志信息

优点:自动抓错, 避免人为因素而产生的错误遗漏

b.错误自动上报

可以利用dropbox每生成新的记录, Dropbox 就会发送广播:

DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED

app可以接收监听改广播获取指定的数据文件内容,内容发送到指定的服务器或邮箱完成错误自动上报。

                                                          

猜你喜欢

转载自blog.csdn.net/conconbenben/article/details/102550977