Loading core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java +8 −4 Original line number Diff line number Diff line Loading @@ -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 " Loading core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java +118 −38 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 { Loading @@ -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); Loading @@ -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; } } tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java +17 −0 Original line number Diff line number Diff line Loading @@ -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(); } } Loading
core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java +8 −4 Original line number Diff line number Diff line Loading @@ -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 " Loading
core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java +118 −38 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 { Loading @@ -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); Loading @@ -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; } }
tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java +17 −0 Original line number Diff line number Diff line Loading @@ -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(); } }