PageRenderTime 60ms CodeModel.GetById 16ms app.highlight 22ms RepoModel.GetById 19ms app.codeStats 0ms

/services/java/com/android/server/BootReceiver.java

https://github.com/aizuzi/platform_frameworks_base
Java | 234 lines | 168 code | 31 blank | 35 comment | 41 complexity | 96381a51bce2c71152cbd63fc23615f4 MD5 | raw file
  1/*
  2 * 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 */
 16
 17package com.android.server;
 18
 19import android.content.BroadcastReceiver;
 20import android.content.Context;
 21import android.content.Intent;
 22import android.content.SharedPreferences;
 23import android.content.pm.IPackageManager;
 24import android.os.Build;
 25import android.os.DropBoxManager;
 26import android.os.FileObserver;
 27import android.os.FileUtils;
 28import android.os.RecoverySystem;
 29import android.os.RemoteException;
 30import android.os.ServiceManager;
 31import android.os.SystemProperties;
 32import android.provider.Downloads;
 33import android.util.Slog;
 34
 35import java.io.File;
 36import java.io.IOException;
 37
 38/**
 39 * Performs a number of miscellaneous, non-system-critical actions
 40 * after the system has finished booting.
 41 */
 42public class BootReceiver extends BroadcastReceiver {
 43    private static final String TAG = "BootReceiver";
 44
 45    // Maximum size of a logged event (files get truncated if they're longer).
 46    // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg.
 47    private static final int LOG_SIZE =
 48        SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536;
 49
 50    private static final File TOMBSTONE_DIR = new File("/data/tombstones");
 51
 52    // The pre-froyo package and class of the system updater, which
 53    // ran in the system process.  We need to remove its packages here
 54    // in order to clean up after a pre-froyo-to-froyo update.
 55    private static final String OLD_UPDATER_PACKAGE =
 56        "com.google.android.systemupdater";
 57    private static final String OLD_UPDATER_CLASS =
 58        "com.google.android.systemupdater.SystemUpdateReceiver";
 59
 60    // Keep a reference to the observer so the finalizer doesn't disable it.
 61    private static FileObserver sTombstoneObserver = null;
 62
 63    @Override
 64    public void onReceive(final Context context, Intent intent) {
 65        // Log boot events in the background to avoid blocking the main thread with I/O
 66        new Thread() {
 67            @Override
 68            public void run() {
 69                try {
 70                    logBootEvents(context);
 71                } catch (Exception e) {
 72                    Slog.e(TAG, "Can't log boot events", e);
 73                }
 74                try {
 75                    boolean onlyCore = false;
 76                    try {
 77                        onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
 78                                "package")).isOnlyCoreApps();
 79                    } catch (RemoteException e) {
 80                    }
 81                    if (!onlyCore) {
 82                        removeOldUpdatePackages(context);
 83                    }
 84                } catch (Exception e) {
 85                    Slog.e(TAG, "Can't remove old update packages", e);
 86                }
 87
 88            }
 89        }.start();
 90    }
 91
 92    private void removeOldUpdatePackages(Context context) {
 93        Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
 94    }
 95
 96    private void logBootEvents(Context ctx) throws IOException {
 97        final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
 98        final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
 99        final String headers = new StringBuilder(512)
100            .append("Build: ").append(Build.FINGERPRINT).append("\n")
101            .append("Hardware: ").append(Build.BOARD).append("\n")
102            .append("Revision: ")
103            .append(SystemProperties.get("ro.revision", "")).append("\n")
104            .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
105            .append("Radio: ").append(Build.RADIO).append("\n")
106            .append("Kernel: ")
107            .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
108            .append("\n").toString();
109
110        String recovery = RecoverySystem.handleAftermath();
111        if (recovery != null && db != null) {
112            db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
113        }
114
115        if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
116            String now = Long.toString(System.currentTimeMillis());
117            SystemProperties.set("ro.runtime.firstboot", now);
118            if (db != null) db.addText("SYSTEM_BOOT", headers);
119
120            // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
121            addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
122                    -LOG_SIZE, "SYSTEM_LAST_KMSG");
123            addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
124                    -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
125            addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
126                    -LOG_SIZE, "APANIC_CONSOLE");
127            addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
128                    -LOG_SIZE, "APANIC_THREADS");
129            addAuditErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_AUDIT");
130            addFsckErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_FSCK");
131        } else {
132            if (db != null) db.addText("SYSTEM_RESTART", headers);
133        }
134
135        // Scan existing tombstones (in case any new ones appeared)
136        File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
137        for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
138            addFileToDropBox(db, prefs, headers, tombstoneFiles[i].getPath(),
139                    LOG_SIZE, "SYSTEM_TOMBSTONE");
140        }
141
142        // Start watching for new tombstone files; will record them as they occur.
143        // This gets registered with the singleton file observer thread.
144        sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
145            @Override
146            public void onEvent(int event, String path) {
147                try {
148                    String filename = new File(TOMBSTONE_DIR, path).getPath();
149                    addFileToDropBox(db, prefs, headers, filename, LOG_SIZE, "SYSTEM_TOMBSTONE");
150                } catch (IOException e) {
151                    Slog.e(TAG, "Can't log tombstone", e);
152                }
153            }
154        };
155
156        sTombstoneObserver.startWatching();
157    }
158
159    private static void addFileToDropBox(
160            DropBoxManager db, SharedPreferences prefs,
161            String headers, String filename, int maxSize, String tag) throws IOException {
162        if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
163
164        File file = new File(filename);
165        long fileTime = file.lastModified();
166        if (fileTime <= 0) return;  // File does not exist
167
168        if (prefs != null) {
169            long lastTime = prefs.getLong(filename, 0);
170            if (lastTime == fileTime) return;  // Already logged this particular file
171            // TODO: move all these SharedPreferences Editor commits
172            // outside this function to the end of logBootEvents
173            prefs.edit().putLong(filename, fileTime).apply();
174        }
175
176        Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
177        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"));
178    }
179
180    private static void addAuditErrorsToDropBox(DropBoxManager db,  SharedPreferences prefs,
181            String headers, int maxSize, String tag) throws IOException {
182        if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
183        Slog.i(TAG, "Copying audit failures to DropBox");
184
185        File file = new File("/proc/last_kmsg");
186        long fileTime = file.lastModified();
187        if (fileTime <= 0) return;  // File does not exist
188
189        if (prefs != null) {
190            long lastTime = prefs.getLong(tag, 0);
191            if (lastTime == fileTime) return;  // Already logged this particular file
192            // TODO: move all these SharedPreferences Editor commits
193            // outside this function to the end of logBootEvents
194            prefs.edit().putLong(tag, fileTime).apply();
195        }
196
197        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
198        StringBuilder sb = new StringBuilder();
199        for (String line : log.split("\n")) {
200            if (line.contains("audit")) {
201                sb.append(line + "\n");
202            }
203        }
204        Slog.i(TAG, "Copied " + sb.toString().length() + " worth of audits to DropBox");
205        db.addText(tag, headers + sb.toString());
206    }
207
208    private static void addFsckErrorsToDropBox(DropBoxManager db,  SharedPreferences prefs,
209            String headers, int maxSize, String tag) throws IOException {
210        boolean upload_needed = false;
211        if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
212        Slog.i(TAG, "Checking for fsck errors");
213
214        File file = new File("/dev/fscklogs/log");
215        long fileTime = file.lastModified();
216        if (fileTime <= 0) return;  // File does not exist
217
218        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
219        StringBuilder sb = new StringBuilder();
220        for (String line : log.split("\n")) {
221            if (line.contains("FILE SYSTEM WAS MODIFIED")) {
222                upload_needed = true;
223                break;
224            }
225        }
226
227        if (upload_needed) {
228            addFileToDropBox(db, prefs, headers, "/dev/fscklogs/log", maxSize, tag);
229        }
230
231        // Remove the file so we don't re-upload if the runtime restarts.
232        file.delete();
233    }
234}