// newParser creates a parser for the given bugreport. func newParser(br string) (*parser, []string, error) { loc, err := bugreportutils.TimeZone(br) if err != nil { return nil, []string{}, err } pm, warnings := bugreportutils.ExtractPIDMappings(br) // Extract the year and month from the bugreport dumpstate line. d, err := bugreportutils.DumpState(br) if err != nil { return nil, warnings, fmt.Errorf("could not find dumpstate information in the bugreport: %v", err) } buf := new(bytes.Buffer) return &parser{ referenceYear: d.Year(), referenceMonth: d.Month(), loc: loc, activeProcMap: make(map[string]*procEntry), buf: buf, csvState: csv.NewState(buf, false), pidMappings: pm, }, warnings, nil }
// parseBugReport analyzes the given bug report contents, and updates the ParsedData object. func (pd *ParsedData) parseBugReport(fname, contents string) error { meta, err := bugreportutils.ParseMetaInfo(contents) if err != nil { // If there are issues getting the meta info, then the file is most likely not a bug report. return errors.New("error parsing the bug report. Please provide a well formed bug report") } log.Printf("Trace started analyzing file.") // Generate the Historian plot and parse batterystats and activity manager simultaneously. historianCh := make(chan historianData) summariesCh := make(chan summariesData) checkinCh := make(chan checkinData) activityManagerCh := make(chan activityManagerData) // Create a temporary file to save the bug report, for the Historian script. brFile, err := writeTempFile(contents) historianOutput := historianData{"", err} if err == nil { // Don't run the Historian script if could not create temporary file. defer os.Remove(brFile) go func() { html, err := generateHistorianPlot(fname, brFile) historianCh <- historianData{html, err} log.Printf("Trace finished generating Historian plot.") }() } var errs []error ce := "" if meta.SdkVersion < minSupportedSDK { ce = "Unsupported bug report version." errs = append(errs, errors.New("unsupported bug report version")) } else { // No point running these if we don't support the sdk version since we won't get any data from them. bs := bugreportutils.ExtractBatterystatsCheckin(contents) if strings.Contains(bs, "Exception occurred while dumping") { // TODO: Display activity manager events even if battery data is invalid. Currently they will not be displayed. ce = "Exception found in battery dump." errs = append(errs, errors.New("exception found in battery dump")) close(summariesCh) close(checkinCh) } else { pkgs, pkgErrs := packageutils.ExtractAppsFromBugReport(contents) errs = append(errs, pkgErrs...) // Activity manager events are only parsed for supported sdk versions, even though they are still present in unsupported sdk version reports. // This is as the events are rendered with Historian v2, which is not generated for unsupported sdk versions. go func() { amCSV, warnings, errs := activity.Parse(pkgs, contents) activityManagerCh <- activityManagerData{amCSV, warnings, errs} }() go func() { var ctr checkinutil.IntCounter s := &sessionpb.Checkin{ Checkin: proto.String(bs), BuildFingerprint: proto.String(meta.BuildFingerprint), } stats, warnings, pbsErrs := checkinparse.ParseBatteryStats(&ctr, checkinparse.CreateCheckinReport(s), pkgs) checkinCh <- checkinData{stats, warnings, pbsErrs} log.Printf("Trace finished processing checkin.") if stats == nil { ce = "Could not parse aggregated battery stats." errs = append(errs, errors.New("could not parse aggregated battery stats")) // Only returning from this goroutine. return } pd.deviceType = stats.GetBuild().GetDevice() }() go func() { summariesCh <- analyze(bs, pkgs) log.Printf("Trace finished processing summary data.") }() } } if historianOutput.err == nil { historianOutput = <-historianCh } if historianOutput.err != nil { historianOutput.html = fmt.Sprintf("Error generating historian plot: %v", historianOutput.err) } var summariesOutput summariesData var checkinOutput checkinData var activityManagerOutput activityManagerData if meta.SdkVersion >= minSupportedSDK { summariesOutput = <-summariesCh checkinOutput = <-checkinCh activityManagerOutput = <-activityManagerCh errs = append(errs, append(summariesOutput.errs, append(activityManagerOutput.errs, checkinOutput.err...)...)...) } log.Printf("Trace finished generating Historian plot and summaries.") var loc string if d, err := bugreportutils.DumpState(contents); err != nil { log.Printf("Failed to extract time information from bugreport dumpstate: %v", err) } else { loc = d.Location().String() } warnings := append(checkinOutput.warnings, activityManagerOutput.warnings...) data := presenter.Data(meta, fname, summariesOutput.summaries, checkinOutput.batterystats, historianOutput.html, warnings, errs, summariesOutput.overflow) pd.responseArr = append(pd.responseArr, uploadResponse{ SDKVersion: data.SDKVersion, HistorianV2CSV: appendCSVs(summariesOutput.historianV2CSV, activityManagerOutput.csv), LevelSummaryCSV: summariesOutput.levelSummaryCSV, ReportVersion: data.CheckinSummary.ReportVersion, AppStats: data.AppStats, DeviceCapacity: checkinOutput.batterystats.GetSystem().GetPowerUseSummary().GetBatteryCapacityMah(), HistogramStats: extractHistogramStats(data), TimeToDelta: summariesOutput.timeToDelta, CriticalError: ce, FileName: data.Filename, Location: loc, }) pd.data = append(pd.data, data) return nil }