blob: 1dbd0aee52466a0aab904b236132c28ad7e6cb34 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Dan Egnor3d40df32009-11-17 13:36:31 -08002 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080016
17package com.android.server;
18
Dan Egnor3d40df32009-11-17 13:36:31 -080019import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
Dan Egnor492c6ed2010-01-27 14:52:57 -080023import android.content.SharedPreferences;
Dan Egnor3d40df32009-11-17 13:36:31 -080024import android.os.Build;
25import android.os.DropBoxManager;
Dan Egnor492c6ed2010-01-27 14:52:57 -080026import android.os.FileObserver;
Dan Egnor3d40df32009-11-17 13:36:31 -080027import android.os.FileUtils;
Doug Zongker1af33d02010-01-05 11:28:55 -080028import android.os.RecoverySystem;
Dan Egnor3d40df32009-11-17 13:36:31 -080029import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.provider.Settings;
Dan Egnor3d40df32009-11-17 13:36:31 -080031import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Dan Egnor3d40df32009-11-17 13:36:31 -080033import java.io.File;
34import java.io.IOException;
35
36/**
37 * Performs a number of miscellaneous, non-system-critical actions
38 * after the system has finished booting.
39 */
40public class BootReceiver extends BroadcastReceiver {
41 private static final String TAG = "BootReceiver";
42
Dan Egnor492c6ed2010-01-27 14:52:57 -080043 // Negative to read the *last* 64K of the file (per FileUtils.readTextFile)
Dan Egnor42471dd2010-01-07 17:25:22 -080044 private static final int LOG_SIZE = -65536;
45
Dan Egnor492c6ed2010-01-27 14:52:57 -080046 private static final File TOMBSTONE_DIR = new File("/data/tombstones");
47
48 // Keep a reference to the observer so the finalizer doesn't disable it.
49 private static FileObserver sTombstoneObserver = null;
50
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 @Override
Dan Egnor3d40df32009-11-17 13:36:31 -080052 public void onReceive(Context context, Intent intent) {
53 try {
54 logBootEvents(context);
55 } catch (Exception e) {
56 Log.e(TAG, "Can't log boot events", e);
57 }
58
59 try {
60 RecoverySystem.handleAftermath();
61 } catch (Exception e) {
62 Log.e(TAG, "Can't handle recovery aftermath", e);
63 }
64
65 try {
66 // Start the load average overlay, if activated
67 ContentResolver res = context.getContentResolver();
68 if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
69 Intent loadavg = new Intent(context, com.android.server.LoadAverageService.class);
70 context.startService(loadavg);
71 }
72 } catch (Exception e) {
73 Log.e(TAG, "Can't start load average service", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 }
75 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076
Dan Egnor492c6ed2010-01-27 14:52:57 -080077 private void logBootEvents(Context ctx) throws IOException {
78 final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
79 final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
80 final String props = new StringBuilder()
81 .append("Build: ").append(Build.FINGERPRINT).append("\n")
82 .append("Hardware: ").append(Build.BOARD).append("\n")
83 .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
84 .append("Radio: ").append(Build.RADIO).append("\n")
85 .append("Kernel: ")
86 .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
87 .toString();
Dan Egnor3d40df32009-11-17 13:36:31 -080088
Dan Egnor492c6ed2010-01-27 14:52:57 -080089 if (db == null || prefs == null) return;
Dan Egnor3d40df32009-11-17 13:36:31 -080090
91 if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
92 String now = Long.toString(System.currentTimeMillis());
93 SystemProperties.set("ro.runtime.firstboot", now);
Dan Egnor492c6ed2010-01-27 14:52:57 -080094 db.addText("SYSTEM_BOOT", props);
95 addFileToDropBox(db, prefs, props, "/proc/last_kmsg", "SYSTEM_LAST_KMSG");
96 addFileToDropBox(db, prefs, props, "/cache/recovery/log", "SYSTEM_RECOVERY_LOG");
97 addFileToDropBox(db, prefs, props, "/data/dontpanic/apanic_console", "APANIC_CONSOLE");
98 addFileToDropBox(db, prefs, props, "/data/dontpanic/apanic_threads", "APANIC_THREADS");
Dan Egnor3d40df32009-11-17 13:36:31 -080099 } else {
Dan Egnor492c6ed2010-01-27 14:52:57 -0800100 db.addText("SYSTEM_RESTART", props);
Dan Egnor3d40df32009-11-17 13:36:31 -0800101 }
102
Dan Egnor492c6ed2010-01-27 14:52:57 -0800103 // Scan existing tombstones (in case any new ones appeared)
104 File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
105 for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
106 addFileToDropBox(db, prefs, props, tombstoneFiles[i].getPath(), "SYSTEM_TOMBSTONE");
107 }
108
109 // Start watching for new tombstone files; will record them as they occur.
110 // This gets registered with the singleton file observer thread.
111 sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
112 @Override
113 public void onEvent(int event, String path) {
114 try {
115 String filename = new File(TOMBSTONE_DIR, path).getPath();
116 addFileToDropBox(db, prefs, props, filename, "SYSTEM_TOMBSTONE");
117 } catch (IOException e) {
118 Log.e(TAG, "Can't log tombstone", e);
119 }
120 }
121 };
122
123 sTombstoneObserver.startWatching();
Dan Egnor3d40df32009-11-17 13:36:31 -0800124 }
125
Dan Egnor492c6ed2010-01-27 14:52:57 -0800126 private static void addFileToDropBox(
127 DropBoxManager db, SharedPreferences prefs,
128 String headers, String filename, String tag) throws IOException {
129 if (!db.isTagEnabled(tag)) return; // Logging disabled
Dan Egnor3d40df32009-11-17 13:36:31 -0800130
131 File file = new File(filename);
132 long fileTime = file.lastModified();
133 if (fileTime <= 0) return; // File does not exist
134
Dan Egnor492c6ed2010-01-27 14:52:57 -0800135 long lastTime = prefs.getLong(filename, 0);
Dan Egnor3d40df32009-11-17 13:36:31 -0800136 if (lastTime == fileTime) return; // Already logged this particular file
Dan Egnor492c6ed2010-01-27 14:52:57 -0800137 prefs.edit().putLong(filename, fileTime).commit();
Dan Egnor42471dd2010-01-07 17:25:22 -0800138
Dan Egnor492c6ed2010-01-27 14:52:57 -0800139 StringBuilder report = new StringBuilder(headers).append("\n");
140 report.append(FileUtils.readTextFile(file, LOG_SIZE, "[[TRUNCATED]]\n"));
Dan Egnor42471dd2010-01-07 17:25:22 -0800141 db.addText(tag, report.toString());
Dan Egnor492c6ed2010-01-27 14:52:57 -0800142 Log.i(TAG, "Logging " + filename + " to DropBox (" + tag + ")");
Dan Egnor3d40df32009-11-17 13:36:31 -0800143 }
144}