aapt.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (C) 2016 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. #include "aapt.h"
  17. #include "command.h"
  18. #include "print.h"
  19. #include "util.h"
  20. #include <regex>
  21. const regex NS_REGEX("( *)N: ([^=]+)=(.*)");
  22. const regex ELEMENT_REGEX("( *)E: ([^ ]+) \\(line=(\\d+)\\)");
  23. const regex ATTR_REGEX("( *)A: ([^\\(=]+)[^=]*=\"([^\"]+)\".*");
  24. const string ANDROID_NS("http://schemas.android.com/apk/res/android");
  25. bool
  26. Apk::HasActivity(const string& className)
  27. {
  28. string fullClassName = full_class_name(package, className);
  29. const size_t N = activities.size();
  30. for (size_t i=0; i<N; i++) {
  31. if (activities[i] == fullClassName) {
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. struct Attribute {
  38. string ns;
  39. string name;
  40. string value;
  41. };
  42. struct Element {
  43. Element* parent;
  44. string ns;
  45. string name;
  46. int lineno;
  47. vector<Attribute> attributes;
  48. vector<Element*> children;
  49. /**
  50. * Indentation in the xmltree dump. Might not be equal to the distance
  51. * from the root because namespace rows (scopes) have their own indentation.
  52. */
  53. int depth;
  54. Element();
  55. ~Element();
  56. string GetAttr(const string& ns, const string& name) const;
  57. void FindElements(const string& ns, const string& name, vector<Element*>* result, bool recurse);
  58. };
  59. Element::Element()
  60. {
  61. }
  62. Element::~Element()
  63. {
  64. const size_t N = children.size();
  65. for (size_t i=0; i<N; i++) {
  66. delete children[i];
  67. }
  68. }
  69. string
  70. Element::GetAttr(const string& ns, const string& name) const
  71. {
  72. const size_t N = attributes.size();
  73. for (size_t i=0; i<N; i++) {
  74. const Attribute& attr = attributes[i];
  75. if (attr.ns == ns && attr.name == name) {
  76. return attr.value;
  77. }
  78. }
  79. return string();
  80. }
  81. void
  82. Element::FindElements(const string& ns, const string& name, vector<Element*>* result, bool recurse)
  83. {
  84. const size_t N = children.size();
  85. for (size_t i=0; i<N; i++) {
  86. Element* child = children[i];
  87. if (child->ns == ns && child->name == name) {
  88. result->push_back(child);
  89. }
  90. if (recurse) {
  91. child->FindElements(ns, name, result, recurse);
  92. }
  93. }
  94. }
  95. struct Scope {
  96. Scope* parent;
  97. int depth;
  98. map<string,string> namespaces;
  99. Scope(Scope* parent, int depth);
  100. };
  101. Scope::Scope(Scope* p, int d)
  102. :parent(p),
  103. depth(d)
  104. {
  105. if (p != NULL) {
  106. namespaces = p->namespaces;
  107. }
  108. }
  109. string
  110. full_class_name(const string& packageName, const string& className)
  111. {
  112. if (className.length() == 0) {
  113. return "";
  114. }
  115. if (className[0] == '.') {
  116. return packageName + className;
  117. }
  118. if (className.find('.') == string::npos) {
  119. return packageName + "." + className;
  120. }
  121. return className;
  122. }
  123. string
  124. pretty_component_name(const string& packageName, const string& className)
  125. {
  126. if (starts_with(packageName, className)) {
  127. size_t pn = packageName.length();
  128. size_t cn = className.length();
  129. if (cn > pn && className[pn] == '.') {
  130. return packageName + "/" + string(className, pn, string::npos);
  131. }
  132. }
  133. return packageName + "/" + className;
  134. }
  135. int
  136. inspect_apk(Apk* apk, const string& filename)
  137. {
  138. // Load the manifest xml
  139. Command cmd("aapt2");
  140. cmd.AddArg("dump");
  141. cmd.AddArg("xmltree");
  142. cmd.AddArg(filename);
  143. cmd.AddArg("--file");
  144. cmd.AddArg("AndroidManifest.xml");
  145. int err;
  146. string output = get_command_output(cmd, &err, false);
  147. check_error(err);
  148. // Parse the manifest xml
  149. Scope* scope = new Scope(NULL, -1);
  150. Element* root = NULL;
  151. Element* current = NULL;
  152. vector<string> lines;
  153. split_lines(&lines, output);
  154. for (size_t i=0; i<lines.size(); i++) {
  155. const string& line = lines[i];
  156. smatch match;
  157. if (regex_match(line, match, NS_REGEX)) {
  158. int depth = match[1].length() / 2;
  159. while (depth < scope->depth) {
  160. Scope* tmp = scope;
  161. scope = scope->parent;
  162. delete tmp;
  163. }
  164. scope = new Scope(scope, depth);
  165. scope->namespaces[match[2]] = match[3];
  166. } else if (regex_match(line, match, ELEMENT_REGEX)) {
  167. Element* element = new Element();
  168. string str = match[2];
  169. size_t colon = str.find(':');
  170. if (colon == string::npos) {
  171. element->name = str;
  172. } else {
  173. element->ns = scope->namespaces[string(str, 0, colon)];
  174. element->name.assign(str, colon+1, string::npos);
  175. }
  176. element->lineno = atoi(match[3].str().c_str());
  177. element->depth = match[1].length() / 2;
  178. if (root == NULL) {
  179. current = element;
  180. root = element;
  181. } else {
  182. while (element->depth <= current->depth && current->parent != NULL) {
  183. current = current->parent;
  184. }
  185. element->parent = current;
  186. current->children.push_back(element);
  187. current = element;
  188. }
  189. } else if (regex_match(line, match, ATTR_REGEX)) {
  190. if (current != NULL) {
  191. Attribute attr;
  192. string str = match[2];
  193. size_t colon = str.rfind(':');
  194. if (colon == string::npos) {
  195. attr.name = str;
  196. } else {
  197. attr.ns.assign(str, 0, colon);
  198. attr.name.assign(str, colon+1, string::npos);
  199. }
  200. attr.value = match[3];
  201. current->attributes.push_back(attr);
  202. }
  203. }
  204. }
  205. while (scope != NULL) {
  206. Scope* tmp = scope;
  207. scope = scope->parent;
  208. delete tmp;
  209. }
  210. // Package name
  211. apk->package = root->GetAttr("", "package");
  212. if (apk->package.size() == 0) {
  213. print_error("%s:%d: Manifest root element doesn't contain a package attribute",
  214. filename.c_str(), root->lineno);
  215. delete root;
  216. return 1;
  217. }
  218. // Instrumentation runner
  219. vector<Element*> instrumentation;
  220. root->FindElements("", "instrumentation", &instrumentation, true);
  221. if (instrumentation.size() > 0) {
  222. // TODO: How could we deal with multiple instrumentation tags?
  223. // We'll just pick the first one.
  224. apk->runner = instrumentation[0]->GetAttr(ANDROID_NS, "name");
  225. }
  226. // Activities
  227. vector<Element*> activities;
  228. root->FindElements("", "activity", &activities, true);
  229. for (size_t i=0; i<activities.size(); i++) {
  230. string name = activities[i]->GetAttr(ANDROID_NS, "name");
  231. if (name.size() == 0) {
  232. continue;
  233. }
  234. apk->activities.push_back(full_class_name(apk->package, name));
  235. }
  236. delete root;
  237. return 0;
  238. }