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

Commit dfe8541e authored by Pablo Gamito's avatar Pablo Gamito
Browse files

Improve error message for ProtoLog decoding failures.

When ProtoLog fails to decode a message hash because it's not loaded in
memory, include the message string and group name from the viewer config
file in the error log.

Bug: 442776354
Flag: EXEMPT error message changes
Change-Id: I59b521bd367f4fc219fc5aa05292ce2bb21085eb
parent 992054a2
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -180,16 +180,20 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl {
        }

        try {
            if (!mViewerConfigReader.messageHashIsAvailableInFile(message.getMessageHash())) {
            ProtoLogViewerConfigReader.MessageData messageData =
                    mViewerConfigReader.getMessageDataForHashFromFile(message.getMessageHash());
            if (messageData == null) {
                return "Failed to decode message for logcat logging. "
                        + "Message hash (" + message.getMessageHash() + ") is not available in "
                        + "viewerConfig file (" +  mViewerConfigFilePath + "). This might be due "
                        + "to the viewer config file and the executing code being out of sync.";
            } else {
                return "Failed to decode message for logcat. "
                        + "Message hash (" + message.getMessageHash() + ") was available in the "
                        + "viewerConfig file (" +  mViewerConfigFilePath + ") but wasn't loaded "
                        + "into memory from file before decoding! This is likely a bug.";
                        + "Message hash (" + message.getMessageHash()
                        + ") was available in the viewerConfig file (" + mViewerConfigFilePath
                        + ") but wasn't loaded into memory from file before decoding! "
                        + "This is likely a bug. Message: '" + messageData.message
                        + "', group: '" + messageData.group + "'.";
            }
        } catch (IOException e) {
            return "Failed to get string message to log but could not identify the root cause due "
+118 −38
Original line number Diff line number Diff line
@@ -34,6 +34,21 @@ public class ProtoLogViewerConfigReader {
        this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
    }

    /**
     * Data class for a log message from the viewer config.
     */
    public static class MessageData {
        @NonNull
        public final String message;
        @NonNull
        public final String group;

        public MessageData(@NonNull String message, @NonNull String group) {
            this.message = message;
            this.group = group;
        }
    }

    /**
     * Returns message format string for its hash or null if unavailable
     * or the viewer config is not loaded into memory.
@@ -130,6 +145,56 @@ public class ProtoLogViewerConfigReader {
        return false;
    }

    /**
     * Returns the message data for a given message hash from the viewer config file.
     *
     * @param messageHash The hash of the message we are looking for in the viewer config file.
     * @return The {@link MessageData} if the message is found, null otherwise.
     * @throws IOException if there was an issue reading the viewer config file.
     */
    @Nullable
    public MessageData getMessageDataForHashFromFile(long messageHash)
            throws IOException {
        try (var pisWrapper = mViewerConfigInputStreamProvider.getInputStream()) {
            final var pis = pisWrapper.get();

            String foundMessage = null;
            long foundGroupId = -1;
            final LongSparseArray<String> groupMap = new LongSparseArray<>();

            while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
                if (pis.getFieldNumber() == (int) MESSAGES) {
                    final long inMessageToken = pis.start(MESSAGES);
                    ParsedMessage parsedMessage = readMessage(pis);
                    if (parsedMessage.messageId == messageHash) {
                        foundMessage = parsedMessage.message;
                        foundGroupId = parsedMessage.groupId;
                    }

                    pis.end(inMessageToken);
                } else if (pis.getFieldNumber() == (int) GROUPS) {
                    final long inMessageToken = pis.start(GROUPS);

                    long groupId = 0;
                    ParsedGroup parsedGroup = readGroup(pis);
                    if (parsedGroup.groupName != null) {
                        groupMap.put(parsedGroup.groupId, parsedGroup.groupName);
                    }
                    pis.end(inMessageToken);
                }
            }

            if (foundMessage != null) {
                String groupName = groupMap.get(foundGroupId);
                if (groupName != null) {
                    return new MessageData(foundMessage, groupName);
                }
            }
        }

        return null;
    }

    @NonNull
    private Map<Long, String> loadViewerConfigMappingForGroup(@NonNull String group)
            throws IOException {
@@ -141,38 +206,22 @@ public class ProtoLogViewerConfigReader {
            while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
                if (pis.getFieldNumber() == (int) MESSAGES) {
                    final long inMessageToken = pis.start(MESSAGES);
                    ParsedMessage parsedMessage = readMessage(pis);

                    long messageId = 0;
                    String message = null;
                    int groupId = 0;
                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
                        switch (pis.getFieldNumber()) {
                            case (int) MESSAGE_ID:
                                messageId = pis.readLong(MESSAGE_ID);
                                break;
                            case (int) MESSAGE:
                                message = pis.readString(MESSAGE);
                                break;
                            case (int) GROUP_ID:
                                groupId = pis.readInt(GROUP_ID);
                                break;
                        }
                    }

                    if (groupId == 0) {
                    if (parsedMessage.groupId == 0) {
                        throw new IOException("Failed to get group id");
                    }

                    if (messageId == 0) {
                    if (parsedMessage.messageId == 0) {
                        throw new IOException("Failed to get message id");
                    }

                    if (message == null) {
                    if (parsedMessage.message == null) {
                        throw new IOException("Failed to get message string");
                    }

                    if (groupId == targetGroupId) {
                        hashesForGroup.put(messageId, message);
                    if (parsedMessage.groupId == targetGroupId) {
                        hashesForGroup.put(parsedMessage.messageId, parsedMessage.message);
                    }

                    pis.end(inMessageToken);
@@ -190,29 +239,60 @@ public class ProtoLogViewerConfigReader {
            while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
                if (pis.getFieldNumber() == (int) GROUPS) {
                    final long inMessageToken = pis.start(GROUPS);
                    ParsedGroup parsedGroup = readGroup(pis);
                    if (Objects.equals(parsedGroup.groupName, group)) {
                        return parsedGroup.groupId;
                    }

                    long groupId = 0;
                    String groupName = null;
                    pis.end(inMessageToken);
                }
            }
        }

        throw new RuntimeException("Group " + group + " not found in viewer config");
    }

    private static class ParsedMessage {
        long messageId = 0;
        String message = null;
        int groupId = 0;
    }

    private static ParsedMessage readMessage(ProtoInputStream pis) throws IOException {
        final ParsedMessage result = new ParsedMessage();
        while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
            switch (pis.getFieldNumber()) {
                            case (int) ID:
                                groupId = pis.readInt(ID);
                case (int) MESSAGE_ID:
                    result.messageId = pis.readLong(MESSAGE_ID);
                    break;
                            case (int) NAME:
                                groupName = pis.readString(NAME);
                case (int) MESSAGE:
                    result.message = pis.readString(MESSAGE);
                    break;
                case (int) GROUP_ID:
                    result.groupId = pis.readInt(GROUP_ID);
                    break;
            }
        }

                    if (Objects.equals(groupName, group)) {
                        return groupId;
        return result;
    }

                    pis.end(inMessageToken);
    private static class ParsedGroup {
        long groupId = 0;
        String groupName = null;
    }

    private static ParsedGroup readGroup(ProtoInputStream pis) throws IOException {
        final ParsedGroup result = new ParsedGroup();
        while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
            switch (pis.getFieldNumber()) {
                case (int) ID:
                    result.groupId = pis.readInt(ID);
                    break;
                case (int) NAME:
                    result.groupName = pis.readString(NAME);
                    break;
            }
        }

        throw new RuntimeException("Group " + group + " not found in viewer config");
        return result;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -163,4 +163,21 @@ public class ProtoLogViewerConfigReaderTest {
        Truth.assertThat(mConfig.messageHashIsAvailableInFile(5)).isTrue();
        Truth.assertThat(mConfig.messageHashIsAvailableInFile(6)).isFalse();
    }

    @Test
    public void testGetMessageDataForHashFromFile() throws IOException {
        ProtoLogViewerConfigReader.MessageData data1 =
                mConfig.getMessageDataForHashFromFile(1);
        Truth.assertThat(data1).isNotNull();
        Truth.assertThat(data1.message).isEqualTo("My Test Log Message 1 %b");
        Truth.assertThat(data1.group).isEqualTo(TEST_GROUP_NAME);

        ProtoLogViewerConfigReader.MessageData data4 =
                mConfig.getMessageDataForHashFromFile(4);
        Truth.assertThat(data4).isNotNull();
        Truth.assertThat(data4.message).isEqualTo("My Test Log Message 4 %b");
        Truth.assertThat(data4.group).isEqualTo(OTHER_TEST_GROUP_NAME);

        Truth.assertThat(mConfig.getMessageDataForHashFromFile(6)).isNull();
    }
}