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