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("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