Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -678,6 +678,7 @@ gensrcs { srcs: [ ":ipconnectivity-proto-src", ":libstats_atom_enum_protos", ":libtombstone_proto-src", "core/proto/**/*.proto", "libs/incident/**/*.proto", ], Loading services/core/java/com/android/server/os/NativeTombstoneManager.java +151 −1 Original line number Diff line number Diff line Loading @@ -16,17 +16,33 @@ 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. Loading @@ -40,7 +56,13 @@ public final class NativeTombstoneManager { 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", Loading Loading @@ -70,8 +92,136 @@ public final class NativeTombstoneManager { 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() { Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -678,6 +678,7 @@ gensrcs { srcs: [ ":ipconnectivity-proto-src", ":libstats_atom_enum_protos", ":libtombstone_proto-src", "core/proto/**/*.proto", "libs/incident/**/*.proto", ], Loading
services/core/java/com/android/server/os/NativeTombstoneManager.java +151 −1 Original line number Diff line number Diff line Loading @@ -16,17 +16,33 @@ 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. Loading @@ -40,7 +56,13 @@ public final class NativeTombstoneManager { 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", Loading Loading @@ -70,8 +92,136 @@ public final class NativeTombstoneManager { 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() { Loading