美文网首页
Android之dropbox 分析

Android之dropbox 分析

作者: 锄禾豆 | 来源:发表于2022-02-18 09:11 被阅读0次

    简介

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

    adb查询

    adb shell dumpsys dropbox
    

    app接口

    源码
    10.0
    
    1.DropBoxManager dropbox = (DropBoxManager) getSystemService(Context.DROPBOX_SERVICE)
    例如,dropbox.addText 可实现把需要记录的数据丢给dropbox进行存储
    
    2.监听广播android.intent.action.DROPBOX_ENTRY_ADDED,可知系统发生了异常
    注意权限:android.permission.READ_LOGS  -- 平台签名或priv-app
    

    dropbox启动

    1.SystemServer:run。SystemServer启动服务
    private void startOtherServices() {
        ···
        mSystemServiceManager.startService(DropBoxManagerService.class);
        ···
    }
    
    2.DropBoxManagerService继承SystemService,启动顺序:构造方法 -->onStart
        a)构造方法
        public DropBoxManagerService(final Context context, File path) {
            super(context);
            mDropBoxDir = path;//dropbox路径/data/system/dropbox
            mContentResolver = getContext().getContentResolver();
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == MSG_SEND_BROADCAST) {
                        getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.SYSTEM,
                                android.Manifest.permission.READ_LOGS);
                    }
                }
            };
        }
    
        b)onStart启动
        public void onStart() {
            // 监听低内存,保证dropbox不占用更多空间
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
            getContext().registerReceiver(mReceiver, filter);
    
            mContentResolver.registerContentObserver(
                Settings.Global.CONTENT_URI, true,
                new ContentObserver(new Handler()) {
                    @Override
                    public void onChange(boolean selfChange) {
                        mReceiver.onReceive(getContext(), (Intent) null);
                    }
                });
    
            //注册dropbox服务
            publishBinderService(Context.DROPBOX_SERVICE, mStub);
        }
    
    3.接口运用,发送广播DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED
    dropbox.add
    
         public void add(DropBoxManager.Entry entry) {
            ···
            try {
                ···
                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);
                }
                ···
                mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent));
            } catch (IOException e) {
                Slog.e(TAG, "Can't write: " + tag, e);
            } finally {
                IoUtils.closeQuietly(output);
                IoUtils.closeQuietly(input);
                entry.close();
                if (temp != null) temp.delete();
            }
        }  
    

    dropbox日志路径:/data/system/dropbox

    C:\Users\99418>adb shell ls -al /data/system/dropbox
    total 432
    drwx------  2 system system  4096 2021-12-23 06:02 .
    drwxrwxr-x 16 system system  4096 2021-12-23 06:01 ..
    -rw-------  1 system system   335 2022-01-25 14:40 SYSTEM_BOOT@1640210494810.txt
    -rw-------  1 system system   334 2022-01-25 15:05 SYSTEM_BOOT@1640210494823.txt
    -rw-------  1 system system   334 2021-12-23 06:01 SYSTEM_BOOT@1640210496077.txt
    -rw-------  1 system system 19264 2022-01-25 14:40 SYSTEM_RECOVERY_KMSG@1640210494811.txt.gz
    -rw-------  1 system system 19191 2022-01-25 15:05 SYSTEM_RECOVERY_KMSG@1640210494824.txt.gz
    -rw-------  1 system system  5661 2022-01-25 14:40 SYSTEM_RECOVERY_LOG@1640210494809.txt.gz
    -rw-------  1 system system  5076 2022-01-25 15:05 SYSTEM_RECOVERY_LOG@1640210494822.txt.gz
    -rw-------  1 system system    30 2022-01-25 14:40 storage_trim@1640210494803.txt
    -rw-------  1 system system  4192 2022-01-25 14:40 system_app_strictmode@1640210494804.txt.gz
    

    记录的系统错误
    1.系统正常启动后的自检工作
    1)SYSTEM_BOOT
    开机一次,记录一次

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

    3)SYSTEM_LAST_KMSG
    kernel异常。
    pstore是persistent storage的缩写,内核发生异常通过此把异常日志记录下来,方便定位问题。
    ramoops指的是采用ram保存oops信息(kernel 异常信息)的一个功能,利用pstore技术实现。

    kernel异常信息保存地:
    panic
    /proc/last_kmsg
    
    oops
    /sys/fs/pstore/console-ramoops
    /sys/fs/pstore/console-ramoops-0
    

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

    5)SYSTEM_RECOVERY_LOG/SYSTEM_RECOVERY_KMSG
    SYSTEM_RECOVERY_KMSG:recovery kerenl日志
    SYSTEM_RECOVERY_LOG:recovery 升级或恢复出厂设置等等日志

    6)SYSTEM_FSCK
    文件系统完整性校验日志

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

    BootReceiver.java
        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) {
                db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
            }
    
            String lastKmsgFooter = "";
            if (bootReason != null) {
                lastKmsgFooter = new StringBuilder(512)
                    .append("\n")
                    .append("Boot info:\n")
                    .append("Last boot reason: ").append(bootReason).append("\n")
                    .toString();
            }
    
            HashMap<String, Long> timestamps = readTimestamps();
    
            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())
                // kernel panic日志,例如异常重启
                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");
                
                //recovery日志。例如OTA升级或恢复出厂设置的时候
                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");
                
                //kernel日志的查漏补缺备份
                addAuditErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_AUDIT");
            } else {
                if (db != null) db.addText("SYSTEM_RESTART", headers);
            }
            // log always available fs_stat last so that logcat collecting tools can wait until
            // fs_stat to get all file system metrics.
            logFsShutdownTime();
            logFsMountTime();
            //fsck文件系统校验日志收集
            //fsck(file system consistency check)是Unix和类Unix系统上用于检查文件系统完整性的工具
            addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
            logSystemServerShutdownTimeMetrics();
    
            // Scan existing tombstones (in case any new ones appeared)
            //native进程崩溃日志收集
            File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
            for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
                if (tombstoneFiles[i].isFile()) {
                    addFileToDropBox(db, timestamps, headers, tombstoneFiles[i].getPath(),
                            LOG_SIZE, "SYSTEM_TOMBSTONE");
                }
            }
    
            writeTimestamps(timestamps);
    
            // Start watching for new tombstone files; will record them as they occur.
            // This gets registered with the singleton file observer thread.
            // /data/tombstones目录监听收集
            sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) {
                @Override
                public void onEvent(int event, String path) {
                    HashMap<String, Long> timestamps = readTimestamps();
                    try {
                        File file = new File(TOMBSTONE_DIR, path);
                        if (file.isFile() && file.getName().startsWith("tombstone_")) {
                            addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
                                    TAG_TOMBSTONE);
                        }
                    } catch (IOException e) {
                        Slog.e(TAG, "Can't log tombstone", e);
                    }
                    writeTimestamps(timestamps);
                }
            };
    
            sTombstoneObserver.startWatching();
        }
    

    2.java/native crash。-- crash/native_crash
    java/native层异常的区分在于eventType:crash/native_crash

    ActivityManagerService
        void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
                ApplicationErrorReport.CrashInfo crashInfo) {
            //event事件的日志记录:EventLogTags.AM_CRASH --> am_crash
            EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                    UserHandle.getUserId(Binder.getCallingUid()), processName,
                    r == null ? -1 : r.info.flags,
                    crashInfo.exceptionClassName,
                    crashInfo.exceptionMessage,
                    crashInfo.throwFileName,
                    crashInfo.throwLineNumber);
    
            ···
            //加入到dropbox
            addErrorToDropBox(
                    eventType, r, processName, null, null, null, null, null, null, crashInfo);
            //其他业务处理
            mAppErrors.crashApplication(r, crashInfo);
        }
    
    java层:handleApplicationCrashInner("crash", r, processName, crashInfo);
    native层: mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
    

    3.anr 异常。-- anr
    这里涉及广播、Service、Provider等组件的anr以及触摸按键事件的anr

    ProcessRecord
        void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
                String parentShortComponentName, WindowProcessController parentProcess,
                boolean aboveSystem, String annotation) {
            ···
            //event事件的日志记录:EventLogTags.AM_ANR --> am_anr
            EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
                        annotation);
            ···
            //加入到dropbox
            mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
                    parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
            ···
        }
    

    4.wtf(What a Terrible Failure)。--- wtf
    android.util.Log.wtf(String, String),应用可调用布局异常点

    ActivityManagerService
    
        ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, IBinder app, String tag,
                final ApplicationErrorReport.CrashInfo crashInfo) {
            final ProcessRecord r = findAppProcess(app, "WTF");
            final String processName = app == null ? "system_server"
                    : (r == null ? "unknown" : r.processName);
            //event事件的日志记录:EventLogTags.AM_WTF --> am_wtf
            EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
                    processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
            ···
            //加入到dropbox
            addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo);
    
            return r;
        }
    注意:
    当系统设置Settings.Global.WTF_IS_FATAL为1时,发送wtf可kill应用
    

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

    ActivityManagerService
    
        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);
            });
        } 
    

    6.lowmem。低内存报告

    ActivityManagerService
        final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
            // If there are no longer any background processes running,
            // and the app that died was not running instrumentation,
            // then tell everyone we are now low on memory.
            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);
            ···
        }
    

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

    WatchDog
        public void run() {
            ···
            while (true) {
                ···
                //event事件的日志记录:EventLogTags.WATCHDOG --> watchdog
                EventLog.writeEvent(EventLogTags.WATCHDOG, name.isEmpty() ? subject : name);
                ···
                /// M: WDT debug enhancement
                /// need to wait the AEE dumps all info, then kill system server @{
                // Try to add the error to the dropbox, but assuming that the ActivityManager
                // itself may be deadlocked.  (which has happened, causing this statement to
                // deadlock and the watchdog as a whole to be ineffective)
                Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
                        public void run() {
                            //加入到dropbox
                            if (mActivity != null) {
                                mActivity.addErrorToDropBox(
                                        "watchdog", null, "system_server", null, null, null,
                                        name.isEmpty() ? subject : name, cpuInfo, 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) {}
    
                ···
            }
        }
    

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

    NetworkStatsService
        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());
            }
        }
        
    NetworkStatsRecorder
        private static final String TAG_NETSTATS_DUMP = "netstats_dump";
    
        private void recoverFromWtf() {
            if (DUMP_BEFORE_DELETE) {
                ···
                mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
            }
            ···
        }
    

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

        // 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);
            }
            ···
        }
    

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

    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);
                ···
                }
                ···
            });
        ···
    }
    

    4)network_watchlist_report
    NetworkWatchlistService

    WatchlistLoggingHandler
    
        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);
                    }
                } else {
                    ···
                }
                ···
            } finally {
                ···
            }
        }
        
        private void addEncodedReportToDropBox(byte[] encodedReport) {
            mDropBoxManager.addData(DROPBOX_TAG, encodedReport, 0);
        }
    

    5)incident
    frameworks/base/cmds/incidentd

    Broadcaster.cpp
    Status status = dropbox->addFile(String16("incident"), readFd, 0);
    

    6)keymaster
    system/security/keystore

    operation_proto_handler.cpp
        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);
    
    key_proto_handler.cpp
        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);
    

    参考学习

    http://xiaocong.github.io/blog/2012/11/21/to-introduce-android-dropboxmanager-service/
    http://huaqianlee.github.io/2020/11/13/Android/pstore/
    http://tjtech.me/analyze-pstore-ramoops-in-android-kernel.html
    https://blog.csdn.net/zangdongming/article/details/37729315
    https://skytoby.github.io/2019/fstrim/
    

    相关文章

      网友评论

          本文标题:Android之dropbox 分析

          本文链接:https://www.haomeiwen.com/subject/hugjlrtx.html