195 lines
7.4 KiB
Awk
195 lines
7.4 KiB
Awk
# Copyright (C) 2010 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
# A nawk/gawk script used to extract the list of launchable activities
|
|
# from an application's manifest (i.e. AndroidManifest.xml). Usage:
|
|
#
|
|
# awk -f <this-script> AndroidManifest.xml
|
|
#
|
|
|
|
#
|
|
# Explanation:
|
|
#
|
|
# A given application can have several activities, and each activity
|
|
# can have several intent filters. We want to only list, in the final
|
|
# output, the activities which have a intent-filter that contains the
|
|
# following elements:
|
|
#
|
|
# <action android:name="android.intent.action.MAIN" />
|
|
# <category android:name="android.intent.category.LAUNCHER" />
|
|
#
|
|
# To do this, we need hooks called when entering and exiting <activity>
|
|
# and <intent-filter> elements.
|
|
#
|
|
|
|
BEGIN {
|
|
while ( xml_event() ) {
|
|
# concat xml event type and tag for simpler comparisons
|
|
event = XML_TYPE "-" XML_TAG;
|
|
# When entering a new <activity>, extract its name and set
|
|
# the 'launchable' flag to false.
|
|
if ( event == "BEGIN-ACTIVITY" &&
|
|
XML_RPATH == "ACTIVITY/APPLICATION/MANIFEST/" ) {
|
|
name = XML_ATTR["android:name"];
|
|
launchable = 0;
|
|
}
|
|
# When exiting an <activity>, check that it has a name and
|
|
# is launchable. If so, print its name to the output
|
|
else if ( event == "END-ACTIVITY" &&
|
|
XML_RPATH == "APPLICATION/MANIFEST/" ) {
|
|
if ( name && launchable ) {
|
|
# If the name doesn't contain any dot, we consider
|
|
# that it is just missing the initial one.
|
|
if (index(name, ".") == 0) {
|
|
name = "." name
|
|
}
|
|
print name;
|
|
}
|
|
}
|
|
# When entering an <intent-filter> inside an <activity>, clear
|
|
# the 'action' and 'category' variables. They are updated when
|
|
# we enter the corresponding elements within the intent-filter.
|
|
else if ( event == "BEGIN-INTENT-FILTER" &&
|
|
XML_RPATH == "INTENT-FILTER/ACTIVITY/APPLICATION/MANIFEST/" ) {
|
|
action_main = 0;
|
|
category_launcher = 0;
|
|
}
|
|
# When exiting an <intent-filter>, set the 'launchable' flag to true
|
|
# for the current activity if both 'action' and 'category' have the
|
|
# correct name.
|
|
else if ( event == "END-INTENT-FILTER" &&
|
|
XML_RPATH == "ACTIVITY/APPLICATION/MANIFEST/" ) {
|
|
if ( category_launcher ) {
|
|
launchable = 1;
|
|
}
|
|
}
|
|
# When entering an <action> element inside an <intent-filter>, record
|
|
# its name.
|
|
else if ( event == "BEGIN-ACTION" &&
|
|
XML_RPATH == "ACTION/INTENT-FILTER/ACTIVITY/APPLICATION/MANIFEST/" ) {
|
|
action_main = 0;
|
|
if ( XML_ATTR["android:name"] == "android.intent.action.MAIN" ) {
|
|
action_main = 1;
|
|
}
|
|
}
|
|
# When entering a <category> element inside an <intent-filter>, record
|
|
# its name.
|
|
else if ( event == "BEGIN-CATEGORY" &&
|
|
XML_RPATH == "CATEGORY/INTENT-FILTER/ACTIVITY/APPLICATION/MANIFEST/" ) {
|
|
if ( action_main && XML_ATTR["android:name"] == "android.intent.category.LAUNCHER" ) {
|
|
category_launcher = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#
|
|
# the following is copied directly from xml.awk - see this file for
|
|
# usage and implementation details.
|
|
#
|
|
function xml_event () {
|
|
RS=">";
|
|
XML_TAG=XML_TYPE="";
|
|
split("", XML_ATTR);
|
|
while ( 1 ) {
|
|
if (_xml_closing) { # delayed direct tag closure
|
|
XML_TAG = _xml_closing;
|
|
XML_TYPE = "END";
|
|
_xml_closing = "";
|
|
_xml_exit(XML_TAG);
|
|
return 1;
|
|
}
|
|
if (getline <= 0) return 0; # read new input line
|
|
_xml_p = index($0, "<"); # get start marker
|
|
if (_xml_p == 0) return 0; # end of file (or malformed input)
|
|
$0 = substr($0, _xml_p) # remove anything before '<'
|
|
# ignore CData / Comments / Processing instructions / Declarations
|
|
if (_xml_in_section("<!\\[[Cc][Dd][Aa][Tt][Aa]\\[", "]]") ||
|
|
_xml_in_section("<!--", "--") ||
|
|
_xml_in_section("<\\?", "\\?") ||
|
|
_xml_in_section("<!", "")) {
|
|
continue;
|
|
}
|
|
if (substr($0, 1, 2) == "</") { # is it a closing tag ?
|
|
XML_TYPE = "END";
|
|
$0 = substr($0, 3);
|
|
} else { # nope, it's an opening one
|
|
XML_TYPE = "BEGIN";
|
|
$0 = substr($0, 2);
|
|
}
|
|
XML_TAG = $0
|
|
sub("[ \r\n\t/].*$", "", XML_TAG); # extract tag name
|
|
XML_TAG = toupper(XML_TAG); # uppercase it
|
|
if ( XML_TAG !~ /^[A-Z][-+_.:0-9A-Z]*$/ ) # validate it
|
|
_xml_panic("Invalid tag name: " XML_TAG);
|
|
if (XML_TYPE == "BEGIN") { # update reverse path
|
|
_xml_enter(XML_TAG);
|
|
} else {
|
|
_xml_exit(XML_TAG);
|
|
}
|
|
sub("[^ \r\n\t]*[ \r\n\t]*", "", $0); # get rid of tag and spaces
|
|
while ($0) { # process attributes
|
|
if ($0 == "/") { # deal with direct closing tag, e.g. </foo>
|
|
_xml_closing = XML_TAG; # record delayed tag closure.
|
|
break
|
|
}
|
|
_xml_attrib = $0;
|
|
sub(/=.*$/,"",_xml_attrib); # extract attribute name
|
|
sub(/^[^=]*/,"",$0); # remove it from record
|
|
_xml_attrib = tolower(_xml_attrib);
|
|
if ( _xml_attrib !~ /^[a-z][-+_0-9a-z:]*$/ ) # validate it
|
|
_xml_panic("Invalid attribute name: " _xml_attrib);
|
|
if (substr($0,1,2) == "=\"") { # value is ="something"
|
|
_xml_value = substr($0,3);
|
|
sub(/".*$/,"",_xml_value);
|
|
sub(/^="[^"]*"/,"",$0);
|
|
} else if (substr($0,1,2) == "='") { # value is ='something'
|
|
_xml_value = substr($0,3);
|
|
sub(/'.*$/,"",_xml_value);
|
|
sub(/^='[^']*'/,"",$0);
|
|
} else {
|
|
_xml_panic("Invalid attribute value syntax for " _xml_attrib ": " $0);
|
|
}
|
|
XML_ATTR[_xml_attrib] = _xml_value; # store attribute name/value
|
|
sub(/^[ \t\r\n]*/,"",$0); # get rid of remaining leading spaces
|
|
}
|
|
return 1; # now return, XML_TYPE/TAG/ATTR/RPATH are set
|
|
}
|
|
}
|
|
|
|
function _xml_panic (msg) {
|
|
print msg > "/dev/stderr"
|
|
exit(1)
|
|
}
|
|
|
|
function _xml_in_section (sec_begin, sec_end) {
|
|
if (!match( $0, "^" sec_begin )) return 0;
|
|
while (!match($0, sec_end "$")) {
|
|
if (getline <= 0) _xml_panic("Unexpected EOF: " ERRNO);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
function _xml_enter (tag) {
|
|
XML_RPATH = tag "/" XML_RPATH;
|
|
}
|
|
|
|
function _xml_exit (tag) {
|
|
_xml_p = index(XML_RPATH, "/");
|
|
_xml_expected = substr(XML_RPATH, 1, _xml_p-1);
|
|
if (_xml_expected != XML_TAG)
|
|
_xml_panic("Unexpected close tag: " XML_TAG ", expecting " _xml_expected);
|
|
XML_RPATH = substr(XML_RPATH, _xml_p+1);
|
|
}
|