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