diff options
4 files changed, 169 insertions, 38 deletions
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index ac2361dff560..c46d7086ca80 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -23,7 +23,6 @@ import android.content.pm.IPackageManager; 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 @@ public class BootReceiver extends BroadcastReceiver { 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 @@ public class BootReceiver extends BroadcastReceiver { 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 @@ public class BootReceiver extends BroadcastReceiver { 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 @@ public class BootReceiver extends BroadcastReceiver { } } - 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 @@ public class BootReceiver extends BroadcastReceiver { } - private String getBootHeadersToLogAndUpdate() throws IOException { + private static String getBootHeadersToLogAndUpdate() throws IOException { final String oldHeaders = getPreviousBootHeaders(); final String newHeaders = getCurrentBootHeaders(); @@ -248,38 +243,27 @@ public class BootReceiver extends BroadcastReceiver { logFsMountTime(); addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK"); logSystemServerShutdownTimeMetrics(); + writeTimestamps(timestamps); + } - // 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"); - } + /** + * 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); - - // 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(); } private static void addLastkToDropBox( @@ -764,7 +748,7 @@ public class BootReceiver extends BroadcastReceiver { } } - 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 000000000000..110666f091ce --- /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 000000000000..cb3c7ff0c07d --- /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 203de9dbcc07..c355b2f627cc 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.oemlock.OemLockService; 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 @@ public final class SystemServer { 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); |