diff options
author | Josh Gao <jmgao@google.com> | 2021-01-29 13:40:30 -0800 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2021-02-03 14:08:12 -0800 |
commit | 1c8dfd4c1e2130d5e65998f138ca7185a852b6e1 (patch) | |
tree | 6b14d856c812c9ada4b396bac83fbc2210345ce7 | |
parent | 9a8b4358d3ae2effc05eefebf58bdb038d79da2d (diff) |
Parse proto tombstones.
Bug: http://b/159164105
Test: manual
Change-Id: I8b85d8eeb343f390567b9d11bafcaa0d9aebddc7
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | services/core/java/com/android/server/os/NativeTombstoneManager.java | 152 |
2 files changed, 152 insertions, 1 deletions
diff --git a/Android.bp b/Android.bp index 6a0bdc3f7fde..6a2bd95a377d 100644 --- a/Android.bp +++ b/Android.bp @@ -678,6 +678,7 @@ gensrcs { srcs: [ ":ipconnectivity-proto-src", ":libstats_atom_enum_protos", + ":libtombstone_proto-src", "core/proto/**/*.proto", "libs/incident/**/*.proto", ], diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index 110666f091ce..a83edb75badb 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -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. @@ -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", @@ -70,7 +92,135 @@ public final class NativeTombstoneManager { return; } - BootReceiver.addTombstoneToDropBox(mContext, path); + 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 { |