Skip to content

Commit

Permalink
Post-process log records of dumpstate to assign process names
Browse files Browse the repository at this point in the history
Some dumpstates have process information after the logcat sections, so
additional pass is needed to make sure LogRecords are properly
configured.

Issue: #279
  • Loading branch information
mlopatkin committed Dec 26, 2023
1 parent 11c9cd5 commit d5a1624
Show file tree
Hide file tree
Showing 4 changed files with 6,255 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.google.common.base.CharMatcher;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain;

import org.checkerframework.checker.nullness.qual.Nullable;
Expand Down Expand Up @@ -94,7 +93,7 @@ public String getCaption() {
private final String tag;
private final String message;
private final @Nullable Buffer buffer;
private final String appName;
private final @Nullable String appName;

LogRecord(
SequenceNumber seqNo,
Expand All @@ -110,7 +109,7 @@ public String getCaption() {
this.time = time;
this.pid = pid;
this.tid = tid;
this.appName = CharMatcher.whitespace().trimFrom(Strings.nullToEmpty(appName));
this.appName = appName != null ? CharMatcher.whitespace().trimFrom(appName) : null;
this.priority = priority;
this.tag = tag;
this.message = message;
Expand Down Expand Up @@ -149,8 +148,12 @@ public String getMessage() {
return buffer;
}

public boolean hasAppName() {
return appName != null;
}

public String getAppName() {
return appName;
return appName != null ? appName : "";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,27 +213,40 @@ public ImportResult readFrom(LineReader in) throws IOException, UnrecognizedForm
if (availableBuffers.isEmpty()) {
throw new UnrecognizedFormatException("Cannot load dumpstate file, no valid logcat section found");
}

OfflineSorter sorter = new OfflineSorter();
records.forEach(sorter::add);

if (sorter.hasTimeTravels()) {
problems.add(new ImportProblem(
"Dumpstate file has time travels. Record ordering across buffers may not be consistent."));
}
if (!hasPsSection && !hasProcessWaitSection) {
problems.add(
new ImportProblem("Failed to find Processes section. Application names are not available."));
} else if ((psSectionHadUnparseableLines || processWaitSectionHadUnparseableLines)
&& pidToProcessConverter.isEmpty()) {
problems.add(
new ImportProblem("Failed to parse Processes section. Application names are not available."));
} else {
updateProcesses();
}

OfflineSorter sorter = new OfflineSorter();
records.forEach(sorter::add);

if (sorter.hasTimeTravels()) {
problems.add(new ImportProblem(
"Dumpstate file has time travels. Record ordering across buffers may not be consistent."));
}
return new ImportResult(
new DumpstateFileDataSource(
fileName, sorter.buildTimestampOrdered(), EnumSet.allOf(Field.class), availableBuffers,
pidToProcessConverter),
problems);
}

private void updateProcesses() {
var iterator = records.listIterator();
while (iterator.hasNext()) {
var record = iterator.next();
final String appName;
if (!record.hasAppName() && (appName = pidToProcessConverter.get(record.getPid())) != null) {
iterator.set(record.withAppName(appName));
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@ public void openDumpstateWithTimeTravel() throws Exception {
assertThat(FileDataSourceFactory.createDataSource("time-travel.dump", log).getProblems()).isNotEmpty();
}

@Test
public void openDumpstateWithProcessAfterLogs() throws Exception {
CharSource log = openTestData("emulator_api34.minimized.dump");

var source = FileDataSourceFactory.createDataSource("process-names.dump", log).getDataSource();

assertThat(source.getPidToProcessConverter()).isNotEmpty();

assertThat(getRecords(source)).as("have some log records with app names").anyMatch(LogRecord::hasAppName);

assertThat(getRecords(source))
.filteredOn(r -> !r.hasAppName())
.as("All records without app names are because the process is not known")
.allSatisfy(r -> assertThat(source.getPidToProcessConverter()).doesNotContainKey(r.getPid()));
}

private CharSource openTestData(String testDataName) {
return Resources.asCharSource(Resources.getResource(getClass(), testDataName), StandardCharsets.UTF_8);
}
Expand Down
Loading

0 comments on commit d5a1624

Please sign in to comment.