Loading Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -678,6 +678,7 @@ gensrcs { srcs: [ srcs: [ ":ipconnectivity-proto-src", ":ipconnectivity-proto-src", ":libstats_atom_enum_protos", ":libstats_atom_enum_protos", ":libtombstone_proto-src", "core/proto/**/*.proto", "core/proto/**/*.proto", "libs/incident/**/*.proto", "libs/incident/**/*.proto", ], ], Loading core/java/com/android/server/BootReceiver.java +22 −38 Original line number Original line Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.pm.IPackageManager; import android.os.Build; import android.os.Build; import android.os.DropBoxManager; import android.os.DropBoxManager; import android.os.Environment; import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.FileUtils; import android.os.RecoverySystem; import android.os.RecoverySystem; import android.os.RemoteException; import android.os.RemoteException; Loading Loading @@ -75,7 +74,6 @@ public class BootReceiver extends BroadcastReceiver { SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536; SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536; private static final int GMSCORE_LASTK_LOG_SIZE = 196608; 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"; private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE"; // The pre-froyo package and class of the system updater, which // The pre-froyo package and class of the system updater, which Loading @@ -86,9 +84,6 @@ public class BootReceiver extends BroadcastReceiver { private static final String OLD_UPDATER_CLASS = private static final String OLD_UPDATER_CLASS = "com.google.android.systemupdater.SystemUpdateReceiver"; "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 String LOG_FILES_FILE = "log-files.xml"; private static final AtomicFile sFile = new AtomicFile(new File( private static final AtomicFile sFile = new AtomicFile(new File( Environment.getDataSystemDirectory(), LOG_FILES_FILE), "log-files"); Environment.getDataSystemDirectory(), LOG_FILES_FILE), "log-files"); Loading Loading @@ -154,7 +149,7 @@ public class BootReceiver extends BroadcastReceiver { Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); } } private String getPreviousBootHeaders() { private static String getPreviousBootHeaders() { try { try { return FileUtils.readTextFile(lastHeaderFile, 0, null); return FileUtils.readTextFile(lastHeaderFile, 0, null); } catch (IOException e) { } catch (IOException e) { Loading @@ -162,7 +157,7 @@ public class BootReceiver extends BroadcastReceiver { } } } } private String getCurrentBootHeaders() throws IOException { private static String getCurrentBootHeaders() throws IOException { return new StringBuilder(512) return new StringBuilder(512) .append("Build: ").append(Build.FINGERPRINT).append("\n") .append("Build: ").append(Build.FINGERPRINT).append("\n") .append("Hardware: ").append(Build.BOARD).append("\n") .append("Hardware: ").append(Build.BOARD).append("\n") Loading @@ -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 oldHeaders = getPreviousBootHeaders(); final String newHeaders = getCurrentBootHeaders(); final String newHeaders = getCurrentBootHeaders(); Loading Loading @@ -248,39 +243,28 @@ public class BootReceiver extends BroadcastReceiver { logFsMountTime(); logFsMountTime(); addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK"); addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK"); logSystemServerShutdownTimeMetrics(); 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); writeTimestamps(timestamps); } // Start watching for new tombstone files; will record them as they occur. /** // This gets registered with the singleton file observer thread. * Add a tombstone to the DropBox. sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) { * @Override * @param ctx Context public void onEvent(int event, String path) { * @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(); HashMap<String, Long> timestamps = readTimestamps(); try { try { File file = new File(TOMBSTONE_DIR, path); final String headers = getBootHeadersToLogAndUpdate(); if (file.isFile() && file.getName().startsWith("tombstone_")) { addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE, addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE, TAG_TOMBSTONE); TAG_TOMBSTONE); } } catch (IOException e) { } catch (IOException e) { Slog.e(TAG, "Can't log tombstone", e); Slog.e(TAG, "Can't log tombstone", e); } } writeTimestamps(timestamps); writeTimestamps(timestamps); } } }; sTombstoneObserver.startWatching(); } private static void addLastkToDropBox( private static void addLastkToDropBox( DropBoxManager db, HashMap<String, Long> timestamps, DropBoxManager db, HashMap<String, Long> timestamps, Loading Loading @@ -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) { synchronized (sFile) { final FileOutputStream stream; final FileOutputStream stream; try { try { Loading services/core/java/com/android/server/os/NativeTombstoneManager.java 0 → 100644 +241 −0 Original line number Original line Diff line number Diff line /* * 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.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import android.annotation.AppIdInt; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.os.FileObserver; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoInputStream; import com.android.internal.annotations.GuardedBy; import com.android.server.BootReceiver; import com.android.server.ServiceThread; import com.android.server.os.TombstoneProtos.Tombstone; import libcore.io.IoUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Optional; /** * 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; private final Object mLock = new Object(); @GuardedBy("mLock") private final SparseArray<TombstoneFile> mTombstones; NativeTombstoneManager(Context context) { mTombstones = new SparseArray<TombstoneFile>(); 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; } if (filename.endsWith(".pb")) { handleProtoTombstone(path); } else { BootReceiver.addTombstoneToDropBox(mContext, path); } } private void handleProtoTombstone(File path) { final String filename = path.getName(); if (!filename.endsWith(".pb")) { Slog.w(TAG, "unexpected tombstone name: " + path); return; } final String suffix = filename.substring("tombstone_".length()); final String numberStr = suffix.substring(0, suffix.length() - 3); int number; try { number = Integer.parseInt(numberStr); if (number < 0 || number > 99) { Slog.w(TAG, "unexpected tombstone name: " + path); return; } } catch (NumberFormatException ex) { Slog.w(TAG, "unexpected tombstone name: " + path); return; } ParcelFileDescriptor pfd; try { pfd = ParcelFileDescriptor.open(path, MODE_READ_WRITE); } catch (FileNotFoundException ex) { Slog.w(TAG, "failed to open " + path, ex); return; } final Optional<TombstoneFile> parsedTombstone = TombstoneFile.parse(pfd); if (!parsedTombstone.isPresent()) { IoUtils.closeQuietly(pfd); return; } synchronized (mLock) { TombstoneFile previous = mTombstones.get(number); if (previous != null) { previous.dispose(); } mTombstones.put(number, parsedTombstone.get()); } } static class TombstoneFile { final ParcelFileDescriptor mPfd; final @UserIdInt int mUserId; final @AppIdInt int mAppId; boolean mPurged = false; TombstoneFile(ParcelFileDescriptor pfd, @UserIdInt int userId, @AppIdInt int appId) { mPfd = pfd; mUserId = userId; mAppId = appId; } public boolean matches(Optional<Integer> userId, Optional<Integer> appId) { if (mPurged) { return false; } if (userId.isPresent() && userId.get() != mUserId) { return false; } if (appId.isPresent() && appId.get() != mAppId) { return false; } return true; } public void dispose() { IoUtils.closeQuietly(mPfd); } static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) { final FileInputStream is = new FileInputStream(pfd.getFileDescriptor()); final ProtoInputStream stream = new ProtoInputStream(is); int uid = 0; String selinuxLabel = ""; try { while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (stream.getFieldNumber()) { case (int) Tombstone.UID: uid = stream.readInt(Tombstone.UID); break; case (int) Tombstone.SELINUX_LABEL: selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL); break; default: break; } } } catch (IOException ex) { Slog.e(TAG, "Failed to parse tombstone", ex); return Optional.empty(); } if (!UserHandle.isApp(uid)) { Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring"); return Optional.empty(); } final int userId = UserHandle.getUserId(uid); final int appId = UserHandle.getAppId(uid); if (!selinuxLabel.startsWith("u:r:untrusted_app")) { Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring"); return Optional.empty(); } return Optional.of(new TombstoneFile(pfd, userId, appId)); } } 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)); }); } } } services/core/java/com/android/server/os/NativeTombstoneManagerService.java 0 → 100644 +50 −0 Original line number Original line Diff line number Diff line /* * 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(); } } } services/java/com/android/server/SystemServer.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -139,6 +139,7 @@ import com.android.server.oemlock.OemLockService; import com.android.server.om.OverlayManagerService; import com.android.server.om.OverlayManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.NativeTombstoneManagerService; import com.android.server.os.SchedulingPolicyService; import com.android.server.os.SchedulingPolicyService; import com.android.server.people.PeopleService; import com.android.server.people.PeopleService; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.BackgroundDexOptService; Loading Loading @@ -1072,6 +1073,11 @@ public final class SystemServer { mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS); mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS); t.traceEnd(); t.traceEnd(); // Tracks native tombstones. t.traceBegin("StartNativeTombstoneManagerService"); mSystemServiceManager.startService(NativeTombstoneManagerService.class); t.traceEnd(); // Service to capture bugreports. // Service to capture bugreports. t.traceBegin("StartBugreportManagerService"); t.traceBegin("StartBugreportManagerService"); mSystemServiceManager.startService(BugreportManagerService.class); mSystemServiceManager.startService(BugreportManagerService.class); Loading Loading
Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -678,6 +678,7 @@ gensrcs { srcs: [ srcs: [ ":ipconnectivity-proto-src", ":ipconnectivity-proto-src", ":libstats_atom_enum_protos", ":libstats_atom_enum_protos", ":libtombstone_proto-src", "core/proto/**/*.proto", "core/proto/**/*.proto", "libs/incident/**/*.proto", "libs/incident/**/*.proto", ], ], Loading
core/java/com/android/server/BootReceiver.java +22 −38 Original line number Original line Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.pm.IPackageManager; import android.os.Build; import android.os.Build; import android.os.DropBoxManager; import android.os.DropBoxManager; import android.os.Environment; import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.FileUtils; import android.os.RecoverySystem; import android.os.RecoverySystem; import android.os.RemoteException; import android.os.RemoteException; Loading Loading @@ -75,7 +74,6 @@ public class BootReceiver extends BroadcastReceiver { SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536; SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536; private static final int GMSCORE_LASTK_LOG_SIZE = 196608; 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"; private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE"; // The pre-froyo package and class of the system updater, which // The pre-froyo package and class of the system updater, which Loading @@ -86,9 +84,6 @@ public class BootReceiver extends BroadcastReceiver { private static final String OLD_UPDATER_CLASS = private static final String OLD_UPDATER_CLASS = "com.google.android.systemupdater.SystemUpdateReceiver"; "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 String LOG_FILES_FILE = "log-files.xml"; private static final AtomicFile sFile = new AtomicFile(new File( private static final AtomicFile sFile = new AtomicFile(new File( Environment.getDataSystemDirectory(), LOG_FILES_FILE), "log-files"); Environment.getDataSystemDirectory(), LOG_FILES_FILE), "log-files"); Loading Loading @@ -154,7 +149,7 @@ public class BootReceiver extends BroadcastReceiver { Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); } } private String getPreviousBootHeaders() { private static String getPreviousBootHeaders() { try { try { return FileUtils.readTextFile(lastHeaderFile, 0, null); return FileUtils.readTextFile(lastHeaderFile, 0, null); } catch (IOException e) { } catch (IOException e) { Loading @@ -162,7 +157,7 @@ public class BootReceiver extends BroadcastReceiver { } } } } private String getCurrentBootHeaders() throws IOException { private static String getCurrentBootHeaders() throws IOException { return new StringBuilder(512) return new StringBuilder(512) .append("Build: ").append(Build.FINGERPRINT).append("\n") .append("Build: ").append(Build.FINGERPRINT).append("\n") .append("Hardware: ").append(Build.BOARD).append("\n") .append("Hardware: ").append(Build.BOARD).append("\n") Loading @@ -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 oldHeaders = getPreviousBootHeaders(); final String newHeaders = getCurrentBootHeaders(); final String newHeaders = getCurrentBootHeaders(); Loading Loading @@ -248,39 +243,28 @@ public class BootReceiver extends BroadcastReceiver { logFsMountTime(); logFsMountTime(); addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK"); addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK"); logSystemServerShutdownTimeMetrics(); 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); writeTimestamps(timestamps); } // Start watching for new tombstone files; will record them as they occur. /** // This gets registered with the singleton file observer thread. * Add a tombstone to the DropBox. sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) { * @Override * @param ctx Context public void onEvent(int event, String path) { * @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(); HashMap<String, Long> timestamps = readTimestamps(); try { try { File file = new File(TOMBSTONE_DIR, path); final String headers = getBootHeadersToLogAndUpdate(); if (file.isFile() && file.getName().startsWith("tombstone_")) { addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE, addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE, TAG_TOMBSTONE); TAG_TOMBSTONE); } } catch (IOException e) { } catch (IOException e) { Slog.e(TAG, "Can't log tombstone", e); Slog.e(TAG, "Can't log tombstone", e); } } writeTimestamps(timestamps); writeTimestamps(timestamps); } } }; sTombstoneObserver.startWatching(); } private static void addLastkToDropBox( private static void addLastkToDropBox( DropBoxManager db, HashMap<String, Long> timestamps, DropBoxManager db, HashMap<String, Long> timestamps, Loading Loading @@ -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) { synchronized (sFile) { final FileOutputStream stream; final FileOutputStream stream; try { try { Loading
services/core/java/com/android/server/os/NativeTombstoneManager.java 0 → 100644 +241 −0 Original line number Original line Diff line number Diff line /* * 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.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import android.annotation.AppIdInt; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.os.FileObserver; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoInputStream; import com.android.internal.annotations.GuardedBy; import com.android.server.BootReceiver; import com.android.server.ServiceThread; import com.android.server.os.TombstoneProtos.Tombstone; import libcore.io.IoUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Optional; /** * 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; private final Object mLock = new Object(); @GuardedBy("mLock") private final SparseArray<TombstoneFile> mTombstones; NativeTombstoneManager(Context context) { mTombstones = new SparseArray<TombstoneFile>(); 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; } if (filename.endsWith(".pb")) { handleProtoTombstone(path); } else { BootReceiver.addTombstoneToDropBox(mContext, path); } } private void handleProtoTombstone(File path) { final String filename = path.getName(); if (!filename.endsWith(".pb")) { Slog.w(TAG, "unexpected tombstone name: " + path); return; } final String suffix = filename.substring("tombstone_".length()); final String numberStr = suffix.substring(0, suffix.length() - 3); int number; try { number = Integer.parseInt(numberStr); if (number < 0 || number > 99) { Slog.w(TAG, "unexpected tombstone name: " + path); return; } } catch (NumberFormatException ex) { Slog.w(TAG, "unexpected tombstone name: " + path); return; } ParcelFileDescriptor pfd; try { pfd = ParcelFileDescriptor.open(path, MODE_READ_WRITE); } catch (FileNotFoundException ex) { Slog.w(TAG, "failed to open " + path, ex); return; } final Optional<TombstoneFile> parsedTombstone = TombstoneFile.parse(pfd); if (!parsedTombstone.isPresent()) { IoUtils.closeQuietly(pfd); return; } synchronized (mLock) { TombstoneFile previous = mTombstones.get(number); if (previous != null) { previous.dispose(); } mTombstones.put(number, parsedTombstone.get()); } } static class TombstoneFile { final ParcelFileDescriptor mPfd; final @UserIdInt int mUserId; final @AppIdInt int mAppId; boolean mPurged = false; TombstoneFile(ParcelFileDescriptor pfd, @UserIdInt int userId, @AppIdInt int appId) { mPfd = pfd; mUserId = userId; mAppId = appId; } public boolean matches(Optional<Integer> userId, Optional<Integer> appId) { if (mPurged) { return false; } if (userId.isPresent() && userId.get() != mUserId) { return false; } if (appId.isPresent() && appId.get() != mAppId) { return false; } return true; } public void dispose() { IoUtils.closeQuietly(mPfd); } static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) { final FileInputStream is = new FileInputStream(pfd.getFileDescriptor()); final ProtoInputStream stream = new ProtoInputStream(is); int uid = 0; String selinuxLabel = ""; try { while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (stream.getFieldNumber()) { case (int) Tombstone.UID: uid = stream.readInt(Tombstone.UID); break; case (int) Tombstone.SELINUX_LABEL: selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL); break; default: break; } } } catch (IOException ex) { Slog.e(TAG, "Failed to parse tombstone", ex); return Optional.empty(); } if (!UserHandle.isApp(uid)) { Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring"); return Optional.empty(); } final int userId = UserHandle.getUserId(uid); final int appId = UserHandle.getAppId(uid); if (!selinuxLabel.startsWith("u:r:untrusted_app")) { Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring"); return Optional.empty(); } return Optional.of(new TombstoneFile(pfd, userId, appId)); } } 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)); }); } } }
services/core/java/com/android/server/os/NativeTombstoneManagerService.java 0 → 100644 +50 −0 Original line number Original line Diff line number Diff line /* * 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(); } } }
services/java/com/android/server/SystemServer.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -139,6 +139,7 @@ import com.android.server.oemlock.OemLockService; import com.android.server.om.OverlayManagerService; import com.android.server.om.OverlayManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.NativeTombstoneManagerService; import com.android.server.os.SchedulingPolicyService; import com.android.server.os.SchedulingPolicyService; import com.android.server.people.PeopleService; import com.android.server.people.PeopleService; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.BackgroundDexOptService; Loading Loading @@ -1072,6 +1073,11 @@ public final class SystemServer { mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS); mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS); t.traceEnd(); t.traceEnd(); // Tracks native tombstones. t.traceBegin("StartNativeTombstoneManagerService"); mSystemServiceManager.startService(NativeTombstoneManagerService.class); t.traceEnd(); // Service to capture bugreports. // Service to capture bugreports. t.traceBegin("StartBugreportManagerService"); t.traceBegin("StartBugreportManagerService"); mSystemServiceManager.startService(BugreportManagerService.class); mSystemServiceManager.startService(BugreportManagerService.class); Loading