diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/aapt2/Resource.h | 2 | ||||
| -rw-r--r-- | tools/aapt2/ResourceParser.cpp | 28 | ||||
| -rw-r--r-- | tools/aapt2/ResourceParser.h | 3 | ||||
| -rw-r--r-- | tools/aapt2/ResourceTable.cpp | 55 | ||||
| -rw-r--r-- | tools/aapt2/ResourceTable.h | 7 | ||||
| -rw-r--r-- | tools/aapt2/Resources.proto | 1 | ||||
| -rw-r--r-- | tools/aapt2/SdkConstants.cpp | 6 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Compile.cpp | 1 | ||||
| -rw-r--r-- | tools/aapt2/format/proto/ProtoDeserialize.cpp | 3 | ||||
| -rw-r--r-- | tools/aapt2/format/proto/ProtoSerialize.cpp | 1 | ||||
| -rw-r--r-- | tools/aapt2/xml/XmlPullParser.cpp | 9 | ||||
| -rw-r--r-- | tools/aapt2/xml/XmlPullParser.h | 7 | ||||
| -rw-r--r-- | tools/lint/fix/README.md | 4 |
13 files changed, 120 insertions, 7 deletions
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index 7ba3277d2093..a274f047586c 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -69,6 +69,8 @@ enum class ResourceType { kXml, }; +enum class FlagStatus { NoFlag = 0, Disabled = 1, Enabled = 2 }; + android::StringPiece to_string(ResourceType type); /** diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 6af39b739e9b..2df941834063 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "ResourceParser.h" #include <functional> @@ -108,6 +107,7 @@ struct ParsedResource { Visibility::Level visibility_level = Visibility::Level::kUndefined; bool staged_api = false; bool allow_new = false; + FlagStatus flag_status; std::optional<OverlayableItem> overlayable_item; std::optional<StagedId> staged_alias; @@ -161,6 +161,8 @@ static bool AddResourcesToTable(ResourceTable* table, android::IDiagnostics* dia res_builder.SetStagedId(res->staged_alias.value()); } + res_builder.SetFlagStatus(res->flag_status); + bool error = false; if (!res->name.entry.empty()) { if (!table->AddResource(res_builder.Build(), diag)) { @@ -544,6 +546,30 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, }); std::string resource_type = parser->element_name(); + std::optional<StringPiece> flag = + xml::FindAttribute(parser, "http://schemas.android.com/apk/res/android", "featureFlag"); + out_resource->flag_status = FlagStatus::NoFlag; + if (flag) { + auto flag_it = options_.feature_flag_values.find(flag.value()); + if (flag_it == options_.feature_flag_values.end()) { + diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) + << "Resource flag value undefined"); + return false; + } + const auto& flag_properties = flag_it->second; + if (!flag_properties.read_only) { + diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) + << "Only read only flags may be used with resources"); + return false; + } + if (!flag_properties.enabled.has_value()) { + diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) + << "Only flags with a value may be used with resources"); + return false; + } + out_resource->flag_status = + flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled; + } // The value format accepted for this resource. uint32_t resource_format = 0u; diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 012a056dccf3..45d41c193cb4 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -27,6 +27,7 @@ #include "androidfw/IDiagnostics.h" #include "androidfw/StringPiece.h" #include "androidfw/StringPool.h" +#include "cmd/Util.h" #include "xml/XmlPullParser.h" namespace aapt { @@ -54,6 +55,8 @@ struct ResourceParserOptions { // If visibility was forced, we need to use it when creating a new resource and also error if we // try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags. std::optional<Visibility::Level> visibility; + + FeatureFlagValues feature_flag_values; }; struct FlattenedXmlSubTree { diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index a3b0b45df5c3..1cdb71551d5d 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -231,6 +231,47 @@ bool ResourceEntry::HasDefaultValue() const { return false; } +ResourceTable::CollisionResult ResourceTable::ResolveFlagCollision(FlagStatus existing, + FlagStatus incoming) { + switch (existing) { + case FlagStatus::NoFlag: + switch (incoming) { + case FlagStatus::NoFlag: + return CollisionResult::kConflict; + case FlagStatus::Disabled: + return CollisionResult::kKeepOriginal; + case FlagStatus::Enabled: + return CollisionResult::kTakeNew; + default: + return CollisionResult::kConflict; + } + case FlagStatus::Disabled: + switch (incoming) { + case FlagStatus::NoFlag: + return CollisionResult::kTakeNew; + case FlagStatus::Disabled: + return CollisionResult::kKeepOriginal; + case FlagStatus::Enabled: + return CollisionResult::kTakeNew; + default: + return CollisionResult::kConflict; + } + case FlagStatus::Enabled: + switch (incoming) { + case FlagStatus::NoFlag: + return CollisionResult::kKeepOriginal; + case FlagStatus::Disabled: + return CollisionResult::kKeepOriginal; + case FlagStatus::Enabled: + return CollisionResult::kConflict; + default: + return CollisionResult::kConflict; + } + default: + return CollisionResult::kConflict; + } +} + // The default handler for collisions. // // Typically, a weak value will be overridden by a strong value. An existing weak @@ -564,16 +605,21 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) if (!config_value->value) { // Resource does not exist, add it now. config_value->value = std::move(res.value); + config_value->flag_status = res.flag_status; } else { // When validation is enabled, ensure that a resource cannot have multiple values defined for - // the same configuration. - auto result = validate ? ResolveValueCollision(config_value->value.get(), res.value.get()) + // the same configuration unless protected by flags. + auto result = validate ? ResolveFlagCollision(config_value->flag_status, res.flag_status) : CollisionResult::kKeepBoth; + if (result == CollisionResult::kConflict) { + result = ResolveValueCollision(config_value->value.get(), res.value.get()); + } switch (result) { case CollisionResult::kKeepBoth: // Insert the value ignoring for duplicate configurations entry->values.push_back(util::make_unique<ResourceConfigValue>(res.config, res.product)); entry->values.back()->value = std::move(res.value); + entry->values.back()->flag_status = res.flag_status; break; case CollisionResult::kTakeNew: @@ -735,6 +781,11 @@ NewResourceBuilder& NewResourceBuilder::SetAllowMangled(bool allow_mangled) { return *this; } +NewResourceBuilder& NewResourceBuilder::SetFlagStatus(FlagStatus flag_status) { + res_.flag_status = flag_status; + return *this; +} + NewResource NewResourceBuilder::Build() { return std::move(res_); } diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index 61e399c7ab68..9530c1750c79 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -104,6 +104,8 @@ class ResourceConfigValue { // The actual Value. std::unique_ptr<Value> value; + FlagStatus flag_status; + ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product) : config(config), product(product) { } @@ -269,6 +271,7 @@ struct NewResource { std::optional<AllowNew> allow_new; std::optional<StagedId> staged_id; bool allow_mangled = false; + FlagStatus flag_status; }; struct NewResourceBuilder { @@ -282,6 +285,7 @@ struct NewResourceBuilder { NewResourceBuilder& SetAllowNew(AllowNew allow_new); NewResourceBuilder& SetStagedId(StagedId id); NewResourceBuilder& SetAllowMangled(bool allow_mangled); + NewResourceBuilder& SetFlagStatus(FlagStatus flag_status); NewResource Build(); private: @@ -330,7 +334,8 @@ class ResourceTable { std::unique_ptr<ResourceTable> Clone() const; - // When a collision of resources occurs, this method decides which value to keep. + // When a collision of resources occurs, these methods decide which value to keep. + static CollisionResult ResolveFlagCollision(FlagStatus existing, FlagStatus incoming); static CollisionResult ResolveValueCollision(Value* existing, Value* incoming); // The string pool used by this resource table. Values that reference strings must use diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 1d7fd1d17dcd..2ecc82ae4792 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -246,6 +246,7 @@ message Entry { message ConfigValue { Configuration config = 1; Value value = 2; + uint32 flag_status = 3; } // The generic meta-data for every value in a resource table. diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp index 83f2eb31aa57..37b1687fd3f1 100644 --- a/tools/aapt2/SdkConstants.cpp +++ b/tools/aapt2/SdkConstants.cpp @@ -64,6 +64,12 @@ static constexpr std::pair<uint16_t, ApiVersion> sAttrIdMap[] = { {0x0616, SDK_R}, {0x064b, SDK_S}, {0x064c, SDK_S_V2}, + // TODO(zyy): add these when we need more rules for converting new attributes to the + // older ones, but don't bother for now as this would increase the array size for no + // real benefit + // {0x0672, SDK_TIRAMISU}, + // {0x0687, SDK_UPSIDE_DOWN_CAKE}, + // {0x06a3, SDK_VANILLA_ICE_CREAM}, }; static_assert(std::is_sorted(std::begin(sAttrIdMap), std::end(sAttrIdMap), diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 9b8c3b3d549c..2a978a5153ca 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -171,6 +171,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, parser_options.error_on_positional_arguments = !options.legacy_mode; parser_options.preserve_visibility_of_styleables = options.preserve_visibility_of_styleables; parser_options.translatable = translatable_file; + parser_options.feature_flag_values = options.feature_flag_values; // If visibility was forced, we need to use it when creating a new resource and also error if // we try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags. diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index e1a3013c07bb..aaab3158f61e 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -16,6 +16,7 @@ #include "format/proto/ProtoDeserialize.h" +#include "Resource.h" #include "ResourceTable.h" #include "ResourceUtils.h" #include "ResourceValues.h" @@ -533,6 +534,8 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr return false; } + config_value->flag_status = (FlagStatus)pb_config_value.flag_status(); + config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config, &out_table->string_pool, files, out_error); if (config_value->value == nullptr) { diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 0903205b5eb2..c1e15bcf9f70 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -426,6 +426,7 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table pb_config_value->mutable_config()->set_product(config_value->product); SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), source_pool.get()); + pb_config_value->set_flag_status((uint32_t)config_value->flag_status); } } } diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp index 8abc26d67c1f..1527d68a6c3b 100644 --- a/tools/aapt2/xml/XmlPullParser.cpp +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -309,7 +309,14 @@ void XMLCALL XmlPullParser::EndCdataSectionHandler(void* user_data) { } std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, StringPiece name) { - auto iter = parser->FindAttribute("", name); + return FindAttribute(parser, "", name); +} + +std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser, + android::StringPiece namespace_uri, + android::StringPiece name) { + auto iter = parser->FindAttribute(namespace_uri, name); + if (iter != parser->end_attributes()) { return StringPiece(util::TrimWhitespace(iter->value)); } diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h index 64274d032c61..d65ba6fb56e3 100644 --- a/tools/aapt2/xml/XmlPullParser.h +++ b/tools/aapt2/xml/XmlPullParser.h @@ -194,6 +194,13 @@ std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser, android::StringPiece name); /** + * Finds the attribute in the current element within the given namespace. + */ +std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser, + android::StringPiece namespace_uri, + android::StringPiece name); + +/** * Finds the attribute in the current element within the global namespace. The * attribute's value * must not be the empty string. diff --git a/tools/lint/fix/README.md b/tools/lint/fix/README.md index a5ac2be1c18a..18bda9287a50 100644 --- a/tools/lint/fix/README.md +++ b/tools/lint/fix/README.md @@ -6,7 +6,7 @@ Inspiration: go/refactor-the-platform-with-lint\ It's a python script that runs the framework linter, and then (optionally) copies modified files back into the source tree.\ -Why python, you ask? Because python is cool ¯\_(ツ)_/¯. +Why python, you ask? Because python is cool ¯\\\_(ツ)\_/¯. Incidentally, this exposes a much simpler way to run individual lint checks against individual modules, so it's useful beyond applying fixes. @@ -15,7 +15,7 @@ against individual modules, so it's useful beyond applying fixes. Lint is not allowed to modify source files directly via lint's `--apply-suggestions` flag. As a compromise, soong zips up the (potentially) modified sources and leaves them in an intermediate -directory. This script runs the lint, unpacks those files, and copies them back into the tree. +directory. This script runs the lint, unpacks those files, and copies them back into the tree. ## How do I run it? **WARNING: You probably want to commit/stash any changes to your working tree before doing this...** |