Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b799838d authored by Keun-young Park's avatar Keun-young Park
Browse files

log fs_stat from fs_mgr and mount_all time

- fs_mgr reports fs_stat int value during bootup when mounting
  an ext4 partition.
- This includes information like:
  if previous shutdown was clean
  if e2fsck has fixed any fs issue
  if any mounting or quota related operations has failed.
- Each information is set as flag. Flag definitions are avaiable from
  FsStatFlags in system/core/fs_mgr/fs_mgr.cpp
- log ro.boottime.init.mount_all.[early|default|late] which represent
  time duration for each mount stage. Depending on device's config, some of
  these stages may not exist. So do not log if value is 0, which means not existing.

bug: 32246772
bug: 35949600
bug: 35329915

Test: manual, check log after boot-up.

Change-Id: I4ceca88776119d88d5352d6793be122e82688279
parent 48a58bae
Loading
Loading
Loading
Loading
+52 −8
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;

@@ -46,6 +48,8 @@ import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -83,6 +87,12 @@ public class BootReceiver extends BroadcastReceiver {
    private static final File lastHeaderFile = new File(
            Environment.getDataSystemDirectory(), LAST_HEADER_FILE);

    // example: fs_stat,/dev/block/platform/soc/by-name/userdata,0x5
    private static final String FS_STAT_PATTERN = "fs_stat,[^,]*/([^/,]+),(0x[0-9a-fA-F]+)";
    // ro.boottime.init.mount_all. + postfix for mount_all duration
    private static final String[] MOUNT_DURATION_PROPS_POSTFIX =
            new String[] { "early", "default", "late" };

    @Override
    public void onReceive(final Context context, Intent intent) {
        // Log boot events in the background to avoid blocking the main thread with I/O
@@ -200,10 +210,11 @@ public class BootReceiver extends BroadcastReceiver {
            addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
                    -LOG_SIZE, "SYSTEM_RECOVERY_KMSG");
            addAuditErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_AUDIT");
            addFsckErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
        } else {
            if (db != null) db.addText("SYSTEM_RESTART", headers);
        }
        addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
        logFsMountTime();

        // Scan existing tombstones (in case any new ones appeared)
        File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
@@ -297,11 +308,14 @@ public class BootReceiver extends BroadcastReceiver {
        db.addText(tag, headers + sb.toString());
    }

    private static void addFsckErrorsToDropBox(DropBoxManager db,
    private static void addFsckErrorsToDropBoxAndLogFsStat(DropBoxManager db,
            HashMap<String, Long> timestamps, String headers, int maxSize, String tag)
            throws IOException {
        boolean upload_needed = false;
        if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
        boolean uploadEnabled = true;
        if (db == null || !db.isTagEnabled(tag)) {
            uploadEnabled = false;
        }
        boolean uploadNeeded = false;
        Slog.i(TAG, "Checking for fsck errors");

        File file = new File("/dev/fscklogs/log");
@@ -310,14 +324,21 @@ public class BootReceiver extends BroadcastReceiver {

        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
        StringBuilder sb = new StringBuilder();
        for (String line : log.split("\n")) {
        Pattern pattern = Pattern.compile(FS_STAT_PATTERN);
        for (String line : log.split("\n")) { // should check all lines
            if (line.contains("FILE SYSTEM WAS MODIFIED")) {
                upload_needed = true;
                break;
                uploadNeeded = true;
            } else if (line.contains("fs_stat")){
                Matcher matcher = pattern.matcher(line);
                if (matcher.find()) {
                    handleFsckFsStat(matcher);
                } else {
                    Slog.w(TAG, "cannot parse fs_stat:" + line);
                }
            }
        }

        if (upload_needed) {
        if (uploadEnabled && uploadNeeded ) {
            addFileToDropBox(db, timestamps, headers, "/dev/fscklogs/log", maxSize, tag);
        }

@@ -325,6 +346,29 @@ public class BootReceiver extends BroadcastReceiver {
        file.delete();
    }

    private static void logFsMountTime() {
        for (String propPostfix : MOUNT_DURATION_PROPS_POSTFIX) {
            int duration = SystemProperties.getInt("ro.boottime.init.mount_all." + propPostfix, 0);
            if (duration != 0) {
                MetricsLogger.histogram(null, "boot_mount_all_duration_" + propPostfix, duration);
            }
        }
    }

    private static void handleFsckFsStat(Matcher match) {
        String partition = match.group(1);
        int stat;
        try {
            stat = Integer.decode(match.group(2));
        } catch (NumberFormatException e) {
            Slog.w(TAG, "cannot parse fs_stat: partition:" + partition + " stat:" + match.group(2));
            return;
        }

        MetricsLogger.histogram(null, "boot_fs_stat_" + partition, stat);
        Slog.i(TAG, "fs_stat, partition:" + partition + " stat:" + match.group(2));
    }

    private static HashMap<String, Long> readTimestamps() {
        synchronized (sFile) {
            HashMap<String, Long> timestamps = new HashMap<String, Long>();