--- /dev/null
+# 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 debuggable flag from an
+# application's manifest (i.e. AndroidManifest.xml). Usage:
+#
+# awk -f <this-script> AndroidManifest.xml
+#
+
+BEGIN {
+ DEBUGGABLE = "";
+ while ( xml_event() ) {
+ # simply extract the 'android:debuggable' attribute value from
+ # the first <manifest><application> element we find.
+ if ( XML_TYPE == "BEGIN" && XML_TAG == "APPLICATION" &&
+ XML_RPATH == "APPLICATION/MANIFEST/" ) {
+ DEBUGGABLE = XML_ATTR["android:debuggable"];
+ break;
+ }
+ }
+ # ensure the value is either "true" or "false"
+ if ( DEBUGGABLE != "true" )
+ DEBUGGABLE = "false";
+
+ print DEBUGGABLE;
+}
+
+#
+# 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("[ \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("[^ \n\t]*[ \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\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);
+}
--- /dev/null
+# 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 ) {
+ 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 = ""
+ category = ""
+ }
+ # 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 ( action == "android.intent.action.MAIN" &&
+ category == "android.intent.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 = XML_ATTR["android:name"];
+ }
+ # 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/" ) {
+ category = XML_ATTR["android:name"];
+ }
+ }
+}
+
+
+#
+# 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("[ \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("[^ \n\t]*[ \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\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);
+}
--- /dev/null
+# 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 package name from an application's
+# manifest (i.e. AndroidManifest.xml). Usage is:
+#
+# awk -f <this-script> AndroidManifest.xml
+#
+# The name itself is the value of the 'package' attribute in the
+# 'manifest' element.
+#
+
+BEGIN {
+ PACKAGE="";
+ while (xml_event()) {
+ # Simply extract the value of the 'name' attribute from
+ # the top-level <manifest> element.
+ if ( XML_TYPE == "BEGIN" && XML_RPATH == "MANIFEST/" ) {
+ PACKAGE = XML_ATTR["package"];
+ break;
+ }
+ }
+ if (!PACKAGE)
+ PACKAGE = "<none>";
+
+ print PACKAGE;
+}
+
+#
+# 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("[ \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("[^ \n\t]*[ \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\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);
+}
--- /dev/null
+# 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.
+#
+
+# Tiny XML parser implementation in awk.
+#
+# This file is not meant to be used directly, instead copy the
+# functions it defines here into your own script then specialize
+# it appropriately.
+#
+
+# See further below for usage instructions and implementation details.
+#
+
+# ---------------------------- cut here ---------------------------
+
+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("[ \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("[^ \n\t]*[ \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\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);
+}
+
+# ---------------------------- cut here ---------------------------
+
+# USAGE:
+#
+# The functions provided here are used to extract the tags and attributes of a
+# given XML file. They do not support extraction of data, CDATA, comments,
+# processing instructions and declarations at all.
+#
+# You should use this from the BEGIN {} action of your awk script (it will
+# not work from an END {} action).
+#
+# Call xml_event() in a while loop. This functions returns 1 for each XML
+# 'event' encountered, or 0 when the end of input is reached. Note that in
+# case of malformed output, an error will be printed and the script will
+# force an exit(1)
+#
+# After each succesful xml_event() call, the following variables will be set:
+#
+# XML_TYPE: type of event: "BEGIN" -> mean an opening tag, "END" a
+# closing one.
+#
+# XML_TAG: name of the tag, always in UPPERCASE!
+#
+# XML_ATTR: a map of attributes for the type. Only set for "BEGIN" types.
+# all attribute names are in lowercase.
+#
+# beware: values are *not* unescaped !
+#
+# XML_RPATH: the _reversed_ element path, using "/" as a separator.
+# if you are within the <manifest><application> tag, then
+# it will be set to "APPLICATION/MANIFEST/"
+# (note the trailing slash).
+#
+
+# This is a simple example that dumps the output of the parsing.
+#
+BEGIN {
+ while ( xml_event() ) {
+ printf "XML_TYPE=%s XML_TAG=%s XML_RPATH=%s", XML_TYPE, XML_TAG, XML_RPATH;
+ if (XML_TYPE == "BEGIN") {
+ for (attr in XML_ATTR) {
+ printf " %s='%s'", attr, XML_ATTR[attr];
+ }
+ }
+ printf "\n";
+ }
+}
+
+# IMPLEMENTATION DETAILS:
+#
+# 1. '>' as the record separator:
+#
+# RS is set to '>' to use this character as the record separator, instead of
+# the default '\n'. This means that something like the following:
+#
+# <foo><bar attrib="value">stuff</bar></foo>
+#
+# will be translated into the following successive 'records':
+#
+# <foo
+# <bar attrib="value"
+# stuff</bar
+# </foo
+#
+# Note that the '>' is never part of the records and thus will not be matched.
+# If the record does not contain a single '<', the input is either
+# malformed XML, or we reached the end of file with data after the last
+# '>'.
+#
+# Newlines in the original input are kept in the records as-is.
+#
+# 2. Getting rid of unwanted stuff:
+#
+# We don't need any of the data within elements, so we get rid of them by
+# simply ignoring anything before the '<' in the current record. This is
+# done with code like this:
+#
+# p = index($0, "<"); # get index of '<'
+# if (p == 0) -> return 0; # malformed input or end of file
+# $0 = substr($0, p+1); # remove anything before the '<' in record
+#
+# We also want to ignore certain sections like CDATA, comments, declarations,
+# etc.. These begin with a certain pattern and end with another one, e.g.
+# "<!--" and "-->" for comments. This is handled by the _xml_in_section()
+# function that accepts two patterns as input:
+#
+# sec_begin: is the pattern for the start of the record.
+# sec_end: is the pattern for the end of the record (minus trailing '>').
+#
+# The function deals with the fact that these section can embed a valid '>'
+# and will then span multiple records, i.e. something like:
+#
+# <!-- A comment with an embedded > right here ! -->
+#
+# will be decomposed into two records:
+#
+# "<!-- A comment with an embedded "
+# " right here ! --"
+#
+# The function deals with this case, and exits when such a section is not
+# properly terminated in the input.
+#
+# _xml_in_section() returns 1 if an ignorable section was found, or 0 otherwise.
+#
+# 3. Extracting the tag name:
+#
+# </foo> is a closing tag, and <foo> an opening tag, this is handled
+# by the following code:
+#
+# if (substr($0, 1, 2) == "</") {
+# XML_TYPE = "END";
+# $0 = substr($0, 3);
+# } else {
+# XML_TYPE = "BEGIN";
+# $0 = substr($0, 2);
+# }
+#
+# which defines XML_TYPE, and removes the leading "</" or "<" from the record.
+# The tag is later extracted and converted to uppercase with:
+#
+# XML_TAG = $0 # copy record
+# sub("[ \n\t/].*$", "", XML_TAG); # remove anything after tag name
+# XML_TAG = toupper(XML_TAG); # conver to uppercase
+# # validate tag
+# if ( XML_TAG !~ /^[A-Z][-+_.:0-9A-Z]*$/ ) -> panic
+#
+# Then the record is purged from the tag name and the spaces after it:
+#
+# # get rid of tag and spaces after it in $0
+# sub("[^ \n\t]*[ \n\t]*", "", $0);
+#
+# 4. Maintaining XML_RPATH:
+#
+# The _xml_enter() and _xml_exit() functions are called to maintain the
+# XML_RPATH variable when entering and exiting specific tags. _xml_exit()
+# will also validate the input, checking proper tag enclosure (or exit(1)
+# in case of error).
+#
+# if (XML_TYPE == "BEGIN") {
+# _xml_enter(XML_TAG);
+# } else {
+# _xml_exit(XML_TAG);
+# }
+#
+# 5. Extracting attributes:
+#
+# A loop is implemented to parse attributes, the idea is to get the attribute
+# name, which is always followed by a '=' character:
+#
+# _xml_attrib = $0; # copy record.
+# sub(/=.*$/,"",_xml_attrib); # get rid of '=' and anything after.
+# sub(/^[^=]*/,"",$0); # remove attribute name from $0
+# _xml_attrib = tolower(_xml_attrib);
+# if ( _xml_attrib !~ /^[a-z][-+_0-9a-z:]*$/ )
+# _xml_panic("Invalid attribute name: " _xml_attrib);
+#
+# Now get the value, which is enclosed by either (") or (')
+#
+# if (substr($0,1,2) == "=\"") { # if $0 begins with ="
+# _xml_value = substr($0,3); # extract value
+# sub(/".*$/,"",_xml_value);
+# sub(/^="[^"]*"/,"",$0); # remove it from $0
+# } else if (substr($0,1,2) == "='") { # if $0 begins with ='
+# _xml_value = substr($0,3); # extract value
+# sub(/'.*$/,"",_xml_value);
+# sub(/^='[^']*'/,"",$0); # remove it from $0
+# } else {
+# -> panic (malformed input)
+# }
+#
+# After that, we simply store the value into the XML_ATTR associative
+# array, and cleanup $0 from leading spaces:
+#
+# XML_ATTR[_xml_attrib] = _xml_value;
+# sub(/^[ \t\n]*/,"",$0);
+#
+#
+# 6. Handling direct tag closure:
+#
+# When a tag is closed directly (as in <foo/>), A single '/' will be
+# parsed in the attribute parsing loop. We need to record this for the
+# next call to xml_event(), since the current one should return a"BEGIN"
+# for the "FOO" tag instead.
+#
+# We do this by setting the special _xml_closing variable, as in:
+#
+# if ($0 == "/") {
+# # record a delayed tag closure for the next call
+# _xml_closing = XML_TAG;
+# break
+# }
+#
+# This variable is checked at the start of xml_event() like this:
+#
+# # delayed tag closure - see below
+# if (_xml_closing) {
+# XML_TAG = _xml_closing;
+# XML_TYPE = "END";
+# _xml_closing = "";
+# _xml_exit(XML_TAG);
+# return 1;
+# }
+#
+# Note the call to _xml_exit() to update XML_RPATH here.
+#
ifndef APP_PLATFORM
_local_props := $(strip $(wildcard $(APP_PROJECT_PATH)/default.properties))
ifdef _local_props
- APP_PLATFORM := $(strip $(shell $(HOST_AWK) -f $(BUILD_SYSTEM)/extract-platform.awk < $(_local_props)))
+ APP_PLATFORM := $(strip $(shell $(HOST_AWK) -f $(BUILD_AWK)/extract-platform.awk < $(_local_props)))
$(call ndk_log, Found APP_PLATFORM=$(APP_PLATFORM) in $(_local_props))
else
APP_PLATFORM := android-3
+++ /dev/null
-# 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 debuggable flag from an application's
-# manifest (i.e. AndroidManifest.xml).
-#
-# The name itself is the value of the 'android:debuggable' attribute in the
-# 'application' element.
-#
-
-BEGIN {
- FS=" "
- in_tag=0
- regex1="android:debuggable=\"true\""
- regex2="android:debuggable='true'"
- DEBUGGABLE="false"
-}
-
-/<application/ {
- in_tag=1
-}
-
-in_tag == 1 && /android:debuggable=/ {
- if (match($0,regex1)) {
- DEBUGGABLE=substr($0,RSTART+20,RLENGTH-21)
- }
- else if (match($0,regex2)) {
- DEBUGGABLE=substr($0,RSTART+20,RLENGTH-21)
- }
-}
-
-in_tag == 1 && />/ {
- in_tag=0
-}
-
-END {
- print DEBUGGABLE
-}
+++ /dev/null
-# 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 package name from an application's
-# manifest (i.e. AndroidManifest.xml).
-#
-# The name itself is the value of the 'package' attribute in the
-# 'manifest' element.
-#
-
-BEGIN {
- FS=" "
- in_manifest=0
- package_regex1="package=\"([[:alnum:].]+)\""
- package_regex2="package='([[:alnum:].]+)'"
- PACKAGE="<none>"
-}
-
-/<manifest/ {
- in_manifest=1
-}
-
-in_manifest == 1 && /package=/ {
- if (match($0,package_regex1)) {
- PACKAGE=substr($0,RSTART+9,RLENGTH-10)
- }
- else if (match($0,package_regex2)) {
- PACKAGE=substr($0,RSTART+9,RLENGTH-10)
- }
-}
-
-in_manifest == 1 && />/ {
- in_manifest=0
-}
-
-END {
- print PACKAGE
-}
$(call ndk_log,Host awk tool from environment: $(HOST_AWK))
endif
-AWK_TEST := $(shell $(HOST_AWK) -f $(NDK_ROOT)/build/check-awk.awk)
+# Location of all awk scripts we use
+BUILD_AWK := $(NDK_ROOT)/build/awk
+
+AWK_TEST := $(shell $(HOST_AWK) -f $(BUILD_AWK)/check-awk.awk)
$(call ndk_log,Host awk test returned: $(AWK_TEST))
ifneq ($(AWK_TEST),Pass)
$(call __ndk_info,Host awk tool is outdated. Please define HOST_AWK to point to Gawk or Nawk !)
NDK_APP_DEBUGGABLE := false
NDK_APP_MANIFEST := $(strip $(wildcard $(NDK_APP_PROJECT_PATH)/AndroidManifest.xml))
ifdef NDK_APP_MANIFEST
- NDK_APP_DEBUGGABLE := $(shell $(HOST_AWK) -f $(BUILD_SYSTEM)/extract-package-debuggable.awk $(NDK_APP_MANIFEST))
+ NDK_APP_DEBUGGABLE := $(shell $(HOST_AWK) -f $(BUILD_AWK)/extract-debuggable.awk $(NDK_APP_MANIFEST))
endif
ifdef NDK_LOG
In other words, your AndroidManifest.xml has an <application>
element that sets the android:debuggable attribute to "true"
- 3. You are running your application on Android 2.2:
+ 3. You are running your application on Android 2.2 (or higher):
ndk-gdb will not work if you try to run your application on
previous versions of the system. That does not mean that your
not contain required support files and native debugging
will not be possible.
- 4. Your application must be launched before ndk-gdb:
-
- At the moment, it is not possible to directly launch your
- application from ndk-gdb. You must thus start it before
- invoking the script.
-
-
'ndk-gdb' handles many error conditions and will dump an informative error
message if it finds a problem. For example, it:
package name is also debuggable.
-When ndk-gdb launches succesfully, it stops the running application and
-gives you a GDB prompt. You can set breakpoints with 'b <location>' and
-resume execution with 'c' (for 'continue'). See the GDB manual for a list
-of commands.
+By default, ndk-gdb will search for an already-running application process,
+and will dump an error if it doesn't find one. You can however use the --start
+or --launch=<name> option to automatically start your activity before the
+debugging session.
-NOTE: ndk-gdb sets up GDB automatically so that it can find your sources
- and generated libraries (with debug information) automatically.
+When it succesfully attaches to your application process, ndk-gdb will give
+you a normal GDB prompt, after setting up the session to properly look for
+your source files and symbol/debug versions of your generated native
+libraries.
+
+You can set breakpoints with 'b <location>' and resume execution with 'c'
+(for 'continue'). See the GDB manual for a list of commands.
IMPORTANT: When quitting the GDB prompt, your debugged application process
will be stopped! This is a gdb limitation.
+IMPORTANT: The GDB prompt will be preceded by a long list of error messages,
+ where gdb complains that it cannot find various system libraries
+ (e.g. libc.so, libstdc++.so, liblog.so, libcutils.so, etc...)
+
+ This is normal, because there are no symbol/debug versions of
+ these libraries corresponding to your target device on your
+ development machine. You can safely ignore these messages.
+
II. Options:
------------
To see a list of options, type 'ndk-gdb --help'. Notable ones are:
+ --verbose:
+ Print verbose information about the native debugging session setup.
+ Only needed to debug problems when you can't connect and that the
+ error messages printed by ndk-gdb are not enough.
+
--force:
By default, ndk-gdb aborts if it finds that another native debugging
session is running on the same device. Using --force will kill the
session, and replace it with a new one. Note that the debugged program
is *not* killed and will be stopped again.
- --verbose:
- Print verbose information about the native debugging session setup.
- Only needed to debug problems when you can't connect and that the
- error messages printed by ndk-gdb are not enough.
+ --start:
+ By default, ndk-gdb will try to attach to an existing running instance
+ of your application on the target device. You can use --start to
+ explicitely launch your application before the debugging session.
+
+ NOTE: This launches the first launchable activity listed from your
+ application manifest. Use --launch=<name> to start another one.
+ See --launch-list to dump the list of such activites.
+
+ --launch=<name>:
+ This is similar to --start, except that it allows you to start a specific
+ activity from your application. This is only useful if your manifest
+ defines several launchable activities.
+
+ --launch-list:
+ Convenience option that prints the list of all launchable activity names
+ found in your application manifest. The first one will be used by --start
--project=<path>:
Specify application project directory. Useful if you want to launch
OPTION_FORCE=no
OPTION_ADB=
OPTION_EXEC=
+OPTION_START=no
+OPTION_LAUNCH=
+OPTION_LAUNCH_LIST=no
check_parameter ()
{
$GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1 APP_ABI=$2
}
+# Used to run an awk script on the manifest
+run_awk_manifest_script ()
+{
+ $AWK_CMD -f $AWK_SCRIPTS/$1 $PROJECT/$MANIFEST
+}
+
VERBOSE=no
while [ -n "$1" ]; do
opt="$1"
--force)
OPTION_FORCE="yes"
;;
+ --launch-list)
+ OPTION_LAUNCH_LIST="yes"
+ ;;
+ --launch=*)
+ OPTION_LAUNCH="$optarg"
+ ;;
+ --start)
+ OPTION_START=yes
+ ;;
-*) # unknown options
echo "ERROR: Unknown option '$opt', use --help for list of valid ones."
exit 1
if [ "$OPTION_HELP" = "yes" ] ; then
echo "Usage: $PROGNAME [options]"
echo ""
+ echo "Setup a gdb debugging session for your Android NDK application."
+ echo "Read $$NDK/docs/NDK-GDB.TXT for complete usage instructions."
+ echo ""
echo "Valid options:"
echo ""
echo " --help|-h|-? Print this help"
echo " --verbose Enable verbose mode"
- echo " --adb=<file> Use specific adb command [$ADB_CMD]"
- echo " --awk=<file> Use specific awk command [$AWK_CMD]"
- echo " --project=<path> Specify application project path"
- echo " --port=<port> Use tcp:localhost:<port> to communicate with gdbserver [$DEBUG_PORT]"
echo " --force Kill existing debug session if it exists"
+ echo " --start Launch application instead of attaching to existing one"
+ echo " --launch=<name> Same as --start, but specify activity name (see below)"
+ echo " --launch-list List all launchable activity names from manifest"
+ echo " --project=<path> Specify application project path"
echo " -p <path> Same as --project=<path>"
+ echo " --port=<port> Use tcp:localhost:<port> to communicate with gdbserver [$DEBUG_PORT]"
echo " --exec=<file> Execute gdb initialization commands in <file> after connection"
echo " -x <file> Same as --exec=<file>"
+ echo " --adb=<file> Use specific adb command [$ADB_CMD]"
+ echo " --awk=<file> Use specific awk command [$AWK_CMD]"
echo " -e Connect to single emulator instance"
echo " -d Connect to single target device"
echo " -s <serial> Connect to specific emulator or device"
# Check the awk tool
-AWK_SCRIPTS=$ANDROID_NDK_ROOT/build/core
-AWK_TEST=`$AWK_CMD -f $ANDROID_NDK_ROOT/build/check-awk.awk`
+AWK_SCRIPTS=$ANDROID_NDK_ROOT/build/awk
+AWK_TEST=`$AWK_CMD -f $AWK_SCRIPTS/check-awk.awk`
if [ $? != 0 ] ; then
- echo "ERROR: Could not run '$AWK_CMD' command. Do you have it installed properly ?"
+ echo "ERROR: Could not run '$AWK_CMD' command. Do you have it installed properly?"
exit 1
fi
if [ "$AWK_TEST" != "Pass" ] ; then
fi
# Extract the package name from the manifest
-PACKAGE_NAME=`$AWK_CMD -f $AWK_SCRIPTS/extract-package-name.awk $PROJECT/$MANIFEST`
+PACKAGE_NAME=`run_awk_manifest_script extract-package-name.awk`
log "Found package name: $PACKAGE_NAME"
if [ $? != 0 -o "$PACKAGE_NAME" = "<none>" ] ; then
echo "ERROR: Could not extract package name from $PROJECT/$MANIFEST."
exit 1
fi
+# If --launch-list is used, list all launchable activities, and be done with it
+if [ "$OPTION_LAUNCH_LIST" = "yes" ] ; then
+ log "Extracting list of launchable activities from manifest:"
+ run_awk_manifest_script extract-launchable.awk
+ exit 0
+fi
+
# Check that the application is debuggable, or nothing will work
-DEBUGGABLE=`$AWK_CMD -f $AWK_SCRIPTS/extract-package-debuggable.awk $PROJECT/$MANIFEST`
+DEBUGGABLE=`run_awk_manifest_script extract-debuggable.awk`
log "Found debuggable flag: $DEBUGGABLE"
if [ $? != 0 -o "$DEBUGGABLE" != "true" ] ; then
echo "ERROR: Package $PACKAGE_NAME is not debuggable ! Please fix your manifest,"
log "Found data directory: '$DATA_DIR'"
if [ $? != 0 ] ; then
echo "ERROR: Could not extract package's data directory. Are you sure that"
- echo " your installed application is debuggable ?"
+ echo " your installed application is debuggable?"
exit 1
fi
+# Launch the activity if needed
+if [ -n "$OPTION_START" ] ; then
+ # If --launch is used, ignore --start, otherwise extract the first
+ # launchable activity name from the manifest and use it as if --launch=<name>
+ # was used instead.
+ #
+ if [ -z "$OPTION_LAUNCH" ] ; then
+ OPTION_LAUNCH=`run_awk_manifest_script extract-launchable.awk | sed 2q`
+ if [ $? != 0 ] ; then
+ echo "ERROR: Could not extract name of launchable activity from manifest!"
+ echo " Try to use --launch=<name> directly instead as a work-around."
+ exit 1
+ fi
+ log "Found first launchable activity: $OPTION_LAUNCH"
+ if [ -z "$OPTION_LAUNCH" ] ; then
+ echo "ERROR: It seems that your Application does not have any launchable activity!"
+ echo " Please fix your manifest file and rebuild/re-install your application."
+ exit 1
+ fi
+ fi
+fi
+
+if [ -n "$OPTION_LAUNCH" ] ; then
+ log "Launching activity: $PACKAGE_NAME/$OPTION_LAUNCH"
+ run $ADB_CMD shell am start -n $PACKAGE_NAME/$OPTION_LAUNCH
+ if [ $? != 0 ] ; then
+ echo "ERROR: Could not launch specified activity: $OPTION_LAUNCH"
+ echo " Use --launch-list to dump a list of valid values."
+ exit 1
+ fi
+ # Sleep a bit, it sometimes take one second to start properly
+ # Note that we use the 'sleep' command on the device here.
+ run $ADB_CMD shell sleep 1
+fi
+
# Find the PID of the application being run
-PID=`$ADB_CMD shell ps | $AWK_CMD -f $AWK_SCRIPTS/extract-package-pid.awk -v PACKAGE=$PACKAGE_NAME`
+PID=`$ADB_CMD shell ps | $AWK_CMD -f $AWK_SCRIPTS/extract-pid.awk -v PACKAGE=$PACKAGE_NAME`
log "Found running PID: $PID"
if [ $? != 0 -o "$PID" = "0" ] ; then
echo "ERROR: Could not extract PID of application on device/emulator."
- echo " Are you sure the application is already started ?"
+ if [ -n "$OPTION_LAUNCH" ] ; then
+ echo " Weird, this probably means that the installed package does not"
+ echo " match your current manifest. Try using the --verbose option and"
+ echo " look at its output for details."
+ else
+ echo " Are you sure the application is already started?"
+ echo " Consider using --start or --launch=<name> if not."
+ fi
exit 1
fi
exit 1
fi
log "Killing existing debugging session"
- GDBSERVER_PID=`echo $GDBSERVER_PS | $AWK_CMD -f $AWK_SCRIPTS/extract-package-pid.awk -v PACKAGE=lib/gdbserver`
+ GDBSERVER_PID=`echo $GDBSERVER_PS | $AWK_CMD -f $AWK_SCRIPTS/extract-pid.awk -v PACKAGE=lib/gdbserver`
if [ $GDBSERVER_PID != 0 ] ; then
run $ADB_CMD shell kill -9 $GDBSERVER_PID
fi
DEBUG_SOCKET=debug-socket
run $ADB_CMD shell run-as $PACKAGE_NAME lib/gdbserver +$DEBUG_SOCKET --attach $PID &
if [ $? != 0 ] ; then
- echo "ERROR: Could not launch gdbserver on the device ?"
+ echo "ERROR: Could not launch gdbserver on the device?"
exit 1
fi
log "Launched gdbserver succesfully."
log "Setup network redirection"
run $ADB_CMD forward tcp:$DEBUG_PORT localfilesystem:$DATA_DIR/$DEBUG_SOCKET
if [ $? != 0 ] ; then
- echo "ERROR: Could not setup network redirection to gdbserver ?"
- echo " Maybe using --port=<port> to use a different TCP port might help ?"
+ echo "ERROR: Could not setup network redirection to gdbserver?"
+ echo " Maybe using --port=<port> to use a different TCP port might help?"
exit 1
fi