diff options
author | 2024-12-13 17:29:18 -0800 | |
---|---|---|
committer | 2024-12-13 17:29:18 -0800 | |
commit | 7b1f850c50427ff38c20c83721c2e7aa173e62c2 (patch) | |
tree | 92f02a12a16318cde6d9a3b3761ca2c0040ce557 /tools | |
parent | 3f4c4881a31f0a24979df539b9d1e9c557a3619d (diff) | |
parent | 10e260fc86f8b879e9a88610994344f30bea7520 (diff) |
Merge "Merge 24Q4 into AOSP main" into main
Diffstat (limited to 'tools')
122 files changed, 2676 insertions, 1058 deletions
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 4c8193990feb..f43cf521edf5 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -55,7 +55,10 @@ cc_defaults { cflags: ["-D_DARWIN_UNLIMITED_STREAMS"], }, }, - header_libs: ["jni_headers"], + header_libs: [ + "jni_headers", + "native_headers", + ], static_libs: [ "libandroidfw", "libutils", @@ -110,6 +113,7 @@ cc_library_host_static { "io/ZipArchive.cpp", "link/AutoVersioner.cpp", "link/FeatureFlagsFilter.cpp", + "link/FlagDisabledResourceRemover.cpp", "link/ManifestFixer.cpp", "link/NoDefaultResourceRemover.cpp", "link/PrivateAttributeMover.cpp", @@ -186,6 +190,8 @@ cc_test_host { "integration-tests/CommandTests/**/*", "integration-tests/ConvertTest/**/*", "integration-tests/DumpTest/**/*", + ":resource-flagging-test-app-apk", + ":resource-flagging-test-app-r-java", ], } diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 6a17ef85a755..df1d51e37660 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -763,10 +763,35 @@ class ChunkPrinter { pool->setTo(chunk, android::util::DeviceToHost32( (reinterpret_cast<const ResChunk_header*>(chunk))->size)); - printer_->Print("\n"); + printer_->Print(StringPrintf(" strings: %zd styles %zd flags: %s|%s\n", pool->size(), + pool->styleCount(), pool->isUTF8() ? "UTF-8" : "UTF-16", + pool->isSorted() ? "SORTED" : "NON-SORTED")); for (size_t i = 0; i < pool->size(); i++) { printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str())); + if (i < pool->styleCount()) { + printer_->Print(" [Style] "); + auto maybe_style = pool->styleAt(i); + if (!maybe_style) { + printer_->Print("??? missing\n"); + } else { + std::vector<const ResStringPool_span*> spans; + for (auto style = maybe_style.value().unsafe_ptr(); + style->name.index != android::ResStringPool_span::END; ++style) { + spans.push_back(style); + } + printer_->Print(StringPrintf("(%zd)", spans.size())); + if (!spans.empty()) { + printer_->Print(" :"); + for (const auto& span : spans) { + printer_->Print(StringPrintf( + " %s:%u,%u", android::util::GetString(*pool, span->name.index).c_str(), + span->firstChar, span->lastChar)); + } + printer_->Print("\n"); + } + } + } } } 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..a5aecc855707 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 = FlagStatus::NoFlag; std::optional<OverlayableItem> overlayable_item; std::optional<StagedId> staged_alias; @@ -151,6 +151,7 @@ static bool AddResourcesToTable(ResourceTable* table, android::IDiagnostics* dia } if (res->value != nullptr) { + res->value->SetFlagStatus(res->flag_status); // Attach the comment, source and config to the value. res->value->SetComment(std::move(res->comment)); res->value->SetSource(std::move(res->source)); @@ -161,6 +162,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 +547,11 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, }); std::string resource_type = parser->element_name(); + auto flag_status = GetFlagStatus(parser); + if (!flag_status) { + return false; + } + out_resource->flag_status = flag_status.value(); // The value format accepted for this resource. uint32_t resource_format = 0u; @@ -725,6 +733,33 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, return false; } +std::optional<FlagStatus> ResourceParser::GetFlagStatus(xml::XmlPullParser* parser) { + auto flag_status = FlagStatus::NoFlag; + + std::optional<StringPiece> flag = xml::FindAttribute(parser, xml::kSchemaAndroid, "featureFlag"); + 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 {}; + } + 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 {}; + } + 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 {}; + } + flag_status = flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled; + } + return flag_status; +} + bool ResourceParser::ParseItem(xml::XmlPullParser* parser, ParsedResource* out_resource, const uint32_t format) { @@ -1631,12 +1666,18 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser, const std::string& element_namespace = parser->element_namespace(); const std::string& element_name = parser->element_name(); if (element_namespace.empty() && element_name == "item") { + auto flag_status = GetFlagStatus(parser); + if (!flag_status) { + error = true; + continue; + } std::unique_ptr<Item> item = ParseXml(parser, typeMask, kNoRawString); if (!item) { diag_->Error(android::DiagMessage(item_source) << "could not parse array item"); error = true; continue; } + item->SetFlagStatus(flag_status.value()); item->SetSource(item_source); array->elements.emplace_back(std::move(item)); diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 012a056dccf3..442dea89ef40 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 { @@ -82,6 +85,8 @@ class ResourceParser { private: DISALLOW_COPY_AND_ASSIGN(ResourceParser); + std::optional<FlagStatus> GetFlagStatus(xml::XmlPullParser* parser); + std::optional<FlattenedXmlSubTree> CreateFlattenSubTree(xml::XmlPullParser* parser); // Parses the XML subtree as a StyleString (flattened XML representation for strings with diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index a3b0b45df5c3..97514599c0b1 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -50,21 +50,21 @@ bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, template <typename T> bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, StringPiece rhs) { - return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0; + return lhs->name < rhs; } template <typename T> bool greater_than_struct_with_name(StringPiece lhs, const std::unique_ptr<T>& rhs) { - return rhs->name.compare(0, rhs->name.size(), lhs.data(), lhs.size()) > 0; + return rhs->name > lhs; } template <typename T> struct NameEqualRange { bool operator()(const std::unique_ptr<T>& lhs, StringPiece rhs) const { - return less_than_struct_with_name<T>(lhs, rhs); + return less_than_struct_with_name(lhs, rhs); } bool operator()(StringPiece lhs, const std::unique_ptr<T>& rhs) const { - return greater_than_struct_with_name<T>(lhs, rhs); + return greater_than_struct_with_name(lhs, rhs); } }; @@ -74,7 +74,7 @@ bool less_than_struct_with_name_and_id(const T& lhs, if (lhs.id != rhs.second) { return lhs.id < rhs.second; } - return lhs.name.compare(0, lhs.name.size(), rhs.first.data(), rhs.first.size()) < 0; + return lhs.name < rhs.first; } template <typename T, typename Func, typename Elements> @@ -90,14 +90,16 @@ struct ConfigKey { StringPiece product; }; -template <typename T> -bool lt_config_key_ref(const T& lhs, const ConfigKey& rhs) { - int cmp = lhs->config.compare(*rhs.config); - if (cmp == 0) { - cmp = StringPiece(lhs->product).compare(rhs.product); +struct lt_config_key_ref { + template <typename T> + bool operator()(const T& lhs, const ConfigKey& rhs) const noexcept { + int cmp = lhs->config.compare(*rhs.config); + if (cmp == 0) { + cmp = lhs->product.compare(rhs.product); + } + return cmp < 0; } - return cmp < 0; -} +}; } // namespace @@ -159,10 +161,10 @@ ResourceEntry* ResourceTableType::FindOrCreateEntry(android::StringPiece name) { ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config, android::StringPiece product) { auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, - lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>); + lt_config_key_ref()); if (iter != values.end()) { ResourceConfigValue* value = iter->get(); - if (value->config == config && StringPiece(value->product) == product) { + if (value->config == config && value->product == product) { return value; } } @@ -172,10 +174,10 @@ ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config, const ResourceConfigValue* ResourceEntry::FindValue(const android::ConfigDescription& config, android::StringPiece product) const { auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, - lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>); + lt_config_key_ref()); if (iter != values.end()) { ResourceConfigValue* value = iter->get(); - if (value->config == config && StringPiece(value->product) == product) { + if (value->config == config && value->product == product) { return value; } } @@ -185,10 +187,10 @@ const ResourceConfigValue* ResourceEntry::FindValue(const android::ConfigDescrip ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config, StringPiece product) { auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, - lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>); + lt_config_key_ref()); if (iter != values.end()) { ResourceConfigValue* value = iter->get(); - if (value->config == config && StringPiece(value->product) == product) { + if (value->config == config && value->product == product) { return value; } } @@ -199,36 +201,62 @@ ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& c std::vector<ResourceConfigValue*> ResourceEntry::FindAllValues(const ConfigDescription& config) { std::vector<ResourceConfigValue*> results; - - auto iter = values.begin(); + auto iter = + std::lower_bound(values.begin(), values.end(), ConfigKey{&config, ""}, lt_config_key_ref()); for (; iter != values.end(); ++iter) { ResourceConfigValue* value = iter->get(); - if (value->config == config) { - results.push_back(value); - ++iter; + if (value->config != config) { break; } - } - - for (; iter != values.end(); ++iter) { - ResourceConfigValue* value = iter->get(); - if (value->config == config) { - results.push_back(value); - } + results.push_back(value); } return results; } bool ResourceEntry::HasDefaultValue() const { - const ConfigDescription& default_config = ConfigDescription::DefaultConfig(); - // The default config should be at the top of the list, since the list is sorted. - for (auto& config_value : values) { - if (config_value->config == default_config) { - return true; - } + return !values.empty() && values.front()->config == ConfigDescription::DefaultConfig(); +} + +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; } - return false; } // The default handler for collisions. @@ -323,14 +351,14 @@ struct SortedVectorInserter : public Comparer { if (found) { return &*it; } - return &*el.insert(it, std::forward<T>(value)); + return &*el.insert(it, std::move(value)); } }; struct PackageViewComparer { bool operator()(const ResourceTablePackageView& lhs, const ResourceTablePackageView& rhs) { return less_than_struct_with_name_and_id<ResourceTablePackageView, uint8_t>( - lhs, std::make_pair(rhs.name, rhs.id)); + lhs, std::tie(rhs.name, rhs.id)); } }; @@ -343,7 +371,7 @@ struct TypeViewComparer { struct EntryViewComparer { bool operator()(const ResourceTableEntryView& lhs, const ResourceTableEntryView& rhs) { return less_than_struct_with_name_and_id<ResourceTableEntryView, uint16_t>( - lhs, std::make_pair(rhs.name, rhs.id)); + lhs, std::tie(rhs.name, rhs.id)); } }; @@ -388,10 +416,10 @@ void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePacka const ResourceConfigValue* ResourceTableEntryView::FindValue(const ConfigDescription& config, android::StringPiece product) const { auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product}, - lt_config_key_ref<const ResourceConfigValue*>); + lt_config_key_ref()); if (iter != values.end()) { const ResourceConfigValue* value = *iter; - if (value->config == config && StringPiece(value->product) == product) { + if (value->config == config && value->product == product) { return value; } } @@ -566,15 +594,23 @@ bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) config_value->value = std::move(res.value); } 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()) - : CollisionResult::kKeepBoth; + // the same configuration unless protected by flags. + auto result = + validate ? ResolveFlagCollision(config_value->value->GetFlagStatus(), res.flag_status) + : CollisionResult::kKeepBoth; + if (result == CollisionResult::kConflict) { + result = ResolveValueCollision(config_value->value.get(), res.value.get()); + } switch (result) { - case CollisionResult::kKeepBoth: + 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); + auto it = entry->values.insert( + std::lower_bound(entry->values.begin(), entry->values.end(), + ConfigKey{&res.config, res.product}, lt_config_key_ref()), + util::make_unique<ResourceConfigValue>(res.config, res.product)); + (*it)->value = std::move(res.value); break; + } case CollisionResult::kTakeNew: // Take the incoming value. @@ -735,6 +771,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..cba6b70cfbd6 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -269,6 +269,7 @@ struct NewResource { std::optional<AllowNew> allow_new; std::optional<StagedId> staged_id; bool allow_mangled = false; + FlagStatus flag_status = FlagStatus::NoFlag; }; struct NewResourceBuilder { @@ -282,6 +283,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 +332,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/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index 166b01bd9154..b75e87c90128 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -971,6 +971,16 @@ void Array::Print(std::ostream* out) const { *out << "(array) [" << util::Joiner(elements, ", ") << "]"; } +void Array::RemoveFlagDisabledElements() { + const auto end_iter = elements.end(); + const auto remove_iter = std::stable_partition( + elements.begin(), end_iter, [](const std::unique_ptr<Item>& item) -> bool { + return item->GetFlagStatus() != FlagStatus::Disabled; + }); + + elements.erase(remove_iter, end_iter); +} + bool Plural::Equals(const Value* value) const { const Plural* other = ValueCast<Plural>(value); if (!other) { @@ -1092,6 +1102,7 @@ template <typename T> std::unique_ptr<T> CopyValueFields(std::unique_ptr<T> new_value, const T* value) { new_value->SetSource(value->GetSource()); new_value->SetComment(value->GetComment()); + new_value->SetFlagStatus(value->GetFlagStatus()); return new_value; } diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h index 5192c2be1f98..a1b1839b19ef 100644 --- a/tools/aapt2/ResourceValues.h +++ b/tools/aapt2/ResourceValues.h @@ -65,6 +65,14 @@ class Value { return translatable_; } + void SetFlagStatus(FlagStatus val) { + flag_status_ = val; + } + + FlagStatus GetFlagStatus() const { + return flag_status_; + } + // Returns the source where this value was defined. const android::Source& GetSource() const { return source_; @@ -109,6 +117,10 @@ class Value { // of brevity and readability. Default implementation just calls Print(). virtual void PrettyPrint(text::Printer* printer) const; + // Removes any part of the value that is beind a disabled flag. + virtual void RemoveFlagDisabledElements() { + } + friend std::ostream& operator<<(std::ostream& out, const Value& value); protected: @@ -116,6 +128,7 @@ class Value { std::string comment_; bool weak_ = false; bool translatable_ = true; + FlagStatus flag_status_ = FlagStatus::NoFlag; private: virtual Value* TransformValueImpl(ValueTransformer& transformer) const = 0; @@ -346,6 +359,7 @@ struct Array : public TransformableValue<Array, BaseValue<Array>> { bool Equals(const Value* value) const override; void Print(std::ostream* out) const override; + void RemoveFlagDisabledElements() override; }; struct Plural : public TransformableValue<Plural, BaseValue<Plural>> { diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp index d788e3fd5fc7..b30348ddd4b4 100644 --- a/tools/aapt2/ResourceValues_test.cpp +++ b/tools/aapt2/ResourceValues_test.cpp @@ -184,6 +184,35 @@ TEST(ResourcesValuesTest, StringClones) { EXPECT_THAT(pool_b.strings()[0]->value, StrEq("hello")); } +TEST(ResourcesValuesTest, StringEquals) { + android::StringPool pool; + + String str(pool.MakeRef("hello", android::StringPool::Context(test::ParseConfigOrDie("en")))); + String str2(pool.MakeRef("hello")); + EXPECT_TRUE(str.Equals(&str2)); + EXPECT_TRUE(str2.Equals(&str)); + + String str3(pool.MakeRef("how are you")); + EXPECT_FALSE(str.Equals(&str3)); +} + +TEST(ResourcesValuesTest, StyledStringEquals) { + android::StringPool pool; + + StyledString ss(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"u", 2, 4}}})); + StyledString ss2(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"u", 2, 4}}})); + StyledString ss3(pool.MakeRef(android::StyleString{"hi", {{"b", 0, 1}, {"u", 2, 4}}})); + StyledString ss4(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}}})); + StyledString ss5(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"u", 3, 4}}})); + StyledString ss6(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"s", 2, 4}}})); + EXPECT_TRUE(ss.Equals(&ss2)); + EXPECT_TRUE(ss2.Equals(&ss)); + EXPECT_FALSE(ss.Equals(&ss3)); + EXPECT_FALSE(ss.Equals(&ss4)); + EXPECT_FALSE(ss.Equals(&ss5)); + EXPECT_FALSE(ss.Equals(&ss6)); +} + TEST(ResourceValuesTest, StyleMerges) { android::StringPool pool_a; android::StringPool pool_b; diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 1d7fd1d17dcd..5c6408940b34 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; + reserved 3; } // The generic meta-data for every value in a resource table. @@ -279,6 +280,9 @@ message Item { Id id = 6; Primitive prim = 7; } + + // The status of the flag the value is behind if any + uint32 flag_status = 8; } // A CompoundValue is an abstract type. It represents a value that is a made of other values. diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp index 993516d07386..5983cf165839 100644 --- a/tools/aapt2/SdkConstants.cpp +++ b/tools/aapt2/SdkConstants.cpp @@ -75,6 +75,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/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp index c132792d374b..6c3eae11eab9 100644 --- a/tools/aapt2/cmd/Convert.cpp +++ b/tools/aapt2/cmd/Convert.cpp @@ -244,6 +244,10 @@ class Context : public IAaptContext { return verbose_; } + void SetVerbose(bool verbose) { + verbose_ = verbose; + } + int GetMinSdkVersion() override { return min_sdk_; } @@ -388,6 +392,8 @@ int ConvertCommand::Action(const std::vector<std::string>& args) { } Context context; + context.SetVerbose(verbose_); + StringPiece path = args[0]; unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics()); if (apk == nullptr) { diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp index 5bfc73233bfe..6da3176b2bee 100644 --- a/tools/aapt2/cmd/Diff.cpp +++ b/tools/aapt2/cmd/Diff.cpp @@ -106,7 +106,7 @@ static bool EmitResourceConfigValueDiff( if (!value_a->Equals(value_b)) { std::stringstream str_stream; str_stream << "value " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name - << " config=" << config_value_a->config << " does not match:\n"; + << " config='" << config_value_a->config << "' does not match:\n"; value_a->Print(&str_stream); str_stream << "\n vs \n"; value_b->Print(&str_stream); diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 642a5618b6ad..498e431097ad 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -57,6 +57,7 @@ #include "java/ManifestClassGenerator.h" #include "java/ProguardRules.h" #include "link/FeatureFlagsFilter.h" +#include "link/FlagDisabledResourceRemover.h" #include "link/Linkers.h" #include "link/ManifestFixer.h" #include "link/NoDefaultResourceRemover.h" @@ -305,6 +306,7 @@ struct ResourceFileFlattenerOptions { OutputFormat output_format = OutputFormat::kApk; std::unordered_set<std::string> extensions_to_not_compress; std::optional<std::regex> regex_to_not_compress; + FeatureFlagValues feature_flag_values; }; // A sampling of public framework resource IDs. @@ -671,6 +673,13 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv } } + FeatureFlagsFilterOptions flags_filter_options; + flags_filter_options.flags_must_be_readonly = true; + FeatureFlagsFilter flags_filter(options_.feature_flag_values, flags_filter_options); + if (!flags_filter.Consume(context_, doc.get())) { + return 1; + } + error |= !FlattenXml(context_, *doc, dst_path, options_.keep_raw_values, false /*utf16*/, options_.output_format, archive_writer); } @@ -1840,11 +1849,57 @@ class Linker { return validate(attr->value); } + class FlagDisabledStringVisitor : public DescendingValueVisitor { + public: + using DescendingValueVisitor::Visit; + + explicit FlagDisabledStringVisitor(android::StringPool& string_pool) + : string_pool_(string_pool) { + } + + void Visit(RawString* value) override { + value->value = string_pool_.MakeRef(""); + } + + void Visit(String* value) override { + value->value = string_pool_.MakeRef(""); + } + + void Visit(StyledString* value) override { + value->value = string_pool_.MakeRef(android::StyleString{{""}, {}}); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FlagDisabledStringVisitor); + android::StringPool& string_pool_; + }; + // Writes the AndroidManifest, ResourceTable, and all XML files referenced by the ResourceTable // to the IArchiveWriter. bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest, ResourceTable* table) { TRACE_CALL(); + + FlagDisabledStringVisitor visitor(table->string_pool); + + for (auto& package : table->packages) { + for (auto& type : package->types) { + for (auto& entry : type->entries) { + for (auto& config_value : entry->values) { + if (config_value->value->GetFlagStatus() == FlagStatus::Disabled) { + config_value->value->Accept(&visitor); + } + } + } + } + } + + if (!FlagDisabledResourceRemover{}.Consume(context_, table)) { + context_->GetDiagnostics()->Error(android::DiagMessage() + << "failed removing resources behind disabled flags"); + return 1; + } + const bool keep_raw_values = (context_->GetPackageType() == PackageType::kStaticLib) || options_.keep_raw_values; bool result = FlattenXml(context_, *manifest, kAndroidManifestPath, keep_raw_values, @@ -1879,6 +1934,7 @@ class Linker { static_cast<bool>(options_.generate_proguard_rules_path); file_flattener_options.output_format = options_.output_format; file_flattener_options.do_not_fail_on_missing_resources = options_.merge_only; + file_flattener_options.feature_flag_values = options_.feature_flag_values; ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set); if (!file_flattener.Flatten(table, writer)) { @@ -2331,6 +2387,12 @@ class Linker { return 1; }; + if (options_.generate_java_class_path || options_.generate_text_symbols_path) { + if (!GenerateJavaClasses()) { + return 1; + } + } + if (!WriteApk(archive_writer.get(), &proguard_keep_set, manifest_xml.get(), &final_table_)) { return 1; } @@ -2339,12 +2401,6 @@ class Linker { return 1; } - if (options_.generate_java_class_path || options_.generate_text_symbols_path) { - if (!GenerateJavaClasses()) { - return 1; - } - } - if (!WriteProguardFile(options_.generate_proguard_rules_path, proguard_keep_set)) { return 1; } diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h index ee53af107b17..012b0f230ca2 100644 --- a/tools/aapt2/cmd/Optimize.h +++ b/tools/aapt2/cmd/Optimize.h @@ -116,6 +116,10 @@ class OptimizeCommand : public Command { "This decreases APK size at the cost of resource retrieval performance.\n" "Applies sparse encoding to all resources regardless of minSdk.", &options_.force_sparse_encoding); + AddOptionalSwitch( + "--enable-compact-entries", + "This decreases APK size by using compact resource entries for simple data types.", + &options_.table_flattener_options.use_compact_entries); AddOptionalSwitch("--collapse-resource-names", "Collapses resource names to a single value in the key string pool. Resources can \n" "be exempted using the \"no_collapse\" directive in a file specified by " diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index e1a3013c07bb..55f5e5668a16 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" @@ -874,11 +875,12 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, return value; } -std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, - const android::ResStringPool& src_pool, - const ConfigDescription& config, - android::StringPool* value_pool, - io::IFileCollection* files, std::string* out_error) { +std::unique_ptr<Item> DeserializeItemFromPbInternal(const pb::Item& pb_item, + const android::ResStringPool& src_pool, + const ConfigDescription& config, + android::StringPool* value_pool, + io::IFileCollection* files, + std::string* out_error) { switch (pb_item.value_case()) { case pb::Item::kRef: { const pb::Reference& pb_ref = pb_item.ref(); @@ -1007,6 +1009,19 @@ std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, return {}; } +std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, + const android::ResStringPool& src_pool, + const ConfigDescription& config, + android::StringPool* value_pool, + io::IFileCollection* files, std::string* out_error) { + auto item = + DeserializeItemFromPbInternal(pb_item, src_pool, config, value_pool, files, out_error); + if (item) { + item->SetFlagStatus((FlagStatus)pb_item.flag_status()); + } + return item; +} + std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node, std::string* out_error) { if (!pb_node.has_element()) { diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 0903205b5eb2..5772b3b0b3e6 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -719,6 +719,9 @@ void SerializeValueToPb(const Value& value, pb::Value* out_value, android::Strin if (src_pool != nullptr) { SerializeSourceToPb(value.GetSource(), src_pool, out_value->mutable_source()); } + if (out_value->has_item()) { + out_value->mutable_item()->set_flag_status((uint32_t)value.GetFlagStatus()); + } } void SerializeItemToPb(const Item& item, pb::Item* out_item) { @@ -726,6 +729,7 @@ void SerializeItemToPb(const Item& item, pb::Item* out_item) { ValueSerializer serializer(&value, nullptr); item.Accept(&serializer); out_item->MergeFrom(value.item()); + out_item->set_flag_status((uint32_t)item.GetFlagStatus()); } void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) { diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/Android.bp b/tools/aapt2/integration-tests/FlaggedResourcesTest/Android.bp new file mode 100644 index 000000000000..c456e5c296d2 --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/Android.bp @@ -0,0 +1,91 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], + default_team: "trendy_team_android_resources", +} + +genrule { + name: "resource-flagging-test-app-compile", + tools: ["aapt2"], + srcs: [ + "res/values/bools.xml", + "res/values/bools2.xml", + "res/values/ints.xml", + "res/values/strings.xml", + "res/layout/layout1.xml", + ], + out: [ + "values_bools.arsc.flat", + "values_bools2.arsc.flat", + "values_ints.arsc.flat", + "values_strings.arsc.flat", + "layout_layout1.xml.flat", + ], + cmd: "$(location aapt2) compile $(in) -o $(genDir) " + + "--feature-flags test.package.falseFlag:ro=false,test.package.trueFlag:ro=true", +} + +genrule { + name: "resource-flagging-test-app-apk", + tools: ["aapt2"], + // The first input file in the list must be the manifest + srcs: [ + "AndroidManifest.xml", + ":resource-flagging-test-app-compile", + ], + out: [ + "resapp.apk", + ], + cmd: "$(location aapt2) link -o $(out) --manifest $(in) " + + "-I $(location :current_android_jar) " + + "--feature-flags test.package.falseFlag:ro=false,test.package.trueFlag:ro=true", + tool_files: [":current_android_jar"], +} + +genrule { + name: "resource-flagging-test-app-r-java", + tools: ["aapt2"], + // The first input file in the list must be the manifest + srcs: [ + "AndroidManifest.xml", + ":resource-flagging-test-app-compile", + ], + out: [ + "resource-flagging-java/com/android/intenal/flaggedresources/R.java", + ], + cmd: "$(location aapt2) link -o $(genDir)/resapp.apk --java $(genDir)/resource-flagging-java --manifest $(in) " + + "-I $(location :current_android_jar) " + + "--feature-flags test.package.falseFlag:ro=false,test.package.trueFlag:ro=true", + tool_files: [":current_android_jar"], +} + +java_genrule { + name: "resource-flagging-test-app-apk-as-resource", + srcs: [ + ":resource-flagging-test-app-apk", + ], + out: ["apks_as_resources.res.zip"], + tools: ["soong_zip"], + + cmd: "mkdir -p $(genDir)/res/raw && " + + "cp $(in) $(genDir)/res/raw/$$(basename $(in)) && " + + "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res", +} diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/AndroidManifest.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/AndroidManifest.xml new file mode 100644 index 000000000000..d6cdeb7b5231 --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/AndroidManifest.xml @@ -0,0 +1,4 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.intenal.flaggedresources"> + <application/> +</manifest>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/res/layout/layout1.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/layout/layout1.xml new file mode 100644 index 000000000000..8b9ce134a9de --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/layout/layout1.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <TextView android:id="@+id/text1" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/disabled_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:featureFlag="test.package.falseFlag" /> + <TextView android:id="@+id/text2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:featureFlag="test.package.trueFlag" /> +</LinearLayout>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools.xml new file mode 100644 index 000000000000..1ed0c8a5f1e6 --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <bool name="bool1">true</bool> + <bool name="bool1" android:featureFlag="test.package.falseFlag">false</bool> + + <bool name="bool2">false</bool> + <bool name="bool2" android:featureFlag="test.package.trueFlag">true</bool> + + <bool name="bool3">false</bool> + + <bool name="bool4" android:featureFlag="test.package.falseFlag">true</bool> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools2.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools2.xml new file mode 100644 index 000000000000..248c45f7fad1 --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/bools2.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <bool name="bool3" android:featureFlag="test.package.trueFlag">true</bool> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/ints.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/ints.xml new file mode 100644 index 000000000000..26a5c40bb338 --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/ints.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <integer-array name="intarr1"> + <item>1</item> + <item>2</item> + <item android:featureFlag="test.package.falseFlag">666</item> + <item>3</item> + </integer-array> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/strings.xml b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/strings.xml new file mode 100644 index 000000000000..3cbb928a64cc --- /dev/null +++ b/tools/aapt2/integration-tests/FlaggedResourcesTest/res/values/strings.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <string name="str">plain string</string> + + <string name="str1" android:featureFlag="test.package.falseFlag">DONTFIND</string> + + <string-array name="strarr1"> + <item>one</item> + <item>two</item> + <item android:featureFlag="test.package.falseFlag">remove</item> + <item android:featureFlag="test.package.trueFlag">three</item> + </string-array> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/link/FeatureFlagsFilter.cpp b/tools/aapt2/link/FeatureFlagsFilter.cpp index 9d40db521e13..4e7c1b4d8e54 100644 --- a/tools/aapt2/link/FeatureFlagsFilter.cpp +++ b/tools/aapt2/link/FeatureFlagsFilter.cpp @@ -65,6 +65,13 @@ class FlagsVisitor : public xml::Visitor { if (auto it = feature_flag_values_.find(flag_name); it != feature_flag_values_.end()) { if (it->second.enabled.has_value()) { + if (options_.flags_must_be_readonly && !it->second.read_only) { + diagnostics_->Error(android::DiagMessage(node->line_number) + << "attribute 'android:featureFlag' has flag '" << flag_name + << "' which must be readonly but is not"); + has_error_ = true; + return false; + } if (options_.remove_disabled_elements) { // Remove if flag==true && attr=="!flag" (negated) OR flag==false && attr=="flag" return *it->second.enabled == negated; diff --git a/tools/aapt2/link/FeatureFlagsFilter.h b/tools/aapt2/link/FeatureFlagsFilter.h index 1d342a71b996..61e4c8015f0e 100644 --- a/tools/aapt2/link/FeatureFlagsFilter.h +++ b/tools/aapt2/link/FeatureFlagsFilter.h @@ -38,6 +38,10 @@ struct FeatureFlagsFilterOptions { // If true, `Consume()` will return false (error) if a flag was found whose value in // `feature_flag_values` is not defined (std::nullopt). bool flags_must_have_value = true; + + // If true, `Consume()` will return false (error) if a flag was found whose value in + // `feature_flag_values` is not readonly. + bool flags_must_be_readonly = false; }; // Looks for the `android:featureFlag` attribute in each XML element, validates the flag names and diff --git a/tools/aapt2/link/FlagDisabledResourceRemover.cpp b/tools/aapt2/link/FlagDisabledResourceRemover.cpp new file mode 100644 index 000000000000..3ac17625023e --- /dev/null +++ b/tools/aapt2/link/FlagDisabledResourceRemover.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "link/FlagDisabledResourceRemover.h" + +#include <algorithm> + +#include "ResourceTable.h" + +using android::ConfigDescription; + +namespace aapt { + +static bool KeepResourceEntry(const std::unique_ptr<ResourceEntry>& entry) { + if (entry->values.empty()) { + return true; + } + const auto end_iter = entry->values.end(); + const auto remove_iter = + std::stable_partition(entry->values.begin(), end_iter, + [](const std::unique_ptr<ResourceConfigValue>& value) -> bool { + return value->value->GetFlagStatus() != FlagStatus::Disabled; + }); + + bool keep = remove_iter != entry->values.begin(); + + entry->values.erase(remove_iter, end_iter); + + for (auto& value : entry->values) { + value->value->RemoveFlagDisabledElements(); + } + + return keep; +} + +bool FlagDisabledResourceRemover::Consume(IAaptContext* context, ResourceTable* table) { + for (auto& pkg : table->packages) { + for (auto& type : pkg->types) { + const auto end_iter = type->entries.end(); + const auto remove_iter = std::stable_partition( + type->entries.begin(), end_iter, [](const std::unique_ptr<ResourceEntry>& entry) -> bool { + return KeepResourceEntry(entry); + }); + + type->entries.erase(remove_iter, end_iter); + } + } + return true; +} + +} // namespace aapt
\ No newline at end of file diff --git a/tools/aapt2/link/FlagDisabledResourceRemover.h b/tools/aapt2/link/FlagDisabledResourceRemover.h new file mode 100644 index 000000000000..2db2cb44c4cc --- /dev/null +++ b/tools/aapt2/link/FlagDisabledResourceRemover.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "android-base/macros.h" +#include "process/IResourceTableConsumer.h" + +namespace aapt { + +// Removes any resource that are behind disabled flags. +class FlagDisabledResourceRemover : public IResourceTableConsumer { + public: + FlagDisabledResourceRemover() = default; + + bool Consume(IAaptContext* context, ResourceTable* table) override; + + private: + DISALLOW_COPY_AND_ASSIGN(FlagDisabledResourceRemover); +}; + +} // namespace aapt diff --git a/tools/aapt2/link/FlaggedResources_test.cpp b/tools/aapt2/link/FlaggedResources_test.cpp new file mode 100644 index 000000000000..3db37c2fa6f8 --- /dev/null +++ b/tools/aapt2/link/FlaggedResources_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LoadedApk.h" +#include "cmd/Dump.h" +#include "io/StringStream.h" +#include "test/Test.h" +#include "text/Printer.h" + +using ::aapt::io::StringOutputStream; +using ::aapt::text::Printer; +using testing::Eq; +using testing::Ne; + +namespace aapt { + +using FlaggedResourcesTest = CommandTestFixture; + +static android::NoOpDiagnostics noop_diag; + +void DumpStringPoolToString(LoadedApk* loaded_apk, std::string* output) { + StringOutputStream output_stream(output); + Printer printer(&output_stream); + + DumpStringsCommand command(&printer, &noop_diag); + ASSERT_EQ(command.Dump(loaded_apk), 0); + output_stream.Flush(); +} + +void DumpResourceTableToString(LoadedApk* loaded_apk, std::string* output) { + StringOutputStream output_stream(output); + Printer printer(&output_stream); + + DumpTableCommand command(&printer, &noop_diag); + ASSERT_EQ(command.Dump(loaded_apk), 0); + output_stream.Flush(); +} + +void DumpChunksToString(LoadedApk* loaded_apk, std::string* output) { + StringOutputStream output_stream(output); + Printer printer(&output_stream); + + DumpChunks command(&printer, &noop_diag); + ASSERT_EQ(command.Dump(loaded_apk), 0); + output_stream.Flush(); +} + +TEST_F(FlaggedResourcesTest, DisabledStringRemovedFromPool) { + auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"}); + auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag); + + std::string output; + DumpStringPoolToString(loaded_apk.get(), &output); + + std::string excluded = "DONTFIND"; + ASSERT_EQ(output.find(excluded), std::string::npos); +} + +TEST_F(FlaggedResourcesTest, DisabledResourcesRemovedFromTable) { + auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"}); + auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag); + + std::string output; + DumpResourceTableToString(loaded_apk.get(), &output); +} + +TEST_F(FlaggedResourcesTest, DisabledResourcesRemovedFromTableChunks) { + auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "resapp.apk"}); + auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag); + + std::string output; + DumpChunksToString(loaded_apk.get(), &output); + + ASSERT_EQ(output.find("bool4"), std::string::npos); + ASSERT_EQ(output.find("str1"), std::string::npos); +} + +TEST_F(FlaggedResourcesTest, DisabledResourcesInRJava) { + auto r_path = file::BuildPath({android::base::GetExecutableDirectory(), "resource-flagging-java", + "com", "android", "intenal", "flaggedresources", "R.java"}); + std::string r_contents; + ::android::base::ReadFileToString(r_path, &r_contents); + + ASSERT_NE(r_contents.find("public static final int bool4"), std::string::npos); + ASSERT_NE(r_contents.find("public static final int str1"), std::string::npos); +} + +} // namespace aapt diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 669cddb9af5a..382b088e4bba 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -18,9 +18,9 @@ #include <unordered_set> -#include "android-base/logging.h" - #include "ResourceUtils.h" +#include "android-base/logging.h" +#include "process/SymbolTable.h" #include "trace/TraceBuffer.h" #include "util/Util.h" #include "xml/XmlActionExecutor.h" @@ -172,6 +172,59 @@ static bool RequiredNameIsJavaClassName(xml::Element* el, android::SourcePathDia return NameIsJavaClassName(el, attr, diag); } +static bool UpdateConfigChangesIfNeeded(xml::Element* el, IAaptContext* context) { + xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges"); + if (attr == nullptr) { + return true; + } + + if (attr->value != "allKnown" && attr->value.find("allKnown") != std::string::npos) { + context->GetDiagnostics()->Error( + android::DiagMessage(el->line_number) + << "If you want to declare 'allKnown' in attribute 'android:configChanges' in <" << el->name + << ">, " << attr->value << " is not allowed', allKnown has to be used " + << "by itself, for example: 'android:configChanges=allKnown', it cannot be combined with " + << "the other flags"); + return false; + } + + if (attr->value == "allKnown") { + SymbolTable* symbol_table = context->GetExternalSymbols(); + const SymbolTable::Symbol* symbol = + symbol_table->FindByName(ResourceName("android", ResourceType::kAttr, "configChanges")); + + if (symbol == nullptr) { + context->GetDiagnostics()->Error( + android::DiagMessage(el->line_number) + << "Cannot find symbol for android:configChanges with min sdk: " + << context->GetMinSdkVersion()); + return false; + } + + std::stringstream new_value; + + const auto& symbols = symbol->attribute->symbols; + for (auto it = symbols.begin(); it != symbols.end(); ++it) { + // Skip 'resourcesUnused' which is the flag to fully disable activity restart specifically + // for games. + if (it->symbol.name.value().entry == "resourcesUnused") { + continue; + } + if (it != symbols.begin()) { + new_value << "|"; + } + new_value << it->symbol.name.value().entry; + } + const auto& old_value = attr->value; + auto new_value_str = new_value.str(); + context->GetDiagnostics()->Note(android::DiagMessage(el->line_number) + << "Updating value of 'android:configChanges' from " + << old_value << " to " << new_value_str); + attr->value = std::move(new_value_str); + } + return true; +} + static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) { xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name"); if (attr == nullptr) { @@ -382,8 +435,9 @@ static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::stri } } -bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag) { +bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, IAaptContext* context) { // First verify some options. + android::IDiagnostics* diag = context->GetDiagnostics(); if (options_.rename_manifest_package) { if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) { diag->Error(android::DiagMessage() << "invalid manifest package override '" @@ -432,6 +486,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagn // Common component actions. xml::XmlNodeAction component_action; component_action.Action(RequiredNameIsJavaClassName); + component_action.Action( + [context](xml::Element* el) -> bool { return UpdateConfigChangesIfNeeded(el, context); }); component_action["intent-filter"] = intent_filter_action; component_action["preferred"] = intent_filter_action; component_action["meta-data"] = meta_data_action; @@ -778,7 +834,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { } xml::XmlActionExecutor executor; - if (!BuildRules(&executor, context->GetDiagnostics())) { + if (!BuildRules(&executor, context)) { return false; } diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index df0ece6fe24a..748a82858175 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -110,7 +110,7 @@ class ManifestFixer : public IXmlResourceConsumer { private: DISALLOW_COPY_AND_ASSIGN(ManifestFixer); - bool BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag); + bool BuildRules(xml::XmlActionExecutor* executor, IAaptContext* context); ManifestFixerOptions options_; }; diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index 3cfdf7832801..50086273a819 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -37,27 +37,30 @@ struct ManifestFixerTest : public ::testing::Test { .SetCompilationPackage("android") .SetPackageId(0x01) .SetNameManglerPolicy(NameManglerPolicy{"android"}) - .AddSymbolSource( - test::StaticSymbolSourceBuilder() - .AddSymbol( - "android:attr/package", ResourceId(0x01010000), - test::AttributeBuilder() - .SetTypeMask(android::ResTable_map::TYPE_STRING) - .Build()) - .AddSymbol( - "android:attr/minSdkVersion", ResourceId(0x01010001), - test::AttributeBuilder() - .SetTypeMask(android::ResTable_map::TYPE_STRING | - android::ResTable_map::TYPE_INTEGER) - .Build()) - .AddSymbol( - "android:attr/targetSdkVersion", ResourceId(0x01010002), - test::AttributeBuilder() - .SetTypeMask(android::ResTable_map::TYPE_STRING | - android::ResTable_map::TYPE_INTEGER) - .Build()) - .AddSymbol("android:string/str", ResourceId(0x01060000)) - .Build()) + .AddSymbolSource(test::StaticSymbolSourceBuilder() + .AddSymbol("android:attr/package", ResourceId(0x01010000), + test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_STRING) + .Build()) + .AddSymbol("android:attr/minSdkVersion", ResourceId(0x01010001), + test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_STRING | + android::ResTable_map::TYPE_INTEGER) + .Build()) + .AddSymbol("android:attr/targetSdkVersion", ResourceId(0x01010002), + test::AttributeBuilder() + .SetTypeMask(android::ResTable_map::TYPE_STRING | + android::ResTable_map::TYPE_INTEGER) + .Build()) + .AddSymbol("android:string/str", ResourceId(0x01060000)) + .AddSymbol("android:attr/configChanges", ResourceId(0x01010003), + test::AttributeBuilder() + .AddItem("testConfigChange1", 1) + .AddItem("testConfigChange2", 2) + .AddItem("resourcesUnused", 4) + .SetTypeMask(android::ResTable_map::TYPE_STRING) + .Build()) + .Build()) .Build(); } @@ -1591,4 +1594,72 @@ TEST_F(ManifestFixerTest, IntentFilterPathMustStartWithLeadingSlashOnDeepLinks) </manifest>)"; EXPECT_THAT(Verify(input), NotNull()); } + +TEST_F(ManifestFixerTest, AllKnownNotDeclaredProperly) { + std::string input = R"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android"> + <application> + <activity android:name=".MainActivity" + android:configChanges="allKnown|testConfigChange1"> + </activity> + </application> + </manifest>)"; + auto doc = Verify(input); + EXPECT_THAT(doc, IsNull()); +} + +TEST_F(ManifestFixerTest, ModifyAttributeValueForAllKnown) { + std::string input = R"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android"> + <application> + <activity android:name=".MainActivity" + android:configChanges="allKnown"> + </activity> + </application> + </manifest>)"; + auto doc = Verify(input); + EXPECT_THAT(doc, NotNull()); + + xml::Element* el; + xml::Attribute* attr; + + el = doc->root.get(); + ASSERT_THAT(el, NotNull()); + el = el->FindChild({}, "application"); + ASSERT_THAT(el, NotNull()); + el = el->FindChild({}, "activity"); + ASSERT_THAT(el, NotNull()); + + attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges"); + ASSERT_THAT(attr->value, "testConfigChange1|testConfigChange2"); +} + +TEST_F(ManifestFixerTest, DoNothingForOtherConfigChanges) { + std::string input = R"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android"> + <application> + <activity android:name=".MainActivity" + android:configChanges="testConfigChange2"> + </activity> + </application> + </manifest>)"; + auto doc = Verify(input); + EXPECT_THAT(doc, NotNull()); + + xml::Element* el; + xml::Attribute* attr; + + el = doc->root.get(); + ASSERT_THAT(el, NotNull()); + el = el->FindChild({}, "application"); + ASSERT_THAT(el, NotNull()); + el = el->FindChild({}, "activity"); + ASSERT_THAT(el, NotNull()); + + attr = el->FindAttribute(xml::kSchemaAndroid, "configChanges"); + ASSERT_THAT(attr->value, "testConfigChange2"); +} } // namespace aapt diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index 67a48283e8b6..37a039e9528f 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -212,7 +212,11 @@ static ResourceTable::CollisionResult MergeConfigValue( collision_result = ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool); } else { - collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value); + collision_result = + ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus()); + if (collision_result == CollisionResult::kConflict) { + collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value); + } } if (collision_result == CollisionResult::kConflict) { diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h index ba4a734e03bb..14298d1678f0 100644 --- a/tools/aapt2/test/Fixture.h +++ b/tools/aapt2/test/Fixture.h @@ -127,4 +127,4 @@ struct LinkCommandBuilder { } // namespace aapt -#endif // AAPT_TEST_FIXTURE_H
\ No newline at end of file +#endif // AAPT_TEST_FIXTURE_H diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp index 203832d2dbe8..1527d68a6c3b 100644 --- a/tools/aapt2/xml/XmlPullParser.cpp +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -14,11 +14,13 @@ * limitations under the License. */ -#include <iostream> +#include "xml/XmlPullParser.h" + +#include <algorithm> #include <string> +#include <tuple> #include "util/Util.h" -#include "xml/XmlPullParser.h" #include "xml/XmlUtil.h" using ::android::InputStream; @@ -307,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)); } @@ -325,5 +334,18 @@ std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, St return {}; } +XmlPullParser::const_iterator XmlPullParser::FindAttribute(android::StringPiece namespace_uri, + android::StringPiece name) const { + const auto end_iter = end_attributes(); + const auto iter = std::lower_bound(begin_attributes(), end_iter, std::tuple(namespace_uri, name), + [](const Attribute& attr, const auto& rhs) { + return std::tie(attr.namespace_uri, attr.name) < rhs; + }); + if (iter != end_iter && namespace_uri == iter->namespace_uri && name == iter->name) { + return iter; + } + return end_iter; +} + } // namespace xml } // namespace aapt diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h index 655e6dc93e75..d65ba6fb56e3 100644 --- a/tools/aapt2/xml/XmlPullParser.h +++ b/tools/aapt2/xml/XmlPullParser.h @@ -19,8 +19,7 @@ #include <expat.h> -#include <algorithm> -#include <istream> +#include <optional> #include <ostream> #include <queue> #include <stack> @@ -195,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. @@ -302,31 +308,6 @@ inline bool XmlPullParser::Attribute::operator!=(const Attribute& rhs) const { return compare(rhs) != 0; } -inline XmlPullParser::const_iterator XmlPullParser::FindAttribute( - android::StringPiece namespace_uri, android::StringPiece name) const { - const auto end_iter = end_attributes(); - const auto iter = std::lower_bound( - begin_attributes(), end_iter, - std::pair<android::StringPiece, android::StringPiece>(namespace_uri, name), - [](const Attribute& attr, - const std::pair<android::StringPiece, android::StringPiece>& rhs) -> bool { - int cmp = attr.namespace_uri.compare( - 0, attr.namespace_uri.size(), rhs.first.data(), rhs.first.size()); - if (cmp < 0) return true; - if (cmp > 0) return false; - cmp = attr.name.compare(0, attr.name.size(), rhs.second.data(), - rhs.second.size()); - if (cmp < 0) return true; - return false; - }); - - if (iter != end_iter && namespace_uri == iter->namespace_uri && - name == iter->name) { - return iter; - } - return end_iter; -} - } // namespace xml } // namespace aapt diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java index 191f38d3df80..718d8987c13b 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java @@ -62,13 +62,11 @@ public class AslConverter { XmlUtils.getSingleChildElement( document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES, true); - return new AndroidSafetyLabelFactory() - .createFromHrElements(XmlUtils.listOf(appMetadataBundles)); + return new AndroidSafetyLabelFactory().createFromHrElement(appMetadataBundles); case ON_DEVICE: Element bundleEle = XmlUtils.getSingleChildElement(document, XmlUtils.OD_TAG_BUNDLE, true); - return new AndroidSafetyLabelFactory() - .createFromOdElements(XmlUtils.listOf(bundleEle)); + return new AndroidSafetyLabelFactory().createFromOdElement(bundleEle); default: throw new IllegalStateException("Unrecognized input format."); } @@ -91,14 +89,10 @@ public class AslConverter { switch (format) { case HUMAN_READABLE: - for (var child : asl.toHrDomElements(document)) { - document.appendChild(child); - } + document.appendChild(asl.toHrDomElement(document)); break; case ON_DEVICE: - for (var child : asl.toOdDomElements(document)) { - document.appendChild(child); - } + document.appendChild(asl.toOdDomElement(document)); break; default: throw new IllegalStateException("Unrecognized input format."); diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java index 72140a17297c..8b2fd93df889 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java @@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - public class AndroidSafetyLabel implements AslMarshallable { private final Long mVersion; @@ -46,36 +44,34 @@ public class AndroidSafetyLabel implements AslMarshallable { } /** Creates an on-device DOM element from an {@link AndroidSafetyLabel} */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element aslEle = doc.createElement(XmlUtils.OD_TAG_BUNDLE); aslEle.appendChild(XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion)); if (mSafetyLabels != null) { - XmlUtils.appendChildren(aslEle, mSafetyLabels.toOdDomElements(doc)); + aslEle.appendChild(mSafetyLabels.toOdDomElement(doc)); } if (mSystemAppSafetyLabel != null) { - XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toOdDomElements(doc)); + aslEle.appendChild(mSystemAppSafetyLabel.toOdDomElement(doc)); } if (mTransparencyInfo != null) { - XmlUtils.appendChildren(aslEle, mTransparencyInfo.toOdDomElements(doc)); + aslEle.appendChild(mTransparencyInfo.toOdDomElement(doc)); } - return XmlUtils.listOf(aslEle); + return aslEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element aslEle = doc.createElement(XmlUtils.HR_TAG_APP_METADATA_BUNDLES); aslEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion)); if (mSafetyLabels != null) { - XmlUtils.appendChildren(aslEle, mSafetyLabels.toHrDomElements(doc)); + aslEle.appendChild(mSafetyLabels.toHrDomElement(doc)); } if (mSystemAppSafetyLabel != null) { - XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toHrDomElements(doc)); + aslEle.appendChild(mSystemAppSafetyLabel.toHrDomElement(doc)); } if (mTransparencyInfo != null) { - XmlUtils.appendChildren(aslEle, mTransparencyInfo.toHrDomElements(doc)); + aslEle.appendChild(mTransparencyInfo.toHrDomElement(doc)); } - return XmlUtils.listOf(aslEle); + return aslEle; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java index c53cbbf99a46..b9eb2a35e63b 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java @@ -21,65 +21,117 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; +import java.util.Map; +import java.util.Set; public class AndroidSafetyLabelFactory implements AslMarshallableFactory<AndroidSafetyLabel> { + private final Map<Long, Set<String>> mRecognizedHrAttrs = + Map.ofEntries(Map.entry(1L, Set.of(XmlUtils.HR_ATTR_VERSION))); + private final Map<Long, Set<String>> mRequiredHrAttrs = + Map.ofEntries(Map.entry(1L, Set.of(XmlUtils.HR_ATTR_VERSION))); + private final Map<Long, Set<String>> mRecognizedHrEles = + Map.ofEntries( + Map.entry( + 1L, + Set.of( + XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, + XmlUtils.HR_TAG_SAFETY_LABELS, + XmlUtils.HR_TAG_TRANSPARENCY_INFO))); + private final Map<Long, Set<String>> mRequiredHrEles = + Map.ofEntries( + Map.entry(1L, Set.of()), + Map.entry( + 2L, + Set.of( + XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, + XmlUtils.HR_TAG_TRANSPARENCY_INFO))); + private final Map<Long, Set<String>> mRecognizedOdEleNames = + Map.ofEntries( + Map.entry( + 1L, + Set.of( + XmlUtils.OD_NAME_VERSION, + XmlUtils.OD_NAME_SAFETY_LABELS, + XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, + XmlUtils.OD_NAME_TRANSPARENCY_INFO))); + private final Map<Long, Set<String>> mRequiredOdEleNames = + Map.ofEntries( + Map.entry(1L, Set.of(XmlUtils.OD_NAME_VERSION)), + Map.entry( + 2L, + Set.of( + XmlUtils.OD_NAME_VERSION, + XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, + XmlUtils.OD_NAME_TRANSPARENCY_INFO))); /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */ - @Override - public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles) + public AndroidSafetyLabel createFromHrElement(Element appMetadataBundlesEle) throws MalformedXmlException { - Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles); long version = XmlUtils.tryGetVersion(appMetadataBundlesEle); + XmlUtils.throwIfExtraneousAttributes( + appMetadataBundlesEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version)); + XmlUtils.throwIfExtraneousChildrenHr( + appMetadataBundlesEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version)); Element safetyLabelsEle = XmlUtils.getSingleChildElement( - appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS, false); + appMetadataBundlesEle, + XmlUtils.HR_TAG_SAFETY_LABELS, + XmlUtils.getMostRecentVersion(mRequiredHrEles, version)); SafetyLabels safetyLabels = - new SafetyLabelsFactory().createFromHrElements(XmlUtils.listOf(safetyLabelsEle)); + new SafetyLabelsFactory().createFromHrElement(safetyLabelsEle, version); Element systemAppSafetyLabelEle = XmlUtils.getSingleChildElement( - appMetadataBundlesEle, XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, false); + appMetadataBundlesEle, + XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL, + XmlUtils.getMostRecentVersion(mRequiredHrEles, version)); SystemAppSafetyLabel systemAppSafetyLabel = new SystemAppSafetyLabelFactory() - .createFromHrElements(XmlUtils.listOf(systemAppSafetyLabelEle)); + .createFromHrElement(systemAppSafetyLabelEle, version); Element transparencyInfoEle = XmlUtils.getSingleChildElement( - appMetadataBundlesEle, XmlUtils.HR_TAG_TRANSPARENCY_INFO, false); + appMetadataBundlesEle, + XmlUtils.HR_TAG_TRANSPARENCY_INFO, + XmlUtils.getMostRecentVersion(mRequiredHrEles, version)); TransparencyInfo transparencyInfo = - new TransparencyInfoFactory() - .createFromHrElements(XmlUtils.listOf(transparencyInfoEle)); + new TransparencyInfoFactory().createFromHrElement(transparencyInfoEle, version); return new AndroidSafetyLabel( version, systemAppSafetyLabel, safetyLabels, transparencyInfo); } /** Creates an {@link AndroidSafetyLabel} from on-device DOM elements */ - @Override - public AndroidSafetyLabel createFromOdElements(List<Element> elements) - throws MalformedXmlException { - Element bundleEle = XmlUtils.getSingleElement(elements); + public AndroidSafetyLabel createFromOdElement(Element bundleEle) throws MalformedXmlException { Long version = XmlUtils.getOdLongEle(bundleEle, XmlUtils.OD_NAME_VERSION, true); + XmlUtils.throwIfExtraneousChildrenOd( + bundleEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version)); Element safetyLabelsEle = - XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_SAFETY_LABELS, false); + XmlUtils.getOdPbundleWithName( + bundleEle, + XmlUtils.OD_NAME_SAFETY_LABELS, + XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version)); SafetyLabels safetyLabels = - new SafetyLabelsFactory().createFromOdElements(XmlUtils.listOf(safetyLabelsEle)); + new SafetyLabelsFactory().createFromOdElement(safetyLabelsEle, version); Element systemAppSafetyLabelEle = XmlUtils.getOdPbundleWithName( - bundleEle, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, false); + bundleEle, + XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, + XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version)); SystemAppSafetyLabel systemAppSafetyLabel = new SystemAppSafetyLabelFactory() - .createFromOdElements(XmlUtils.listOf(systemAppSafetyLabelEle)); + .createFromOdElement(systemAppSafetyLabelEle, version); Element transparencyInfoEle = - XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_TRANSPARENCY_INFO, false); + XmlUtils.getOdPbundleWithName( + bundleEle, + XmlUtils.OD_NAME_TRANSPARENCY_INFO, + XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version)); TransparencyInfo transparencyInfo = - new TransparencyInfoFactory() - .createFromOdElements(XmlUtils.listOf(transparencyInfoEle)); + new TransparencyInfoFactory().createFromOdElement(transparencyInfoEle, version); return new AndroidSafetyLabel( version, systemAppSafetyLabel, safetyLabels, transparencyInfo); diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java index 129733ebc1b6..d2557aec5f82 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java @@ -39,6 +39,14 @@ public class AppInfo implements AslMarshallable { private final String mEmail; private final String mWebsite; + private final Boolean mApsCompliant; + private final String mDeveloperId; + private final String mApplicationId; + + // private final String mPrivacyPolicy; + // private final List<String> mFirstPartyEndpoints; + // private final List<String> mServiceProviderEndpoints; + public AppInfo( String title, String description, @@ -52,7 +60,10 @@ public class AppInfo implements AslMarshallable { List<String> serviceProviderEndpoints, String category, String email, - String website) { + String website, + Boolean apsCompliant, + String developerId, + String applicationId) { this.mTitle = title; this.mDescription = description; this.mContainsAds = containsAds; @@ -66,12 +77,15 @@ public class AppInfo implements AslMarshallable { this.mCategory = category; this.mEmail = email; this.mWebsite = website; + this.mApsCompliant = apsCompliant; + this.mDeveloperId = developerId; + this.mApplicationId = applicationId; } /** Creates an on-device DOM element from the {@link SafetyLabels}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element appInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_APP_INFO); + if (this.mTitle != null) { appInfoEle.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_TITLE, mTitle)); } @@ -109,7 +123,7 @@ public class AppInfo implements AslMarshallable { XmlUtils.createOdArray( doc, XmlUtils.OD_TAG_STRING_ARRAY, - XmlUtils.OD_NAME_SECURITY_ENDPOINT, + XmlUtils.OD_NAME_SECURITY_ENDPOINTS, mSecurityEndpoints)); } if (this.mFirstPartyEndpoints != null) { @@ -117,7 +131,7 @@ public class AppInfo implements AslMarshallable { XmlUtils.createOdArray( doc, XmlUtils.OD_TAG_STRING_ARRAY, - XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT, + XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, mFirstPartyEndpoints)); } if (this.mServiceProviderEndpoints != null) { @@ -125,7 +139,7 @@ public class AppInfo implements AslMarshallable { XmlUtils.createOdArray( doc, XmlUtils.OD_TAG_STRING_ARRAY, - XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT, + XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, mServiceProviderEndpoints)); } if (this.mCategory != null) { @@ -140,13 +154,28 @@ public class AppInfo implements AslMarshallable { appInfoEle.appendChild( XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_WEBSITE, this.mWebsite)); } - return XmlUtils.listOf(appInfoEle); + + if (this.mApsCompliant != null) { + appInfoEle.appendChild( + XmlUtils.createOdBooleanEle( + doc, XmlUtils.OD_NAME_APS_COMPLIANT, mApsCompliant)); + } + if (this.mDeveloperId != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_DEVELOPER_ID, mDeveloperId)); + } + if (this.mApplicationId != null) { + appInfoEle.appendChild( + XmlUtils.createOdStringEle( + doc, XmlUtils.OD_NAME_APPLICATION_ID, mApplicationId)); + } + return appInfoEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element appInfoEle = doc.createElement(XmlUtils.HR_TAG_APP_INFO); + if (this.mTitle != null) { appInfoEle.setAttribute(XmlUtils.HR_ATTR_TITLE, this.mTitle); } @@ -176,16 +205,6 @@ public class AppInfo implements AslMarshallable { appInfoEle.setAttribute( XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, String.join("|", this.mSecurityEndpoints)); } - if (this.mFirstPartyEndpoints != null) { - appInfoEle.setAttribute( - XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS, - String.join("|", this.mFirstPartyEndpoints)); - } - if (this.mServiceProviderEndpoints != null) { - appInfoEle.setAttribute( - XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, - String.join("|", this.mServiceProviderEndpoints)); - } if (this.mCategory != null) { appInfoEle.setAttribute(XmlUtils.HR_ATTR_CATEGORY, this.mCategory); } @@ -195,6 +214,30 @@ public class AppInfo implements AslMarshallable { if (this.mWebsite != null) { appInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, this.mWebsite); } - return XmlUtils.listOf(appInfoEle); + + if (this.mApsCompliant != null) { + appInfoEle.setAttribute( + XmlUtils.HR_ATTR_APS_COMPLIANT, String.valueOf(this.mApsCompliant)); + } + if (this.mFirstPartyEndpoints != null) { + appInfoEle.appendChild( + XmlUtils.createHrArray( + doc, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, mFirstPartyEndpoints)); + } + if (this.mServiceProviderEndpoints != null) { + appInfoEle.appendChild( + XmlUtils.createHrArray( + doc, + XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS, + mServiceProviderEndpoints)); + } + if (this.mDeveloperId != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_DEVELOPER_ID, this.mDeveloperId); + } + if (this.mApplicationId != null) { + appInfoEle.setAttribute(XmlUtils.HR_ATTR_APPLICATION_ID, this.mApplicationId); + } + + return appInfoEle; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java index c5069619e069..5ecf5cf0b723 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java @@ -16,47 +16,154 @@ package com.android.asllib.marshallable; -import com.android.asllib.util.AslgenUtil; import com.android.asllib.util.MalformedXmlException; import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; import java.util.List; +import java.util.Map; +import java.util.Set; public class AppInfoFactory implements AslMarshallableFactory<AppInfo> { + // We don't need to support V1 for HR. + private final Map<Long, Set<String>> mRecognizedHrAttrs = + Map.ofEntries( + Map.entry( + 2L, + Set.of( + XmlUtils.HR_ATTR_APS_COMPLIANT, + XmlUtils.HR_ATTR_PRIVACY_POLICY, + XmlUtils.HR_ATTR_DEVELOPER_ID, + XmlUtils.HR_ATTR_APPLICATION_ID))); + private final Map<Long, Set<String>> mRequiredHrAttrs = + Map.ofEntries( + Map.entry( + 2L, + Set.of( + XmlUtils.HR_ATTR_APS_COMPLIANT, + XmlUtils.HR_ATTR_PRIVACY_POLICY, + XmlUtils.HR_ATTR_DEVELOPER_ID, + XmlUtils.HR_ATTR_APPLICATION_ID))); + private final Map<Long, Set<String>> mRecognizedHrEles = + Map.ofEntries( + Map.entry( + 2L, + Set.of( + XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, + XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS))); + private final Map<Long, Set<String>> mRequiredHrEles = + Map.ofEntries( + Map.entry( + 2L, + Set.of( + XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, + XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS))); + private final Map<Long, Set<String>> mRecognizedOdEleNames = + Map.ofEntries( + Map.entry( + 1L, + Set.of( + XmlUtils.OD_NAME_TITLE, + XmlUtils.OD_NAME_DESCRIPTION, + XmlUtils.OD_NAME_CONTAINS_ADS, + XmlUtils.OD_NAME_OBEY_APS, + XmlUtils.OD_NAME_ADS_FINGERPRINTING, + XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, + XmlUtils.OD_NAME_PRIVACY_POLICY, + XmlUtils.OD_NAME_SECURITY_ENDPOINTS, + XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, + XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, + XmlUtils.OD_NAME_CATEGORY, + XmlUtils.OD_NAME_EMAIL, + XmlUtils.OD_NAME_WEBSITE)), + Map.entry( + 2L, + Set.of( + XmlUtils.OD_NAME_APS_COMPLIANT, + XmlUtils.OD_NAME_PRIVACY_POLICY, + XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, + XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, + XmlUtils.OD_NAME_DEVELOPER_ID, + XmlUtils.OD_NAME_APPLICATION_ID))); + private final Map<Long, Set<String>> mRequiredOdEles = + Map.ofEntries( + Map.entry( + 1L, + Set.of( + XmlUtils.OD_NAME_TITLE, + XmlUtils.OD_NAME_DESCRIPTION, + XmlUtils.OD_NAME_CONTAINS_ADS, + XmlUtils.OD_NAME_OBEY_APS, + XmlUtils.OD_NAME_ADS_FINGERPRINTING, + XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, + XmlUtils.OD_NAME_PRIVACY_POLICY, + XmlUtils.OD_NAME_SECURITY_ENDPOINTS, + XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, + XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, + XmlUtils.OD_NAME_CATEGORY)), + Map.entry( + 2L, + Set.of( + XmlUtils.OD_NAME_APS_COMPLIANT, + XmlUtils.OD_NAME_PRIVACY_POLICY, + XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, + XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, + XmlUtils.OD_NAME_DEVELOPER_ID, + XmlUtils.OD_NAME_APPLICATION_ID))); /** Creates a {@link AppInfo} from the human-readable DOM element. */ - @Override - public AppInfo createFromHrElements(List<Element> elements) throws MalformedXmlException { - Element appInfoEle = XmlUtils.getSingleElement(elements); + public AppInfo createFromHrElement(Element appInfoEle, long version) + throws MalformedXmlException { if (appInfoEle == null) { - AslgenUtil.logI("No AppInfo found in hr format."); return null; } + XmlUtils.throwIfExtraneousAttributes( + appInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version)); + XmlUtils.throwIfExtraneousChildrenHr( + appInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version)); - String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE, true); - String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION, true); - Boolean containsAds = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS, true); - Boolean obeyAps = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS, true); + var requiredHrAttrs = XmlUtils.getMostRecentVersion(mRequiredHrAttrs, version); + var requiredHrEles = XmlUtils.getMostRecentVersion(mRequiredHrEles, version); + + String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE, requiredHrAttrs); + String description = + XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION, requiredHrAttrs); + Boolean containsAds = + XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS, requiredHrAttrs); + Boolean obeyAps = + XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS, requiredHrAttrs); Boolean adsFingerprinting = - XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING, true); + XmlUtils.getBoolAttr( + appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING, requiredHrAttrs); Boolean securityFingerprinting = - XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, true); + XmlUtils.getBoolAttr( + appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, requiredHrAttrs); String privacyPolicy = - XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, true); + XmlUtils.getStringAttr( + appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, requiredHrAttrs); List<String> securityEndpoints = XmlUtils.getPipelineSplitAttr( - appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, true); + appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, requiredHrAttrs); + String category = + XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY, requiredHrAttrs); + String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL, requiredHrAttrs); + String website = + XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_WEBSITE, requiredHrAttrs); + String developerId = + XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DEVELOPER_ID, requiredHrAttrs); + String applicationId = + XmlUtils.getStringAttr( + appInfoEle, XmlUtils.HR_ATTR_APPLICATION_ID, requiredHrAttrs); + + Boolean apsCompliant = + XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_APS_COMPLIANT, requiredHrAttrs); List<String> firstPartyEndpoints = - XmlUtils.getPipelineSplitAttr( - appInfoEle, XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS, true); + XmlUtils.getHrItemsAsStrings( + appInfoEle, XmlUtils.HR_TAG_FIRST_PARTY_ENDPOINTS, requiredHrEles); List<String> serviceProviderEndpoints = - XmlUtils.getPipelineSplitAttr( - appInfoEle, XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, true); - String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY, true); - String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL, true); - String website = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_WEBSITE, false); + XmlUtils.getHrItemsAsStrings( + appInfoEle, XmlUtils.HR_TAG_SERVICE_PROVIDER_ENDPOINTS, requiredHrEles); return new AppInfo( title, @@ -71,40 +178,60 @@ public class AppInfoFactory implements AslMarshallableFactory<AppInfo> { serviceProviderEndpoints, category, email, - website); + website, + apsCompliant, + developerId, + applicationId); } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public AppInfo createFromOdElements(List<Element> elements) throws MalformedXmlException { - Element appInfoEle = XmlUtils.getSingleElement(elements); + public AppInfo createFromOdElement(Element appInfoEle, long version) + throws MalformedXmlException { if (appInfoEle == null) { - AslgenUtil.logI("No AppInfo found in od format."); return null; } + XmlUtils.throwIfExtraneousChildrenOd( + appInfoEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version)); + var requiredOdEles = XmlUtils.getMostRecentVersion(mRequiredOdEles, version); - String title = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_TITLE, true); + String title = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_TITLE, requiredOdEles); String description = - XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DESCRIPTION, true); + XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DESCRIPTION, requiredOdEles); Boolean containsAds = - XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_CONTAINS_ADS, true); - Boolean obeyAps = XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_OBEY_APS, true); + XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_CONTAINS_ADS, requiredOdEles); + Boolean obeyAps = + XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_OBEY_APS, requiredOdEles); Boolean adsFingerprinting = - XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_ADS_FINGERPRINTING, true); + XmlUtils.getOdBoolEle( + appInfoEle, XmlUtils.OD_NAME_ADS_FINGERPRINTING, requiredOdEles); Boolean securityFingerprinting = - XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, true); + XmlUtils.getOdBoolEle( + appInfoEle, XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, requiredOdEles); String privacyPolicy = - XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, true); + XmlUtils.getOdStringEle( + appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, requiredOdEles); List<String> securityEndpoints = - XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_SECURITY_ENDPOINT, true); + XmlUtils.getOdStringArray( + appInfoEle, XmlUtils.OD_NAME_SECURITY_ENDPOINTS, requiredOdEles); + String category = + XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_CATEGORY, requiredOdEles); + String email = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_EMAIL, requiredOdEles); + String website = + XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_WEBSITE, requiredOdEles); + String developerId = + XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DEVELOPER_ID, requiredOdEles); + String applicationId = + XmlUtils.getOdStringEle( + appInfoEle, XmlUtils.OD_NAME_APPLICATION_ID, requiredOdEles); + + Boolean apsCompliant = + XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_APS_COMPLIANT, requiredOdEles); List<String> firstPartyEndpoints = - XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT, true); + XmlUtils.getOdStringArray( + appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINTS, requiredOdEles); List<String> serviceProviderEndpoints = XmlUtils.getOdStringArray( - appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT, true); - String category = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_CATEGORY, true); - String email = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_EMAIL, true); - String website = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_WEBSITE, false); + appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINTS, requiredOdEles); return new AppInfo( title, @@ -119,6 +246,9 @@ public class AppInfoFactory implements AslMarshallableFactory<AppInfo> { serviceProviderEndpoints, category, email, - website); + website, + apsCompliant, + developerId, + applicationId); } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java index 0a70e7d0d74b..b6c789dc5ec7 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java @@ -16,16 +16,11 @@ package com.android.asllib.marshallable; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import java.util.List; - public interface AslMarshallable { /** Creates the on-device DOM elements from the AslMarshallable Java Object. */ - List<Element> toOdDomElements(Document doc); + // List<Element> toOdDomElements(Document doc); /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - List<Element> toHrDomElements(Document doc); + // List<Element> toHrDomElements(Document doc); } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java index 39582900f3a0..67f106948e79 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java @@ -16,17 +16,11 @@ package com.android.asllib.marshallable; -import com.android.asllib.util.MalformedXmlException; - -import org.w3c.dom.Element; - -import java.util.List; - public interface AslMarshallableFactory<T extends AslMarshallable> { /** Creates an {@link AslMarshallableFactory} from human-readable DOM elements */ - T createFromHrElements(List<Element> elements) throws MalformedXmlException; + // T createFromHrElements(List<Element> elements) throws MalformedXmlException; /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - T createFromOdElements(List<Element> elements) throws MalformedXmlException; + // T createFromOdElements(List<Element> elements) throws MalformedXmlException; } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java index c16d18b34360..501f170ad317 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java @@ -57,18 +57,16 @@ public class DataCategory implements AslMarshallable { } /** Creates on-device DOM element(s) from the {@link DataCategory}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, this.getCategoryName()); for (DataType dataType : mDataTypes.values()) { - XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc)); + dataCategoryEle.appendChild(dataType.toOdDomElement(doc)); } - return XmlUtils.listOf(dataCategoryEle); + return dataCategoryEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public List<Element> toHrDomElement(Document doc) { throw new IllegalStateException( "Turning DataCategory or DataType into human-readable DOM elements requires" + " visibility into parent elements. The logic resides in DataLabels."); diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java index 724416285acd..fb84e508ff7f 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java @@ -23,13 +23,11 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; public class DataCategoryFactory { /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - public DataCategory createFromOdElements(List<Element> elements) throws MalformedXmlException { - Element dataCategoryEle = XmlUtils.getSingleElement(elements); + public DataCategory createFromOdElement(Element dataCategoryEle) throws MalformedXmlException { Map<String, DataType> dataTypeMap = new LinkedHashMap<String, DataType>(); String categoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME); var odDataTypes = XmlUtils.asElementList(dataCategoryEle.getChildNodes()); @@ -45,9 +43,7 @@ public class DataCategoryFactory { "Unrecognized data type name %s for category %s", dataTypeName, categoryName)); } - dataTypeMap.put( - dataTypeName, - new DataTypeFactory().createFromOdElements(XmlUtils.listOf(odDataTypeEle))); + dataTypeMap.put(dataTypeName, new DataTypeFactory().createFromOdElement(odDataTypeEle)); } return new DataCategory(categoryName, dataTypeMap); diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java index ba0e3db52027..2cf7c82fdb3e 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java @@ -22,8 +22,8 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * Data label representation with data shared and data collected maps containing zero or more {@link @@ -56,20 +56,18 @@ public class DataLabels implements AslMarshallable { } /** Gets the on-device DOM element for the {@link DataLabels}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element dataLabelsEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DATA_LABELS); maybeAppendDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.OD_NAME_DATA_COLLECTED); maybeAppendDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.OD_NAME_DATA_SHARED); - return XmlUtils.listOf(dataLabelsEle); + return dataLabelsEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element dataLabelsEle = doc.createElement(XmlUtils.HR_TAG_DATA_LABELS); maybeAppendHrDataUsages( doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED, false); @@ -77,7 +75,7 @@ public class DataLabels implements AslMarshallable { doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED_EPHEMERAL, true); maybeAppendHrDataUsages( doc, dataLabelsEle, mDataShared, XmlUtils.HR_TAG_DATA_SHARED, false); - return XmlUtils.listOf(dataLabelsEle); + return dataLabelsEle; } private void maybeAppendDataUsages( @@ -95,7 +93,7 @@ public class DataLabels implements AslMarshallable { DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName); for (String dataTypeName : dataCategory.getDataTypes().keySet()) { DataType dataType = dataCategory.getDataTypes().get(dataTypeName); - XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc)); + dataCategoryEle.appendChild(dataType.toOdDomElement(doc)); } dataUsageEle.appendChild(dataCategoryEle); } @@ -138,7 +136,7 @@ public class DataLabels implements AslMarshallable { "|", dataType.getPurposes().stream() .map(DataType.Purpose::toString) - .toList())); + .collect(Collectors.toList()))); dataLabelsEle.appendChild(hrDataTypeEle); } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java index c4d88761835a..b1cf3ea0d39a 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java @@ -31,9 +31,7 @@ import java.util.Map; public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> { /** Creates a {@link DataLabels} from the human-readable DOM element. */ - @Override - public DataLabels createFromHrElements(List<Element> elements) throws MalformedXmlException { - Element ele = XmlUtils.getSingleElement(elements); + public DataLabels createFromHrElement(Element ele) throws MalformedXmlException { if (ele == null) { AslgenUtil.logI("Found no DataLabels in hr format."); return null; @@ -83,9 +81,7 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> { } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public DataLabels createFromOdElements(List<Element> elements) throws MalformedXmlException { - Element dataLabelsEle = XmlUtils.getSingleElement(elements); + public DataLabels createFromOdElement(Element dataLabelsEle) throws MalformedXmlException { if (dataLabelsEle == null) { AslgenUtil.logI("Found no DataLabels in od format."); return null; @@ -111,7 +107,7 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> { for (Element dataCategoryEle : dataCategoryEles) { String dataCategoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME); DataCategory dataCategory = - new DataCategoryFactory().createFromOdElements(List.of(dataCategoryEle)); + new DataCategoryFactory().createFromOdElement(dataCategoryEle); dataCategoryMap.put(dataCategoryName, dataCategory); } return dataCategoryMap; diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java index d2326d10e176..83bb61144efa 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java @@ -25,6 +25,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; /** * Data usage type representation. Types are specific to a {@link DataCategory} and contains @@ -171,8 +172,8 @@ public class DataType implements AslMarshallable { return mEphemeral; } - @Override - public List<Element> toOdDomElements(Document doc) { + /** Gets the on-device dom element */ + public Element toOdDomElement(Document doc) { Element dataTypeEle = XmlUtils.createPbundleEleWithName(doc, this.getDataTypeName()); if (!this.getPurposes().isEmpty()) { dataTypeEle.appendChild( @@ -182,7 +183,7 @@ public class DataType implements AslMarshallable { XmlUtils.OD_NAME_PURPOSES, this.getPurposes().stream() .map(p -> String.valueOf(p.getValue())) - .toList())); + .collect(Collectors.toList()))); } maybeAddBoolToOdElement( @@ -196,11 +197,10 @@ public class DataType implements AslMarshallable { this.getIsSharingOptional(), XmlUtils.OD_NAME_IS_SHARING_OPTIONAL); maybeAddBoolToOdElement(doc, dataTypeEle, this.getEphemeral(), XmlUtils.OD_NAME_EPHEMERAL); - return XmlUtils.listOf(dataTypeEle); + return dataTypeEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override public List<Element> toHrDomElements(Document doc) { throw new IllegalStateException( "Turning DataCategory or DataType into human-readable DOM elements requires" diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java index a5559d801349..96a58fa34707 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java @@ -64,8 +64,7 @@ public class DataTypeFactory { } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - public DataType createFromOdElements(List<Element> elements) throws MalformedXmlException { - Element odDataTypeEle = XmlUtils.getSingleElement(elements); + public DataType createFromOdElement(Element odDataTypeEle) throws MalformedXmlException { String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME); List<Integer> purposeInts = XmlUtils.getOdIntArray(odDataTypeEle, XmlUtils.OD_NAME_PURPOSES, true); diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java index 94fad9607880..96a64dc29526 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java @@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - /** DeveloperInfo representation */ public class DeveloperInfo implements AslMarshallable { public enum DeveloperRelationship { @@ -97,8 +95,7 @@ public class DeveloperInfo implements AslMarshallable { } /** Creates an on-device DOM element from the {@link SafetyLabels}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element developerInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_DEVELOPER_INFO); if (mName != null) { @@ -136,13 +133,11 @@ public class DeveloperInfo implements AslMarshallable { XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, mAppDeveloperRegistryId)); } - - return XmlUtils.listOf(developerInfoEle); + return developerInfoEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element developerInfoEle = doc.createElement(XmlUtils.HR_TAG_DEVELOPER_INFO); if (mName != null) { developerInfoEle.setAttribute(XmlUtils.HR_ATTR_NAME, mName); @@ -167,7 +162,6 @@ public class DeveloperInfo implements AslMarshallable { developerInfoEle.setAttribute( XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, mAppDeveloperRegistryId); } - - return XmlUtils.listOf(developerInfoEle); + return developerInfoEle; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java index 0f3b41cd5d1a..e82a53a53b25 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java @@ -22,14 +22,10 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; - public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInfo> { - /** Creates a {@link DeveloperInfo} from the human-readable DOM element. */ - @Override - public DeveloperInfo createFromHrElements(List<Element> elements) throws MalformedXmlException { - Element developerInfoEle = XmlUtils.getSingleElement(elements); + public DeveloperInfo createFromHrElement(Element developerInfoEle) + throws MalformedXmlException { if (developerInfoEle == null) { AslgenUtil.logI("No DeveloperInfo found in hr format."); return null; @@ -47,7 +43,6 @@ public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInf String appDeveloperRegistryId = XmlUtils.getStringAttr( developerInfoEle, XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, false); - return new DeveloperInfo( name, email, @@ -59,9 +54,8 @@ public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInf } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public DeveloperInfo createFromOdElements(List<Element> elements) throws MalformedXmlException { - Element developerInfoEle = XmlUtils.getSingleElement(elements); + public DeveloperInfo createFromOdElement(Element developerInfoEle) + throws MalformedXmlException { if (developerInfoEle == null) { AslgenUtil.logI("No DeveloperInfo found in od format."); return null; @@ -83,7 +77,6 @@ public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInf String appDeveloperRegistryId = XmlUtils.getOdStringEle( developerInfoEle, XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, false); - return new DeveloperInfo( name, email, diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java index 6af80715f7c1..1a83c02de3e4 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java @@ -21,71 +21,50 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - /** Safety Label representation containing zero or more {@link DataCategory} for data shared */ public class SafetyLabels implements AslMarshallable { - - private final Long mVersion; private final DataLabels mDataLabels; private final SecurityLabels mSecurityLabels; private final ThirdPartyVerification mThirdPartyVerification; public SafetyLabels( - Long version, DataLabels dataLabels, SecurityLabels securityLabels, ThirdPartyVerification thirdPartyVerification) { - this.mVersion = version; this.mDataLabels = dataLabels; this.mSecurityLabels = securityLabels; this.mThirdPartyVerification = thirdPartyVerification; } - /** Returns the data label for the safety label */ - public DataLabels getDataLabel() { - return mDataLabels; - } - - /** Gets the version of the {@link SafetyLabels}. */ - public Long getVersion() { - return mVersion; - } - /** Creates an on-device DOM element from the {@link SafetyLabels}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element safetyLabelsEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SAFETY_LABELS); - safetyLabelsEle.appendChild( - XmlUtils.createOdLongEle(doc, XmlUtils.OD_NAME_VERSION, mVersion)); if (mDataLabels != null) { - XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toOdDomElements(doc)); + safetyLabelsEle.appendChild(mDataLabels.toOdDomElement(doc)); } if (mSecurityLabels != null) { - XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toOdDomElements(doc)); + safetyLabelsEle.appendChild(mSecurityLabels.toOdDomElement(doc)); } if (mThirdPartyVerification != null) { - XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toOdDomElements(doc)); + safetyLabelsEle.appendChild(mThirdPartyVerification.toOdDomElement(doc)); } - return XmlUtils.listOf(safetyLabelsEle); + return safetyLabelsEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element safetyLabelsEle = doc.createElement(XmlUtils.HR_TAG_SAFETY_LABELS); - safetyLabelsEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion)); if (mDataLabels != null) { - XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toHrDomElements(doc)); + safetyLabelsEle.appendChild(mDataLabels.toHrDomElement(doc)); } if (mSecurityLabels != null) { - XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toHrDomElements(doc)); + safetyLabelsEle.appendChild(mSecurityLabels.toHrDomElement(doc)); } if (mThirdPartyVerification != null) { - XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toHrDomElements(doc)); + safetyLabelsEle.appendChild(mThirdPartyVerification.toHrDomElement(doc)); } - return XmlUtils.listOf(safetyLabelsEle); + return safetyLabelsEle; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java index 2644b435311b..35804d9351b4 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java @@ -16,87 +16,109 @@ package com.android.asllib.marshallable; -import com.android.asllib.util.AslgenUtil; import com.android.asllib.util.MalformedXmlException; import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; +import java.util.Map; +import java.util.Set; public class SafetyLabelsFactory implements AslMarshallableFactory<SafetyLabels> { + private final Map<Long, Set<String>> mRecognizedHrAttrs = + Map.ofEntries(Map.entry(1L, Set.of())); + private final Map<Long, Set<String>> mRequiredHrAttrs = Map.ofEntries(Map.entry(1L, Set.of())); + private final Map<Long, Set<String>> mRecognizedHrEles = + Map.ofEntries( + Map.entry( + 1L, + Set.of( + XmlUtils.HR_TAG_DATA_LABELS, + XmlUtils.HR_TAG_SECURITY_LABELS, + XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION)), + Map.entry(2L, Set.of(XmlUtils.HR_TAG_DATA_LABELS))); + private final Map<Long, Set<String>> mRequiredHrEles = Map.ofEntries(Map.entry(1L, Set.of())); + private final Map<Long, Set<String>> mRecognizedOdEleNames = + Map.ofEntries( + Map.entry( + 1L, + Set.of( + XmlUtils.OD_NAME_DATA_LABELS, + XmlUtils.OD_NAME_SECURITY_LABELS, + XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION)), + Map.entry(2L, Set.of(XmlUtils.OD_NAME_DATA_LABELS))); + private final Map<Long, Set<String>> mRequiredOdEles = Map.ofEntries(Map.entry(1L, Set.of())); /** Creates a {@link SafetyLabels} from the human-readable DOM element. */ - @Override - public SafetyLabels createFromHrElements(List<Element> elements) throws MalformedXmlException { - Element safetyLabelsEle = XmlUtils.getSingleElement(elements); + public SafetyLabels createFromHrElement(Element safetyLabelsEle, long version) + throws MalformedXmlException { if (safetyLabelsEle == null) { - AslgenUtil.logI("No SafetyLabels found in hr format."); return null; } - long version = XmlUtils.tryGetVersion(safetyLabelsEle); + + XmlUtils.throwIfExtraneousAttributes( + safetyLabelsEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version)); + XmlUtils.throwIfExtraneousChildrenHr( + safetyLabelsEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version)); + + var requiredHrEles = XmlUtils.getMostRecentVersion(mRequiredHrEles, version); DataLabels dataLabels = new DataLabelsFactory() - .createFromHrElements( - XmlUtils.listOf( - XmlUtils.getSingleChildElement( - safetyLabelsEle, - XmlUtils.HR_TAG_DATA_LABELS, - false))); + .createFromHrElement( + XmlUtils.getSingleChildElement( + safetyLabelsEle, + XmlUtils.HR_TAG_DATA_LABELS, + requiredHrEles)); SecurityLabels securityLabels = new SecurityLabelsFactory() - .createFromHrElements( - XmlUtils.listOf( - XmlUtils.getSingleChildElement( - safetyLabelsEle, - XmlUtils.HR_TAG_SECURITY_LABELS, - false))); + .createFromHrElement( + XmlUtils.getSingleChildElement( + safetyLabelsEle, + XmlUtils.HR_TAG_SECURITY_LABELS, + requiredHrEles)); ThirdPartyVerification thirdPartyVerification = new ThirdPartyVerificationFactory() - .createFromHrElements( - XmlUtils.listOf( - XmlUtils.getSingleChildElement( - safetyLabelsEle, - XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION, - false))); - return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification); + .createFromHrElement( + XmlUtils.getSingleChildElement( + safetyLabelsEle, + XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION, + requiredHrEles)); + return new SafetyLabels(dataLabels, securityLabels, thirdPartyVerification); } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public SafetyLabels createFromOdElements(List<Element> elements) throws MalformedXmlException { - Element safetyLabelsEle = XmlUtils.getSingleElement(elements); + public SafetyLabels createFromOdElement(Element safetyLabelsEle, long version) + throws MalformedXmlException { if (safetyLabelsEle == null) { - AslgenUtil.logI("No SafetyLabels found in od format."); return null; } - Long version = XmlUtils.getOdLongEle(safetyLabelsEle, XmlUtils.OD_NAME_VERSION, true); + + XmlUtils.throwIfExtraneousChildrenOd( + safetyLabelsEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version)); + var requiredOdEles = XmlUtils.getMostRecentVersion(mRequiredOdEles, version); DataLabels dataLabels = new DataLabelsFactory() - .createFromOdElements( - XmlUtils.listOf( - XmlUtils.getOdPbundleWithName( - safetyLabelsEle, - XmlUtils.OD_NAME_DATA_LABELS, - false))); + .createFromOdElement( + XmlUtils.getOdPbundleWithName( + safetyLabelsEle, + XmlUtils.OD_NAME_DATA_LABELS, + requiredOdEles)); SecurityLabels securityLabels = new SecurityLabelsFactory() - .createFromOdElements( - XmlUtils.listOf( - XmlUtils.getOdPbundleWithName( - safetyLabelsEle, - XmlUtils.OD_NAME_SECURITY_LABELS, - false))); + .createFromOdElement( + XmlUtils.getOdPbundleWithName( + safetyLabelsEle, + XmlUtils.OD_NAME_SECURITY_LABELS, + requiredOdEles)); ThirdPartyVerification thirdPartyVerification = new ThirdPartyVerificationFactory() - .createFromOdElements( - XmlUtils.listOf( - XmlUtils.getOdPbundleWithName( - safetyLabelsEle, - XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION, - false))); - return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification); + .createFromOdElement( + XmlUtils.getOdPbundleWithName( + safetyLabelsEle, + XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION, + requiredOdEles)); + return new SafetyLabels(dataLabels, securityLabels, thirdPartyVerification); } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java index 48643ba0e3ab..ccb84451c96f 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java @@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - /** Security Labels representation */ public class SecurityLabels implements AslMarshallable { @@ -35,8 +33,7 @@ public class SecurityLabels implements AslMarshallable { } /** Creates an on-device DOM element from the {@link SecurityLabels}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element ele = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SECURITY_LABELS); if (mIsDataDeletable != null) { ele.appendChild( @@ -48,12 +45,11 @@ public class SecurityLabels implements AslMarshallable { XmlUtils.createOdBooleanEle( doc, XmlUtils.OD_NAME_IS_DATA_ENCRYPTED, mIsDataEncrypted)); } - return XmlUtils.listOf(ele); + return ele; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element ele = doc.createElement(XmlUtils.HR_TAG_SECURITY_LABELS); if (mIsDataDeletable != null) { ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_DELETABLE, String.valueOf(mIsDataDeletable)); @@ -61,6 +57,6 @@ public class SecurityLabels implements AslMarshallable { if (mIsDataEncrypted != null) { ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, String.valueOf(mIsDataEncrypted)); } - return XmlUtils.listOf(ele); + return ele; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java index 525a80388261..da98a4291b4a 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java @@ -22,15 +22,10 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; - public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLabels> { /** Creates a {@link SecurityLabels} from the human-readable DOM element. */ - @Override - public SecurityLabels createFromHrElements(List<Element> elements) - throws MalformedXmlException { - Element ele = XmlUtils.getSingleElement(elements); + public SecurityLabels createFromHrElement(Element ele) throws MalformedXmlException { if (ele == null) { AslgenUtil.logI("No SecurityLabels found in hr format."); return null; @@ -43,10 +38,7 @@ public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLab } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public SecurityLabels createFromOdElements(List<Element> elements) - throws MalformedXmlException { - Element ele = XmlUtils.getSingleElement(elements); + public SecurityLabels createFromOdElement(Element ele) throws MalformedXmlException { if (ele == null) { AslgenUtil.logI("No SecurityLabels found in od format."); return null; diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java index 242e7be66d76..10d6e1aaac7d 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java @@ -21,34 +21,43 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - /** Safety Label representation containing zero or more {@link DataCategory} for data shared */ public class SystemAppSafetyLabel implements AslMarshallable { + private final String mUrl; private final Boolean mDeclaration; - public SystemAppSafetyLabel(Boolean d) { + public SystemAppSafetyLabel(String url, Boolean d) { this.mDeclaration = d; + this.mUrl = null; } /** Creates an on-device DOM element from the {@link SystemAppSafetyLabel}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element systemAppSafetyLabelEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL); - systemAppSafetyLabelEle.appendChild( - XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_DECLARATION, mDeclaration)); - return XmlUtils.listOf(systemAppSafetyLabelEle); + if (mUrl != null) { + systemAppSafetyLabelEle.appendChild( + XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl)); + } + if (mDeclaration != null) { + systemAppSafetyLabelEle.appendChild( + XmlUtils.createOdBooleanEle(doc, XmlUtils.OD_NAME_DECLARATION, mDeclaration)); + } + return systemAppSafetyLabelEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element systemAppSafetyLabelEle = doc.createElement(XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL); - XmlUtils.maybeSetHrBoolAttr( - systemAppSafetyLabelEle, XmlUtils.HR_ATTR_DECLARATION, mDeclaration); - return XmlUtils.listOf(systemAppSafetyLabelEle); + if (mUrl != null) { + systemAppSafetyLabelEle.setAttribute(XmlUtils.HR_ATTR_URL, mUrl); + } + if (mDeclaration != null) { + systemAppSafetyLabelEle.setAttribute( + XmlUtils.HR_ATTR_DECLARATION, String.valueOf(mDeclaration)); + } + return systemAppSafetyLabelEle; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java index 7f4aa7a3b690..971ae9296eb8 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java @@ -16,42 +16,77 @@ package com.android.asllib.marshallable; -import com.android.asllib.util.AslgenUtil; import com.android.asllib.util.MalformedXmlException; import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; +import java.util.Map; +import java.util.Set; public class SystemAppSafetyLabelFactory implements AslMarshallableFactory<SystemAppSafetyLabel> { + private final Map<Long, Set<String>> mRecognizedHrAttrs = + Map.ofEntries( + Map.entry(1L, Set.of(XmlUtils.HR_ATTR_URL)), + Map.entry(2L, Set.of(XmlUtils.HR_ATTR_DECLARATION))); + private final Map<Long, Set<String>> mRequiredHrAttrs = + Map.ofEntries( + Map.entry(1L, Set.of(XmlUtils.HR_ATTR_URL)), + Map.entry(2L, Set.of(XmlUtils.HR_ATTR_DECLARATION))); + private final Map<Long, Set<String>> mRecognizedHrEles = Map.ofEntries(Map.entry(1L, Set.of())); + private final Map<Long, Set<String>> mRecognizedOdEleNames = + Map.ofEntries( + Map.entry(1L, Set.of(XmlUtils.OD_NAME_URL)), + Map.entry(2L, Set.of(XmlUtils.OD_NAME_DECLARATION))); + private final Map<Long, Set<String>> mRequiredOdEleNames = + Map.ofEntries( + Map.entry(1L, Set.of(XmlUtils.OD_NAME_URL)), + Map.entry(2L, Set.of(XmlUtils.OD_NAME_DECLARATION))); /** Creates a {@link SystemAppSafetyLabel} from the human-readable DOM element. */ - @Override - public SystemAppSafetyLabel createFromHrElements(List<Element> elements) + public SystemAppSafetyLabel createFromHrElement(Element systemAppSafetyLabelEle, long version) throws MalformedXmlException { - Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements); if (systemAppSafetyLabelEle == null) { - AslgenUtil.logI("No SystemAppSafetyLabel found in hr format."); return null; } + XmlUtils.throwIfExtraneousAttributes( + systemAppSafetyLabelEle, + XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version)); + XmlUtils.throwIfExtraneousChildrenHr( + systemAppSafetyLabelEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version)); + String url = + XmlUtils.getStringAttr( + systemAppSafetyLabelEle, + XmlUtils.HR_ATTR_URL, + XmlUtils.getMostRecentVersion(mRequiredHrAttrs, version)); Boolean declaration = - XmlUtils.getBoolAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_DECLARATION, true); - return new SystemAppSafetyLabel(declaration); + XmlUtils.getBoolAttr( + systemAppSafetyLabelEle, + XmlUtils.HR_ATTR_DECLARATION, + XmlUtils.getMostRecentVersion(mRequiredHrAttrs, version)); + return new SystemAppSafetyLabel(url, declaration); } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public SystemAppSafetyLabel createFromOdElements(List<Element> elements) + public SystemAppSafetyLabel createFromOdElement(Element systemAppSafetyLabelEle, long version) throws MalformedXmlException { - Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements); if (systemAppSafetyLabelEle == null) { - AslgenUtil.logI("No SystemAppSafetyLabel found in od format."); return null; } + XmlUtils.throwIfExtraneousChildrenOd( + systemAppSafetyLabelEle, + XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version)); + String url = + XmlUtils.getOdStringEle( + systemAppSafetyLabelEle, + XmlUtils.OD_NAME_URL, + XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version)); Boolean declaration = - XmlUtils.getOdBoolEle(systemAppSafetyLabelEle, XmlUtils.OD_NAME_DECLARATION, true); - return new SystemAppSafetyLabel(declaration); + XmlUtils.getOdBoolEle( + systemAppSafetyLabelEle, + XmlUtils.OD_NAME_DECLARATION, + XmlUtils.getMostRecentVersion(mRequiredOdEleNames, version)); + return new SystemAppSafetyLabel(url, declaration); } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java index d74f3f062513..151cdb1e2f51 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java @@ -21,8 +21,6 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - /** ThirdPartyVerification representation. */ public class ThirdPartyVerification implements AslMarshallable { @@ -33,19 +31,17 @@ public class ThirdPartyVerification implements AslMarshallable { } /** Creates an on-device DOM element from the {@link ThirdPartyVerification}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element ele = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION); ele.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl)); - return XmlUtils.listOf(ele); + return ele; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element ele = doc.createElement(XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION); ele.setAttribute(XmlUtils.HR_ATTR_URL, mUrl); - return XmlUtils.listOf(ele); + return ele; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java index 197e7aa77743..f229ad6c861f 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java @@ -22,16 +22,11 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; - public class ThirdPartyVerificationFactory implements AslMarshallableFactory<ThirdPartyVerification> { /** Creates a {@link ThirdPartyVerification} from the human-readable DOM element. */ - @Override - public ThirdPartyVerification createFromHrElements(List<Element> elements) - throws MalformedXmlException { - Element ele = XmlUtils.getSingleElement(elements); + public ThirdPartyVerification createFromHrElement(Element ele) throws MalformedXmlException { if (ele == null) { AslgenUtil.logI("No ThirdPartyVerification found in hr format."); return null; @@ -42,10 +37,7 @@ public class ThirdPartyVerificationFactory } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public ThirdPartyVerification createFromOdElements(List<Element> elements) - throws MalformedXmlException { - Element ele = XmlUtils.getSingleElement(elements); + public ThirdPartyVerification createFromOdElement(Element ele) throws MalformedXmlException { if (ele == null) { AslgenUtil.logI("No ThirdPartyVerification found in od format."); return null; diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java index 6a8700a10d3f..f24e6bf58efb 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java @@ -21,9 +21,7 @@ import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.List; - -/** TransparencyInfo representation containing {@link DeveloperInfo} and {@link AppInfo} */ +/** TransparencyInfo representation containing {@link AppInfo} */ public class TransparencyInfo implements AslMarshallable { private final DeveloperInfo mDeveloperInfo; @@ -34,40 +32,28 @@ public class TransparencyInfo implements AslMarshallable { this.mAppInfo = appInfo; } - /** Gets the {@link DeveloperInfo} of the {@link TransparencyInfo}. */ - public DeveloperInfo getDeveloperInfo() { - return mDeveloperInfo; - } - - /** Gets the {@link AppInfo} of the {@link TransparencyInfo}. */ - public AppInfo getAppInfo() { - return mAppInfo; - } - /** Creates an on-device DOM element from the {@link TransparencyInfo}. */ - @Override - public List<Element> toOdDomElements(Document doc) { + public Element toOdDomElement(Document doc) { Element transparencyInfoEle = XmlUtils.createPbundleEleWithName(doc, XmlUtils.OD_NAME_TRANSPARENCY_INFO); if (mDeveloperInfo != null) { - XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toOdDomElements(doc)); + transparencyInfoEle.appendChild(mDeveloperInfo.toOdDomElement(doc)); } if (mAppInfo != null) { - XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toOdDomElements(doc)); + transparencyInfoEle.appendChild(mAppInfo.toOdDomElement(doc)); } - return XmlUtils.listOf(transparencyInfoEle); + return transparencyInfoEle; } /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ - @Override - public List<Element> toHrDomElements(Document doc) { + public Element toHrDomElement(Document doc) { Element transparencyInfoEle = doc.createElement(XmlUtils.HR_TAG_TRANSPARENCY_INFO); if (mDeveloperInfo != null) { - XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toHrDomElements(doc)); + transparencyInfoEle.appendChild(mDeveloperInfo.toHrDomElement(doc)); } if (mAppInfo != null) { - XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toHrDomElements(doc)); + transparencyInfoEle.appendChild(mAppInfo.toHrDomElement(doc)); } - return XmlUtils.listOf(transparencyInfoEle); + return transparencyInfoEle; } } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java index 94c564087918..9e98941e0d6d 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java @@ -16,60 +16,83 @@ package com.android.asllib.marshallable; -import com.android.asllib.util.AslgenUtil; import com.android.asllib.util.MalformedXmlException; import com.android.asllib.util.XmlUtils; import org.w3c.dom.Element; -import java.util.List; +import java.util.Map; +import java.util.Set; public class TransparencyInfoFactory implements AslMarshallableFactory<TransparencyInfo> { + private final Map<Long, Set<String>> mRecognizedHrAttrs = + Map.ofEntries(Map.entry(1L, Set.of())); + private final Map<Long, Set<String>> mRequiredHrAttrs = Map.ofEntries(Map.entry(1L, Set.of())); + private final Map<Long, Set<String>> mRecognizedHrEles = + Map.ofEntries( + Map.entry(1L, Set.of(XmlUtils.HR_TAG_DEVELOPER_INFO, XmlUtils.HR_TAG_APP_INFO)), + Map.entry(2L, Set.of(XmlUtils.HR_TAG_APP_INFO))); + private final Map<Long, Set<String>> mRequiredHrEles = + Map.ofEntries(Map.entry(1L, Set.of()), Map.entry(2L, Set.of(XmlUtils.HR_TAG_APP_INFO))); + private final Map<Long, Set<String>> mRecognizedOdEleNames = + Map.ofEntries( + Map.entry( + 1L, Set.of(XmlUtils.OD_NAME_DEVELOPER_INFO, XmlUtils.OD_NAME_APP_INFO)), + Map.entry(2L, Set.of(XmlUtils.OD_NAME_APP_INFO))); + private final Map<Long, Set<String>> mRequiredOdEles = + Map.ofEntries( + Map.entry(1L, Set.of()), Map.entry(2L, Set.of(XmlUtils.OD_NAME_APP_INFO))); /** Creates a {@link TransparencyInfo} from the human-readable DOM element. */ - @Override - public TransparencyInfo createFromHrElements(List<Element> elements) + public TransparencyInfo createFromHrElement(Element transparencyInfoEle, long version) throws MalformedXmlException { - Element transparencyInfoEle = XmlUtils.getSingleElement(elements); if (transparencyInfoEle == null) { - AslgenUtil.logI("No TransparencyInfo found in hr format."); return null; } + XmlUtils.throwIfExtraneousAttributes( + transparencyInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrAttrs, version)); + XmlUtils.throwIfExtraneousChildrenHr( + transparencyInfoEle, XmlUtils.getMostRecentVersion(mRecognizedHrEles, version)); Element developerInfoEle = XmlUtils.getSingleChildElement( - transparencyInfoEle, XmlUtils.HR_TAG_DEVELOPER_INFO, false); + transparencyInfoEle, + XmlUtils.HR_TAG_DEVELOPER_INFO, + XmlUtils.getMostRecentVersion(mRequiredHrEles, version)); DeveloperInfo developerInfo = - new DeveloperInfoFactory().createFromHrElements(XmlUtils.listOf(developerInfoEle)); - + new DeveloperInfoFactory().createFromHrElement(developerInfoEle); Element appInfoEle = XmlUtils.getSingleChildElement( - transparencyInfoEle, XmlUtils.HR_TAG_APP_INFO, false); - AppInfo appInfo = new AppInfoFactory().createFromHrElements(XmlUtils.listOf(appInfoEle)); + transparencyInfoEle, + XmlUtils.HR_TAG_APP_INFO, + XmlUtils.getMostRecentVersion(mRequiredHrEles, version)); + AppInfo appInfo = new AppInfoFactory().createFromHrElement(appInfoEle, version); return new TransparencyInfo(developerInfo, appInfo); } /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ - @Override - public TransparencyInfo createFromOdElements(List<Element> elements) + public TransparencyInfo createFromOdElement(Element transparencyInfoEle, long version) throws MalformedXmlException { - Element transparencyInfoEle = XmlUtils.getSingleElement(elements); if (transparencyInfoEle == null) { - AslgenUtil.logI("No TransparencyInfo found in od format."); return null; } + XmlUtils.throwIfExtraneousChildrenOd( + transparencyInfoEle, XmlUtils.getMostRecentVersion(mRecognizedOdEleNames, version)); Element developerInfoEle = XmlUtils.getOdPbundleWithName( - transparencyInfoEle, XmlUtils.OD_NAME_DEVELOPER_INFO, false); + transparencyInfoEle, + XmlUtils.OD_NAME_DEVELOPER_INFO, + XmlUtils.getMostRecentVersion(mRequiredOdEles, version)); DeveloperInfo developerInfo = - new DeveloperInfoFactory().createFromOdElements(XmlUtils.listOf(developerInfoEle)); - + new DeveloperInfoFactory().createFromOdElement(developerInfoEle); Element appInfoEle = XmlUtils.getOdPbundleWithName( - transparencyInfoEle, XmlUtils.OD_NAME_APP_INFO, false); - AppInfo appInfo = new AppInfoFactory().createFromOdElements(XmlUtils.listOf(appInfoEle)); + transparencyInfoEle, + XmlUtils.OD_NAME_APP_INFO, + XmlUtils.getMostRecentVersion(mRequiredOdEles, version)); + AppInfo appInfo = new AppInfoFactory().createFromOdElement(appInfoEle, version); return new TransparencyInfo(developerInfo, appInfo); } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java index 97cbc3950490..52c4390036f3 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java @@ -25,6 +25,9 @@ import org.w3c.dom.NodeList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; public class XmlUtils { public static final String DATA_TYPE_SEPARATOR = "_data_type_"; @@ -42,6 +45,7 @@ public class XmlUtils { public static final String HR_TAG_DATA_COLLECTED = "data-collected"; public static final String HR_TAG_DATA_COLLECTED_EPHEMERAL = "data-collected-ephemeral"; public static final String HR_TAG_DATA_SHARED = "data-shared"; + public static final String HR_TAG_ITEM = "item"; public static final String HR_ATTR_NAME = "name"; public static final String HR_ATTR_EMAIL = "email"; public static final String HR_ATTR_ADDRESS = "address"; @@ -64,12 +68,15 @@ public class XmlUtils { public static final String HR_ATTR_DESCRIPTION = "description"; public static final String HR_ATTR_CONTAINS_ADS = "containsAds"; public static final String HR_ATTR_OBEY_APS = "obeyAps"; + public static final String HR_ATTR_APS_COMPLIANT = "apsCompliant"; public static final String HR_ATTR_ADS_FINGERPRINTING = "adsFingerprinting"; public static final String HR_ATTR_SECURITY_FINGERPRINTING = "securityFingerprinting"; public static final String HR_ATTR_PRIVACY_POLICY = "privacyPolicy"; + public static final String HR_ATTR_DEVELOPER_ID = "developerId"; + public static final String HR_ATTR_APPLICATION_ID = "applicationId"; public static final String HR_ATTR_SECURITY_ENDPOINTS = "securityEndpoints"; - public static final String HR_ATTR_FIRST_PARTY_ENDPOINTS = "firstPartyEndpoints"; - public static final String HR_ATTR_SERVICE_PROVIDER_ENDPOINTS = "serviceProviderEndpoints"; + public static final String HR_TAG_FIRST_PARTY_ENDPOINTS = "first-party-endpoints"; + public static final String HR_TAG_SERVICE_PROVIDER_ENDPOINTS = "service-provider-endpoints"; public static final String HR_ATTR_CATEGORY = "category"; public static final String OD_TAG_BUNDLE = "bundle"; @@ -98,12 +105,15 @@ public class XmlUtils { public static final String OD_NAME_DESCRIPTION = "description"; public static final String OD_NAME_CONTAINS_ADS = "contains_ads"; public static final String OD_NAME_OBEY_APS = "obey_aps"; + public static final String OD_NAME_APS_COMPLIANT = "aps_compliant"; + public static final String OD_NAME_DEVELOPER_ID = "developer_id"; + public static final String OD_NAME_APPLICATION_ID = "application_id"; public static final String OD_NAME_ADS_FINGERPRINTING = "ads_fingerprinting"; public static final String OD_NAME_SECURITY_FINGERPRINTING = "security_fingerprinting"; public static final String OD_NAME_PRIVACY_POLICY = "privacy_policy"; - public static final String OD_NAME_SECURITY_ENDPOINT = "security_endpoint"; - public static final String OD_NAME_FIRST_PARTY_ENDPOINT = "first_party_endpoint"; - public static final String OD_NAME_SERVICE_PROVIDER_ENDPOINT = "service_provider_endpoint"; + public static final String OD_NAME_SECURITY_ENDPOINTS = "security_endpoints"; + public static final String OD_NAME_FIRST_PARTY_ENDPOINTS = "first_party_endpoints"; + public static final String OD_NAME_SERVICE_PROVIDER_ENDPOINTS = "service_provider_endpoints"; public static final String OD_NAME_CATEGORY = "category"; public static final String OD_NAME_VERSION = "version"; public static final String OD_NAME_URL = "url"; @@ -128,7 +138,18 @@ public class XmlUtils { /** Gets the top-level children with the tag name.. */ public static List<Element> getChildrenByTagName(Node parentEle, String tagName) { var elements = XmlUtils.asElementList(parentEle.getChildNodes()); - return elements.stream().filter(e -> e.getTagName().equals(tagName)).toList(); + return elements.stream() + .filter(e -> e.getTagName().equals(tagName)) + .collect(Collectors.toList()); + } + + /** + * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}. + */ + public static Element getSingleChildElement( + Node parentEle, String tagName, Set<String> requiredStrings) + throws MalformedXmlException { + return getSingleChildElement(parentEle, tagName, requiredStrings.contains(tagName)); } /** @@ -237,7 +258,18 @@ public class XmlUtils { return ele; } - /** Create OD style array DOM Element, which can represent any time but is stored as Strings. */ + /** Create HR style array DOM Element. */ + public static Element createHrArray(Document doc, String arrayTagName, List<String> arrayVals) { + Element arrEle = doc.createElement(arrayTagName); + for (String s : arrayVals) { + Element itemEle = doc.createElement(XmlUtils.HR_TAG_ITEM); + itemEle.setTextContent(s); + arrEle.appendChild(itemEle); + } + return arrEle; + } + + /** Create OD style array DOM Element, which can represent any type but is stored as Strings. */ public static Element createOdArray( Document doc, String arrayTag, String arrayName, List<String> arrayVals) { Element arrEle = doc.createElement(arrayTag); @@ -270,18 +302,36 @@ public class XmlUtils { } /** Gets a pipeline-split attribute. */ + public static List<String> getPipelineSplitAttr( + Element ele, String attrName, Set<String> requiredNames) throws MalformedXmlException { + return getPipelineSplitAttr(ele, attrName, requiredNames.contains(attrName)); + } + + /** Gets a pipeline-split attribute. */ public static List<String> getPipelineSplitAttr(Element ele, String attrName, boolean required) throws MalformedXmlException { - List<String> list = Arrays.stream(ele.getAttribute(attrName).split("\\|")).toList(); - if ((list.isEmpty() || list.get(0).isEmpty()) && required) { - throw new MalformedXmlException( - String.format( - "Delimited string %s was required but missing, in %s.", - attrName, ele.getTagName())); + List<String> list = + Arrays.stream(ele.getAttribute(attrName).split("\\|")).collect(Collectors.toList()); + if ((list.isEmpty() || list.get(0).isEmpty())) { + if (required) { + throw new MalformedXmlException( + String.format( + "Delimited string %s was required but missing, in %s.", + attrName, ele.getTagName())); + } + return null; } return list; } + /** + * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}. + */ + public static Boolean getBoolAttr(Element ele, String attrName, Set<String> requiredStrings) + throws MalformedXmlException { + return getBoolAttr(ele, attrName, requiredStrings.contains(attrName)); + } + /** Gets a Boolean attribute. */ public static Boolean getBoolAttr(Element ele, String attrName, boolean required) throws MalformedXmlException { @@ -296,12 +346,18 @@ public class XmlUtils { } /** Gets a Boolean attribute. */ + public static Boolean getOdBoolEle(Element ele, String nameName, Set<String> requiredNames) + throws MalformedXmlException { + return getOdBoolEle(ele, nameName, requiredNames.contains(nameName)); + } + + /** Gets a Boolean attribute. */ public static Boolean getOdBoolEle(Element ele, String nameName, boolean required) throws MalformedXmlException { List<Element> boolEles = XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_BOOLEAN).stream() .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) - .toList(); + .collect(Collectors.toList()); if (boolEles.size() > 1) { throw new MalformedXmlException( String.format( @@ -332,7 +388,7 @@ public class XmlUtils { List<Element> longEles = XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_LONG).stream() .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) - .toList(); + .collect(Collectors.toList()); if (longEles.size() > 1) { throw new MalformedXmlException( String.format( @@ -358,12 +414,18 @@ public class XmlUtils { } /** Gets an on-device String attribute. */ + public static String getOdStringEle(Element ele, String nameName, Set<String> requiredNames) + throws MalformedXmlException { + return getOdStringEle(ele, nameName, requiredNames.contains(nameName)); + } + + /** Gets an on-device String attribute. */ public static String getOdStringEle(Element ele, String nameName, boolean required) throws MalformedXmlException { List<Element> eles = XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_STRING).stream() .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) - .toList(); + .collect(Collectors.toList()); if (eles.size() > 1) { throw new MalformedXmlException( String.format( @@ -386,12 +448,19 @@ public class XmlUtils { } /** Gets a OD Pbundle Element attribute with the specified name. */ + public static Element getOdPbundleWithName( + Element ele, String nameName, Set<String> requiredStrings) + throws MalformedXmlException { + return getOdPbundleWithName(ele, nameName, requiredStrings.contains(nameName)); + } + + /** Gets a OD Pbundle Element attribute with the specified name. */ public static Element getOdPbundleWithName(Element ele, String nameName, boolean required) throws MalformedXmlException { List<Element> eles = XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_PBUNDLE_AS_MAP).stream() .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) - .toList(); + .collect(Collectors.toList()); if (eles.size() > 1) { throw new MalformedXmlException( String.format( @@ -407,6 +476,14 @@ public class XmlUtils { return eles.get(0); } + /** + * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}. + */ + public static String getStringAttr(Element ele, String attrName, Set<String> requiredStrings) + throws MalformedXmlException { + return getStringAttr(ele, attrName, requiredStrings.contains(attrName)); + } + /** Gets a required String attribute. */ public static String getStringAttr(Element ele, String attrName) throws MalformedXmlException { return getStringAttr(ele, attrName, true); @@ -435,7 +512,7 @@ public class XmlUtils { List<Element> intArrayEles = XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_INT_ARRAY).stream() .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) - .toList(); + .collect(Collectors.toList()); if (intArrayEles.size() > 1) { throw new MalformedXmlException( String.format("Found more than one %s in %s.", nameName, ele.getTagName())); @@ -456,13 +533,52 @@ public class XmlUtils { return ints; } + /** Gets human-readable style String array. */ + public static List<String> getHrItemsAsStrings( + Element parent, String elementName, Set<String> requiredNames) + throws MalformedXmlException { + return getHrItemsAsStrings(parent, elementName, requiredNames.contains(elementName)); + } + + /** Gets human-readable style String array. */ + public static List<String> getHrItemsAsStrings( + Element parent, String elementName, boolean required) throws MalformedXmlException { + + List<Element> arrayEles = XmlUtils.getChildrenByTagName(parent, elementName); + if (arrayEles.size() > 1) { + throw new MalformedXmlException( + String.format( + "Found more than one %s in %s.", elementName, parent.getTagName())); + } + if (arrayEles.isEmpty()) { + if (required) { + throw new MalformedXmlException( + String.format("Found no %s in %s.", elementName, parent.getTagName())); + } + return null; + } + Element arrayEle = arrayEles.get(0); + List<Element> itemEles = XmlUtils.getChildrenByTagName(arrayEle, XmlUtils.HR_TAG_ITEM); + List<String> strs = new ArrayList<String>(); + for (Element itemEle : itemEles) { + strs.add(itemEle.getTextContent()); + } + return strs; + } + + /** Gets on-device style String array. */ + public static List<String> getOdStringArray( + Element ele, String nameName, Set<String> requiredNames) throws MalformedXmlException { + return getOdStringArray(ele, nameName, requiredNames.contains(nameName)); + } + /** Gets on-device style String array. */ public static List<String> getOdStringArray(Element ele, String nameName, boolean required) throws MalformedXmlException { List<Element> arrayEles = XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_STRING_ARRAY).stream() .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) - .toList(); + .collect(Collectors.toList()); if (arrayEles.size() > 1) { throw new MalformedXmlException( String.format( @@ -486,6 +602,73 @@ public class XmlUtils { return strs; } + /** Throws if extraneous child elements detected */ + public static void throwIfExtraneousChildrenHr(Element ele, Set<String> expectedChildNames) + throws MalformedXmlException { + var childEles = XmlUtils.asElementList(ele.getChildNodes()); + List<Element> extraneousEles = + childEles.stream() + .filter(e -> !expectedChildNames.contains(e.getTagName())) + .collect(Collectors.toList()); + if (!extraneousEles.isEmpty()) { + throw new MalformedXmlException( + String.format( + "Unexpected element(s) %s in %s.", + extraneousEles.stream() + .map(Element::getTagName) + .collect(Collectors.joining(",")), + ele.getTagName())); + } + } + + /** Throws if extraneous child elements detected */ + public static void throwIfExtraneousChildrenOd(Element ele, Set<String> expectedChildNames) + throws MalformedXmlException { + var allChildElements = XmlUtils.asElementList(ele.getChildNodes()); + List<Element> extraneousEles = + allChildElements.stream() + .filter( + e -> + !e.getAttribute(XmlUtils.OD_ATTR_NAME).isEmpty() + && !expectedChildNames.contains( + e.getAttribute(XmlUtils.OD_ATTR_NAME))) + .collect(Collectors.toList()); + if (!extraneousEles.isEmpty()) { + throw new MalformedXmlException( + String.format( + "Unexpected element(s) in %s: %s", + ele.getTagName(), + extraneousEles.stream() + .map( + e -> + String.format( + "%s name=%s", + e.getTagName(), + e.getAttribute(XmlUtils.OD_ATTR_NAME))) + .collect(Collectors.joining(",")))); + } + } + + /** Throws if extraneous attributes detected */ + public static void throwIfExtraneousAttributes(Element ele, Set<String> expectedAttrNames) + throws MalformedXmlException { + var attrs = ele.getAttributes(); + List<String> attrNames = new ArrayList<>(); + for (int i = 0; i < attrs.getLength(); i++) { + attrNames.add(attrs.item(i).getNodeName()); + } + List<String> extraneousAttrs = + attrNames.stream() + .filter(s -> !expectedAttrNames.contains(s)) + .collect(Collectors.toList()); + if (!extraneousAttrs.isEmpty()) { + throw new MalformedXmlException( + String.format( + "Unexpected attr(s) %s in %s.", + String.join(",", extraneousAttrs), ele.getTagName())); + } + } + /** * Utility method for making a List from one element, to support easier refactoring if needed. * For example, List.of() doesn't support null elements. @@ -493,4 +676,26 @@ public class XmlUtils { public static List<Element> listOf(Element e) { return Arrays.asList(e); } + + /** + * Gets the most recent version of fields in the mapping. This way when a new version is + * released, we only need to update the mappings that were modified. The rest will fall back to + * the most recent previous version. + */ + public static Set<String> getMostRecentVersion( + Map<Long, Set<String>> versionToFieldsMapping, long version) + throws MalformedXmlException { + long bestVersion = 0; + Set<String> bestSet = null; + for (Map.Entry<Long, Set<String>> entry : versionToFieldsMapping.entrySet()) { + if (entry.getKey() > bestVersion && entry.getKey() <= version) { + bestVersion = entry.getKey(); + bestSet = entry.getValue(); + } + } + if (bestSet == null) { + throw new MalformedXmlException("Unexpected version: " + version); + } + return bestSet; + } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java index dbeeb496144a..e3aa50a4cee2 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AllTests.java @@ -35,14 +35,13 @@ import org.junit.runners.Suite; AslgenTests.class, AndroidSafetyLabelTest.class, AppInfoTest.class, - // DataCategoryTest.class, DataLabelsTest.class, DataTypeEqualityTest.class, - DeveloperInfoTest.class, SafetyLabelsTest.class, - SecurityLabelsTest.class, SystemAppSafetyLabelTest.class, - ThirdPartyVerificationTest.class, - TransparencyInfoTest.class + TransparencyInfoTest.class, + DeveloperInfoTest.class, + SecurityLabelsTest.class, + ThirdPartyVerificationTest.class }) public class AllTests {} diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java index 5d1d45a9a29b..262f76d52c90 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java @@ -41,6 +41,18 @@ public class AslgenTests { /** Logic for setting up tests (empty if not yet needed). */ public static void main(String[] params) throws Exception {} + @Test + public void testValidOd() throws Exception { + System.out.println("start testing valid od."); + Path odPath = Paths.get(VALID_MAPPINGS_PATH, "general-v1", OD_XML_FILENAME); + InputStream odStream = getClass().getClassLoader().getResourceAsStream(odPath.toString()); + String odContents = + TestUtils.getFormattedXml( + new String(odStream.readAllBytes(), StandardCharsets.UTF_8), false); + AndroidSafetyLabel unusedAsl = + AslConverter.readFromString(odContents, AslConverter.Format.ON_DEVICE); + } + /** Tests valid mappings between HR and OD. */ @Test public void testValidMappings() throws Exception { diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java index 61a78232801c..6470c060af87 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java @@ -16,12 +16,19 @@ package com.android.asllib.marshallable; +import static org.junit.Assert.assertThrows; + import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; + +import java.nio.file.Paths; +import java.util.List; @RunWith(JUnit4.class) public class AndroidSafetyLabelTest { @@ -31,12 +38,16 @@ public class AndroidSafetyLabelTest { "com/android/asllib/androidsafetylabel/od"; private static final String MISSING_VERSION_FILE_NAME = "missing-version.xml"; - private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml"; + private static final String VALID_V2_FILE_NAME = "valid-empty.xml"; + private static final String VALID_V1_FILE_NAME = "valid-v1.xml"; private static final String WITH_SAFETY_LABELS_FILE_NAME = "with-safety-labels.xml"; private static final String WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME = "with-system-app-safety-label.xml"; private static final String WITH_TRANSPARENCY_INFO_FILE_NAME = "with-transparency-info.xml"; + public static final List<String> REQUIRED_FIELD_NAMES_OD_V2 = + List.of("system_app_safety_label", "transparency_info"); + @Before public void setUp() throws Exception { System.out.println("set up."); @@ -50,12 +61,12 @@ public class AndroidSafetyLabelTest { odToHrExpectException(MISSING_VERSION_FILE_NAME); } - /** Test for android safety label valid empty. */ + /** Test for android safety label valid v2. */ @Test - public void testAndroidSafetyLabelValidEmptyFile() throws Exception { - System.out.println("starting testAndroidSafetyLabelValidEmptyFile."); - testHrToOdAndroidSafetyLabel(VALID_EMPTY_FILE_NAME); - testOdToHrAndroidSafetyLabel(VALID_EMPTY_FILE_NAME); + public void testAndroidSafetyLabelValidV2File() throws Exception { + System.out.println("starting testAndroidSafetyLabelValidV2File."); + testHrToOdAndroidSafetyLabel(VALID_V2_FILE_NAME); + testOdToHrAndroidSafetyLabel(VALID_V2_FILE_NAME); } /** Test for android safety label with safety labels. */ @@ -66,47 +77,77 @@ public class AndroidSafetyLabelTest { testOdToHrAndroidSafetyLabel(WITH_SAFETY_LABELS_FILE_NAME); } - /** Test for android safety label with system app safety label. */ + /** Tests missing required fields fails, V2. */ @Test - public void testAndroidSafetyLabelWithSystemAppSafetyLabel() throws Exception { - System.out.println("starting testAndroidSafetyLabelWithSystemAppSafetyLabel."); - testHrToOdAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME); - testOdToHrAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME); + public void testMissingRequiredFieldsOdV2() throws Exception { + for (String reqField : REQUIRED_FIELD_NAMES_OD_V2) { + System.out.println("testing missing required field od v2: " + reqField); + var ele = + TestUtils.getElementFromResource( + Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, VALID_V2_FILE_NAME)); + TestUtils.removeOdChildEleWithName(ele, reqField); + assertThrows( + MalformedXmlException.class, + () -> new AndroidSafetyLabelFactory().createFromOdElement(ele)); + } } - /** Test for android safety label with transparency info. */ + /** Tests missing optional fields succeeds, V1. */ @Test - public void testAndroidSafetyLabelWithTransparencyInfo() throws Exception { - System.out.println("starting testAndroidSafetyLabelWithTransparencyInfo."); - testHrToOdAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME); - testOdToHrAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME); + public void testMissingOptionalFieldsOdV1() throws Exception { + for (String reqField : REQUIRED_FIELD_NAMES_OD_V2) { + System.out.println("testing missing optional field od v1: " + reqField); + var ele = + TestUtils.getElementFromResource( + Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, VALID_V1_FILE_NAME)); + TestUtils.removeOdChildEleWithName(ele, reqField); + var unused = new AndroidSafetyLabelFactory().createFromOdElement(ele); + } } private void hrToOdExpectException(String fileName) { - TestUtils.hrToOdExpectException( - new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_HR_PATH, fileName); + assertThrows( + MalformedXmlException.class, + () -> { + new AndroidSafetyLabelFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(ANDROID_SAFETY_LABEL_HR_PATH, fileName))); + }); } private void odToHrExpectException(String fileName) { - TestUtils.odToHrExpectException( - new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_OD_PATH, fileName); + assertThrows( + MalformedXmlException.class, + () -> { + new AndroidSafetyLabelFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, fileName))); + }); } private void testHrToOdAndroidSafetyLabel(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new AndroidSafetyLabelFactory(), - ANDROID_SAFETY_LABEL_HR_PATH, - ANDROID_SAFETY_LABEL_OD_PATH, - fileName); + var doc = TestUtils.document(); + AndroidSafetyLabel asl = + new AndroidSafetyLabelFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(ANDROID_SAFETY_LABEL_HR_PATH, fileName))); + Element aslEle = asl.toOdDomElement(doc); + doc.appendChild(aslEle); + TestUtils.testFormatToFormat(doc, Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, fileName)); } private void testOdToHrAndroidSafetyLabel(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new AndroidSafetyLabelFactory(), - ANDROID_SAFETY_LABEL_OD_PATH, - ANDROID_SAFETY_LABEL_HR_PATH, - fileName); + var doc = TestUtils.document(); + AndroidSafetyLabel asl = + new AndroidSafetyLabelFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(ANDROID_SAFETY_LABEL_OD_PATH, fileName))); + Element aslEle = asl.toHrDomElement(doc); + doc.appendChild(aslEle); + TestUtils.testFormatToFormat(doc, Paths.get(ANDROID_SAFETY_LABEL_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java index 9e91c6f22641..b4a7663a1839 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java @@ -20,34 +20,34 @@ import static org.junit.Assert.assertThrows; import com.android.asllib.testutils.TestUtils; import com.android.asllib.util.MalformedXmlException; +import com.android.asllib.util.XmlUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; import java.nio.file.Paths; import java.util.List; @RunWith(JUnit4.class) public class AppInfoTest { + private static final long DEFAULT_VERSION = 2L; private static final String APP_INFO_HR_PATH = "com/android/asllib/appinfo/hr"; private static final String APP_INFO_OD_PATH = "com/android/asllib/appinfo/od"; public static final List<String> REQUIRED_FIELD_NAMES = - List.of( - "title", - "description", - "containsAds", - "obeyAps", - "adsFingerprinting", - "securityFingerprinting", - "privacyPolicy", - "securityEndpoints", - "firstPartyEndpoints", - "serviceProviderEndpoints", - "category", - "email"); + List.of("apsCompliant", "privacyPolicy"); public static final List<String> REQUIRED_FIELD_NAMES_OD = + List.of("aps_compliant", "privacy_policy"); + public static final List<String> REQUIRED_CHILD_NAMES = + List.of("first-party-endpoints", "service-provider-endpoints"); + public static final List<String> REQUIRED_CHILD_NAMES_OD = + List.of("first_party_endpoints", "service_provider_endpoints"); + public static final List<String> OPTIONAL_FIELD_NAMES = List.of(); + public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of(); + + public static final List<String> REQUIRED_FIELD_NAMES_OD_V1 = List.of( "title", "description", @@ -56,15 +56,15 @@ public class AppInfoTest { "ads_fingerprinting", "security_fingerprinting", "privacy_policy", - "security_endpoint", - "first_party_endpoint", - "service_provider_endpoint", - "category", - "email"); - public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website"); - public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of("website"); + "security_endpoints", + "first_party_endpoints", + "service_provider_endpoints", + "category"); + public static final List<String> OPTIONAL_FIELD_NAMES_OD_V1 = List.of("website", "email"); private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; + private static final String ALL_FIELDS_VALID_V1_FILE_NAME = "all-fields-valid-v1.xml"; + public static final String UNRECOGNIZED_V1_FILE_NAME = "unrecognized-v1.xml"; /** Logic for setting up tests (empty if not yet needed). */ public static void main(String[] params) throws Exception {} @@ -82,6 +82,62 @@ public class AppInfoTest { testOdToHrAppInfo(ALL_FIELDS_VALID_FILE_NAME); } + /** Test for all fields valid v1. */ + @Test + public void testAllFieldsValidV1() throws Exception { + System.out.println("starting testAllFieldsValidV1."); + var unused = + new AppInfoFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_V1_FILE_NAME)), + 1L); + } + + /** Test for unrecognized field v1. */ + @Test + public void testUnrecognizedFieldV1() throws Exception { + System.out.println("starting testUnrecognizedFieldV1."); + assertThrows( + MalformedXmlException.class, + () -> + new AppInfoFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get( + APP_INFO_OD_PATH, + UNRECOGNIZED_V1_FILE_NAME)), + 1L)); + } + + /** Tests missing required fields fails, V1. */ + @Test + public void testMissingRequiredFieldsOdV1() throws Exception { + for (String reqField : REQUIRED_FIELD_NAMES_OD_V1) { + System.out.println("testing missing required field od v1: " + reqField); + var appInfoEle = + TestUtils.getElementFromResource( + Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_V1_FILE_NAME)); + TestUtils.removeOdChildEleWithName(appInfoEle, reqField); + assertThrows( + MalformedXmlException.class, + () -> new AppInfoFactory().createFromOdElement(appInfoEle, 1L)); + } + } + + /** Tests missing optional fields passes, V1. */ + @Test + public void testMissingOptionalFieldsOdV1() throws Exception { + for (String optField : OPTIONAL_FIELD_NAMES_OD_V1) { + System.out.println("testing missing optional field od v1: " + optField); + var appInfoEle = + TestUtils.getElementFromResource( + Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_V1_FILE_NAME)); + TestUtils.removeOdChildEleWithName(appInfoEle, optField); + var unused = new AppInfoFactory().createFromOdElement(appInfoEle, 1L); + } + } + /** Tests missing required fields fails. */ @Test public void testMissingRequiredFields() throws Exception { @@ -89,24 +145,52 @@ public class AppInfoTest { for (String reqField : REQUIRED_FIELD_NAMES) { System.out.println("testing missing required field hr: " + reqField); var appInfoEle = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); - appInfoEle.get(0).removeAttribute(reqField); + appInfoEle.removeAttribute(reqField); assertThrows( MalformedXmlException.class, - () -> new AppInfoFactory().createFromHrElements(appInfoEle)); + () -> new AppInfoFactory().createFromHrElement(appInfoEle, DEFAULT_VERSION)); } for (String reqField : REQUIRED_FIELD_NAMES_OD) { System.out.println("testing missing required field od: " + reqField); var appInfoEle = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); - TestUtils.removeOdChildEleWithName(appInfoEle.get(0), reqField); + TestUtils.removeOdChildEleWithName(appInfoEle, reqField); assertThrows( MalformedXmlException.class, - () -> new AppInfoFactory().createFromOdElements(appInfoEle)); + () -> new AppInfoFactory().createFromOdElement(appInfoEle, DEFAULT_VERSION)); + } + } + + /** Tests missing required child fails. */ + @Test + public void testMissingRequiredChild() throws Exception { + System.out.println("Starting testMissingRequiredFields"); + for (String reqChildName : REQUIRED_CHILD_NAMES) { + System.out.println("testing missing required child hr: " + reqChildName); + var appInfoEle = + TestUtils.getElementFromResource( + Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); + var child = XmlUtils.getChildrenByTagName(appInfoEle, reqChildName).get(0); + appInfoEle.removeChild(child); + assertThrows( + MalformedXmlException.class, + () -> new AppInfoFactory().createFromHrElement(appInfoEle, DEFAULT_VERSION)); + } + + for (String reqField : REQUIRED_CHILD_NAMES_OD) { + System.out.println("testing missing required child od: " + reqField); + var appInfoEle = + TestUtils.getElementFromResource( + Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); + TestUtils.removeOdChildEleWithName(appInfoEle, reqField); + assertThrows( + MalformedXmlException.class, + () -> new AppInfoFactory().createFromOdElement(appInfoEle, DEFAULT_VERSION)); } } @@ -115,38 +199,51 @@ public class AppInfoTest { public void testMissingOptionalFields() throws Exception { for (String optField : OPTIONAL_FIELD_NAMES) { var ele = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); - ele.get(0).removeAttribute(optField); - AppInfo appInfo = new AppInfoFactory().createFromHrElements(ele); - appInfo.toOdDomElements(TestUtils.document()); + ele.removeAttribute(optField); + AppInfo appInfo = new AppInfoFactory().createFromHrElement(ele, DEFAULT_VERSION); + var unused = appInfo.toOdDomElement(TestUtils.document()); } for (String optField : OPTIONAL_FIELD_NAMES_OD) { var ele = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); - TestUtils.removeOdChildEleWithName(ele.get(0), optField); - AppInfo appInfo = new AppInfoFactory().createFromOdElements(ele); - appInfo.toHrDomElements(TestUtils.document()); + TestUtils.removeOdChildEleWithName(ele, optField); + AppInfo appInfo = new AppInfoFactory().createFromOdElement(ele, DEFAULT_VERSION); + var unused = appInfo.toHrDomElement(TestUtils.document()); } } private void testHrToOdAppInfo(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new AppInfoFactory(), - APP_INFO_HR_PATH, - APP_INFO_OD_PATH, - fileName); + var doc = TestUtils.document(); + AppInfo appInfo = + new AppInfoFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(APP_INFO_HR_PATH, fileName)), + DEFAULT_VERSION); + Element appInfoEle = appInfo.toOdDomElement(doc); + doc.appendChild(appInfoEle); + TestUtils.testFormatToFormat(doc, Paths.get(APP_INFO_OD_PATH, fileName)); } + private void testOdToHrAppInfo(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new AppInfoFactory(), - APP_INFO_OD_PATH, - APP_INFO_HR_PATH, - fileName); + testOdToHrAppInfo(fileName, DEFAULT_VERSION); + } + + private void testOdToHrAppInfo(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + AppInfo appInfo = + new AppInfoFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(APP_INFO_OD_PATH, fileName)), + version); + Element appInfoEle = appInfo.toHrDomElement(doc); + doc.appendChild(appInfoEle); + TestUtils.testFormatToFormat(doc, Paths.get(APP_INFO_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java index ff4374166dd3..cc58a61760f4 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java @@ -16,12 +16,22 @@ package com.android.asllib.marshallable; +import static org.junit.Assert.assertThrows; + import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.nio.file.Paths; + +import javax.xml.parsers.ParserConfigurationException; @RunWith(JUnit4.class) public class DataLabelsTest { @@ -297,29 +307,43 @@ public class DataLabelsTest { odToHrExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME); } - private void hrToOdExpectException(String fileName) { - TestUtils.hrToOdExpectException(new DataLabelsFactory(), DATA_LABELS_HR_PATH, fileName); + private void hrToOdExpectException(String fileName) + throws ParserConfigurationException, IOException, SAXException { + var ele = TestUtils.getElementFromResource(Paths.get(DATA_LABELS_HR_PATH, fileName)); + assertThrows( + MalformedXmlException.class, + () -> new DataLabelsFactory().createFromHrElement(ele)); } - private void odToHrExpectException(String fileName) { - TestUtils.odToHrExpectException(new DataLabelsFactory(), DATA_LABELS_OD_PATH, fileName); + private void odToHrExpectException(String fileName) + throws ParserConfigurationException, IOException, SAXException { + var ele = TestUtils.getElementFromResource(Paths.get(DATA_LABELS_OD_PATH, fileName)); + assertThrows( + MalformedXmlException.class, + () -> new DataLabelsFactory().createFromOdElement(ele)); } private void testHrToOdDataLabels(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new DataLabelsFactory(), - DATA_LABELS_HR_PATH, - DATA_LABELS_OD_PATH, - fileName); + var doc = TestUtils.document(); + DataLabels dataLabels = + new DataLabelsFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(DATA_LABELS_HR_PATH, fileName))); + Element resultingEle = dataLabels.toOdDomElement(doc); + doc.appendChild(resultingEle); + TestUtils.testFormatToFormat(doc, Paths.get(DATA_LABELS_OD_PATH, fileName)); } private void testOdToHrDataLabels(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new DataLabelsFactory(), - DATA_LABELS_OD_PATH, - DATA_LABELS_HR_PATH, - fileName); + var doc = TestUtils.document(); + DataLabels dataLabels = + new DataLabelsFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(DATA_LABELS_OD_PATH, fileName))); + Element resultingEle = dataLabels.toHrDomElement(doc); + doc.appendChild(resultingEle); + TestUtils.testFormatToFormat(doc, Paths.get(DATA_LABELS_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java index 72e8d654b542..2746800532ab 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java @@ -25,6 +25,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; import java.nio.file.Paths; import java.util.List; @@ -66,25 +67,25 @@ public class DeveloperInfoTest { for (String reqField : REQUIRED_FIELD_NAMES) { System.out.println("testing missing required field: " + reqField); var developerInfoEle = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(DEVELOPER_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); - developerInfoEle.get(0).removeAttribute(reqField); + developerInfoEle.removeAttribute(reqField); assertThrows( MalformedXmlException.class, - () -> new DeveloperInfoFactory().createFromHrElements(developerInfoEle)); + () -> new DeveloperInfoFactory().createFromHrElement(developerInfoEle)); } for (String reqField : REQUIRED_FIELD_NAMES_OD) { System.out.println("testing missing required field od: " + reqField); var developerInfoEle = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); - TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), reqField); + TestUtils.removeOdChildEleWithName(developerInfoEle, reqField); assertThrows( MalformedXmlException.class, - () -> new DeveloperInfoFactory().createFromOdElements(developerInfoEle)); + () -> new DeveloperInfoFactory().createFromOdElement(developerInfoEle)); } } @@ -93,40 +94,46 @@ public class DeveloperInfoTest { public void testMissingOptionalFields() throws Exception { for (String optField : OPTIONAL_FIELD_NAMES) { var developerInfoEle = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(DEVELOPER_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); - developerInfoEle.get(0).removeAttribute(optField); + developerInfoEle.removeAttribute(optField); DeveloperInfo developerInfo = - new DeveloperInfoFactory().createFromHrElements(developerInfoEle); - developerInfo.toOdDomElements(TestUtils.document()); + new DeveloperInfoFactory().createFromHrElement(developerInfoEle); + var unused = developerInfo.toOdDomElement(TestUtils.document()); } for (String optField : OPTIONAL_FIELD_NAMES_OD) { var developerInfoEle = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); - TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), optField); + TestUtils.removeOdChildEleWithName(developerInfoEle, optField); DeveloperInfo developerInfo = - new DeveloperInfoFactory().createFromOdElements(developerInfoEle); - developerInfo.toHrDomElements(TestUtils.document()); + new DeveloperInfoFactory().createFromOdElement(developerInfoEle); + var unused = developerInfo.toHrDomElement(TestUtils.document()); } } private void testHrToOdDeveloperInfo(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new DeveloperInfoFactory(), - DEVELOPER_INFO_HR_PATH, - DEVELOPER_INFO_OD_PATH, - fileName); + var doc = TestUtils.document(); + DeveloperInfo developerInfo = + new DeveloperInfoFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(DEVELOPER_INFO_HR_PATH, fileName))); + Element developerInfoEle = developerInfo.toOdDomElement(doc); + doc.appendChild(developerInfoEle); + TestUtils.testFormatToFormat(doc, Paths.get(DEVELOPER_INFO_OD_PATH, fileName)); } private void testOdToHrDeveloperInfo(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new DeveloperInfoFactory(), - DEVELOPER_INFO_OD_PATH, - DEVELOPER_INFO_HR_PATH, - fileName); + var doc = TestUtils.document(); + DeveloperInfo developerInfo = + new DeveloperInfoFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(DEVELOPER_INFO_OD_PATH, fileName))); + Element developerInfoEle = developerInfo.toHrDomElement(doc); + doc.appendChild(developerInfoEle); + TestUtils.testFormatToFormat(doc, Paths.get(DEVELOPER_INFO_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java index bba6b548beaf..fc8ff00794ad 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java @@ -16,93 +16,95 @@ package com.android.asllib.marshallable; +import static org.junit.Assert.assertThrows; + import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; + +import java.nio.file.Paths; @RunWith(JUnit4.class) public class SafetyLabelsTest { + private static final long DEFAULT_VERSION = 2L; + private static final String SAFETY_LABELS_HR_PATH = "com/android/asllib/safetylabels/hr"; private static final String SAFETY_LABELS_OD_PATH = "com/android/asllib/safetylabels/od"; - private static final String MISSING_VERSION_FILE_NAME = "missing-version.xml"; private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml"; private static final String WITH_DATA_LABELS_FILE_NAME = "with-data-labels.xml"; - private static final String WITH_SECURITY_LABELS_FILE_NAME = "with-security-labels.xml"; - private static final String WITH_THIRD_PARTY_VERIFICATION_FILE_NAME = - "with-third-party-verification.xml"; + private static final String VALID_V1_FILE_NAME = "valid-v1.xml"; + private static final String UNRECOGNIZED_FIELD_V2_FILE_NAME = "unrecognized-field-v2.xml"; @Before public void setUp() throws Exception { System.out.println("set up."); } - /** Test for safety labels missing version. */ - @Test - public void testSafetyLabelsMissingVersion() throws Exception { - System.out.println("starting testSafetyLabelsMissingVersion."); - hrToOdExpectException(MISSING_VERSION_FILE_NAME); - odToHrExpectException(MISSING_VERSION_FILE_NAME); - } - /** Test for safety labels valid empty. */ @Test public void testSafetyLabelsValidEmptyFile() throws Exception { System.out.println("starting testSafetyLabelsValidEmptyFile."); - testHrToOdSafetyLabels(VALID_EMPTY_FILE_NAME); - testOdToHrSafetyLabels(VALID_EMPTY_FILE_NAME); + testHrToOdSafetyLabels(VALID_EMPTY_FILE_NAME, DEFAULT_VERSION); + testOdToHrSafetyLabels(VALID_EMPTY_FILE_NAME, DEFAULT_VERSION); } /** Test for safety labels with data labels. */ @Test public void testSafetyLabelsWithDataLabels() throws Exception { System.out.println("starting testSafetyLabelsWithDataLabels."); - testHrToOdSafetyLabels(WITH_DATA_LABELS_FILE_NAME); - testOdToHrSafetyLabels(WITH_DATA_LABELS_FILE_NAME); + testHrToOdSafetyLabels(WITH_DATA_LABELS_FILE_NAME, DEFAULT_VERSION); + testOdToHrSafetyLabels(WITH_DATA_LABELS_FILE_NAME, DEFAULT_VERSION); } - /** Test for safety labels with security labels. */ + /** Tests valid fields v1. */ @Test - public void testSafetyLabelsWithSecurityLabels() throws Exception { - System.out.println("starting testSafetyLabelsWithSecurityLabels."); - testHrToOdSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME); - testOdToHrSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME); + public void testValidFieldsV1() throws Exception { + var ele = + TestUtils.getElementFromResource( + Paths.get(SAFETY_LABELS_OD_PATH, VALID_V1_FILE_NAME)); + var unused = new SafetyLabelsFactory().createFromOdElement(ele, 1L); } - /** Test for safety labels with third party verification. */ + /** Tests unrecognized field v2. */ @Test - public void testSafetyLabelsWithThirdPartyVerification() throws Exception { - System.out.println("starting testSafetyLabelsWithThirdPartyVerification."); - testHrToOdSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME); - testOdToHrSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME); - } - - private void hrToOdExpectException(String fileName) { - TestUtils.hrToOdExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_HR_PATH, fileName); - } - - private void odToHrExpectException(String fileName) { - TestUtils.odToHrExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_OD_PATH, fileName); + public void testUnrecognizedFieldV2() throws Exception { + var ele = + TestUtils.getElementFromResource( + Paths.get(SAFETY_LABELS_OD_PATH, VALID_V1_FILE_NAME)); + assertThrows( + MalformedXmlException.class, + () -> new SafetyLabelsFactory().createFromOdElement(ele, 2L)); } - private void testHrToOdSafetyLabels(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new SafetyLabelsFactory(), - SAFETY_LABELS_HR_PATH, - SAFETY_LABELS_OD_PATH, - fileName); + private void testHrToOdSafetyLabels(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + SafetyLabels safetyLabels = + new SafetyLabelsFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(SAFETY_LABELS_HR_PATH, fileName)), + version); + Element appInfoEle = safetyLabels.toOdDomElement(doc); + doc.appendChild(appInfoEle); + TestUtils.testFormatToFormat(doc, Paths.get(SAFETY_LABELS_OD_PATH, fileName)); } - private void testOdToHrSafetyLabels(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new SafetyLabelsFactory(), - SAFETY_LABELS_OD_PATH, - SAFETY_LABELS_HR_PATH, - fileName); + private void testOdToHrSafetyLabels(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + SafetyLabels safetyLabels = + new SafetyLabelsFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(SAFETY_LABELS_OD_PATH, fileName)), + version); + Element appInfoEle = safetyLabels.toHrDomElement(doc); + doc.appendChild(appInfoEle); + TestUtils.testFormatToFormat(doc, Paths.get(SAFETY_LABELS_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java index a940bc63c685..27f8720868dc 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java @@ -16,13 +16,13 @@ package com.android.asllib.marshallable; - import com.android.asllib.testutils.TestUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; import java.nio.file.Paths; import java.util.List; @@ -60,37 +60,43 @@ public class SecurityLabelsTest { public void testMissingOptionalFields() throws Exception { for (String optField : OPTIONAL_FIELD_NAMES) { var ele = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(SECURITY_LABELS_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); - ele.get(0).removeAttribute(optField); - SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElements(ele); - securityLabels.toOdDomElements(TestUtils.document()); + ele.removeAttribute(optField); + SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElement(ele); + var unused = securityLabels.toOdDomElement(TestUtils.document()); } for (String optField : OPTIONAL_FIELD_NAMES_OD) { var ele = - TestUtils.getElementsFromResource( + TestUtils.getElementFromResource( Paths.get(SECURITY_LABELS_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); - TestUtils.removeOdChildEleWithName(ele.get(0), optField); - SecurityLabels securityLabels = new SecurityLabelsFactory().createFromOdElements(ele); - securityLabels.toHrDomElements(TestUtils.document()); + TestUtils.removeOdChildEleWithName(ele, optField); + SecurityLabels securityLabels = new SecurityLabelsFactory().createFromOdElement(ele); + var unused = securityLabels.toHrDomElement(TestUtils.document()); } } private void testHrToOdSecurityLabels(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new SecurityLabelsFactory(), - SECURITY_LABELS_HR_PATH, - SECURITY_LABELS_OD_PATH, - fileName); + var doc = TestUtils.document(); + SecurityLabels securityLabels = + new SecurityLabelsFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(SECURITY_LABELS_HR_PATH, fileName))); + Element ele = securityLabels.toOdDomElement(doc); + doc.appendChild(ele); + TestUtils.testFormatToFormat(doc, Paths.get(SECURITY_LABELS_OD_PATH, fileName)); } private void testOdToHrSecurityLabels(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new SecurityLabelsFactory(), - SECURITY_LABELS_OD_PATH, - SECURITY_LABELS_HR_PATH, - fileName); + var doc = TestUtils.document(); + SecurityLabels securityLabels = + new SecurityLabelsFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(SECURITY_LABELS_OD_PATH, fileName))); + Element ele = securityLabels.toHrDomElement(doc); + doc.appendChild(ele); + TestUtils.testFormatToFormat(doc, Paths.get(SECURITY_LABELS_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java index 87d3e4499f5c..04bcd783a1dd 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java @@ -16,21 +16,34 @@ package com.android.asllib.marshallable; +import static org.junit.Assert.assertThrows; + import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.nio.file.Paths; + +import javax.xml.parsers.ParserConfigurationException; @RunWith(JUnit4.class) public class SystemAppSafetyLabelTest { + private static final long DEFAULT_VERSION = 2L; + private static final String SYSTEM_APP_SAFETY_LABEL_HR_PATH = "com/android/asllib/systemappsafetylabel/hr"; private static final String SYSTEM_APP_SAFETY_LABEL_OD_PATH = "com/android/asllib/systemappsafetylabel/od"; private static final String VALID_FILE_NAME = "valid.xml"; + private static final String VALID_V1_FILE_NAME = "valid-v1.xml"; private static final String MISSING_BOOL_FILE_NAME = "missing-bool.xml"; /** Logic for setting up tests (empty if not yet needed). */ @@ -45,43 +58,83 @@ public class SystemAppSafetyLabelTest { @Test public void testValid() throws Exception { System.out.println("starting testValid."); - testHrToOdSystemAppSafetyLabel(VALID_FILE_NAME); - testOdToHrSystemAppSafetyLabel(VALID_FILE_NAME); + testHrToOdSystemAppSafetyLabel(VALID_FILE_NAME, DEFAULT_VERSION); + testOdToHrSystemAppSafetyLabel(VALID_FILE_NAME, DEFAULT_VERSION); + } + + /** Test for valid v1. */ + @Test + public void testValidV1() throws Exception { + System.out.println("starting testValidV1."); + var doc = TestUtils.document(); + var unused = + new SystemAppSafetyLabelFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get( + SYSTEM_APP_SAFETY_LABEL_OD_PATH, + VALID_V1_FILE_NAME)), + 1L); + } + + /** Test for testV1InvalidAsV2. */ + @Test + public void testV1InvalidAsV2() throws Exception { + System.out.println("starting testV1InvalidAsV2."); + odToHrExpectException(VALID_V1_FILE_NAME, 2L); } /** Tests missing bool. */ @Test public void testMissingBool() throws Exception { System.out.println("starting testMissingBool."); - hrToOdExpectException(MISSING_BOOL_FILE_NAME); - odToHrExpectException(MISSING_BOOL_FILE_NAME); + hrToOdExpectException(MISSING_BOOL_FILE_NAME, DEFAULT_VERSION); + odToHrExpectException(MISSING_BOOL_FILE_NAME, DEFAULT_VERSION); } - private void hrToOdExpectException(String fileName) { - TestUtils.hrToOdExpectException( - new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName); + private void hrToOdExpectException(String fileName, long version) + throws ParserConfigurationException, IOException, SAXException { + var ele = + TestUtils.getElementFromResource( + Paths.get(SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName)); + assertThrows( + MalformedXmlException.class, + () -> new SystemAppSafetyLabelFactory().createFromHrElement(ele, version)); } - private void odToHrExpectException(String fileName) { - TestUtils.odToHrExpectException( - new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName); + private void odToHrExpectException(String fileName, long version) + throws ParserConfigurationException, IOException, SAXException { + var ele = + TestUtils.getElementFromResource( + Paths.get(SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName)); + assertThrows( + MalformedXmlException.class, + () -> new SystemAppSafetyLabelFactory().createFromOdElement(ele, version)); } - private void testHrToOdSystemAppSafetyLabel(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new SystemAppSafetyLabelFactory(), - SYSTEM_APP_SAFETY_LABEL_HR_PATH, - SYSTEM_APP_SAFETY_LABEL_OD_PATH, - fileName); + private void testHrToOdSystemAppSafetyLabel(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + SystemAppSafetyLabel systemAppSafetyLabel = + new SystemAppSafetyLabelFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName)), + version); + Element resultingEle = systemAppSafetyLabel.toOdDomElement(doc); + doc.appendChild(resultingEle); + TestUtils.testFormatToFormat(doc, Paths.get(SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName)); } - private void testOdToHrSystemAppSafetyLabel(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new SystemAppSafetyLabelFactory(), - SYSTEM_APP_SAFETY_LABEL_OD_PATH, - SYSTEM_APP_SAFETY_LABEL_HR_PATH, - fileName); + private void testOdToHrSystemAppSafetyLabel(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + SystemAppSafetyLabel systemAppSafetyLabel = + new SystemAppSafetyLabelFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName)), + version); + Element resultingEle = systemAppSafetyLabel.toHrDomElement(doc); + doc.appendChild(resultingEle); + TestUtils.testFormatToFormat(doc, Paths.get(SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java index ec86d0f863af..ebb2e93af920 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java @@ -16,12 +16,18 @@ package com.android.asllib.marshallable; +import static org.junit.Assert.assertThrows; + import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; + +import java.nio.file.Paths; @RunWith(JUnit4.class) public class ThirdPartyVerificationTest { @@ -58,30 +64,48 @@ public class ThirdPartyVerificationTest { } private void hrToOdExpectException(String fileName) { - TestUtils.hrToOdExpectException( - new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_HR_PATH, fileName); + assertThrows( + MalformedXmlException.class, + () -> { + new ThirdPartyVerificationFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(THIRD_PARTY_VERIFICATION_HR_PATH, fileName))); + }); } private void odToHrExpectException(String fileName) { - TestUtils.odToHrExpectException( - new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_OD_PATH, fileName); + assertThrows( + MalformedXmlException.class, + () -> { + new ThirdPartyVerificationFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(THIRD_PARTY_VERIFICATION_OD_PATH, fileName))); + }); } private void testHrToOdThirdPartyVerification(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new ThirdPartyVerificationFactory(), - THIRD_PARTY_VERIFICATION_HR_PATH, - THIRD_PARTY_VERIFICATION_OD_PATH, - fileName); + var doc = TestUtils.document(); + ThirdPartyVerification thirdPartyVerification = + new ThirdPartyVerificationFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(THIRD_PARTY_VERIFICATION_HR_PATH, fileName))); + Element ele = thirdPartyVerification.toOdDomElement(doc); + doc.appendChild(ele); + TestUtils.testFormatToFormat(doc, Paths.get(THIRD_PARTY_VERIFICATION_OD_PATH, fileName)); } private void testOdToHrThirdPartyVerification(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new ThirdPartyVerificationFactory(), - THIRD_PARTY_VERIFICATION_OD_PATH, - THIRD_PARTY_VERIFICATION_HR_PATH, - fileName); + var doc = TestUtils.document(); + ThirdPartyVerification thirdPartyVerification = + new ThirdPartyVerificationFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(THIRD_PARTY_VERIFICATION_OD_PATH, fileName))); + Element ele = thirdPartyVerification.toHrDomElement(doc); + doc.appendChild(ele); + TestUtils.testFormatToFormat(doc, Paths.get(THIRD_PARTY_VERIFICATION_HR_PATH, fileName)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java index f49424061427..b27d6ddb6243 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java @@ -16,68 +16,118 @@ package com.android.asllib.marshallable; +import static org.junit.Assert.assertThrows; + import com.android.asllib.testutils.TestUtils; +import com.android.asllib.util.MalformedXmlException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.nio.file.Paths; + +import javax.xml.parsers.ParserConfigurationException; @RunWith(JUnit4.class) public class TransparencyInfoTest { + private static final long DEFAULT_VERSION = 2L; + private static final String TRANSPARENCY_INFO_HR_PATH = "com/android/asllib/transparencyinfo/hr"; private static final String TRANSPARENCY_INFO_OD_PATH = "com/android/asllib/transparencyinfo/od"; - - private static final String VALID_EMPTY_FILE_NAME = "valid-empty.xml"; - private static final String WITH_DEVELOPER_INFO_FILE_NAME = "with-developer-info.xml"; private static final String WITH_APP_INFO_FILE_NAME = "with-app-info.xml"; + private static final String VALID_EMPTY_V1_FILE_NAME = "valid-empty-v1.xml"; + private static final String VALID_DEV_INFO_V1_FILE_NAME = "valid-dev-info-v1.xml"; + private static final String WITH_APP_INFO_AND_DEV_INFO_FILE_NAME = + "with-app-info-v2-and-dev-info-v1.xml"; @Before public void setUp() throws Exception { System.out.println("set up."); } - /** Test for transparency info valid empty. */ + /** Test for transparency info with app info. */ @Test - public void testTransparencyInfoValidEmptyFile() throws Exception { - System.out.println("starting testTransparencyInfoValidEmptyFile."); - testHrToOdTransparencyInfo(VALID_EMPTY_FILE_NAME); - testOdToHrTransparencyInfo(VALID_EMPTY_FILE_NAME); + public void testTransparencyInfoWithAppInfo() throws Exception { + System.out.println("starting testTransparencyInfoWithAppInfo."); + testHrToOdTransparencyInfo(WITH_APP_INFO_FILE_NAME, DEFAULT_VERSION); + testOdToHrTransparencyInfo(WITH_APP_INFO_FILE_NAME, DEFAULT_VERSION); } - /** Test for transparency info with developer info. */ + /** Test for testMissingAppInfoFailsInV2. */ @Test - public void testTransparencyInfoWithDeveloperInfo() throws Exception { - System.out.println("starting testTransparencyInfoWithDeveloperInfo."); - testHrToOdTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME); - testOdToHrTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME); + public void testMissingAppInfoFailsInV2() throws Exception { + System.out.println("starting testMissingAppInfoFailsInV2."); + odToHrExpectException(VALID_EMPTY_V1_FILE_NAME, 2L); } - /** Test for transparency info with app info. */ + /** Test for testMissingAppInfoPassesInV1. */ @Test - public void testTransparencyInfoWithAppInfo() throws Exception { - System.out.println("starting testTransparencyInfoWithAppInfo."); - testHrToOdTransparencyInfo(WITH_APP_INFO_FILE_NAME); - testOdToHrTransparencyInfo(WITH_APP_INFO_FILE_NAME); + public void testMissingAppInfoPassesInV1() throws Exception { + System.out.println("starting testMissingAppInfoPassesInV1."); + testParseOdTransparencyInfo(VALID_EMPTY_V1_FILE_NAME, 1L); + } + + /** Test for testDeveloperInfoExistencePassesInV1. */ + @Test + public void testDeveloperInfoExistencePassesInV1() throws Exception { + System.out.println("starting testDeveloperInfoExistencePassesInV1."); + testParseOdTransparencyInfo(VALID_DEV_INFO_V1_FILE_NAME, 1L); + } + + /** Test for testDeveloperInfoExistenceFailsInV2. */ + @Test + public void testDeveloperInfoExistenceFailsInV2() throws Exception { + System.out.println("starting testDeveloperInfoExistenceFailsInV2."); + odToHrExpectException(WITH_APP_INFO_AND_DEV_INFO_FILE_NAME, 2L); + } + + private void testHrToOdTransparencyInfo(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + TransparencyInfo transparencyInfo = + new TransparencyInfoFactory() + .createFromHrElement( + TestUtils.getElementFromResource( + Paths.get(TRANSPARENCY_INFO_HR_PATH, fileName)), + version); + Element resultingEle = transparencyInfo.toOdDomElement(doc); + doc.appendChild(resultingEle); + TestUtils.testFormatToFormat(doc, Paths.get(TRANSPARENCY_INFO_OD_PATH, fileName)); + } + + private void testParseOdTransparencyInfo(String fileName, long version) throws Exception { + var unused = + new TransparencyInfoFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(TRANSPARENCY_INFO_OD_PATH, fileName)), + version); } - private void testHrToOdTransparencyInfo(String fileName) throws Exception { - TestUtils.testHrToOd( - TestUtils.document(), - new TransparencyInfoFactory(), - TRANSPARENCY_INFO_HR_PATH, - TRANSPARENCY_INFO_OD_PATH, - fileName); + private void testOdToHrTransparencyInfo(String fileName, long version) throws Exception { + var doc = TestUtils.document(); + TransparencyInfo transparencyInfo = + new TransparencyInfoFactory() + .createFromOdElement( + TestUtils.getElementFromResource( + Paths.get(TRANSPARENCY_INFO_OD_PATH, fileName)), + version); + Element resultingEle = transparencyInfo.toHrDomElement(doc); + doc.appendChild(resultingEle); + TestUtils.testFormatToFormat(doc, Paths.get(TRANSPARENCY_INFO_HR_PATH, fileName)); } - private void testOdToHrTransparencyInfo(String fileName) throws Exception { - TestUtils.testOdToHr( - TestUtils.document(), - new TransparencyInfoFactory(), - TRANSPARENCY_INFO_OD_PATH, - TRANSPARENCY_INFO_HR_PATH, - fileName); + private void odToHrExpectException(String fileName, long version) + throws ParserConfigurationException, IOException, SAXException { + var ele = TestUtils.getElementFromResource(Paths.get(TRANSPARENCY_INFO_OD_PATH, fileName)); + assertThrows( + MalformedXmlException.class, + () -> new TransparencyInfoFactory().createFromOdElement(ele, version)); } } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java index ea90993e0785..f8ef40a9c509 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java @@ -17,11 +17,8 @@ package com.android.asllib.testutils; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; import com.android.asllib.marshallable.AslMarshallable; -import com.android.asllib.marshallable.AslMarshallableFactory; -import com.android.asllib.util.MalformedXmlException; import com.android.asllib.util.XmlUtils; import org.w3c.dom.Document; @@ -36,7 +33,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.Optional; @@ -60,7 +56,19 @@ public class TestUtils { } /** Gets List of Element from a path to an existing Resource. */ - public static List<Element> getElementsFromResource(Path filePath) + public static Element getElementFromResource(Path filePath) + throws ParserConfigurationException, IOException, SAXException { + String str = readStrFromResource(filePath); + InputStream stream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + Document document = factory.newDocumentBuilder().parse(stream); + return document.getDocumentElement(); + } + + /** Gets List of Element from a path to an existing Resource. */ + public static List<Element> getChildElementsFromResource(Path filePath) throws ParserConfigurationException, IOException, SAXException { String str = readStrFromResource(filePath); InputStream stream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)); @@ -69,16 +77,13 @@ public class TestUtils { factory.setNamespaceAware(true); Document document = factory.newDocumentBuilder().parse(stream); Element root = document.getDocumentElement(); - if (root.getTagName().equals(HOLDER_TAG_NAME)) { - String tagName = - XmlUtils.asElementList(root.getChildNodes()).stream() - .findFirst() - .get() - .getTagName(); - return XmlUtils.getChildrenByTagName(root, tagName); - } else { - return List.of(root); - } + + String tagName = + XmlUtils.asElementList(root.getChildNodes()).stream() + .findFirst() + .get() + .getTagName(); + return XmlUtils.getChildrenByTagName(root, tagName); } /** Reads a Document into a String. */ @@ -130,86 +135,13 @@ public class TestUtils { return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); } - /** Helper for testing human-readable to on-device conversion expecting exception */ - public static <T extends AslMarshallable> void hrToOdExpectException( - AslMarshallableFactory<T> factory, String hrFolderPath, String fileName) { - assertThrows( - MalformedXmlException.class, - () -> { - factory.createFromHrElements( - TestUtils.getElementsFromResource(Paths.get(hrFolderPath, fileName))); - }); - } - - /** Helper for testing on-device to human-readable conversion expecting exception */ - public static <T extends AslMarshallable> void odToHrExpectException( - AslMarshallableFactory<T> factory, String odFolderPath, String fileName) { - assertThrows( - MalformedXmlException.class, - () -> { - factory.createFromOdElements( - TestUtils.getElementsFromResource(Paths.get(odFolderPath, fileName))); - }); - } - - /** Helper for testing human-readable to on-device conversion */ - public static <T extends AslMarshallable> void testHrToOd( - Document doc, - AslMarshallableFactory<T> factory, - String hrFolderPath, - String odFolderPath, - String fileName) - throws Exception { - testFormatToFormat(doc, factory, hrFolderPath, odFolderPath, fileName, true); - } - - /** Helper for testing on-device to human-readable conversion */ - public static <T extends AslMarshallable> void testOdToHr( - Document doc, - AslMarshallableFactory<T> factory, - String odFolderPath, - String hrFolderPath, - String fileName) - throws Exception { - testFormatToFormat(doc, factory, odFolderPath, hrFolderPath, fileName, false); - } - /** Helper for testing format to format conversion */ - private static <T extends AslMarshallable> void testFormatToFormat( - Document doc, - AslMarshallableFactory<T> factory, - String inFolderPath, - String outFolderPath, - String fileName, - boolean hrToOd) - throws Exception { - AslMarshallable marshallable = - hrToOd - ? factory.createFromHrElements( - TestUtils.getElementsFromResource( - Paths.get(inFolderPath, fileName))) - : factory.createFromOdElements( - TestUtils.getElementsFromResource( - Paths.get(inFolderPath, fileName))); - - List<Element> elements = - hrToOd ? marshallable.toOdDomElements(doc) : marshallable.toHrDomElements(doc); - if (elements.isEmpty()) { - throw new IllegalStateException("elements was empty."); - } else if (elements.size() == 1) { - doc.appendChild(elements.get(0)); - } else { - Element root = doc.createElement(TestUtils.HOLDER_TAG_NAME); - for (var child : elements) { - root.appendChild(child); - } - doc.appendChild(root); - } + public static <T extends AslMarshallable> void testFormatToFormat( + Document doc, Path expectedOutPath) throws Exception { String converted = TestUtils.getFormattedXml(TestUtils.docToStr(doc, true), true); System.out.println("Converted: " + converted); String expectedOutContents = - TestUtils.getFormattedXml( - TestUtils.readStrFromResource(Paths.get(outFolderPath, fileName)), true); + TestUtils.getFormattedXml(TestUtils.readStrFromResource(expectedOutPath), true); System.out.println("Expected: " + expectedOutContents); assertEquals(expectedOutContents, converted); } diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml index ec0cd702fd43..7478e39ce366 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/missing-version.xml @@ -1,3 +1,17 @@ <app-metadata-bundles> - + <system-app-safety-label declaration="true"> + </system-app-safety-label> + <transparency-info> + <app-info + apsCompliant="false" + privacyPolicy="www.example.com" developerId="dev1" applicationId="app1"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> + </app-info> + </transparency-info> </app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml index 19bfd826f770..587c49add47e 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/valid-empty.xml @@ -1 +1,17 @@ -<app-metadata-bundles version="123456"></app-metadata-bundles>
\ No newline at end of file +<app-metadata-bundles version="2"> + <system-app-safety-label declaration="true"> + </system-app-safety-label> + <transparency-info> + <app-info + apsCompliant="false" + privacyPolicy="www.example.com" developerId="dev1" applicationId="app1"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> + </app-info> + </transparency-info> +</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml index 53794a1d1c80..9cfb8bc4d5da 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-safety-labels.xml @@ -1,4 +1,19 @@ -<app-metadata-bundles version="123456"> - <safety-labels version="12345"> +<app-metadata-bundles version="2"> + <safety-labels> </safety-labels> + <system-app-safety-label declaration="true"> + </system-app-safety-label> + <transparency-info> + <app-info + apsCompliant="false" + privacyPolicy="www.example.com" developerId="dev1" applicationId="app1"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> + </app-info> + </transparency-info> </app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml deleted file mode 100644 index afb048632bc6..000000000000 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-system-app-safety-label.xml +++ /dev/null @@ -1,4 +0,0 @@ -<app-metadata-bundles version="123456"> -<system-app-safety-label declaration="true"> -</system-app-safety-label> -</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml deleted file mode 100644 index 00bcfa80e9b1..000000000000 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/hr/with-transparency-info.xml +++ /dev/null @@ -1,4 +0,0 @@ -<app-metadata-bundles version="123456"> -<transparency-info> -</transparency-info> -</app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml index 1aa3aa94ca6d..9adfa98f05a3 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml @@ -1,2 +1,20 @@ <bundle> + <pbundle_as_map name="system_app_safety_label"> + <boolean name="declaration" value="true"/> + </pbundle_as_map> + <pbundle_as_map name="transparency_info"> + <pbundle_as_map name="app_info"> + <boolean name="aps_compliant" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> + </pbundle_as_map> + </pbundle_as_map> </bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml index 37bdfad4065f..7a4c82a9e65f 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-empty.xml @@ -1,3 +1,21 @@ <bundle> - <long name="version" value="123456"/> + <long name="version" value="2"/> + <pbundle_as_map name="system_app_safety_label"> + <boolean name="declaration" value="true"/> + </pbundle_as_map> + <pbundle_as_map name="transparency_info"> + <pbundle_as_map name="app_info"> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <boolean name="aps_compliant" value="false"/> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> + </pbundle_as_map> + </pbundle_as_map> </bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-v1.xml new file mode 100644 index 000000000000..7e984e333ceb --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/valid-v1.xml @@ -0,0 +1,8 @@ +<bundle> + <long name="version" value="1"/> + <pbundle_as_map name="system_app_safety_label"> + <string name="url" value="www.example.com"/> + </pbundle_as_map> + <pbundle_as_map name="transparency_info"> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml index 74644ed0413c..3a3e5d383ca9 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-safety-labels.xml @@ -1,6 +1,22 @@ <bundle> - <long name="version" value="123456"/> - <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> + <long name="version" value="2"/> + <pbundle_as_map name="safety_labels"/> + <pbundle_as_map name="system_app_safety_label"> + <boolean name="declaration" value="true"/> </pbundle_as_map> -</bundle> + <pbundle_as_map name="transparency_info"> + <pbundle_as_map name="app_info"> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <boolean name="aps_compliant" value="false"/> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> + </pbundle_as_map> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml deleted file mode 100644 index e8640c4f0934..000000000000 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-system-app-safety-label.xml +++ /dev/null @@ -1,6 +0,0 @@ -<bundle> - <long name="version" value="123456"/> - <pbundle_as_map name="system_app_safety_label"> - <boolean name="declaration" value="true"/> - </pbundle_as_map> -</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml deleted file mode 100644 index 63c5094333cc..000000000000 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/with-transparency-info.xml +++ /dev/null @@ -1,4 +0,0 @@ -<bundle> - <long name="version" value="123456"/> - <pbundle_as_map name="transparency_info"/> -</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml index 883170a2d36f..306e01533731 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/hr/all-fields-valid.xml @@ -1,14 +1,11 @@ <app-info - title="beervision" - description="a beer app" - containsAds="true" - obeyAps="false" - adsFingerprinting="false" - securityFingerprinting="false" - privacyPolicy="www.example.com" - securityEndpoints="url1|url2|url3" - firstPartyEndpoints="url1" - serviceProviderEndpoints="url55|url56" - category="Food and drink" - email="max@maxloh.com" - website="www.example.com" />
\ No newline at end of file + apsCompliant="false" + privacyPolicy="www.example.com" developerId="dev1" applicationId="app1"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> +</app-info>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml new file mode 100644 index 000000000000..b026cf33e5f0 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid-v1.xml @@ -0,0 +1,24 @@ +<pbundle_as_map name="app_info"> + <string name="title" value="beervision"/> + <string name="description" value="a beer app"/> + <boolean name="contains_ads" value="true"/> + <boolean name="obey_aps" value="false"/> + <boolean name="ads_fingerprinting" value="false"/> + <boolean name="security_fingerprinting" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="security_endpoints" num="3"> + <item value="url1"/> + <item value="url2"/> + <item value="url3"/> + </string-array> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="category" value="Food and drink"/> + <string name="email" value="max@maxloh.com"/> + <string name="website" value="www.example.com"/> +</pbundle_as_map> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml index 6e976a3278de..7aae4a715b79 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/all-fields-valid.xml @@ -1,25 +1,14 @@ <pbundle_as_map name="app_info"> - <string name="title" value="beervision"/> - <string name="description" value="a beer app"/> - <boolean name="contains_ads" value="true"/> - <boolean name="obey_aps" value="false"/> - <boolean name="ads_fingerprinting" value="false"/> - <boolean name="security_fingerprinting" value="false"/> <string name="privacy_policy" value="www.example.com"/> - <string-array name="security_endpoint" num="3"> + <string-array name="first_party_endpoints" num="1"> <item value="url1"/> - <item value="url2"/> - <item value="url3"/> </string-array> - <string-array name="first_party_endpoint" num="1"> - <item value="url1"/> - </string-array> - <string-array name="service_provider_endpoint" num="2"> + <string-array name="service_provider_endpoints" num="2"> <item value="url55"/> <item value="url56"/> </string-array> - <string name="category" value="Food and drink"/> - <string name="email" value="max@maxloh.com"/> - <string name="website" value="www.example.com"/> + <boolean name="aps_compliant" value="false"/> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> </pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml new file mode 100644 index 000000000000..01fd7180c3a6 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/appinfo/od/unrecognized-v1.xml @@ -0,0 +1,25 @@ +<pbundle_as_map name="app_info"> + <string name="title" value="beervision"/> + <string name="description" value="a beer app"/> + <boolean name="contains_ads" value="true"/> + <boolean name="obey_aps" value="false"/> + <boolean name="ads_fingerprinting" value="false"/> + <boolean name="security_fingerprinting" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="security_endpoints" num="3"> + <item value="url1"/> + <item value="url2"/> + <item value="url3"/> + </string-array> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="category" value="Food and drink"/> + <string name="email" value="max@maxloh.com"/> + <string name="website" value="www.example.com"/> + <boolean name="aps_compliant" value="false"/> +</pbundle_as_map> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml deleted file mode 100644 index 762f3bdf7875..000000000000 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/missing-version.xml +++ /dev/null @@ -1,2 +0,0 @@ -<safety-labels> -</safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml index 7decfd4865b1..92d10ca0349b 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/valid-empty.xml @@ -1 +1 @@ -<safety-labels version="12345"></safety-labels>
\ No newline at end of file +<safety-labels></safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml index 84456daedbd5..ca3d9f066129 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-data-labels.xml @@ -1,4 +1,4 @@ -<safety-labels version="12345"> +<safety-labels> <data-labels> <data-shared dataType="location_data_type_approx_location" isSharingOptional="false" diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml index 940e48a68ce8..c96278554865 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-security-labels.xml @@ -1,4 +1,4 @@ -<safety-labels version="12345"> +<safety-labels> <security-labels isDataDeletable="true" isDataEncrypted="false" diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml index bfbc5ae70974..08052904e8e5 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/hr/with-third-party-verification.xml @@ -1,4 +1,4 @@ -<safety-labels version="12345"> +<safety-labels> <third-party-verification url="www.example.com"> </third-party-verification> </safety-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml deleted file mode 100644 index 3fbe3599cd82..000000000000 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml +++ /dev/null @@ -1,2 +0,0 @@ -<pbundle_as_map name="safety_labels"> -</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml index 4f03d88a3bd2..3fbe3599cd82 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-empty.xml @@ -1,3 +1,2 @@ <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> </pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-v1.xml new file mode 100644 index 000000000000..1384a2f6dd52 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/valid-v1.xml @@ -0,0 +1,9 @@ +<pbundle_as_map name="safety_labels"> + <pbundle_as_map name="security_labels"> + <boolean name="is_data_deletable" value="true" /> + <boolean name="is_data_encrypted" value="false" /> + </pbundle_as_map> + <pbundle_as_map name="third_party_verification"> + <string name="url" value="www.example.com"/> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml index fa2a3f841e09..db92e0291ee8 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-data-labels.xml @@ -1,5 +1,4 @@ <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> <pbundle_as_map name="data_labels"> <pbundle_as_map name="data_shared"> <pbundle_as_map name="location"> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml index b39c562b30d0..924618087b4f 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-security-labels.xml @@ -1,5 +1,4 @@ <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> <pbundle_as_map name="security_labels"> <boolean name="is_data_deletable" value="true" /> <boolean name="is_data_encrypted" value="false" /> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml index 10653ff5027b..fd435c550a54 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/with-third-party-verification.xml @@ -1,5 +1,4 @@ <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> <pbundle_as_map name="third_party_verification"> <string name="url" value="www.example.com"/> </pbundle_as_map> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/valid-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/valid-v1.xml new file mode 100644 index 000000000000..f96535b4b49b --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/valid-v1.xml @@ -0,0 +1,3 @@ +<pbundle_as_map name="system_app_safety_label"> + <string name="url" value="www.example.com"/> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml index a7c48fc68cf1..2c5cf866547a 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-app-info.xml @@ -1,4 +1,14 @@ <transparency-info> - <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" /> + <app-info + apsCompliant="false" + privacyPolicy="www.example.com" developerId="dev1" applicationId="app1"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> + </app-info> </transparency-info>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml index d16caaea320f..29c88d23abad 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml @@ -1,5 +1,16 @@ <transparency-info> + <app-info + apsCompliant="false" + privacyPolicy="www.example.com" developerId="dev1" applicationId="app1"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> + </app-info> <developer-info name="max" email="max@example.com" diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-dev-info-v1.xml index d7a4e1a959b7..d7a4e1a959b7 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-dev-info-v1.xml diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty-v1.xml index af574cf92b3a..af574cf92b3a 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/valid-empty-v1.xml diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info-v2-and-dev-info-v1.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info-v2-and-dev-info-v1.xml new file mode 100644 index 000000000000..b5e64b925ca5 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info-v2-and-dev-info-v1.xml @@ -0,0 +1,25 @@ + +<pbundle_as_map name="transparency_info"> + <pbundle_as_map name="app_info"> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <boolean name="aps_compliant" value="false"/> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> + </pbundle_as_map> + <pbundle_as_map name="developer_info"> + <string name="name" value="max"/> + <string name="email" value="max@example.com"/> + <string name="address" value="111 blah lane"/> + <string name="country_region" value="US"/> + <long name="relationship" value="5"/> + <string name="website" value="example.com"/> + <string name="app_developer_registry_id" value="registry_id"/> + </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml index b813641f74f8..c46cec1da336 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-app-info.xml @@ -1,26 +1,16 @@ <pbundle_as_map name="transparency_info"> <pbundle_as_map name="app_info"> - <string name="title" value="beervision"/> - <string name="description" value="a beer app"/> - <boolean name="contains_ads" value="true"/> - <boolean name="obey_aps" value="false"/> - <boolean name="ads_fingerprinting" value="false"/> - <boolean name="security_fingerprinting" value="false"/> <string name="privacy_policy" value="www.example.com"/> - <string-array name="security_endpoint" num="3"> + <string-array name="first_party_endpoints" num="1"> <item value="url1"/> - <item value="url2"/> - <item value="url3"/> </string-array> - <string-array name="first_party_endpoint" num="1"> - <item value="url1"/> - </string-array> - <string-array name="service_provider_endpoint" num="2"> + <string-array name="service_provider_endpoints" num="2"> <item value="url55"/> <item value="url56"/> </string-array> - <string name="category" value="Food and drink"/> - <string name="email" value="max@maxloh.com"/> + <boolean name="aps_compliant" value="false"/> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> </pbundle_as_map> </pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml index b2ff4495a6d2..cadf213c3e2e 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/hr.xml @@ -1,5 +1,5 @@ <app-metadata-bundles version="123"> - <safety-labels version="12345"> + <safety-labels> <data-labels> <data-shared dataCategory="contacts" dataType="contacts" diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml index 81277bf456a4..7aafd2346846 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/contacts/od.xml @@ -1,7 +1,6 @@ <bundle> <long name="version" value="123"/> <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> <pbundle_as_map name="data_labels"> <pbundle_as_map name="data_shared"> <pbundle_as_map name="contacts"> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml new file mode 100644 index 000000000000..e8b0c17ecada --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general-v1/od.xml @@ -0,0 +1,70 @@ +<bundle> + <long name="version" value="1"/> + <pbundle_as_map name="safety_labels"> + <pbundle_as_map name="data_labels"> + <pbundle_as_map name="data_shared"> + <pbundle_as_map name="location"> + <pbundle_as_map name="approx_location"> + <int-array name="purposes" num="1"> + <item value="1"/> + </int-array> + <boolean name="is_sharing_optional" value="false"/> + <boolean name="ephemeral" value="false"/> + </pbundle_as_map> + <pbundle_as_map name="precise_location"> + <int-array name="purposes" num="2"> + <item value="1"/> + <item value="2"/> + </int-array> + <boolean name="is_sharing_optional" value="true"/> + <boolean name="ephemeral" value="true"/> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="security_labels"> + <boolean name="is_data_deletable" value="true"/> + <boolean name="is_data_encrypted" value="false"/> + </pbundle_as_map> + <pbundle_as_map name="third_party_verification"> + <string name="url" value="www.example.com"/> + </pbundle_as_map> + </pbundle_as_map> + <pbundle_as_map name="system_app_safety_label"> + <string name="url" value="www.example.com"/> + </pbundle_as_map> + <pbundle_as_map name="transparency_info"> + <pbundle_as_map name="developer_info"> + <string name="name" value="max"/> + <string name="email" value="max@example.com"/> + <string name="address" value="111 blah lane"/> + <string name="country_region" value="US"/> + <long name="relationship" value="5"/> + <string name="website" value="example.com"/> + <string name="app_developer_registry_id" value="registry_id"/> + </pbundle_as_map> + <pbundle_as_map name="app_info"> + <string name="title" value="beervision"/> + <string name="description" value="a beer app"/> + <boolean name="contains_ads" value="true"/> + <boolean name="obey_aps" value="false"/> + <boolean name="ads_fingerprinting" value="false"/> + <boolean name="security_fingerprinting" value="false"/> + <string name="privacy_policy" value="www.example.com"/> + <string-array name="security_endpoints" num="3"> + <item value="url1"/> + <item value="url2"/> + <item value="url3"/> + </string-array> + <string-array name="first_party_endpoints" num="1"> + <item value="url1"/> + </string-array> + <string-array name="service_provider_endpoints" num="2"> + <item value="url55"/> + <item value="url56"/> + </string-array> + <string name="category" value="Food and drink"/> + <string name="email" value="max@maxloh.com"/> + </pbundle_as_map> + </pbundle_as_map> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml index 41b32b5ed7b0..f93298286944 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml @@ -1,33 +1,20 @@ -<app-metadata-bundles version="123"> - <safety-labels version="12345"> +<app-metadata-bundles version="2"> + <safety-labels> <data-labels> - <data-shared - dataType="location_data_type_approx_location" - isSharingOptional="false" - purposes="app_functionality" /> - <data-shared - dataType="location_data_type_precise_location" - isSharingOptional="true" - purposes="app_functionality|analytics" /> + <data-shared dataType="location_data_type_approx_location" isSharingOptional="false" purposes="app_functionality"/> + <data-shared dataType="location_data_type_precise_location" isSharingOptional="true" purposes="app_functionality|analytics"/> </data-labels> - <security-labels - isDataDeletable="true" - isDataEncrypted="false" - /> - <third-party-verification url="www.example.com"> - </third-party-verification> </safety-labels> - <system-app-safety-label declaration="true"> - </system-app-safety-label> + <system-app-safety-label declaration="true"/> <transparency-info> - <developer-info - name="max" - email="max@example.com" - address="111 blah lane" - countryRegion="US" - relationship="aosp" - website="example.com" - registryId="registry_id" /> - <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" /> + <app-info applicationId="app1" apsCompliant="false" developerId="dev1" privacyPolicy="www.example.com"> + <first-party-endpoints> + <item>url1</item> + </first-party-endpoints> + <service-provider-endpoints> + <item>url55</item> + <item>url56</item> + </service-provider-endpoints> + </app-info> </transparency-info> </app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml index c11ac4359ecd..c7def7227a34 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml @@ -1,7 +1,6 @@ <bundle> - <long name="version" value="123"/> + <long name="version" value="2"/> <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> <pbundle_as_map name="data_labels"> <pbundle_as_map name="data_shared"> <pbundle_as_map name="location"> @@ -21,49 +20,23 @@ </pbundle_as_map> </pbundle_as_map> </pbundle_as_map> - <pbundle_as_map name="security_labels"> - <boolean name="is_data_deletable" value="true"/> - <boolean name="is_data_encrypted" value="false"/> - </pbundle_as_map> - <pbundle_as_map name="third_party_verification"> - <string name="url" value="www.example.com"/> - </pbundle_as_map> </pbundle_as_map> <pbundle_as_map name="system_app_safety_label"> <boolean name="declaration" value="true"/> </pbundle_as_map> <pbundle_as_map name="transparency_info"> - <pbundle_as_map name="developer_info"> - <string name="name" value="max"/> - <string name="email" value="max@example.com"/> - <string name="address" value="111 blah lane"/> - <string name="country_region" value="US"/> - <long name="relationship" value="5"/> - <string name="website" value="example.com"/> - <string name="app_developer_registry_id" value="registry_id"/> - </pbundle_as_map> <pbundle_as_map name="app_info"> - <string name="title" value="beervision"/> - <string name="description" value="a beer app"/> - <boolean name="contains_ads" value="true"/> - <boolean name="obey_aps" value="false"/> - <boolean name="ads_fingerprinting" value="false"/> - <boolean name="security_fingerprinting" value="false"/> <string name="privacy_policy" value="www.example.com"/> - <string-array name="security_endpoint" num="3"> - <item value="url1"/> - <item value="url2"/> - <item value="url3"/> - </string-array> - <string-array name="first_party_endpoint" num="1"> + <string-array name="first_party_endpoints" num="1"> <item value="url1"/> </string-array> - <string-array name="service_provider_endpoint" num="2"> + <string-array name="service_provider_endpoints" num="2"> <item value="url55"/> <item value="url56"/> </string-array> - <string name="category" value="Food and drink"/> - <string name="email" value="max@maxloh.com"/> + <boolean name="aps_compliant" value="false"/> + <string name="developer_id" value="dev1"/> + <string name="application_id" value="app1"/> </pbundle_as_map> </pbundle_as_map> </bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml index ac844b3b2767..a4242d06fb15 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/hr.xml @@ -1,5 +1,5 @@ <app-metadata-bundles version="123"> - <safety-labels version="12345"> + <safety-labels> <data-labels> <data-shared dataCategory="location" dataType="precise_location" diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml index d0a3bfa7e64f..79afaf7d70d5 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/location/od.xml @@ -1,7 +1,6 @@ <bundle> <long name="version" value="123"/> <pbundle_as_map name="safety_labels"> - <long name="version" value="12345"/> <pbundle_as_map name="data_labels"> <pbundle_as_map name="data_shared"> <pbundle_as_map name="location"> diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt index 1087ae6ee41d..c3595b7ac288 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt @@ -120,6 +120,8 @@ class ProtoLogCallProcessorImpl( logCallVisitor?.processCall(call, messageString, getLevelForMethodName( call.name.toString(), call, context), groupMap.getValue(groupName)) + } else if (call.name.id == "init") { + // No processing } else { // Process non-log message calls otherCallVisitor?.processCall(call) diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index fd7d2b35bb6f..22858803b597 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -17,7 +17,6 @@ package com.android.protolog.tool import com.android.internal.protolog.common.LogLevel -import com.android.internal.protolog.common.ProtoLog import com.android.internal.protolog.common.ProtoLogToolInjected import com.android.protolog.tool.CommandOptions.Companion.USAGE import com.github.javaparser.ParseProblemException @@ -63,6 +62,8 @@ object ProtoLogTool { const val PROTOLOG_IMPL_SRC_PATH = "frameworks/base/core/java/com/android/internal/protolog/ProtoLogImpl.java" + private const val PROTOLOG_CLASS_NAME = "ProtoLog"; // ProtoLog::class.java.simpleName + data class LogCall( val messageString: String, val logLevel: LogLevel, @@ -126,7 +127,7 @@ object ProtoLogTool { val text = injector.readText(file) val outSrc = try { val code = tryParse(text, path) - if (containsProtoLogText(text, ProtoLog::class.java.simpleName)) { + if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) { transformer.processClass(text, path, packagePath(file, code), code) } else { text @@ -461,10 +462,10 @@ object ProtoLogTool { val command = CommandOptions(args) invoke(command) } catch (ex: InvalidCommandException) { - println("\n${ex.message}\n") + println("InvalidCommandException: \n${ex.message}\n") showHelpAndExit() } catch (ex: CodeProcessingException) { - println("\n${ex.message}\n") + println("CodeProcessingException: \n${ex.message}\n") exitProcess(1) } } diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index 6a8a0717b2f1..c478f5844de6 100644 --- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -130,28 +130,27 @@ class SourceTransformer( val hash = CodeUtils.hash(packagePath, messageString, level, group) val newCall = call.clone() - if (!group.textEnabled) { - // Remove message string if text logging is not enabled by default. - // Out: ProtoLog.e(GROUP, null, arg) - newCall.arguments[1].replace(NameExpr("null")) - } + // Remove message string. + // Out: ProtoLog.e(GROUP, args) + newCall.arguments.removeAt(1) // Insert message string hash as a second argument. - // Out: ProtoLog.e(GROUP, 1234, null, arg) + // Out: ProtoLog.e(GROUP, 1234, args) newCall.arguments.add(1, LongLiteralExpr("" + hash + "L")) val argTypes = LogDataType.parseFormatString(messageString) val typeMask = LogDataType.logDataTypesToBitMask(argTypes) // Insert bitmap representing which Number parameters are to be considered as // floating point numbers. - // Out: ProtoLog.e(GROUP, 1234, 0, null, arg) + // Out: ProtoLog.e(GROUP, 1234, 0, args) newCall.arguments.add(2, IntegerLiteralExpr(typeMask)) // Replace call to a stub method with an actual implementation. - // Out: ProtoLogImpl.e(GROUP, 1234, null, arg) + // Out: ProtoLogImpl.e(GROUP, 1234, 0, args) newCall.setScope(protoLogImplClassNode) if (argTypes.size != call.arguments.size - 2) { throw InvalidProtoLogCallException( "Number of arguments (${argTypes.size} does not match format" + " string in: $call", ParsingContext(path, call)) } + val argsOffset = 3 val blockStmt = BlockStmt() if (argTypes.isNotEmpty()) { // Assign every argument to a variable to check its type in compile time @@ -160,9 +159,9 @@ class SourceTransformer( argTypes.forEachIndexed { idx, type -> val varName = "protoLogParam$idx" val declaration = VariableDeclarator(getASTTypeForDataType(type), varName, - getConversionForType(type)(newCall.arguments[idx + 4].clone())) + getConversionForType(type)(newCall.arguments[idx + argsOffset].clone())) blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration))) - newCall.setArgument(idx + 4, NameExpr(SimpleName(varName))) + newCall.setArgument(idx + argsOffset, NameExpr(SimpleName(varName))) } } else { // Assign (Object[])null as the vararg parameter to prevent allocating an empty diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt index cf0876a1f072..245e802df49b 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt @@ -53,8 +53,9 @@ class ViewerConfigProtoBuilder : ProtoLogTool.ProtologViewerConfigBuilder { .setMessageId(key) .setMessage(log.messageString) .setLevel( - ProtoLogLevel.forNumber(log.logLevel.ordinal + 1)) + ProtoLogLevel.forNumber(log.logLevel.id)) .setGroupId(groupId) + .setLocation(log.position) ) } diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt index 822118cc5343..0cbbd483fe59 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt @@ -35,7 +35,7 @@ class EndToEndTest { val output = run( srcs = mapOf("frameworks/base/org/example/Example.java" to """ package org.example; - import com.android.internal.protolog.common.ProtoLog; + import com.android.internal.protolog.ProtoLog; import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { @@ -48,7 +48,7 @@ class EndToEndTest { """.trimIndent()), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", - "--protolog-class", "com.android.internal.protolog.common.ProtoLog", + "--protolog-class", "com.android.internal.protolog.ProtoLog", "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-config-file-path", "not_required.pb", @@ -60,7 +60,7 @@ class EndToEndTest { .containsMatch(Pattern.compile("\\{ String protoLogParam0 = " + "String\\.valueOf\\(argString\\); long protoLogParam1 = argInt; " + "com\\.android\\.internal\\.protolog.ProtoLogImpl_.*\\.d\\(" + - "GROUP, -6872339441335321086L, 4, null, protoLogParam0, protoLogParam1" + + "GROUP, -6872339441335321086L, 4, protoLogParam0, protoLogParam1" + "\\); \\}")) } @@ -69,7 +69,7 @@ class EndToEndTest { val output = run( srcs = mapOf("frameworks/base/org/example/Example.java" to """ package org.example; - import com.android.internal.protolog.common.ProtoLog; + import com.android.internal.protolog.ProtoLog; import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { @@ -82,7 +82,7 @@ class EndToEndTest { """.trimIndent()), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("generate-viewer-config", - "--protolog-class", "com.android.internal.protolog.common.ProtoLog", + "--protolog-class", "com.android.internal.protolog.ProtoLog", "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-config-type", "json", diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt index 82aa93da613b..6cde7a72db53 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt @@ -76,7 +76,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -86,7 +86,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, protoLogParam0, protoLogParam1, protoLogParam2); } } @@ -98,8 +98,8 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -109,7 +109,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, "test", (Object[]) null); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, (Object[]) null); } } } """.trimIndent() @@ -119,7 +119,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, null, protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -129,7 +129,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.Cache.TEST_GROUP_enabled[3]) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, protoLogParam0, protoLogParam1, protoLogParam2); } } @@ -172,13 +172,12 @@ class SourceTransformerTest { Truth.assertThat(protoLogCalls).hasSize(1) val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) - assertEquals(6, methodCall.arguments.size) + assertEquals(5, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) assertEquals("-1473209266730422156L", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) - assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) - assertEquals("protoLogParam0", methodCall.arguments[4].toString()) - assertEquals("protoLogParam1", methodCall.arguments[5].toString()) + assertEquals("protoLogParam0", methodCall.arguments[3].toString()) + assertEquals("protoLogParam1", methodCall.arguments[4].toString()) assertEquals(TRANSFORMED_CODE_TEXT_ENABLED, out) } @@ -214,13 +213,12 @@ class SourceTransformerTest { Truth.assertThat(protoLogCalls).hasSize(3) val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) - assertEquals(6, methodCall.arguments.size) + assertEquals(5, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) assertEquals("-1473209266730422156L", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) - assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) - assertEquals("protoLogParam0", methodCall.arguments[4].toString()) - assertEquals("protoLogParam1", methodCall.arguments[5].toString()) + assertEquals("protoLogParam0", methodCall.arguments[3].toString()) + assertEquals("protoLogParam1", methodCall.arguments[4].toString()) assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT, out) } @@ -252,13 +250,13 @@ class SourceTransformerTest { Truth.assertThat(protoLogCalls).hasSize(1) val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) - assertEquals(7, methodCall.arguments.size) + assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) assertEquals("-4447034859795564700L", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) - assertEquals("protoLogParam0", methodCall.arguments[4].toString()) - assertEquals("protoLogParam1", methodCall.arguments[5].toString()) - assertEquals("protoLogParam2", methodCall.arguments[6].toString()) + assertEquals("protoLogParam0", methodCall.arguments[3].toString()) + assertEquals("protoLogParam1", methodCall.arguments[4].toString()) + assertEquals("protoLogParam2", methodCall.arguments[5].toString()) assertEquals(TRANSFORMED_CODE_MULTILINE_TEXT_ENABLED, out) } @@ -289,7 +287,7 @@ class SourceTransformerTest { Truth.assertThat(protoLogCalls).hasSize(1) val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) - assertEquals(5, methodCall.arguments.size) + assertEquals(4, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) assertEquals("3218600869538902408L", methodCall.arguments[1].toString()) assertEquals(0.toString(), methodCall.arguments[2].toString()) @@ -323,13 +321,12 @@ class SourceTransformerTest { Truth.assertThat(protoLogCalls).hasSize(1) val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) - assertEquals(6, methodCall.arguments.size) + assertEquals(5, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) assertEquals("-1473209266730422156L", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) - assertEquals("null", methodCall.arguments[3].toString()) - assertEquals("protoLogParam0", methodCall.arguments[4].toString()) - assertEquals("protoLogParam1", methodCall.arguments[5].toString()) + assertEquals("protoLogParam0", methodCall.arguments[3].toString()) + assertEquals("protoLogParam1", methodCall.arguments[4].toString()) assertEquals(TRANSFORMED_CODE_TEXT_DISABLED, out) } @@ -361,14 +358,13 @@ class SourceTransformerTest { Truth.assertThat(protoLogCalls).hasSize(1) val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) - assertEquals(7, methodCall.arguments.size) + assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) assertEquals("-4447034859795564700L", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) - assertEquals("null", methodCall.arguments[3].toString()) - assertEquals("protoLogParam0", methodCall.arguments[4].toString()) - assertEquals("protoLogParam1", methodCall.arguments[5].toString()) - assertEquals("protoLogParam2", methodCall.arguments[6].toString()) + assertEquals("protoLogParam0", methodCall.arguments[3].toString()) + assertEquals("protoLogParam1", methodCall.arguments[4].toString()) + assertEquals("protoLogParam2", methodCall.arguments[5].toString()) assertEquals(TRANSFORMED_CODE_MULTILINE_TEXT_DISABLED, out) } } |