Mathew Inwood | 5ebc4cc | 2018-03-08 09:47:46 +0000 | [diff] [blame] | 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 | |
| 16 | use strict; |
| 17 | use Getopt::Long; |
| 18 | use Pod::Usage; |
| 19 | |
| 20 | =pod |
| 21 | |
| 22 | =head1 DESCRIPTION |
| 23 | |
| 24 | This script parses API violations from C<adb logcat>. Output is in CSV format |
| 25 | with columns C<package>, C<symbol>, C<list>. |
| 26 | |
| 27 | The package name is mapped from a PID, parsed from the same log. To ensure you |
| 28 | get 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 | |
| 53 | Process a bugreport, rather than raw logcat |
| 54 | |
Mathew Inwood | cebbb65 | 2018-03-19 15:15:06 +0000 | [diff] [blame] | 55 | =item --short|-s |
| 56 | |
| 57 | Output API signatures only, don't include CSV header/package names/list name. |
| 58 | |
Mathew Inwood | 5ebc4cc | 2018-03-08 09:47:46 +0000 | [diff] [blame] | 59 | =item --help |
| 60 | |
| 61 | =back |
| 62 | |
| 63 | =cut |
| 64 | |
| 65 | my $lightgrey = 1; |
| 66 | my $darkgrey = 1; |
| 67 | my $black = 1; |
| 68 | my $bugreport = 0; |
Mathew Inwood | cebbb65 | 2018-03-19 15:15:06 +0000 | [diff] [blame] | 69 | my $short = 0; |
Mathew Inwood | 5ebc4cc | 2018-03-08 09:47:46 +0000 | [diff] [blame] | 70 | my $help = 0; |
| 71 | |
| 72 | GetOptions("lightgrey!" => \$lightgrey, |
| 73 | "darkgrey!" => \$darkgrey, |
| 74 | "black!" => \$black, |
| 75 | "bugreport|b" => \$bugreport, |
Mathew Inwood | cebbb65 | 2018-03-19 15:15:06 +0000 | [diff] [blame] | 76 | "short|s" => \$short, |
Mathew Inwood | 5ebc4cc | 2018-03-08 09:47:46 +0000 | [diff] [blame] | 77 | "help" => \$help) |
| 78 | or pod2usage(q(-verbose) => 1); |
| 79 | |
| 80 | pod2usage(q(-verbose) => 2) if ($help); |
| 81 | |
| 82 | my $in; |
| 83 | |
| 84 | if ($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 | |
| 98 | my $procmap = {}; |
Mathew Inwood | cebbb65 | 2018-03-19 15:15:06 +0000 | [diff] [blame] | 99 | print "package,symbol,list\n" unless $short; |
Mathew Inwood | 5ebc4cc | 2018-03-08 09:47:46 +0000 | [diff] [blame] | 100 | while (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 | } |
Mathew Inwood | cebbb65 | 2018-03-19 15:15:06 +0000 | [diff] [blame] | 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 | } |
Mathew Inwood | 5ebc4cc | 2018-03-08 09:47:46 +0000 | [diff] [blame] | 130 | } |
| 131 | } |
| 132 | } |
| 133 | |