diff options
3 files changed, 70 insertions, 4 deletions
diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java index e0a77d2be724..1f9df3cc842a 100644 --- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java @@ -28,6 +28,7 @@ import com.android.internal.protolog.common.IProtoLogGroup; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { @@ -161,15 +162,39 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { messageString = message.getMessage(mViewerConfigReader); if (messageString == null) { - throw new RuntimeException("Failed to decode message for logcat. " - + "Message hash (" + message.getMessageHash() + ") either not available in " - + "viewerConfig file (" + mViewerConfigFilePath + ") or " - + "not loaded into memory from file before decoding."); + // Either we failed to load the config for this log message from the viewer config file + // into memory, or the message hash is simply not available in the viewer config file. + // We want to confirm that the message hash is not available in the viewer config file + // before throwing an exception. + throw new RuntimeException(getReasonForFailureToGetMessageString(message)); } return messageString; } + private String getReasonForFailureToGetMessageString(Message message) { + if (message.getMessageHash() == null) { + return "Trying to get message from null message hash"; + } + + try { + if (mViewerConfigReader.messageHashIsAvailableInFile(message.getMessageHash())) { + 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."; + } + } catch (IOException e) { + return "Failed to get string message to log but could not identify the root cause due " + + "to an IO error in reading the viewer config file."; + } + } + private void loadLogcatGroupsViewerConfig(@NonNull IProtoLogGroup[] protoLogGroups) { final var groupsLoggingToLogcat = new ArrayList<String>(); for (IProtoLogGroup protoLogGroup : protoLogGroups) { diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java index 524f64225084..f77179949fbf 100644 --- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java +++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java @@ -100,6 +100,36 @@ public class ProtoLogViewerConfigReader { } } + /** + * Return whether or not the viewer config file contains a message with the specified hash. + * @param messageHash The hash message we are looking for in the viewer config file + * @return True iff the message with message hash is contained in the viewer config. + * @throws IOException if there was an issue reading the viewer config file. + */ + public boolean messageHashIsAvailableInFile(long messageHash) + throws IOException { + try (var pisWrapper = mViewerConfigInputStreamProvider.getInputStream()) { + final var pis = pisWrapper.get(); + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (pis.getFieldNumber() == (int) MESSAGES) { + final long inMessageToken = pis.start(MESSAGES); + + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (pis.getFieldNumber() == (int) MESSAGE_ID) { + if (pis.readLong(MESSAGE_ID) == messageHash) { + return true; + } + } + } + + pis.end(inMessageToken); + } + } + } + + return false; + } + @NonNull private Map<Long, String> loadViewerConfigMappingForGroup(@NonNull String group) throws IOException { diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java index 9e029a8d5e57..72b1780ceb06 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java @@ -33,6 +33,7 @@ import org.junit.runners.JUnit4; import perfetto.protos.ProtologCommon; import java.io.File; +import java.io.IOException; @Presubmit @RunWith(JUnit4.class) @@ -159,4 +160,14 @@ public class ProtoLogViewerConfigReaderTest { loadViewerConfig(); unloadViewerConfig(); } + + @Test + public void testMessageHashIsAvailableInFile() throws IOException { + Truth.assertThat(mConfig.messageHashIsAvailableInFile(1)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(2)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(3)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(4)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(5)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(6)).isFalse(); + } } |