OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / tools / aapt2 / link / ManifestFixer.cpp
1 /*
2  * Copyright (C) 2015 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 "ResourceUtils.h"
18 #include "link/ManifestFixer.h"
19 #include "util/Util.h"
20 #include "xml/XmlActionExecutor.h"
21 #include "xml/XmlDom.h"
22
23 namespace aapt {
24
25 /**
26  * This is how PackageManager builds class names from AndroidManifest.xml entries.
27  */
28 static bool nameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
29                                 SourcePathDiagnostics* diag) {
30     std::u16string className = attr->value;
31     if (className.find(u'.') == std::u16string::npos) {
32         // There is no '.', so add one to the beginning.
33         className = u".";
34         className += attr->value;
35     }
36
37     // We allow unqualified class names (ie: .HelloActivity)
38     // Since we don't know the package name, we can just make a fake one here and
39     // the test will be identical as long as the real package name is valid too.
40     Maybe<std::u16string> fullyQualifiedClassName =
41             util::getFullyQualifiedClassName(u"a", className);
42
43     StringPiece16 qualifiedClassName = fullyQualifiedClassName
44             ? fullyQualifiedClassName.value() : className;
45     if (!util::isJavaClassName(qualifiedClassName)) {
46         diag->error(DiagMessage(el->lineNumber)
47                     << "attribute 'android:name' in <"
48                     << el->name << "> tag must be a valid Java class name");
49         return false;
50     }
51     return true;
52 }
53
54 static bool optionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
55     if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) {
56         return nameIsJavaClassName(el, attr, diag);
57     }
58     return true;
59 }
60
61 static bool requiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
62     if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name")) {
63         return nameIsJavaClassName(el, attr, diag);
64     }
65     diag->error(DiagMessage(el->lineNumber)
66                 << "<" << el->name << "> is missing attribute 'android:name'");
67     return false;
68 }
69
70 static bool verifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
71     xml::Attribute* attr = el->findAttribute({}, u"package");
72     if (!attr) {
73         diag->error(DiagMessage(el->lineNumber) << "<manifest> tag is missing 'package' attribute");
74         return false;
75     } else if (ResourceUtils::isReference(attr->value)) {
76         diag->error(DiagMessage(el->lineNumber)
77                     << "attribute 'package' in <manifest> tag must not be a reference");
78         return false;
79     } else if (!util::isJavaPackageName(attr->value)) {
80         diag->error(DiagMessage(el->lineNumber)
81                     << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
82                     << attr->value << "'");
83         return false;
84     }
85     return true;
86 }
87
88 bool ManifestFixer::buildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag) {
89     // First verify some options.
90     if (mOptions.renameManifestPackage) {
91         if (!util::isJavaPackageName(mOptions.renameManifestPackage.value())) {
92             diag->error(DiagMessage() << "invalid manifest package override '"
93                         << mOptions.renameManifestPackage.value() << "'");
94             return false;
95         }
96     }
97
98     if (mOptions.renameInstrumentationTargetPackage) {
99         if (!util::isJavaPackageName(mOptions.renameInstrumentationTargetPackage.value())) {
100             diag->error(DiagMessage() << "invalid instrumentation target package override '"
101                         << mOptions.renameInstrumentationTargetPackage.value() << "'");
102             return false;
103         }
104     }
105
106     // Common intent-filter actions.
107     xml::XmlNodeAction intentFilterAction;
108     intentFilterAction[u"action"];
109     intentFilterAction[u"category"];
110     intentFilterAction[u"data"];
111
112     // Common meta-data actions.
113     xml::XmlNodeAction metaDataAction;
114
115     // Manifest actions.
116     xml::XmlNodeAction& manifestAction = (*executor)[u"manifest"];
117     manifestAction.action(verifyManifest);
118     manifestAction.action([&](xml::Element* el) -> bool {
119         if (mOptions.versionNameDefault) {
120             if (el->findAttribute(xml::kSchemaAndroid, u"versionName") == nullptr) {
121                 el->attributes.push_back(xml::Attribute{
122                         xml::kSchemaAndroid,
123                         u"versionName",
124                         mOptions.versionNameDefault.value() });
125             }
126         }
127
128         if (mOptions.versionCodeDefault) {
129             if (el->findAttribute(xml::kSchemaAndroid, u"versionCode") == nullptr) {
130                 el->attributes.push_back(xml::Attribute{
131                         xml::kSchemaAndroid,
132                         u"versionCode",
133                         mOptions.versionCodeDefault.value() });
134             }
135         }
136         return true;
137     });
138
139     // Meta tags.
140     manifestAction[u"eat-comment"];
141
142     // Uses-sdk actions.
143     manifestAction[u"uses-sdk"].action([&](xml::Element* el) -> bool {
144         if (mOptions.minSdkVersionDefault &&
145                 el->findAttribute(xml::kSchemaAndroid, u"minSdkVersion") == nullptr) {
146             // There was no minSdkVersion defined and we have a default to assign.
147             el->attributes.push_back(xml::Attribute{
148                     xml::kSchemaAndroid, u"minSdkVersion",
149                     mOptions.minSdkVersionDefault.value() });
150         }
151
152         if (mOptions.targetSdkVersionDefault &&
153                 el->findAttribute(xml::kSchemaAndroid, u"targetSdkVersion") == nullptr) {
154             // There was no targetSdkVersion defined and we have a default to assign.
155             el->attributes.push_back(xml::Attribute{
156                     xml::kSchemaAndroid, u"targetSdkVersion",
157                     mOptions.targetSdkVersionDefault.value() });
158         }
159         return true;
160     });
161
162     // Instrumentation actions.
163     manifestAction[u"instrumentation"].action([&](xml::Element* el) -> bool {
164         if (!mOptions.renameInstrumentationTargetPackage) {
165             return true;
166         }
167
168         if (xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"targetPackage")) {
169             attr->value = mOptions.renameInstrumentationTargetPackage.value();
170         }
171         return true;
172     });
173
174     manifestAction[u"original-package"];
175     manifestAction[u"protected-broadcast"];
176     manifestAction[u"uses-permission"];
177     manifestAction[u"permission"];
178     manifestAction[u"permission-tree"];
179     manifestAction[u"permission-group"];
180
181     manifestAction[u"uses-configuration"];
182     manifestAction[u"uses-feature"];
183     manifestAction[u"supports-screens"];
184     manifestAction[u"compatible-screens"];
185     manifestAction[u"supports-gl-texture"];
186
187     // Application actions.
188     xml::XmlNodeAction& applicationAction = (*executor)[u"manifest"][u"application"];
189     applicationAction.action(optionalNameIsJavaClassName);
190
191     // Uses library actions.
192     applicationAction[u"uses-library"];
193
194     // Activity actions.
195     applicationAction[u"activity"].action(requiredNameIsJavaClassName);
196     applicationAction[u"activity"][u"intent-filter"] = intentFilterAction;
197     applicationAction[u"activity"][u"meta-data"] = metaDataAction;
198
199     // Activity alias actions.
200     applicationAction[u"activity-alias"][u"intent-filter"] = intentFilterAction;
201     applicationAction[u"activity-alias"][u"meta-data"] = metaDataAction;
202
203     // Service actions.
204     applicationAction[u"service"].action(requiredNameIsJavaClassName);
205     applicationAction[u"service"][u"intent-filter"] = intentFilterAction;
206     applicationAction[u"service"][u"meta-data"] = metaDataAction;
207
208     // Receiver actions.
209     applicationAction[u"receiver"].action(requiredNameIsJavaClassName);
210     applicationAction[u"receiver"][u"intent-filter"] = intentFilterAction;
211     applicationAction[u"receiver"][u"meta-data"] = metaDataAction;
212
213     // Provider actions.
214     applicationAction[u"provider"].action(requiredNameIsJavaClassName);
215     applicationAction[u"provider"][u"grant-uri-permissions"];
216     applicationAction[u"provider"][u"meta-data"] = metaDataAction;
217     applicationAction[u"provider"][u"path-permissions"];
218     return true;
219 }
220
221 class FullyQualifiedClassNameVisitor : public xml::Visitor {
222 public:
223     using xml::Visitor::visit;
224
225     FullyQualifiedClassNameVisitor(const StringPiece16& package) : mPackage(package) {
226     }
227
228     void visit(xml::Element* el) override {
229         for (xml::Attribute& attr : el->attributes) {
230             if (Maybe<std::u16string> newValue =
231                     util::getFullyQualifiedClassName(mPackage, attr.value)) {
232                 attr.value = std::move(newValue.value());
233             }
234         }
235
236         // Super implementation to iterate over the children.
237         xml::Visitor::visit(el);
238     }
239
240 private:
241     StringPiece16 mPackage;
242 };
243
244 static bool renameManifestPackage(const StringPiece16& packageOverride, xml::Element* manifestEl) {
245     xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
246
247     // We've already verified that the manifest element is present, with a package name specified.
248     assert(attr);
249
250     std::u16string originalPackage = std::move(attr->value);
251     attr->value = packageOverride.toString();
252
253     FullyQualifiedClassNameVisitor visitor(originalPackage);
254     manifestEl->accept(&visitor);
255     return true;
256 }
257
258 bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
259     xml::Element* root = xml::findRootElement(doc->root.get());
260     if (!root || !root->namespaceUri.empty() || root->name != u"manifest") {
261         context->getDiagnostics()->error(DiagMessage(doc->file.source)
262                                          << "root tag must be <manifest>");
263         return false;
264     }
265
266     if ((mOptions.minSdkVersionDefault || mOptions.targetSdkVersionDefault)
267             && root->findChild({}, u"uses-sdk") == nullptr) {
268         // Auto insert a <uses-sdk> element.
269         std::unique_ptr<xml::Element> usesSdk = util::make_unique<xml::Element>();
270         usesSdk->name = u"uses-sdk";
271         root->addChild(std::move(usesSdk));
272     }
273
274     xml::XmlActionExecutor executor;
275     if (!buildRules(&executor, context->getDiagnostics())) {
276         return false;
277     }
278
279     if (!executor.execute(xml::XmlActionExecutorPolicy::Whitelist, context->getDiagnostics(),
280                           doc)) {
281         return false;
282     }
283
284     if (mOptions.renameManifestPackage) {
285         // Rename manifest package outside of the XmlActionExecutor.
286         // We need to extract the old package name and FullyQualify all class names.
287         if (!renameManifestPackage(mOptions.renameManifestPackage.value(), root)) {
288             return false;
289         }
290     }
291     return true;
292 }
293
294 } // namespace aapt