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

Commit 3d40df33 authored by Dan Egnor's avatar Dan Egnor
Browse files

Add boot events (SYSTEM_LAST_KMSG and friends) to the dropbox.

Optimize DropBoxManagerService.dump() a bit.
parent a57632fe
Loading
Loading
Loading
Loading
+95 −27
Original line number Original line Diff line number Diff line
/*
/*
**
 * Copyright (C) 2009 The Android Open Source Project
** Copyright 2007, The Android Open Source Project
 *
**
 * Licensed under the Apache License, Version 2.0 (the "License");
** Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
** you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at
** You may obtain a copy of the License at 
 *
**
 *      http://www.apache.org/licenses/LICENSE-2.0
**     http://www.apache.org/licenses/LICENSE-2.0 
 *
**
 * Unless required by applicable law or agreed to in writing, software
** Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
** distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and
** See the License for the specific language governing permissions and 
 * limitations under the License.
** limitations under the License.
 */
 */


package com.android.server;
package com.android.server;


import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.provider.Settings;
import android.provider.Settings;
import android.util.Log;

import com.android.internal.os.RecoverySystem;

import java.io.File;
import java.io.IOException;

/**
 * Performs a number of miscellaneous, non-system-critical actions
 * after the system has finished booting.
 */
public class BootReceiver extends BroadcastReceiver {
    private static final String TAG = "BootReceiver";


public class BootReceiver extends BroadcastReceiver
{
    @Override
    @Override
    public void onReceive(Context context, Intent intent)
    public void onReceive(Context context, Intent intent) {
    {
        try {
        Intent service = new Intent(context, com.android.server.LoadAverageService.class);
            logBootEvents(context);
        } catch (Exception e) {
            Log.e(TAG, "Can't log boot events", e);
        }

        try {
            RecoverySystem.handleAftermath();
        } catch (Exception e) {
            Log.e(TAG, "Can't handle recovery aftermath", e);
        }

        try {
            // Start the load average overlay, if activated
            ContentResolver res = context.getContentResolver();
            ContentResolver res = context.getContentResolver();
        boolean shown = Settings.System.getInt(
            if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
                res, Settings.System.SHOW_PROCESSES, 0) != 0;
                Intent loadavg = new Intent(context, com.android.server.LoadAverageService.class);
        if (shown) {
                context.startService(loadavg);
            context.startService(service);
            }
            }
        } catch (Exception e) {
            Log.e(TAG, "Can't start load average service", e);
        }
        }
    }
    }


    private void logBootEvents(Context context) throws IOException {
        DropBoxManager db = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);

        String build =
                "Build: " + Build.FINGERPRINT + "\nKernel: " +
                FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n");

        if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
            String now = Long.toString(System.currentTimeMillis());
            SystemProperties.set("ro.runtime.firstboot", now);
            if (db != null) db.addText("SYSTEM_BOOT", build);
        } else {
            if (db != null) db.addText("SYSTEM_RESTART", build);
            return;  // Subsequent boot, don't log kernel boot log
        }

        ContentResolver cr = context.getContentResolver();
        logBootFile(cr, db, "/cache/recovery/log", "SYSTEM_RECOVERY_LOG");
        logBootFile(cr, db, "/data/dontpanic/last_kmsg", "SYSTEM_LAST_KMSG");
        logBootFile(cr, db, "/data/dontpanic/apanic_console", "APANIC_CONSOLE");
        logBootFile(cr, db, "/data/dontpanic/apanic_threads", "APANIC_THREADS");
    }

    private void logBootFile(ContentResolver cr, DropBoxManager db, String filename, String tag)
            throws IOException {
        if (cr == null || db == null || !db.isTagEnabled(tag)) return;  // Logging disabled

        File file = new File(filename);
        long fileTime = file.lastModified();
        if (fileTime <= 0) return;  // File does not exist

        String setting = "logfile:" + filename;
        long lastTime = Settings.Secure.getLong(cr, setting, 0);
        if (lastTime == fileTime) return;  // Already logged this particular file

        db.addFile(tag,
                ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY),
                DropBoxManager.IS_TEXT);
    }
}
+42 −40
Original line number Original line Diff line number Diff line
@@ -23,12 +23,13 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.net.Uri;
import android.os.Debug;
import android.os.DropBoxManager;
import android.os.DropBoxManager;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor;
import android.os.StatFs;
import android.os.StatFs;
import android.os.SystemClock;
import android.os.SystemClock;
import android.provider.Settings;
import android.provider.Settings;
import android.text.format.DateFormat;
import android.text.format.Time;
import android.util.Log;
import android.util.Log;


import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.os.IDropBoxManagerService;
@@ -56,8 +57,6 @@ import java.util.zip.GZIPOutputStream;
/**
/**
 * Implementation of {@link IDropBoxManagerService} using the filesystem.
 * Implementation of {@link IDropBoxManagerService} using the filesystem.
 * Clients use {@link DropBoxManager} to access this service.
 * Clients use {@link DropBoxManager} to access this service.
 *
 * {@hide}
 */
 */
public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
    private static final String TAG = "DropBoxManagerService";
    private static final String TAG = "DropBoxManagerService";
@@ -67,6 +66,8 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
    private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
    private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
    private static final int QUOTA_RESCAN_MILLIS = 5000;
    private static final int QUOTA_RESCAN_MILLIS = 5000;


    private static final boolean PROFILE_DUMP = false;

    // TODO: This implementation currently uses one file per entry, which is
    // TODO: This implementation currently uses one file per entry, which is
    // inefficient for smallish entries -- consider using a single queue file
    // inefficient for smallish entries -- consider using a single queue file
    // per tag (or even globally) instead.
    // per tag (or even globally) instead.
@@ -257,6 +258,9 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
            return;
            return;
        }
        }


        if (PROFILE_DUMP) Debug.startMethodTracing("/data/trace/dropbox.dump");

        Formatter out = new Formatter();
        boolean doPrint = false, doFile = false;
        boolean doPrint = false, doFile = false;
        ArrayList<String> searchArgs = new ArrayList<String>();
        ArrayList<String> searchArgs = new ArrayList<String>();
        for (int i = 0; args != null && i < args.length; i++) {
        for (int i = 0; args != null && i < args.length; i++) {
@@ -265,53 +269,51 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
            } else if (args[i].equals("-f") || args[i].equals("--file")) {
            } else if (args[i].equals("-f") || args[i].equals("--file")) {
                doFile = true;
                doFile = true;
            } else if (args[i].startsWith("-")) {
            } else if (args[i].startsWith("-")) {
                pw.print("Unknown argument: ");
                out.format("Unknown argument: %s\n", args[i]);
                pw.println(args[i]);
            } else {
            } else {
                searchArgs.add(args[i]);
                searchArgs.add(args[i]);
            }
            }
        }
        }


        pw.format("Drop box contents: %d entries", mAllFiles.contents.size());
        out.format("Drop box contents: %d entries\n", mAllFiles.contents.size());
        pw.println();


        if (!searchArgs.isEmpty()) {
        if (!searchArgs.isEmpty()) {
            pw.print("Searching for:");
            out.format("Searching for:");
            for (String a : searchArgs) pw.format(" %s", a);
            for (String a : searchArgs) out.format(" %s", a);
            pw.println();
            out.format("\n");
        }
        }


        int numFound = 0;
        int numFound = 0, numArgs = searchArgs.size();
        pw.println();
        Time time = new Time();
        out.format("\n");
        for (EntryFile entry : mAllFiles.contents) {
        for (EntryFile entry : mAllFiles.contents) {
            String date = new Formatter().format("%s.%03d",
            time.set(entry.timestampMillis);
                    DateFormat.format("yyyy-MM-dd kk:mm:ss", entry.timestampMillis),
            String date = time.format("%Y-%m-%d %H:%M:%S");
                    entry.timestampMillis % 1000).toString();

            boolean match = true;
            boolean match = true;
            for (String a: searchArgs) match = match && (date.contains(a) || a.equals(entry.tag));
            for (int i = 0; i < numArgs && match; i++) {
                String arg = searchArgs.get(i);
                match = (date.contains(arg) || arg.equals(entry.tag));
            }
            if (!match) continue;
            if (!match) continue;


            numFound++;
            numFound++;
            pw.print(date);
            out.format("%s.%03d %s", date, entry.timestampMillis % 1000,
            pw.print(" ");
                     entry.tag == null ? "(no tag)" : entry.tag);
            pw.print(entry.tag == null ? "(no tag)" : entry.tag);
            if (entry.file == null) {
            if (entry.file == null) {
                pw.println(" (no file)");
                out.format(" (no file)\n");
                continue;
                continue;
            } else if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
            } else if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
                pw.println(" (contents lost)");
                out.format(" (contents lost)\n");
                continue;
                continue;
            } else {
            } else {
                pw.print((entry.flags & DropBoxManager.IS_GZIPPED) != 0 ? " (comopressed " : " (");
                out.format(" (%s%s, %d bytes)\n",
                pw.print((entry.flags & DropBoxManager.IS_TEXT) != 0 ? "text" : "data");
                        (entry.flags & DropBoxManager.IS_GZIPPED) != 0 ? "compressed " : "",
                pw.format(", %d bytes)", entry.file.length());
                        (entry.flags & DropBoxManager.IS_TEXT) != 0 ? "text" : "data",
                pw.println();
                        entry.file.length());
            }
            }


            if (doFile || (doPrint && (entry.flags & DropBoxManager.IS_TEXT) == 0)) {
            if (doFile || (doPrint && (entry.flags & DropBoxManager.IS_TEXT) == 0)) {
                if (!doPrint) pw.print("    ");
                out.format("%s%s\n", (doPrint ? "" : "    "), entry.file.getPath());
                pw.println(entry.file.getPath());
            }
            }


            if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
            if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
@@ -327,36 +329,36 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
                        for (;;) {
                        for (;;) {
                            int n = r.read(buf);
                            int n = r.read(buf);
                            if (n <= 0) break;
                            if (n <= 0) break;
                            pw.write(buf, 0, n);
                            out.format("%s", new String(buf, 0, n));
                            newline = (buf[n - 1] == '\n');
                            newline = (buf[n - 1] == '\n');
                        }
                        }
                        if (!newline) pw.println();
                        if (!newline) out.format("\n");
                    } else {
                    } else {
                        String text = dbe.getText(70);
                        String text = dbe.getText(70);
                        boolean truncated = (text.length() == 70);
                        boolean truncated = (text.length() == 70);
                        pw.print("    ");
                        out.format("    %s%s\n", text.trim().replace('\n', '/'),
                        pw.print(text.trim().replace('\n', '/'));
                                truncated ? " ..." : "");
                        if (truncated) pw.print(" ...");
                        pw.println();
                    }
                    }
                } catch (IOException e) {
                } catch (IOException e) {
                    pw.print("*** ");
                    out.format("*** %s\n", e.toString());
                    pw.println(e.toString());
                    Log.e(TAG, "Can't read: " + entry.file, e);
                    Log.e(TAG, "Can't read: " + entry.file, e);
                } finally {
                } finally {
                    if (dbe != null) dbe.close();
                    if (dbe != null) dbe.close();
                }
                }
            }
            }


            if (doPrint) pw.println();
            if (doPrint) out.format("\n");
        }
        }


        if (numFound == 0) pw.println("(No entries found.)");
        if (numFound == 0) out.format("(No entries found.)\n");


        if (args == null || args.length == 0) {
        if (args == null || args.length == 0) {
            if (!doPrint) pw.println();
            if (!doPrint) out.format("\n");
            pw.println("Usage: dumpsys dropbox [--print|--file] [YYYY-mm-dd] [HH:MM:SS.SSS] [tag]");
            out.format("Usage: dumpsys dropbox [--print|--file] [YYYY-mm-dd] [HH:MM:SS] [tag]\n");
        }
        }

        pw.write(out.toString());
        if (PROFILE_DUMP) Debug.stopMethodTracing();
    }
    }


    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////