Parse proto tombstones.
Bug: http://b/159164105 Test: manual Change-Id: I8b85d8eeb343f390567b9d11bafcaa0d9aebddc7
This commit is contained in:
@@ -678,6 +678,7 @@ gensrcs {
|
||||
srcs: [
|
||||
":ipconnectivity-proto-src",
|
||||
":libstats_atom_enum_protos",
|
||||
":libtombstone_proto-src",
|
||||
"core/proto/**/*.proto",
|
||||
"libs/incident/**/*.proto",
|
||||
],
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user