blob: a583057427e60f858e2fac7d5bc65cc5c00456f0 [file] [log] [blame]
Shane Farmercb6c3f92017-11-27 13:19:36 -08001/*
2 * Copyright (C) 2017 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#ifndef AAPT2_CONFIGURATIONPARSER_INTERNAL_H
18#define AAPT2_CONFIGURATIONPARSER_INTERNAL_H
19
Shane Farmer78c43d72017-12-04 09:08:38 -080020#include "configuration/ConfigurationParser.h"
21
22#include <algorithm>
23#include <limits>
24
Shane Farmercb6c3f92017-11-27 13:19:36 -080025namespace aapt {
Shane Farmer78c43d72017-12-04 09:08:38 -080026
27// Forward declaration of classes used in the API.
28namespace xml {
29class Element;
30}
31
Shane Farmercb6c3f92017-11-27 13:19:36 -080032namespace configuration {
33
Shane Farmer78c43d72017-12-04 09:08:38 -080034template <typename T>
35struct OrderedEntry {
36 size_t order;
37 std::vector<T> entry;
38};
39
Shane Farmercb6c3f92017-11-27 13:19:36 -080040/** A mapping of group labels to group of configuration items. */
41template <class T>
Shane Farmer78c43d72017-12-04 09:08:38 -080042using Group = std::unordered_map<std::string, OrderedEntry<T>>;
Shane Farmercb6c3f92017-11-27 13:19:36 -080043
44/** A mapping of group label to a single configuration item. */
45template <class T>
46using Entry = std::unordered_map<std::string, T>;
47
Shane Farmer78c43d72017-12-04 09:08:38 -080048/** Retrieves an entry from the provided Group, creating a new instance if one does not exist. */
49template <typename T>
50std::vector<T>& GetOrCreateGroup(std::string label, Group<T>* group) {
51 OrderedEntry<T>& entry = (*group)[label];
52 // If this is a new entry, set the order.
53 if (entry.order == 0) {
54 entry.order = group->size();
55 }
56 return entry.entry;
57}
58
59/**
60 * A ComparisonChain is a grouping of comparisons to perform when sorting groups that have a well
61 * defined order of precedence. Comparisons are only made if none of the previous comparisons had a
62 * definite result. A comparison has a result if at least one of the items has an entry for that
63 * value and that they are not equal.
64 */
65class ComparisonChain {
66 public:
67 /**
68 * Adds a new comparison of items in a group to the chain. The new comparison is only used if we
69 * have not been able to determine the sort order with the previous comparisons.
70 */
71 template <typename T>
72 ComparisonChain& Add(const Group<T>& groups, const Maybe<std::string>& lhs,
73 const Maybe<std::string>& rhs) {
74 return Add(GetGroupOrder(groups, lhs), GetGroupOrder(groups, rhs));
75 }
76
77 /**
78 * Adds a new comparison to the chain. The new comparison is only used if we have not been able to
79 * determine the sort order with the previous comparisons.
80 */
81 ComparisonChain& Add(int lhs, int rhs) {
82 if (!has_result_) {
83 has_result_ = (lhs != rhs);
84 result_ = (lhs < rhs);
85 }
86 return *this;
87 }
88
89 /** Returns true if the left hand side should come before the right hand side. */
90 bool Compare() {
91 return result_;
92 }
93
94 private:
95 template <typename T>
96 inline size_t GetGroupOrder(const Group<T>& groups, const Maybe<std::string>& label) {
97 if (!label) {
98 return std::numeric_limits<size_t>::max();
99 }
100 return groups.at(label.value()).order;
101 }
102
103 bool has_result_ = false;
104 bool result_ = false;
105};
106
Shane Farmercb6c3f92017-11-27 13:19:36 -0800107/** Output artifact configuration options. */
108struct ConfiguredArtifact {
109 /** Name to use for output of processing foo.apk -> foo.<name>.apk. */
110 Maybe<std::string> name;
Shane Farmercb6c3f92017-11-27 13:19:36 -0800111 /** If present, uses the ABI group with this name. */
112 Maybe<std::string> abi_group;
113 /** If present, uses the screen density group with this name. */
114 Maybe<std::string> screen_density_group;
115 /** If present, uses the locale group with this name. */
116 Maybe<std::string> locale_group;
Shane Farmer78c43d72017-12-04 09:08:38 -0800117 /** If present, uses the Android SDK with this name. */
118 Maybe<std::string> android_sdk;
Shane Farmercb6c3f92017-11-27 13:19:36 -0800119 /** If present, uses the device feature group with this name. */
120 Maybe<std::string> device_feature_group;
121 /** If present, uses the OpenGL texture group with this name. */
122 Maybe<std::string> gl_texture_group;
123
124 /** Convert an artifact name template into a name string based on configuration contents. */
125 Maybe<std::string> ToArtifactName(const android::StringPiece& format,
126 const android::StringPiece& apk_name, IDiagnostics* diag) const;
127
128 /** Convert an artifact name template into a name string based on configuration contents. */
129 Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
Shane Farmercb6c3f92017-11-27 13:19:36 -0800130};
131
132/** AAPT2 XML configuration file binary representation. */
133struct PostProcessingConfiguration {
Shane Farmercb6c3f92017-11-27 13:19:36 -0800134 std::vector<ConfiguredArtifact> artifacts;
135 Maybe<std::string> artifact_format;
136
137 Group<Abi> abi_groups;
138 Group<ConfigDescription> screen_density_groups;
139 Group<ConfigDescription> locale_groups;
Shane Farmercb6c3f92017-11-27 13:19:36 -0800140 Group<DeviceFeature> device_feature_groups;
141 Group<GlTexture> gl_texture_groups;
Shane Farmer78c43d72017-12-04 09:08:38 -0800142 Entry<AndroidSdk> android_sdks;
143
144 /**
145 * Sorts the configured artifacts based on the ordering of the groups in the configuration file.
146 * The only exception to this rule is Android SDK versions. Larger SDK versions will have a larger
147 * versionCode to ensure users get the correct APK when they upgrade their OS.
148 */
149 void SortArtifacts() {
150 std::sort(artifacts.begin(), artifacts.end(), *this);
151 }
152
153 /** Comparator that ensures artifacts are in the preferred order for versionCode rewriting. */
154 bool operator()(const ConfiguredArtifact& lhs, const ConfiguredArtifact& rhs) {
155 // Split dimensions are added in the order of precedence. Items higher in the list result in
156 // higher version codes.
157 return ComparisonChain()
158 // All splits with a minSdkVersion specified must be last to ensure the application will be
159 // updated if a user upgrades the version of Android on their device.
160 .Add(GetMinSdk(lhs), GetMinSdk(rhs))
161 // ABI version is important, especially on x86 phones where they may begin to run in ARM
162 // emulation mode on newer Android versions. This allows us to ensure that the x86 version
163 // is installed on these devices rather than ARM.
164 .Add(abi_groups, lhs.abi_group, rhs.abi_group)
165 // The rest are in arbitrary order based on estimated usage.
166 .Add(screen_density_groups, lhs.screen_density_group, rhs.screen_density_group)
167 .Add(locale_groups, lhs.locale_group, rhs.locale_group)
168 .Add(gl_texture_groups, lhs.gl_texture_group, rhs.gl_texture_group)
169 .Add(device_feature_groups, lhs.device_feature_group, rhs.device_feature_group)
170 .Compare();
171 }
172
173 private:
174 /**
175 * Returns the min_sdk_version from the provided artifact or 0 if none is present. This allows
176 * artifacts that have an Android SDK version to have a higher versionCode than those that do not.
177 */
178 inline int GetMinSdk(const ConfiguredArtifact& artifact) {
179 if (!artifact.android_sdk) {
180 return 0;
181 }
182 const auto& entry = android_sdks.find(artifact.android_sdk.value());
183 if (entry == android_sdks.end()) {
184 return 0;
185 }
186 return entry->second.min_sdk_version;
187 }
Shane Farmercb6c3f92017-11-27 13:19:36 -0800188};
189
Shane Farmer78c43d72017-12-04 09:08:38 -0800190/** Parses the provided XML document returning the post processing configuration. */
191Maybe<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
192 const std::string& config_path,
193 IDiagnostics* diag);
194
Shane Farmercb6c3f92017-11-27 13:19:36 -0800195namespace handler {
196
197/** Handler for <artifact> tags. */
198bool ArtifactTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
199 IDiagnostics* diag);
200
201/** Handler for <artifact-format> tags. */
202bool ArtifactFormatTagHandler(configuration::PostProcessingConfiguration* config,
203 xml::Element* element, IDiagnostics* diag);
204
205/** Handler for <abi-group> tags. */
206bool AbiGroupTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
207 IDiagnostics* diag);
208
209/** Handler for <screen-density-group> tags. */
210bool ScreenDensityGroupTagHandler(configuration::PostProcessingConfiguration* config,
211 xml::Element* element, IDiagnostics* diag);
212
213/** Handler for <locale-group> tags. */
214bool LocaleGroupTagHandler(configuration::PostProcessingConfiguration* config,
215 xml::Element* element, IDiagnostics* diag);
216
Shane Farmer78c43d72017-12-04 09:08:38 -0800217/** Handler for <android-sdk> tags. */
218bool AndroidSdkTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
219 IDiagnostics* diag);
Shane Farmercb6c3f92017-11-27 13:19:36 -0800220
221/** Handler for <gl-texture-group> tags. */
222bool GlTextureGroupTagHandler(configuration::PostProcessingConfiguration* config,
223 xml::Element* element, IDiagnostics* diag);
224
225/** Handler for <device-feature-group> tags. */
226bool DeviceFeatureGroupTagHandler(configuration::PostProcessingConfiguration* config,
227 xml::Element* element, IDiagnostics* diag);
228
229} // namespace handler
230} // namespace configuration
231} // namespace aapt
232#endif // AAPT2_CONFIGURATIONPARSER_INTERNAL_H