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

Commit de8baa8a authored by Siim Sammul's avatar Siim Sammul Committed by Gerrit Code Review
Browse files

Merge "Revert^2 "Change the way tombstones are added to dropbox."" into main

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

STABILITY_OWNERS

0 → 100644
+2 −0
Original line number Diff line number Diff line
gaillard@google.com
+57 −26
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
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.XmlPullParserException;
@@ -60,11 +62,14 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

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

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

        HashMap<String, Long> timestamps = readTimestamps();
        try {
            if (proto) {
            // Remove the memory data from the 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)) {
                    // 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();
                try {
                        addAugmentedProtoToDropbox(tombstone, db, rateLimitResult);
                    addAugmentedProtoToDropbox(tombstone, tombstoneBytes, db, rateLimitResult);
                } finally {
                    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) {
            Slog.e(TAG, "Can't log tombstone", e);
        }
@@ -375,11 +382,8 @@ public class BootReceiver extends BroadcastReceiver {
    }

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

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

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

    private static void addLastkToDropBox(
            DropBoxManager db, HashMap<String, Long> timestamps,
            String headers, String footers, String filename, int maxSize,
@@ -429,6 +435,31 @@ public class BootReceiver extends BroadcastReceiver {
        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(
            DropBoxManager db, HashMap<String, Long> timestamps,
            String headers, String filename, int maxSize, String tag) throws IOException {
+66 −69
Original line number Diff line number Diff line
@@ -41,14 +41,13 @@ import android.system.Os;
import android.system.StructStat;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoParseException;

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

import libcore.io.IoUtils;

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

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

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

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

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

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

@@ -330,6 +332,27 @@ 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 {
        final ParcelFileDescriptor mPfd;

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

        static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) {
            final FileInputStream is = new FileInputStream(pfd.getFileDescriptor());
            final ProtoInputStream stream = new ProtoInputStream(is);

            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;
        static Optional<ParsedTombstone> parse(ParcelFileDescriptor pfd) {
            Tombstone tombstoneProto;
            try (FileInputStream is = new FileInputStream(pfd.getFileDescriptor())) {
                final byte[] tombstoneBytes = is.readAllBytes();

                        case (int) Tombstone.CAUSES:
                            if (!crashReason.equals("")) {
                                // 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) {
                tombstoneProto = Tombstone.parseFrom(
                        CodedInputStream.newInstance(tombstoneBytes));
            } catch (IOException ex) {
                Slog.e(TAG, "Failed to parse tombstone", ex);
                return Optional.empty();
            }

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

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

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

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

        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() {
Loading