Example #1
0
func (p *parser) parseANR(pkgs []*usagepb.PackageInfo, timestamp int64, v string) (string, error) {
	// Expected format of v is: User,pid,Package Name,Flags,reason.
	parts := strings.Split(v, ",")
	if len(parts) < 5 {
		return "", fmt.Errorf("%s: got %d parts, want 5", ANREvent, len(parts))
	}
	warning := ""
	if len(parts) > 5 {
		warning = fmt.Sprintf("%s: got %d parts, expected 5", ANREvent, len(parts))
	}

	var uid string
	// ANR event should still be displayed even if uid could not be matched.
	// Any error is returned at end of function.
	pkg, err := packageutils.GuessPackage(parts[2], "", pkgs)
	if pkg != nil {
		uid = fmt.Sprintf("%d", pkg.GetUid())
	}
	// We store the UID as part of the ANR value rather than in the Opt field.
	// Usually the Opt field is used to populate a service mapper in the JS, however a less roundabout way is to just have the UID as part of the event itself, which will be specially parsed in the JS code.
	parts = append(parts[1:5], uid)
	p.csvState.PrintInstantEvent(csv.Entry{
		Desc:  "ANR",
		Start: timestamp,
		Type:  "service",
		Value: strings.Join(parts, "~"),
	})
	return warning, err
}
Example #2
0
// Parse writes a CSV entry for each line matching activity manager proc start and died, ANR and low memory events.
// Package info is used to match crash events to UIDs. Errors encountered during parsing will be collected into an errors slice and will continue parsing remaining events.
func Parse(pkgs []*usagepb.PackageInfo, f string) (string, []string, []error) {
	p, warnings, err := newParser(f)
	if err != nil {
		return "", nil, []error{err}
	}

	var errs []error
	crashSource := ""
	for _, line := range strings.Split(f, "\n") {
		m, result := historianutils.SubexpNames(logEntryRE, line)
		if !m {
			continue
		}
		timestamp, err := p.fullTimestamp(result["month"], result["day"], result["timeStamp"], result["remainder"])
		if err != nil {
			errs = append(errs, err)
			continue
		}
		details := result["details"]
		pid := result["pid"]

		if m, _ = historianutils.SubexpNames(bluetoothScanRE, details); m {
			p.parseBluetoothScan(timestamp, pid)
			continue
		}
		if m, result = historianutils.SubexpNames(crashStartRE, details); m {
			crashSource = result["source"]
			continue
		}
		if m, result = historianutils.SubexpNames(crashProcessRE, details); m && crashSource != "" {
			var uid string
			pkg, err := packageutils.GuessPackage(result["process"], "", pkgs)
			if err != nil {
				errs = append(errs, err)
				// Still want to show the crash event even if there was an error matching a package.
			} else if pkg != nil {
				uid = fmt.Sprintf("%d", pkg.GetUid())
			}

			p.csvState.PrintInstantEvent(csv.Entry{
				Desc:  "Crashes",
				Start: timestamp,
				Type:  "service",
				Value: fmt.Sprintf("%s: %s", result["process"], crashSource),
				Opt:   uid,
			})
			crashSource = ""
			continue
		}

		m, result = historianutils.SubexpNames(activityManagerRE, details)
		if !m {
			// Non matching lines are ignored but not considered errors.
			continue
		}
		t := result["transitionType"]
		// Format of the value is defined at frameworks/base/services/core/java/com/android/server/am/EventLogTags.logtags.
		v := result["value"]

		switch t {
		case LowMemoryEvent:
			p.parseLowMemory(timestamp, v)

		case ANREvent:
			warning, err := p.parseANR(pkgs, timestamp, v)
			if err != nil {
				errs = append(errs, err)
			}
			if warning != "" {
				warnings = append(warnings, warning)
			}

		case ProcStartEvent, ProcDiedEvent:
			warning, err := p.parseProc(timestamp, v, t)
			if err != nil {
				errs = append(errs, err)
			}
			if warning != "" {
				warnings = append(warnings, warning)
			}

		default:
			errs = append(errs, fmt.Errorf("unknown transition for %q: %q", AMProc, t))
		}
	}
	// If there was no corresponding am_proc_died event, set the end time to 0.
	p.csvState.PrintAllReset(0)
	return p.buf.String(), warnings, errs
}