前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android DropBox模块笔记

Android DropBox模块笔记

作者头像
wizzie
发布2022-11-21 15:53:06
3K0
发布2022-11-21 15:53:06
举报
文章被收录于专栏:Android Framework
My Table

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

1. dropbox查看方式

系统服务dropbox以文件形式记录了系统各种异常信息,例如app crash、native crash、anr、kernel panic等等

1.1. ABD dump

adb shell dumpsys dropbox

1.2. 日志文件查看

日志文件存储在/data/system/dropbox

代码语言:javascript
复制
/data/system/dropbox # ls -thl
total 36K
-rw------- 1 system system 2.2K 2022-10-03 18:27 system_server_wtf@1639267200804.txt
-rw------- 1 system system 1.8K 2022-10-03 18:27 system_app_wtf@1639267200803.txt
-rw------- 1 system system 1.6K 2022-10-03 18:27 system_app_strictmode@1639267200802.txt
-rw------- 1 system system 1.8K 2022-10-03 18:27 system_server_strictmode@1639267200801.txt
-rw------- 1 system system 1.3K 2022-10-03 18:27 system_server_strictmode@1639267200800.txt
-rw------- 1 system system 1.3K 2022-10-03 18:27 system_server_strictmode@1639267200799.txt
-rw------- 1 system system 1.2K 2022-10-03 18:27 system_server_strictmode@1639267200798.txt
-rw------- 1 system system 1.2K 2022-10-03 18:27 system_server_strictmode@1639267200797.txt
-rw------- 1 system system 1.2K 2022-10-03 18:27 system_server_strictmode@1639267200796.txt
-rw------- 1 system system 1.8K 2022-10-03 18:27 system_server_strictmode@1639267200795.txt
-rw------- 1 system system 1.5K 2022-10-03 18:27 system_server_strictmode@1639267200793.txt
-rw------- 1 system system 1.5K 2022-10-03 18:27 system_server_strictmode@1639267200794.txt
-rw------- 1 system system 1.2K 2022-10-03 18:27 system_server_strictmode@1639267200791.txt
-rw------- 1 system system 1.5K 2022-10-03 18:27 system_server_strictmode@1639267200792.txt
-rw------- 1 system system 1.8K 2021-12-12 08:59 system_server_wtf@1639270794860.txt
-rw------- 1 system system 1.8K 2021-12-12 08:29 system_server_wtf@1639268994862.txt
-rw------- 1 system system 1.8K 2021-12-12 08:00 system_server_wtf@1639267254499.txt
-rw------- 1 system system  557 2021-12-12 08:00 SYSTEM_BOOT@1639267200805.txt

2. 源码文件

代码语言:javascript
复制
frameworks/base/core/java/android/os/DropBoxManager.java 
frameworks/base/core/java/android/os/DropBoxManager.aidl

frameworks/base/core/java/com/android/internal/os/IDropBoxManagerService.aidl

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

frameworks/base/libs/services/include/android/os/DropBoxManager.h
frameworks/base/libs/services/src/os/DropBoxManager.cpp

3. dropbox服务启动

3.1. systamserver启动服务

dropbox通过systemserver:run启动

frameworks/base/services/java/com/android/server/SystemServer.java - 函数run() —–> 调用函数startOtherServices() —–> 调用类SystemServiceManager的函数startService(),注册到SystemService列表

代码语言:javascript
复制
private void startOtherServices() {
    ...
            traceBeginAndSlog("StartDropBoxManager");
            mSystemServiceManager.startService(DropBoxManagerService.class);
            traceEnd();
    ...
}

在这个startService函数中,做了两件事:(DropBoxManagerService继承SystemService

  1. 调用newInstance(mContext)创建对象,从而会调用DropBoxManagerService构造函数
  2. 调用onStart()函数,即DropBoxManagerService的onStart函数(只是注册dropbox服务)

3.2. 构造函数

先调用上面的构造函数,后调用后面的构造函数

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/DropBoxManagerService.java
   public DropBoxManagerService(final Context context) {
       //创建File对象,并非创建文件
        this(context, new File("/data/system/dropbox"), FgThread.get().getLooper());
    }

    @VisibleForTesting
    public DropBoxManagerService(final Context context, File path, Looper looper) {
        super(context);
        //全局对象,定义private final File mDropBoxDir,此处进行赋值
        mDropBoxDir = path;
        //PS:ContentResolver直译为内容解析器,和ContentProvider成对出现。
        //程序间数据的共享是通过Provider/Resolver进行的。提供数据(内容)的就叫Provider,Resovler提供接口对这个内容进行解读
        mContentResolver = getContext().getContentResolver();
        //创建handler对象
        mHandler = new DropBoxManagerBroadcastHandler(looper);
    }

—-> DropBoxManagerBroadcastHandler是一个私有类,继承Handler,主要用于处理广播消息

代码语言:javascript
复制
   private class DropBoxManagerBroadcastHandler extends Handler {
        static final int MSG_SEND_BROADCAST = 1;
        static final int MSG_SEND_DEFERRED_BROADCAST = 2;
       .....
       //构造函数
        DropBoxManagerBroadcastHandler(Looper looper) {
            super(looper);
        }
        //处理消息函数
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SEND_BROADCAST://正常广播
                    prepareAndSendBroadcast((Intent) msg.obj);
                    break;
                case MSG_SEND_DEFERRED_BROADCAST://延时广播
                    Intent deferredIntent;
                    synchronized (mLock) {
                        deferredIntent = mDeferredMap.remove((String) msg.obj);
                    }
                    if (deferredIntent != null) {
                        prepareAndSendBroadcast(deferredIntent);
                    }
                    break;
            }
        }

        private void prepareAndSendBroadcast(Intent intent) {
            if (!DropBoxManagerService.this.mBooted) {
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            }
            getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM,
                    android.Manifest.permission.READ_LOGS);
        }

3.3. onBootPhase函数

3.3.1. systemserver的startBootPhase()概念

SystemServer启动的服务很多,服务间也会有相互依赖的情况,为了解决依赖的时序问题,SystemServer主要通过分批启动和分阶段启动来处理。 主要利用了SystemServiceManager的startBootPhase()

这些启动阶段会穿插在各项的服务启动序列中。 startBootPhase会去回调用service的onBootPhase方法,对应的servcie才会去执行对应的操作

比如此处dropbox服务,对应的是PHASE_SYSTEM_SERVICES_READY以及启动完成后的PHASE_BOOT_COMPLETED

日志参考:

代码语言:javascript
复制
# logcat |grep -Ei "BootPhase|Starting phase"
01-01 08:00:10.953  2678  2678 I SystemServiceManager: Starting phase 100
01-01 08:00:11.005  2678  2678 W SystemServiceManager: Service com.android.server.display.DisplayManagerService took 52 ms in onBootPhase
10-03 18:27:31.494  2678  2678 I SystemServer: StartBootPhaseLockSettingsReady
10-03 18:27:31.494  2678  2678 I SystemServiceManager: Starting phase 480
10-03 18:27:31.502  2678  2678 D SystemServerTiming: StartBootPhaseLockSettingsReady took to complete: 8ms
//dropbox服务的onBootPhase函数在这个范围执行
10-03 18:27:31.502  2678  2678 I SystemServer: StartBootPhaseSystemServicesReady
10-03 18:27:31.502  2678  2678 I SystemServiceManager: Starting phase 500
10-03 18:27:31.554  2678  2678 D ContextHubSystemService: onBootPhase: PHASE_SYSTEM_SERVICES_READY
10-03 18:27:31.555  2678  2678 D SystemServerTiming: StartBootPhaseSystemServicesReady took to complete: 53ms
10-03 18:27:31.598  2678  2678 I SystemServer: StartBootPhaseDeviceSpecificServicesReady
10-03 18:27:31.598  2678  2678 I SystemServiceManager: Starting phase 520
10-03 18:27:31.598  2678  2678 D SystemServerTiming: StartBootPhaseDeviceSpecificServicesReady took to complete: 0ms
10-03 18:27:31.656  2678  2678 I SystemServiceManager: Starting phase 550
10-03 18:27:31.805  2678  2678 I SystemServiceManager: Starting phase 600
10-03 18:27:31.823  2678  2678 D CarServiceHelper: onBootPhase:600
10-03 18:27:32.935  2678  2749 I SystemServiceManager: Starting phase 1000
10-03 18:27:32.957  2678  2749 D CarServiceHelper: onBootPhase:1000

3.3.2. 调用流程

frameworks/base/services/java/com/android/server/SystemServer.java - startOtherServices()

代码语言:javascript
复制
//PHASE_LOCK_SETTINGS_READY=480
//PHASE_SYSTEM_SERVICES_READY=500
        traceBeginAndSlog("StartBootPhaseLockSettingsReady");
        mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
        traceEnd();

        traceBeginAndSlog("StartBootPhaseSystemServicesReady");
        mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        traceEnd();

—-> SystemServiceManager.java - 调用startBootPhase(final int phase),此处入参phase=500,mCurrentPhase=480,然后将mCurrentPhase赋值为500,再调用service.onBootPhase(mCurrentPhase) —-> SystemService.java - 调用onBootPhase(int phase) —-> DropBoxManagerService.java - 调用父类函数onBootPhase(int phase)

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/DropBoxManagerService.java
    @Override
    public void onBootPhase(int phase) {
        switch (phase) {
            case PHASE_SYSTEM_SERVICES_READY:
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
                getContext().registerReceiver(mReceiver, filter);
                //注册Observer,通过指定Uri可以仅对数据库中感兴趣的数据有变化时,进行监听
                mContentResolver.registerContentObserver(
                    Settings.Global.CONTENT_URI, true,
                    new ContentObserver(new Handler()) {
                        @Override
                        public void onChange(boolean selfChange) {
                            mReceiver.onReceive(getContext(), (Intent) null);
                        }
                    });
                //低优先级(frameworks/base/core/res/res/values/config.xml)
                //config_dropboxLowPriorityBroadcastRateLimitPeriod=2000
                //config_dropboxLowPriorityTags
                getLowPriorityResourceConfigs();
                break;
            //启动完成后设置mBooted属性
            case PHASE_BOOT_COMPLETED:
                mBooted = true;
                break;
        }
    }

3.4. dump函数


4. DropBoxManager上层API接口

4.1. AIDL接口调用流程

  1. frameworks/base/core/java/android/os/DropBoxManager.java定义private final IDropBoxManagerService mService;
  2. frameworks/base/core/java/com/android/internal/os/IDropBoxManagerService.aidl定义接口函数,包含add、isTagEnabled、getNextEntry
  3. frameworks/base/services/core/java/com/android/server/DropBoxManagerService.java - 通过private final IDropBoxManagerService.Stub mStub = new IDropBoxManagerService.Stub() {....实现接口函数

4.2. DropBoxManager addText函数

代码语言:javascript
复制
//DropBoxManager.java
    public void addText(String tag, String data) {
        try {
            //调用IDropBoxManagerService的add函数,到service层
            //入参entry类型
            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();
        }
    }

       /** Create a new Entry with plain text contents. */
        public Entry(String tag, long millis, String text) {
            if (tag == null) throw new NullPointerException("tag == null");
            if (text == null) throw new NullPointerException("text == null");

            mTag = tag;
            mTimeMillis = millis;
            mData = text.getBytes();
            mFileDescriptor = null;
            mFlags = IS_TEXT;
        }

4.3. DropBoxManagerService add函数

代码语言:javascript
复制
//DropBoxManagerService.java
//调用DropBoxManagerService的add函数
 private final IDropBoxManagerService.Stub mStub = new IDropBoxManagerService.Stub() {
        @Override
        public void add(DropBoxManager.Entry entry) {
            DropBoxManagerService.this.add(entry);
        }
        ....
 }

add函数详细代码,从日志看打印:

代码语言:javascript
复制
# logcat |grep -Ei "isTagEnabled"
10-03 18:27:30.993  2678  2748 I DropBoxManagerService: add tag=system_server_strictmode isTagEnabled=true flags=0x2
10-03 18:27:31.050  2678  2748 I DropBoxManagerService: add tag=system_server_strictmode isTagEnabled=true flags=0x2
10-03 18:27:33.509  2678  3459 I DropBoxManagerService: add tag=system_app_wtf isTagEnabled=true flags=0x2
10-03 18:27:34.366  2678  2748 I DropBoxManagerService: add tag=system_app_strictmode isTagEnabled=true flags=0x2
10-03 18:27:36.926  2678  2851 I DropBoxManagerService: add tag=system_server_wtf isTagEnabled=true flags=0x2
12-12 08:00:00.282  2678  3941 I DropBoxManagerService: add tag=SYSTEM_BOOT isTagEnabled=true flags=0x2
12-12 08:00:54.426  2678  2849 I DropBoxManagerService: add tag=system_server_wtf isTagEnabled=true flags=0x2
12-12 08:29:54.778  2678  2849 I DropBoxManagerService: add tag=system_server_wtf isTagEnabled=true flags=0x2
代码语言:javascript
复制
 public void add(DropBoxManager.Entry entry) {
        File temp = null;
        InputStream input = null;
        OutputStream output = null;
        //获取日志tag标签信息
        final String tag = entry.getTag();
        try {
            int flags = entry.getFlags();
            Slog.i(TAG, "add tag=" + tag + " isTagEnabled=" + isTagEnabled(tag)
                    + " flags=0x" + Integer.toHexString(flags));
            if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();
            //调用init函数,主要是创建EntryFile即日志文件  --> new EntryFile(file, mBlockSize)
            //如果文件存在,则调用enrollEntry(entry)
            init();
            //检查tag是否启动
            if (!isTagEnabled(tag)) return;
            //修剪磁盘上的文件以确保它们不会占用太多空间
            long max = trimToFit();
            long lastTrim = System.currentTimeMillis();
            //创建buffer
            byte[] buffer = new byte[mBlockSize];
            input = entry.getInputStream();

            // 首先,在决定是否压缩数据之前,在内存中累积最多一块数据
            int read = 0;
            while (read < buffer.length) {
                int n = input.read(buffer, read, buffer.length - read);
                if (n <= 0) break;
                read += n;
            }

            //如果我们至少有一个块,就压缩它——否则,只需以未压缩的形式写入数据
            //临时文件
            temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp");
            int bufferSize = mBlockSize;
            if (bufferSize > 4096) bufferSize = 4096;
            if (bufferSize < 512) bufferSize = 512;
            FileOutputStream foutput = new FileOutputStream(temp);
            output = new BufferedOutputStream(foutput, bufferSize);
            if (read == buffer.length && ((flags & DropBoxManager.IS_GZIPPED) == 0)) {
                output = new GZIPOutputStream(output);
                flags = flags | DropBoxManager.IS_GZIPPED;
            }

            do {
                //写入buffer数据到文件
                output.write(buffer, 0, read);
                //时间戳判断,以防数据缓慢流入
                long now = System.currentTimeMillis();
                if (now - lastTrim > 30 * 1000) {
                    max = trimToFit();  
                    lastTrim = now;
                }

                read = input.read(buffer);
                //获得最终尺寸测量
                if (read <= 0) {
                    FileUtils.sync(foutput);
                    output.close();  // Get a final size measurement
                    output = null;
                } else {
                    //所以尺寸测量是伪合理的
                    output.flush();  // So the size measurement is pseudo-reasonable
                }

                long len = temp.length();
                if (len > max) {
                    Slog.w(TAG, "Dropping: " + tag + " (" + temp.length() + " > "
                            + max + " bytes)");
                    temp.delete();
                    temp = null;  // Pass temp = null to createEntry() to leave a tombstone
                    break;
                }
            } while (read > 0);
            //将临时文件移动到最终日志文件名并注册
            long time = createEntry(temp, tag, flags);
            temp = null;

            //在此调用返回后调用sendBroadcast以避免死锁。
            //特别是,调用方可能持有WindowManagerService锁,但sendBroadcast需要ActivityManagerService中的锁。
            //ActivityManagerService在等待WindowManagerService锁定时被发现持有该锁定。
            if (mLowPriorityTags != null && mLowPriorityTags.contains(tag)) {
                // Rate limit low priority Dropbox entries
                mHandler.maybeDeferBroadcast(tag, time);
            } else {
                //发送ACTION_DROPBOX_ENTRY_ADDED广播
                //此处会调用 sendMessage(obtainMessage(MSG_SEND_BROADCAST, createIntent(tag, time)))
                mHandler.sendBroadcast(tag, time);
            }
        } .....
    }

4.3.1. ACTION_DROPBOX_ENTRY_ADDED广播

利用dropbox每生成新的记录, Dropbox就会发送广播:DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED

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

利用前提:app要具有系统权限 因为:DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED是保护性广播,且读取系统日志也需要android.Manifest.permission.READ_LOGS权限


4.3.2. DropBoxManagerService中dump和add数据控制定义

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

代码语言:javascript
复制
   private static final int DEFAULT_AGE_SECONDS = 3 * 86400; //文件最长可存活时长为3天 
   //这两个最大文件数,通过AM.java的isLowRamDeviceStatic()控制,即debug.force_low_ram属性(默认false)
    private static final int DEFAULT_MAX_FILES = 1000; //最大dropbox文件个数为1000
    private static final int DEFAULT_MAX_FILES_LOWRAM = 300; //低rom时最大dropbox文件个数为300
    private static final int DEFAULT_QUOTA_KB = 5 * 1024; //分配dropbox空间的最大值5M
    private static final int DEFAULT_QUOTA_PERCENT = 10; //指dropbox目录最多可占用空间比例10% 
    private static final int DEFAULT_RESERVE_PERCENT = 10; //指dropbox不可使用的存储空间比例10% 
    private static final int QUOTA_RESCAN_MILLIS = 5000; //重新扫描retrim时长为5s

4.4. ActivityManagerService应用crash案例

java/native层异常的区分在于eventType:crash/native_crash

  • java层:handleApplicationCrashInner("crash", r, processName, crashInfo);
  • native层: mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);

调用流程:

  • native crash:frameworks/base/services/core/java/com/android/server/am/NativeCrashListener.java - 子线程run()调用mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
  • java crash: frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java - handleApplicationCrash调用handleApplicationCrashInner("crash", r, processName, crashInfo);

—-> ActivityManagerService.java - handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo)调用addErrorToDropBox(eventType, r, processName, null, null, null, null, null, null, crashInfo); —-> ActivityManagerService.java - addErrorToDropBox函数分析

代码语言:javascript
复制
//将一个error错误的详细描述(例如crash、WTF、ANR)写入到drop box中
public void addErrorToDropBox(String eventType,
            ProcessRecord process, String processName, String activityShortComponentName,
            String parentShortComponentName, ProcessRecord parentProcess,
            String subject, final String report, final File dataFile,
            final ApplicationErrorReport.CrashInfo crashInfo) {
        //这绝对不能获取ActivityManagerService锁,
        //否则可以防止看门狗重置系统

        // 获取DropBoxManager服务对象
        if (ServiceManager.getService(Context.DROPBOX_SERVICE) == null) return;
        final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
        ......
        //头部信息,包含进程号、线程好、包名等
        final StringBuilder sb = new StringBuilder(1024);
        appendDropBoxProcessHeaders(process, processName, sb);
        //写入Activity名字、父进程、父Activity、对象、build时间、crash-tag标签等信息到sb对象中
        ......
        //创建一个子线程。在其中执行其余操作,以避免在I/O上阻塞调用程序
        //(在此之后,我们不应该访问AMS内部数据结构
        Thread worker = new Thread("Error dump: " + dropboxTag) {
            @Override
            public void run() {
                .....
                //调用DropBoxManager的addText,传入sb错误信息数据
                dbox.addText(dropboxTag, sb.toString());
            ......
            }
        }
        ......
            }

5. dropbox记录错误信息类型

5.1. 系统正常启动后的自检

5.1.1. SYSTEM_BOOT开机日志记录

日志对应data/system/dropbox:SYSTEM_BOOT@1639267200299.txt

SYSTEM_BOOT一次开机会记录一次

调用方式:

代码语言:javascript
复制
//frameworks/base/core/java/com/android/server/BootReceiver.java
public class BootReceiver extends BroadcastReceiver {
    private static final String TAG = "BootReceiver";
    ....
    @Override
    public void onReceive(final Context context, Intent intent) {
        // Log boot events in the background to avoid blocking the main thread with I/O
        new Thread() {
            @Override
            public void run() {
                try {
                    //调用logBootEvents输出日志信息
                    logBootEvents(context);
                } catch (Exception e) {
                    Slog.e(TAG, "Can't log boot events", e);
                }
                ....
            }
        }
    }
    .....
    private void logBootEvents(Context ctx) throws IOException {
        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
        final String headers = getBootHeadersToLogAndUpdate();
        final String bootReason = SystemProperties.get("ro.boot.bootreason", null);

        String recovery = RecoverySystem.handleAftermath(ctx);
        if (recovery != null && db != null) {
            //调用DropBoxManager的addText函数
            db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
        }
        ....
}

5.1.2. SYSTEM_RESTART系统异常记录

如果system_server在设备运行过程中异常,则会有记录

同上,在frameworks/base/core/java/com/android/server/BootReceiver.java - 函数logBootEvents

根据属性ro.runtime.firstboot值判断

代码语言:javascript
复制
    private void logBootEvents(Context ctx) throws IOException {
        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
        ......
        if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
            ......
        } else {
            if (db != null) db.addText("SYSTEM_RESTART", headers);
        }

5.1.3. SYSTEM_LAST_KMSG内核异常记录

kernel异常

  • pstore是persistent storage的缩写,内核发生异常通过此把异常日志记录下来,方便定位问题
  • ramoops指的是采用ram保存oops信息(kernel 异常信息)的一个功能,利用pstore技术实现
代码语言:javascript
复制
kernel异常信息保存地:
panic
/proc/last_kmsg

oops
/sys/fs/pstore/console-ramoops
/sys/fs/pstore/console-ramoops-0

源码位置同上,在BootReceiver.java

代码语言:javascript
复制
    private void logBootEvents(Context ctx) throws IOException {
        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
        ......
        if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
            if (StorageManager.inCryptKeeperBounce()) {
                // Encrypted, first boot to get PIN/pattern/password so data is tmpfs
                // Don't set ro.runtime.firstboot so that we will do this again
                // when data is properly mounted
            } else {
                String now = Long.toString(System.currentTimeMillis());
                SystemProperties.set("ro.runtime.firstboot", now);
            }
            if (db != null) db.addText("SYSTEM_BOOT", headers);

            // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
            //各个节点的日志信息
            addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
                    "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
            addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
                    "/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG");
            addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
                    "/sys/fs/pstore/console-ramoops-0", -LOG_SIZE, "SYSTEM_LAST_KMSG");
            addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE,
                    "SYSTEM_RECOVERY_LOG");
            addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
                    -LOG_SIZE, "SYSTEM_RECOVERY_KMSG");
            addAuditErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_AUDIT");
        } else {
            if (db != null) db.addText("SYSTEM_RESTART", headers);
        }

5.1.4. SYSTEM_TOMBSTONE记录

TOMBSTONE是Android用来记录native进程崩溃的core dump日志, 系统服务在启动完成后会增加一个Observer来侦测tombstone日志文件的变化, 每当生成新的tombstone文件, 就会增加一条 SYSTEM_TOMBSTONE记录到DropBoxManager中

源码位置同上文件

5.1.5. SYSTEM_RECOVERY_LOG/SYSTEM_RECOVERY_KMSG

代码语言:javascript
复制
SYSTEM_RECOVERY_KMSG:recovery kerenl日志
SYSTEM_RECOVERY_LOG:recovery 升级或恢复出厂设置等等日志

源码位置同上文件


5.1.6. SYSTEM_FSCK

文件系统完整性校验日志

源码位置同上文件


5.1.7. SYSTEM_AUDIT

kernel异常信息的查漏补缺日志

源码位置同上文件


5.2. ANR异常收集

涉及广播、Service、Provider等组件的anr以及触摸按键事件的ANR(正常也可以在data/anr查看)

代码流程: frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java - appNotResponding调用mService.addErrorToDropBox("anr", this, processName, activityShortComponentName, parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null); —-> ActivityManagerService.java - addErrorToDropBox

接下来的流程同上面Crash流程


5.3. wtf(What a Terrible Failure)

android.util.Log.wtf(String, String),应用可调用布局异常点

代码流程同上面Crash流程

PS:当系统设置Settings.Global.WTF_IS_FATAL为1时,发送wtf可kill应用


5.4. 严格模式—**_strictmode

严格模式,主要为性能监测使用

StrictMode (严格模式), 顾名思义, 就是在比正常模式检测得更严格, 通常用来监测不应当在主线程执行的网络, 文件等操作。任何 StrictMode违例都会被 ActivityManagerService 在 DropBoxManager 中记录为一次strict_mode违例。

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void handleApplicationStrictModeViolation(
        IBinder app,
        int penaltyMask,
        StrictMode.ViolationInfo info) {
    ···
    //需要满足触发dropbox的条件
    if ((penaltyMask & StrictMode.PENALTY_DROPBOX) != 0) {
        Integer stackFingerprint = info.hashCode();
        boolean logIt = true;
        ···
        if (logIt) {//执行dropbox业务
            logStrictModeViolationToDropBox(r, info);
        }
    }

    ···
}

private void logStrictModeViolationToDropBox(
        ProcessRecord process,
        StrictMode.ViolationInfo info) {
    if (info == null) {
        return;
    }
    //收集信息,tag:***_strictmode
    ···省略···
    
    //加入到dropbox
    IoThread.getHandler().post(() -> {
        dbox.addText(dropboxTag, res);
    });
} 

5.5. lowmem—低内存报告

代码语言:javascript
复制
final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
    //如果不再有任何后台进程在运行,并且死亡的应用程序没有运行检测,那么告诉所有人我们现在的内存不足
    if (!mProcessList.haveBackgroundProcessLocked()) {
        ···
        //event事件的日志记录:EventLogTags.AM_LOW_MEMORY --> am_low_memory
        EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mProcessList.getLruSizeLocked());
        ···
        if (doReport) {//如果报告,最后调入reportMemUsage
            Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
            mHandler.sendMessage(msg);
        }
        ···
    }
}

void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
    ···
    addErrorToDropBox("lowmem", null, "system_server", null,
            null, null, tag.toString(), dropBuilder.toString(), null, null);
    ···
}

5.6. watchdog

如果 WatchDog 监测到系统进程(system_server)出现问题, 会增加一条watchdog记录到DropBoxManager中, 并终止系统进程的执行

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/Watchdog.java
@Override
    public void run() {
            ......

            // 尝试将错误添加到下拉框中,但假设ActivityManager本身可能已死锁。
            //(发生了这种情况,导致此语句死锁,整个监视器无效)
            Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
                    public void run() {
                        // If a watched thread hangs before init() is called, we don't have a
                        // valid mActivity. So we can't log the error to dropbox.
                        if (mActivity != null) {
                            mActivity.addErrorToDropBox(
                                    "watchdog", null, "system_server", null, null, null,
                                    subject, null, stack, null);
                        }
                        StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
                    }
                };
            dropboxThread.start();
            try {
                dropboxThread.join(2000);  // wait up to 2 seconds for it to return.
            } catch (InterruptedException ignored) {}
            ....
    }

5.7. 其他

5.7.1. netstats_error/netstats_dump

NetworkStatsService负责收集并持久化存储网络状态的统计数据, 当遇到明显的网络状态错误时, 它会增加一条netstats_error记录到DropBoxManager

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/net/NetworkStatsService.java
private static final String TAG_NETSTATS_ERROR = "netstats_error";

private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
    @Override
    public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
            int rightIndex, String cookie) {
        Log.w(TAG, "Found non-monotonic values; saving to dropbox");

        // record error for debugging
        final StringBuilder builder = new StringBuilder();
        builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex
                + "] - right[" + rightIndex + "]\n");
        builder.append("left=").append(left).append('\n');
        builder.append("right=").append(right).append('\n');

        mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
                builder.toString());
    }

    @Override
    public void foundNonMonotonic(
            NetworkStats stats, int statsIndex, String cookie) {
        Log.w(TAG, "Found non-monotonic values; saving to dropbox");

        final StringBuilder builder = new StringBuilder();
        builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n");
        builder.append("stats=").append(stats).append('\n');

        mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
                builder.toString());
    }
}
代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/net/NetworkStatsRecorder.java
private static final String TAG_NETSTATS_DUMP = "netstats_dump";

private void recoverFromWtf() {
    if (DUMP_BEFORE_DELETE) {
        ···
        mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
    }
    ···
}

5.7.2. BATTERY_DISCHARGE_INFO

BatteryService负责检测充电状态, 并更新手机电池信息. 当遇到明显的discharge事件, 它会增加一条BATTERY_DISCHARGE_INFO记录到DropBoxManager

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/BatteryService.java
// TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed.
private void logBatteryStatsLocked() {
    ···
    DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
    ···
    try {
        ··· 
        // add dump file to drop box
        db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
    }
    ···
}

5.7.3. storage_benchmark/storage_trim

StorageManagerService负责存储设备管理,例如sdcard或usb mass storage fstrim提升磁盘性能,缓解Android卡顿

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/StorageManagerService.java
private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
private static final String TAG_STORAGE_TRIM = "storage_trim";
    
public void benchmark(String volId, IVoldTaskListener listener) {
    ···
    mVold.benchmark(volId, new IVoldTaskListener.Stub() {
        ···
        final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
        dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
                    + " " + ident + " " + create + " " + run + " " + destroy);
    ···
    });
}

public void fstrim(int flags, IVoldTaskListener listener) {
    ···
    mVold.fstrim(flags, new IVoldTaskListener.Stub() {
        @Override
        public void onStatus(int status, PersistableBundle extras) {
            ···
            final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
                dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);
            ···
            }
            ···
        });
    ···
}

5.7.4. network_watchlist_report

NetworkWatchlistService::WatchlistLoggingHandler

代码语言:javascript
复制
//frameworks/base/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
private static final String DROPBOX_TAG = "network_watchlist_report";

private void tryAggregateRecords(long lastRecordTime) {
    try {
        ···
        if (mDropBoxManager != null && mDropBoxManager.isTagEnabled(DROPBOX_TAG)) {
            ···
            if (encodedResult != null) {
                addEncodedReportToDropBox(encodedResult);
            }
        ......
    }
}

private void addEncodedReportToDropBox(byte[] encodedReport) {
    mDropBoxManager.addData(DROPBOX_TAG, encodedReport, 0);
}

5.7.5. incident

时间驱动机制库

代码语言:javascript
复制
//frameworks/base/cmds/incidentd/src/Broadcaster.cpp
status_t Broadcaster::send_to_dropbox(const sp<ReportFile>& file,
        const IncidentReportArgs& args) {
    status_t err;

    sp<DropBoxManager> dropbox = new DropBoxManager();
    if (dropbox == nullptr) {
        ALOGW("Can't reach dropbox now, so we won't be able to write the incident report to there");
        return NO_ERROR;
    }
    .....
    // Takes ownership of readFd.
    Status status = dropbox->addFile(String16("incident"), readFd, 0);
    ......
    return NO_ERROR;
}

5.7.6. keymaster

由硬件支持的密钥库。 Android Keystore API 和底层 Keymaster HAL 提供了一套基本的但足以满足需求的加密基元,以便使用访问受控且由硬件支持的密钥实现相关协议。 Keymaster HAL 是由原始设备制造商 (OEM) 提供的动态加载库,Keystore 服务使用它来提供由硬件支持的加密服务。为了确保安全性,HAL 实现不会在用户空间乃至内核空间中执行任何敏感操作。敏感操作会被分配给通过某个内核接口连接的安全处理器

代码语言:javascript
复制
//system/security/keystore/operation_proto_handler.cpp 
void OperationProtoHandler::uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
    ......
android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
size_t size = opConfigEvents.ByteSize();
auto data = std::make_unique<uint8_t[]>(size);
opConfigEvents.SerializeWithCachedSizesToArray(data.get());
dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
.....
}
代码语言:javascript
复制
//system/security/keystore/key_proto_handler.cpp
void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams, bool wasCreationSuccessful) {
    .....
android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager());
keyConfig.set_was_creation_successful(wasCreationSuccessful);
size_t size = keyConfig.ByteSize();
auto data = std::make_unique<uint8_t[]>(size);
keyConfig.SerializeWithCachedSizesToArray(data.get());
dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
....
}

6. 参考

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. dropbox查看方式
    • 1.1. ABD dump
      • 1.2. 日志文件查看
      • 2. 源码文件
      • 3. dropbox服务启动
        • 3.1. systamserver启动服务
          • 3.2. 构造函数
            • 3.3. onBootPhase函数
              • 3.3.1. systemserver的startBootPhase()概念
              • 3.3.2. 调用流程
            • 3.4. dump函数
            • 4. DropBoxManager上层API接口
              • 4.1. AIDL接口调用流程
                • 4.2. DropBoxManager addText函数
                  • 4.3. DropBoxManagerService add函数
                    • 4.3.1. ACTION_DROPBOX_ENTRY_ADDED广播
                    • 4.3.2. DropBoxManagerService中dump和add数据控制定义
                  • 4.4. ActivityManagerService应用crash案例
                  • 5. dropbox记录错误信息类型
                    • 5.1. 系统正常启动后的自检
                      • 5.1.1. SYSTEM_BOOT开机日志记录
                      • 5.1.2. SYSTEM_RESTART系统异常记录
                      • 5.1.3. SYSTEM_LAST_KMSG内核异常记录
                      • 5.1.4. SYSTEM_TOMBSTONE记录
                      • 5.1.5. SYSTEM_RECOVERY_LOG/SYSTEM_RECOVERY_KMSG
                      • 5.1.6. SYSTEM_FSCK
                      • 5.1.7. SYSTEM_AUDIT
                    • 5.2. ANR异常收集
                      • 5.3. wtf(What a Terrible Failure)
                        • 5.4. 严格模式—**_strictmode
                          • 5.5. lowmem—低内存报告
                            • 5.6. watchdog
                              • 5.7. 其他
                                • 5.7.1. netstats_error/netstats_dump
                                • 5.7.2. BATTERY_DISCHARGE_INFO
                                • 5.7.3. storage_benchmark/storage_trim
                                • 5.7.4. network_watchlist_report
                                • 5.7.5. incident
                                • 5.7.6. keymaster
                            • 6. 参考
                            相关产品与服务
                            文件存储
                            文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档