Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f472abba authored by Greg Kaiser's avatar Greg Kaiser Committed by Automerger Merge Worker
Browse files

Merge "Revert "Change the way tombstones are added to dropbox."" into main am: 9c766095

parents 8ddfeb06 9c766095
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -201,7 +201,6 @@ java_library {
        "apex_aidl_interface-java",
        "apex_aidl_interface-java",
        "packagemanager_aidl-java",
        "packagemanager_aidl-java",
        "framework-protos",
        "framework-protos",
        "libtombstone_proto_java",
        "updatable-driver-protos",
        "updatable-driver-protos",
        "ota_metadata_proto_java",
        "ota_metadata_proto_java",
        "android.hidl.base-V1.0-java",
        "android.hidl.base-V1.0-java",
+1 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@ gensrcs {
        ":ipconnectivity-proto-src",
        ":ipconnectivity-proto-src",
        ":libstats_atom_enum_protos",
        ":libstats_atom_enum_protos",
        ":libstats_atom_message_protos",
        ":libstats_atom_message_protos",
        ":libtombstone_proto-src",
        "core/proto/**/*.proto",
        "core/proto/**/*.proto",
        "libs/incident/**/*.proto",
        "libs/incident/**/*.proto",
    ],
    ],

STABILITY_OWNERS

deleted100644 → 0
+0 −2
Original line number Original line Diff line number Diff line
gaillard@google.com
+26 −57
Original line number Original line Diff line number Diff line
@@ -48,8 +48,6 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.am.DropboxRateLimiter;
import com.android.server.am.DropboxRateLimiter;
import com.android.server.os.TombstoneProtos;
import com.android.server.os.TombstoneProtos.Tombstone;


import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserException;
@@ -62,14 +60,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermissions;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
/**
 * Performs a number of miscellaneous, non-system-critical actions
 * Performs a number of miscellaneous, non-system-critical actions
@@ -332,12 +327,12 @@ public class BootReceiver extends BroadcastReceiver {
     *
     *
     * @param ctx Context
     * @param ctx Context
     * @param tombstone path to the tombstone
     * @param tombstone path to the tombstone
     * @param tombstoneProto the parsed proto tombstone
     * @param proto whether the tombstone is stored as proto
     * @param processName the name of the process corresponding to the tombstone
     * @param processName the name of the process corresponding to the tombstone
     * @param tmpFileLock the lock for reading/writing tmp files
     * @param tmpFileLock the lock for reading/writing tmp files
     */
     */
    public static void addTombstoneToDropBox(
    public static void addTombstoneToDropBox(
                Context ctx, File tombstone, Tombstone tombstoneProto, String processName,
                Context ctx, File tombstone, boolean proto, String processName,
                ReentrantLock tmpFileLock) {
                ReentrantLock tmpFileLock) {
        final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
        final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
        if (db == null) {
        if (db == null) {
@@ -347,34 +342,32 @@ public class BootReceiver extends BroadcastReceiver {


        // Check if we should rate limit and abort early if needed.
        // Check if we should rate limit and abort early if needed.
        DropboxRateLimiter.RateLimitResult rateLimitResult =
        DropboxRateLimiter.RateLimitResult rateLimitResult =
                sDropboxRateLimiter.shouldRateLimit(TAG_TOMBSTONE_PROTO_WITH_HEADERS, processName);
                sDropboxRateLimiter.shouldRateLimit(
                        proto ? TAG_TOMBSTONE_PROTO_WITH_HEADERS : TAG_TOMBSTONE, processName);
        if (rateLimitResult.shouldRateLimit()) return;
        if (rateLimitResult.shouldRateLimit()) return;


        HashMap<String, Long> timestamps = readTimestamps();
        HashMap<String, Long> timestamps = readTimestamps();
        try {
        try {
            // Remove the memory data from the proto.
            if (proto) {
            Tombstone tombstoneProtoWithoutMemory = removeMemoryFromTombstone(tombstoneProto);

            final byte[] tombstoneBytes = tombstoneProtoWithoutMemory.toByteArray();

            // Use JNI to call the c++ proto to text converter and add the headers to the tombstone.
            String tombstoneWithoutMemory = new StringBuilder(getBootHeadersToLogAndUpdate())
                    .append(rateLimitResult.createHeader())
                    .append(getTombstoneText(tombstoneBytes))
                    .toString();

            // Add the tombstone without memory data to dropbox.
            db.addText(TAG_TOMBSTONE, tombstoneWithoutMemory);

            // Add the tombstone proto to dropbox.
                if (recordFileTimestamp(tombstone, timestamps)) {
                if (recordFileTimestamp(tombstone, timestamps)) {
                    // We need to attach the count indicating the number of dropped dropbox entries
                    // due to rate limiting. Do this by enclosing the proto tombsstone in a
                    // container proto that has the dropped entry count and the proto tombstone as
                    // bytes (to avoid the complexity of reading and writing nested protos).
                    tmpFileLock.lock();
                    tmpFileLock.lock();
                    try {
                    try {
                    addAugmentedProtoToDropbox(tombstone, tombstoneBytes, db, rateLimitResult);
                        addAugmentedProtoToDropbox(tombstone, db, rateLimitResult);
                    } finally {
                    } finally {
                        tmpFileLock.unlock();
                        tmpFileLock.unlock();
                    }
                    }
                }
                }
            } else {
                // Add the header indicating how many events have been dropped due to rate limiting.
                final String headers = getBootHeadersToLogAndUpdate()
                        + rateLimitResult.createHeader();
                addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE,
                                 TAG_TOMBSTONE);
            }
        } catch (IOException e) {
        } catch (IOException e) {
            Slog.e(TAG, "Can't log tombstone", e);
            Slog.e(TAG, "Can't log tombstone", e);
        }
        }
@@ -382,8 +375,11 @@ public class BootReceiver extends BroadcastReceiver {
    }
    }


    private static void addAugmentedProtoToDropbox(
    private static void addAugmentedProtoToDropbox(
                File tombstone, byte[] tombstoneBytes, DropBoxManager db,
                File tombstone, DropBoxManager db,
                DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException {
                DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException {
        // Read the proto tombstone file as bytes.
        final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath());

        final File tombstoneProtoWithHeaders = File.createTempFile(
        final File tombstoneProtoWithHeaders = File.createTempFile(
                tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
                tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR);
        Files.setPosixFilePermissions(
        Files.setPosixFilePermissions(
@@ -416,8 +412,6 @@ public class BootReceiver extends BroadcastReceiver {
        }
        }
    }
    }


    private static native String getTombstoneText(byte[] tombstoneBytes);

    private static void addLastkToDropBox(
    private static void addLastkToDropBox(
            DropBoxManager db, HashMap<String, Long> timestamps,
            DropBoxManager db, HashMap<String, Long> timestamps,
            String headers, String footers, String filename, int maxSize,
            String headers, String footers, String filename, int maxSize,
@@ -435,31 +429,6 @@ public class BootReceiver extends BroadcastReceiver {
        addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag);
        addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag);
    }
    }


    /** Removes memory information from the Tombstone proto. */
    @VisibleForTesting
    public static Tombstone removeMemoryFromTombstone(Tombstone tombstoneProto) {
        Tombstone.Builder tombstoneBuilder = tombstoneProto.toBuilder()
                .clearMemoryMappings()
                .clearThreads()
                .putAllThreads(tombstoneProto.getThreadsMap().entrySet()
                        .stream()
                        .map(BootReceiver::clearMemoryDump)
                        .collect(Collectors.toMap(e->e.getKey(), e->e.getValue())));

        if (tombstoneProto.hasSignalInfo()) {
            tombstoneBuilder.setSignalInfo(
                    tombstoneProto.getSignalInfo().toBuilder().clearFaultAdjacentMetadata());
        }

        return tombstoneBuilder.build();
    }

    private static AbstractMap.SimpleEntry<Integer, TombstoneProtos.Thread> clearMemoryDump(
            Map.Entry<Integer, TombstoneProtos.Thread> e) {
        return new AbstractMap.SimpleEntry<Integer, TombstoneProtos.Thread>(
            e.getKey(), e.getValue().toBuilder().clearMemoryDump().build());
    }

    private static void addFileToDropBox(
    private static void addFileToDropBox(
            DropBoxManager db, HashMap<String, Long> timestamps,
            DropBoxManager db, HashMap<String, Long> timestamps,
            String headers, String filename, int maxSize, String tag) throws IOException {
            String headers, String filename, int maxSize, String tag) throws IOException {
+69 −66
Original line number Original line Diff line number Diff line
@@ -41,13 +41,14 @@ import android.system.Os;
import android.system.StructStat;
import android.system.StructStat;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoParseException;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.server.BootReceiver;
import com.android.server.BootReceiver;
import com.android.server.ServiceThread;
import com.android.server.ServiceThread;
import com.android.server.os.TombstoneProtos.Cause;
import com.android.server.os.TombstoneProtos.Cause;
import com.android.server.os.TombstoneProtos.Tombstone;
import com.android.server.os.TombstoneProtos.Tombstone;
import com.android.server.os.protobuf.CodedInputStream;


import libcore.io.IoUtils;
import libcore.io.IoUtils;


@@ -127,21 +128,18 @@ public final class NativeTombstoneManager {
            return;
            return;
        }
        }


        String processName = "UNKNOWN";
        final boolean isProtoFile = filename.endsWith(".pb");
        final boolean isProtoFile = filename.endsWith(".pb");
        if (!isProtoFile) {
        File protoPath = isProtoFile ? path : new File(path.getAbsolutePath() + ".pb");
            return;
        }


        Optional<ParsedTombstone> parsedTombstone = handleProtoTombstone(path, true);
        Optional<TombstoneFile> parsedTombstone = handleProtoTombstone(protoPath, isProtoFile);
        if (parsedTombstone.isPresent()) {
        if (parsedTombstone.isPresent()) {
            BootReceiver.addTombstoneToDropBox(
            processName = parsedTombstone.get().getProcessName();
                    mContext, path, parsedTombstone.get().getTombstone(),
                    parsedTombstone.get().getProcessName(), mTmpFileLock);
        }
        }
        BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName, mTmpFileLock);
    }
    }


    private Optional<ParsedTombstone> handleProtoTombstone(
    private Optional<TombstoneFile> handleProtoTombstone(File path, boolean addToList) {
            File path, boolean addToList) {
        final String filename = path.getName();
        final String filename = path.getName();
        if (!filename.endsWith(".pb")) {
        if (!filename.endsWith(".pb")) {
            Slog.w(TAG, "unexpected tombstone name: " + path);
            Slog.w(TAG, "unexpected tombstone name: " + path);
@@ -171,7 +169,7 @@ public final class NativeTombstoneManager {
            return Optional.empty();
            return Optional.empty();
        }
        }


        final Optional<ParsedTombstone> parsedTombstone = TombstoneFile.parse(pfd);
        final Optional<TombstoneFile> parsedTombstone = TombstoneFile.parse(pfd);
        if (!parsedTombstone.isPresent()) {
        if (!parsedTombstone.isPresent()) {
            IoUtils.closeQuietly(pfd);
            IoUtils.closeQuietly(pfd);
            return Optional.empty();
            return Optional.empty();
@@ -184,7 +182,7 @@ public final class NativeTombstoneManager {
                    previous.dispose();
                    previous.dispose();
                }
                }


                mTombstones.put(number, parsedTombstone.get().getTombstoneFile());
                mTombstones.put(number, parsedTombstone.get());
            }
            }
        }
        }


@@ -332,27 +330,6 @@ public final class NativeTombstoneManager {
        }
        }
    }
    }


    static class ParsedTombstone {
        TombstoneFile mTombstoneFile;
        Tombstone mTombstone;
        ParsedTombstone(TombstoneFile tombstoneFile, Tombstone tombstone) {
            mTombstoneFile = tombstoneFile;
            mTombstone = tombstone;
        }

        public String getProcessName() {
            return mTombstoneFile.getProcessName();
        }

        public TombstoneFile getTombstoneFile() {
            return mTombstoneFile;
        }

        public Tombstone getTombstone() {
            return mTombstone;
        }
    }

    static class TombstoneFile {
    static class TombstoneFile {
        final ParcelFileDescriptor mPfd;
        final ParcelFileDescriptor mPfd;


@@ -435,21 +412,67 @@ public final class NativeTombstoneManager {
            }
            }
        }
        }


        static Optional<ParsedTombstone> parse(ParcelFileDescriptor pfd) {
        static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) {
            Tombstone tombstoneProto;
            final FileInputStream is = new FileInputStream(pfd.getFileDescriptor());
            try (FileInputStream is = new FileInputStream(pfd.getFileDescriptor())) {
            final ProtoInputStream stream = new ProtoInputStream(is);
                final byte[] tombstoneBytes = is.readAllBytes();

            int pid = 0;
            int uid = 0;
            String processName = null;
            String crashReason = "";
            String selinuxLabel = "";

            try {
                while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
                    switch (stream.getFieldNumber()) {
                        case (int) Tombstone.PID:
                            pid = stream.readInt(Tombstone.PID);
                            break;

                        case (int) Tombstone.UID:
                            uid = stream.readInt(Tombstone.UID);
                            break;

                        case (int) Tombstone.COMMAND_LINE:
                            if (processName == null) {
                                processName = stream.readString(Tombstone.COMMAND_LINE);
                            }
                            break;


                tombstoneProto = Tombstone.parseFrom(
                        case (int) Tombstone.CAUSES:
                        CodedInputStream.newInstance(tombstoneBytes));
                            if (!crashReason.equals("")) {
            } catch (IOException ex) {
                                // Causes appear in decreasing order of likelihood. For now we only
                                // want the most likely crash reason here, so ignore all others.
                                break;
                            }
                            long token = stream.start(Tombstone.CAUSES);
                        cause:
                            while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
                                switch (stream.getFieldNumber()) {
                                    case (int) Cause.HUMAN_READABLE:
                                        crashReason = stream.readString(Cause.HUMAN_READABLE);
                                        break cause;

                                    default:
                                        break;
                                }
                            }
                            stream.end(token);
                            break;

                        case (int) Tombstone.SELINUX_LABEL:
                            selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL);
                            break;

                        default:
                            break;
                    }
                }
            } catch (IOException | ProtoParseException ex) {
                Slog.e(TAG, "Failed to parse tombstone", ex);
                Slog.e(TAG, "Failed to parse tombstone", ex);
                return Optional.empty();
                return Optional.empty();
            }
            }


            int pid = tombstoneProto.getPid();
            int uid = tombstoneProto.getUid();

            if (!UserHandle.isApp(uid)) {
            if (!UserHandle.isApp(uid)) {
                Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring");
                Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring");
                return Optional.empty();
                return Optional.empty();
@@ -466,7 +489,6 @@ public final class NativeTombstoneManager {
            final int userId = UserHandle.getUserId(uid);
            final int userId = UserHandle.getUserId(uid);
            final int appId = UserHandle.getAppId(uid);
            final int appId = UserHandle.getAppId(uid);


            String selinuxLabel = tombstoneProto.getSelinuxLabel();
            if (!selinuxLabel.startsWith("u:r:untrusted_app")) {
            if (!selinuxLabel.startsWith("u:r:untrusted_app")) {
                Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring");
                Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring");
                return Optional.empty();
                return Optional.empty();
@@ -478,30 +500,11 @@ public final class NativeTombstoneManager {
            result.mAppId = appId;
            result.mAppId = appId;
            result.mPid = pid;
            result.mPid = pid;
            result.mUid = uid;
            result.mUid = uid;
            result.mProcessName = getCmdLineProcessName(tombstoneProto);
            result.mProcessName = processName == null ? "" : processName;
            result.mTimestampMs = timestampMs;
            result.mTimestampMs = timestampMs;
            result.mCrashReason = getCrashReason(tombstoneProto);
            result.mCrashReason = crashReason;


            return Optional.of(new ParsedTombstone(result, tombstoneProto));
            return Optional.of(result);
        }

        private static String getCmdLineProcessName(Tombstone tombstoneProto) {
            for (String cmdline : tombstoneProto.getCommandLineList()) {
                if (cmdline != null) {
                    return cmdline;
                }
            }
            return "";
        }

        private static String getCrashReason(Tombstone tombstoneProto) {
            for (Cause cause : tombstoneProto.getCausesList()) {
                if (cause.getHumanReadable() != null
                        && !cause.getHumanReadable().equals("")) {
                    return cause.getHumanReadable();
                }
            }
            return "";
        }
        }


        public IParcelFileDescriptorRetriever getPfdRetriever() {
        public IParcelFileDescriptorRetriever getPfdRetriever() {
Loading