Home | History | Annotate | Download | only in bit
      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("aapt2");
    163     cmd.AddArg("dump");
    164     cmd.AddArg("xmltree");
    165     cmd.AddArg(filename);
    166     cmd.AddArg("--file");
    167     cmd.AddArg("AndroidManifest.xml");
    168 
    169     int err;
    170 
    171     string output = get_command_output(cmd, &err, false);
    172     check_error(err);
    173 
    174     // Parse the manifest xml
    175     Scope* scope = new Scope(NULL, -1);
    176     Element* root = NULL;
    177     Element* current = NULL;
    178     vector<string> lines;
    179     split_lines(&lines, output);
    180     for (size_t i=0; i<lines.size(); i++) {
    181         const string& line = lines[i];
    182         smatch match;
    183         if (regex_match(line, match, NS_REGEX)) {
    184             int depth = match[1].length() / 2;
    185             while (depth < scope->depth) {
    186                 Scope* tmp = scope;
    187                 scope = scope->parent;
    188                 delete tmp;
    189             }
    190             scope = new Scope(scope, depth);
    191             scope->namespaces[match[2]] = match[3];
    192         } else if (regex_match(line, match, ELEMENT_REGEX)) {
    193             Element* element = new Element();
    194 
    195             string str = match[2];
    196             size_t colon = str.find(':');
    197             if (colon == string::npos) {
    198                 element->name = str;
    199             } else {
    200                 element->ns = scope->namespaces[string(str, 0, colon)];
    201                 element->name.assign(str, colon+1, string::npos);
    202             }
    203             element->lineno = atoi(match[3].str().c_str());
    204             element->depth = match[1].length() / 2;
    205 
    206             if (root == NULL) {
    207                 current = element;
    208                 root = element;
    209             } else {
    210                 while (element->depth <= current->depth && current->parent != NULL) {
    211                     current = current->parent;
    212                 }
    213                 element->parent = current;
    214                 current->children.push_back(element);
    215                 current = element;
    216             }
    217         } else if (regex_match(line, match, ATTR_REGEX)) {
    218             if (current != NULL) {
    219                 Attribute attr;
    220                 string str = match[2];
    221                 size_t colon = str.rfind(':');
    222                 if (colon == string::npos) {
    223                     attr.name = str;
    224                 } else {
    225                     attr.ns.assign(str, 0, colon);
    226                     attr.name.assign(str, colon+1, string::npos);
    227                 }
    228                 attr.value = match[3];
    229                 current->attributes.push_back(attr);
    230             }
    231         }
    232     }
    233     while (scope != NULL) {
    234         Scope* tmp = scope;
    235         scope = scope->parent;
    236         delete tmp;
    237     }
    238 
    239     // Package name
    240     apk->package = root->GetAttr("", "package");
    241     if (apk->package.size() == 0) {
    242         print_error("%s:%d: Manifest root element doesn't contain a package attribute",
    243                 filename.c_str(), root->lineno);
    244         delete root;
    245         return 1;
    246     }
    247 
    248     // Instrumentation runner
    249     vector<Element*> instrumentation;
    250     root->FindElements("", "instrumentation", &instrumentation, true);
    251     if (instrumentation.size() > 0) {
    252         // TODO: How could we deal with multiple instrumentation tags?
    253         // We'll just pick the first one.
    254         apk->runner = instrumentation[0]->GetAttr(ANDROID_NS, "name");
    255     }
    256 
    257     // Activities
    258     vector<Element*> activities;
    259     root->FindElements("", "activity", &activities, true);
    260     for (size_t i=0; i<activities.size(); i++) {
    261         string name = activities[i]->GetAttr(ANDROID_NS, "name");
    262         if (name.size() == 0) {
    263             continue;
    264         }
    265         apk->activities.push_back(full_class_name(apk->package, name));
    266     }
    267 
    268     delete root;
    269     return 0;
    270 }
    271 
    272