Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 127 lines (105 sloc) 3.23 KB
#!/usr/bin/env perl
###############################################################################
##
## Simple script designed to insert after "adb logcat" in a pipeline to track a
## specific package's logcat messages.
##
## I typically invoke this script as a function in my profile:
##
## function plogcat() {
## adb logcat | proclogcat $* | coloredlogcat.py
## }
##
## Then run as:
##
## $ plogcat org.devtcg.five
##
###############################################################################
use strict;
use Data::Dumper;
###############################################################################
@ARGV > 0 or usage($0);
# We support tracking multiple process names. Fill %trackingInfo keys with the
# process names, where the values are to be filled with the current pid for
# that process or -1 if it is presumed dead.
my $trackingInfo = { map { $_ => -1 } @ARGV };
# Flush all writes immediately. This is necessary as we expect this script to
# be placed between two other programs in a pipe which outputs text very slowly
# (adb logcat outputs only when events happen), so it's rare to fill up the
# buffer quickly. Without this, the normal buffering that occurs between piped
# programs not directly attached to a pty would prevent the user from seeing
# messages as they arrive.
$| = 1;
# Lookup the pids of the processes before we start. From then on, rely on
# the ActivityManager to tell us as the processes dies and starts.
my $numPids = get_pids($trackingInfo);
if ($numPids == 0) {
print "- waiting for process ", join(' or ', keys %$trackingInfo), " -\n";
}
while (<STDIN>) {
my $line = $_;
my ($level, $tag, $pid, $message) = $line =~
m/^([A-Z])\/(.*?)\(\s*(\d+)\s*\): (.*)$/;
chomp $message;
if ($tag eq 'ActivityManager') {
if ($message =~ m/^Start proc (.*?) .*?: pid=(\d+) /) {
if (exists $trackingInfo->{$1}) {
$trackingInfo->{$1} = $2;
print $line;
}
} elsif ($message =~ m/Start proc (\d+):(.*?)\//) {
if (exists $trackingInfo->{$2}) {
$trackingInfo->{$2} = $1;
print $line;
}
} elsif ($message =~ m/Process (.*?) \(pid (\d+)\) has died./) {
if (exists $trackingInfo->{$1}) {
$trackingInfo->{$1} = -1;
print $line;
}
}
} elsif (in_list($pid, values %$trackingInfo)) {
print $line;
}
}
###############################################################################
sub in_list($@) {
my $needle = shift;
my @haystack = @_;
foreach my $hay (@haystack) {
if ($hay eq $needle) {
return 1;
}
}
return 0;
}
sub get_pids {
my $info = shift;
my @ps = qx{adb shell ps};
if (@ps == 0) {
return -1;
}
my @columns = split /\s+/, (shift @ps);
# There's a "STATE" column slipped in between WCHAN and NAME that has no
# room for a column...
splice @columns, $#columns, 0, 'STATE';
my $numFound = 0;
foreach (@ps) {
s/\s+$//;
my @data = split /\s+/, $_, scalar @columns;
my %row = map { $_ => (shift @data) } @columns;
if (exists $info->{$row{NAME}}) {
$info->{$row{NAME}} = $row{PID};
$numFound++;
}
}
return $numFound;
}
sub usage {
my $prog = shift;
die <<"EOF"
Usage: adb logcat | $0 <process-name>
Usually, `process-name' is usually the same as your package, but not
necessarily. To make sure, type `adb shell ps' and look through the list.
EOF
}