1#!/usr/bin/perl 2# Copyright (C) 2018 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16use strict; 17use Getopt::Long; 18use Pod::Usage; 19 20=pod 21 22=head1 DESCRIPTION 23 24This script parses API violations from C<adb logcat>. Output is in CSV format 25with columns C<package>, C<symbol>, C<list>. 26 27The package name is mapped from a PID, parsed from the same log. To ensure you 28get all packages names, you should process the logcat from device boot time. 29 30=head1 SYNOPSIS 31 32 adb logcat | perl find_api_violations.pl > violations.csv 33 cat bugreport.txt | perl find_api_violations.pl --bugreport > violations.csv 34 35=head1 OPTIONS 36 37=over 38 39=item --[no]lightgrey 40 41(Don't) show light grey list accesses (default true) 42 43=item --[no]darkgrey 44 45(Don't) show dark grey list accesses (default true) 46 47=item --[no]black 48 49(Don't) show black list accesses (default true) 50 51=item --bugreport|-b 52 53Process a bugreport, rather than raw logcat 54 55=item --short|-s 56 57Output API signatures only, don't include CSV header/package names/list name. 58 59=item --help 60 61=back 62 63=cut 64 65my $lightgrey = 1; 66my $darkgrey = 1; 67my $black = 1; 68my $bugreport = 0; 69my $short = 0; 70my $help = 0; 71 72GetOptions("lightgrey!" => \$lightgrey, 73 "darkgrey!" => \$darkgrey, 74 "black!" => \$black, 75 "bugreport|b" => \$bugreport, 76 "short|s" => \$short, 77 "help" => \$help) 78 or pod2usage(q(-verbose) => 1); 79 80pod2usage(q(-verbose) => 2) if ($help); 81 82my $in; 83 84if ($bugreport) { 85 my $found_main = 0; 86 while (my $line = <>) { 87 chomp $line; 88 if ($line =~ m/^------ SYSTEM LOG /) { 89 $found_main = 1; 90 last; 91 } 92 } 93 if (!$found_main) { 94 die "Couldn't find main log in bugreport\n"; 95 } 96} 97 98my $procmap = {}; 99print "package,symbol,list\n" unless $short; 100while (my $line = <>) { 101 chomp $line; 102 last if $bugreport and $line =~ m/^------ \d+\.\d+s was the duration of 'SYSTEM LOG' ------/; 103 next if $line =~ m/^--------- beginning of/; 104 unless ($line =~ m/^\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}\s+(?:\w+\s+)?(\d+)\s+(\d+)\s+([VWIDE])\s+(.*?): (.*)$/) { 105 die "Cannot match line: $line\n"; 106 next; 107 } 108 my ($pid, $tid, $class, $tag, $msg) = ($1, $2, $3, $4, $5); 109 if ($tag eq "ActivityManager" && $msg =~ m/^Start proc (\d+):(.*?) for /) { 110 my ($new_pid, $proc_name) = ($1, $2); 111 my $package; 112 if ($proc_name =~ m/^(.*?)(:.*?)?\/(.*)$/) { 113 $package = $1; 114 } else { 115 $package = $proc_name; 116 } 117 $procmap->{$new_pid} = $package; 118 } 119 if ($msg =~ m/Accessing hidden (\w+) (L.*?) \((.*list), (.*?)\)/) { 120 my ($member_type, $symbol, $list, $access_type) = ($1, $2, $3, $4); 121 my $package = $procmap->{$pid} || "unknown($pid)"; 122 if (($list =~ m/light/ && $lightgrey) 123 || ($list =~ m/dark/ && $darkgrey) 124 || ($list =~ m/black/ && $black)) { 125 if ($short) { 126 print "$symbol\n"; 127 } else { 128 print "$package,$symbol,$list\n" 129 } 130 } 131 } 132} 133 134