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

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

Distinguish the reason why decoding failed.

We were throwing a RuntimeException that the message hash wasn't in the
viewer config file, but this can also happen when the viewer config file
wasn't loaded into memory from disk, which is more likely a bug.

Update the exception to clarify what's happening.

Test: atest com.android.internal.protolog.ProtoLogViewerConfigReaderTest
Bug: 388235335
Flag: EXEMPT updating error message clarity
Change-Id: I484c918ec196d57bb910900e3a7a7870923d64a5
parent 1dd200f9
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -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) {
+30 −0
Original line number Diff line number Diff line
@@ -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 {
+11 −0
Original line number Diff line number Diff line
@@ -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();
    }
}