Extract tombstone tracking to a separate service.
In preparation for making tombstones available to apps, extract the
tombstone tracking code from BootReceiver to its own service.
Bug: http://b/159164105
Test: manual
Change-Id: I789f41f12a8be312b6e966226646c4ec4becc1aa
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index ac2361d..c46d708 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -23,7 +23,6 @@
import android.os.Build;
import android.os.DropBoxManager;
import android.os.Environment;
-import android.os.FileObserver;
import android.os.FileUtils;
import android.os.RecoverySystem;
import android.os.RemoteException;
@@ -75,7 +74,6 @@
SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536;
private static final int GMSCORE_LASTK_LOG_SIZE = 196608;
- private static final File TOMBSTONE_DIR = new File("/data/tombstones");
private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE";
// The pre-froyo package and class of the system updater, which
@@ -86,9 +84,6 @@
private static final String OLD_UPDATER_CLASS =
"com.google.android.systemupdater.SystemUpdateReceiver";
- // Keep a reference to the observer so the finalizer doesn't disable it.
- private static FileObserver sTombstoneObserver = null;
-
private static final String LOG_FILES_FILE = "log-files.xml";
private static final AtomicFile sFile = new AtomicFile(new File(
Environment.getDataSystemDirectory(), LOG_FILES_FILE), "log-files");
@@ -154,7 +149,7 @@
Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
}
- private String getPreviousBootHeaders() {
+ private static String getPreviousBootHeaders() {
try {
return FileUtils.readTextFile(lastHeaderFile, 0, null);
} catch (IOException e) {
@@ -162,7 +157,7 @@
}
}
- private String getCurrentBootHeaders() throws IOException {
+ private static String getCurrentBootHeaders() throws IOException {
return new StringBuilder(512)
.append("Build: ").append(Build.FINGERPRINT).append("\n")
.append("Hardware: ").append(Build.BOARD).append("\n")
@@ -176,7 +171,7 @@
}
- private String getBootHeadersToLogAndUpdate() throws IOException {
+ private static String getBootHeadersToLogAndUpdate() throws IOException {
final String oldHeaders = getPreviousBootHeaders();
final String newHeaders = getCurrentBootHeaders();
@@ -248,38 +243,27 @@
logFsMountTime();
addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
logSystemServerShutdownTimeMetrics();
-
- // Scan existing tombstones (in case any new ones appeared)
- File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
- for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
- if (tombstoneFiles[i].isFile()) {
- addFileToDropBox(db, timestamps, headers, tombstoneFiles[i].getPath(),
- LOG_SIZE, "SYSTEM_TOMBSTONE");
- }
- }
-
writeTimestamps(timestamps);
+ }
- // Start watching for new tombstone files; will record them as they occur.
- // This gets registered with the singleton file observer thread.
- sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) {
- @Override
- public void onEvent(int event, String path) {
- HashMap<String, Long> timestamps = readTimestamps();
- try {
- File file = new File(TOMBSTONE_DIR, path);
- if (file.isFile() && file.getName().startsWith("tombstone_")) {
- addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
- TAG_TOMBSTONE);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Can't log tombstone", e);
- }
- writeTimestamps(timestamps);
- }
- };
-
- sTombstoneObserver.startWatching();
+ /**
+ * Add a tombstone to the DropBox.
+ *
+ * @param ctx Context
+ * @param tombstone path to the tombstone
+ */
+ public static void addTombstoneToDropBox(Context ctx, File tombstone) {
+ final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
+ final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
+ HashMap<String, Long> timestamps = readTimestamps();
+ try {
+ final String headers = getBootHeadersToLogAndUpdate();
+ addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE,
+ TAG_TOMBSTONE);
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't log tombstone", e);
+ }
+ writeTimestamps(timestamps);
}
private static void addLastkToDropBox(
@@ -764,7 +748,7 @@
}
}
- private void writeTimestamps(HashMap<String, Long> timestamps) {
+ private static void writeTimestamps(HashMap<String, Long> timestamps) {
synchronized (sFile) {
final FileOutputStream stream;
try {
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
new file mode 100644
index 0000000..110666f
--- /dev/null
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.FileObserver;
+import android.os.Handler;
+
+import com.android.server.BootReceiver;
+import com.android.server.ServiceThread;
+
+import java.io.File;
+
+/**
+ * A class to manage native tombstones.
+ */
+public final class NativeTombstoneManager {
+ private static final String TAG = NativeTombstoneManager.class.getSimpleName();
+
+ private static final File TOMBSTONE_DIR = new File("/data/tombstones");
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final TombstoneWatcher mWatcher;
+
+ NativeTombstoneManager(Context context) {
+ mContext = context;
+
+ final ServiceThread thread = new ServiceThread(TAG + ":tombstoneWatcher",
+ THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+ thread.start();
+ mHandler = thread.getThreadHandler();
+
+ mWatcher = new TombstoneWatcher();
+ mWatcher.startWatching();
+ }
+
+ void onSystemReady() {
+ // Scan existing tombstones.
+ mHandler.post(() -> {
+ final File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
+ for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
+ if (tombstoneFiles[i].isFile()) {
+ handleTombstone(tombstoneFiles[i]);
+ }
+ }
+ });
+ }
+
+ private void handleTombstone(File path) {
+ final String filename = path.getName();
+ if (!filename.startsWith("tombstone_")) {
+ return;
+ }
+
+ BootReceiver.addTombstoneToDropBox(mContext, path);
+ }
+
+ class TombstoneWatcher extends FileObserver {
+ TombstoneWatcher() {
+ // Tombstones can be created either by linking an O_TMPFILE temporary file (CREATE),
+ // or by moving a named temporary file in the same directory on kernels where O_TMPFILE
+ // isn't supported (MOVED_TO).
+ super(TOMBSTONE_DIR, FileObserver.CREATE | FileObserver.MOVED_TO);
+ }
+
+ @Override
+ public void onEvent(int event, @Nullable String path) {
+ mHandler.post(() -> {
+ handleTombstone(new File(TOMBSTONE_DIR, path));
+ });
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManagerService.java b/services/core/java/com/android/server/os/NativeTombstoneManagerService.java
new file mode 100644
index 0000000..cb3c7ff0
--- /dev/null
+++ b/services/core/java/com/android/server/os/NativeTombstoneManagerService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.content.Context;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+/**
+ * Service that tracks and manages native tombstones.
+ *
+ * @hide
+ */
+public class NativeTombstoneManagerService extends SystemService {
+ private static final String TAG = "NativeTombstoneManagerService";
+
+ private NativeTombstoneManager mManager;
+
+ public NativeTombstoneManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mManager = new NativeTombstoneManager(getContext());
+ LocalServices.addService(NativeTombstoneManager.class, mManager);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mManager.onSystemReady();
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 203de9d..c355b2f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -139,6 +139,7 @@
import com.android.server.om.OverlayManagerService;
import com.android.server.os.BugreportManagerService;
import com.android.server.os.DeviceIdentifiersPolicyService;
+import com.android.server.os.NativeTombstoneManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.people.PeopleService;
import com.android.server.pm.BackgroundDexOptService;
@@ -1072,6 +1073,11 @@
mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ // Tracks native tombstones.
+ t.traceBegin("StartNativeTombstoneManagerService");
+ mSystemServiceManager.startService(NativeTombstoneManagerService.class);
+ t.traceEnd();
+
// Service to capture bugreports.
t.traceBegin("StartBugreportManagerService");
mSystemServiceManager.startService(BugreportManagerService.class);