diff options
Diffstat (limited to 'tools')
103 files changed, 759 insertions, 4467 deletions
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp index a594e5bf0ce1..c75ba71c4432 100644 --- a/tools/aapt/Android.bp +++ b/tools/aapt/Android.bp @@ -19,6 +19,23 @@ // targets here. // ========================================================== +package { + default_applicable_licenses: ["frameworks_base_tools_aapt_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_base_tools_aapt_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_defaults { name: "aapt_defaults", diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h index b4ea624524b3..6e9dc3d9456a 100644 --- a/tools/aapt/ConfigDescription.h +++ b/tools/aapt/ConfigDescription.h @@ -34,8 +34,8 @@ struct ConfigDescription : public android::ResTable_config { size = sizeof(android::ResTable_config); } - ConfigDescription(const ConfigDescription&o) { - *static_cast<android::ResTable_config*>(this) = o; + ConfigDescription(const ConfigDescription&o) + : android::ResTable_config(o) { } ConfigDescription& operator=(const android::ResTable_config& o) { diff --git a/tools/aapt/OWNERS b/tools/aapt/OWNERS new file mode 100644 index 000000000000..c232ccd457a7 --- /dev/null +++ b/tools/aapt/OWNERS @@ -0,0 +1 @@ +include /tools/aapt2/OWNERS diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index ab6dced5b67d..dd3ebdbdea09 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -519,7 +519,7 @@ static int validateAttr(const String8& path, const ResTable& table, String8(parser.getElementName(&len)).string(), attr); return ATTR_NOT_FOUND; } - if ((str=pool->stringAt(value.data, &len)) == NULL) { + if ((str = UnpackOptionalString(pool->stringAt(value.data), &len)) == NULL) { fprintf(stderr, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n", path.string(), parser.getLineNumber(), String8(parser.getElementName(&len)).string(), attr); diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index d02f44edaa4c..257e96b6e51a 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -3066,7 +3066,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& for (size_t ti=0; ti<N; ti++) { // Retrieve them in the same order as the type string block. size_t len; - String16 typeName(p->getTypeStrings().stringAt(ti, &len)); + String16 typeName(UnpackOptionalString(p->getTypeStrings().stringAt(ti), &len)); sp<Type> t = p->getTypes().valueFor(typeName); LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"), "Type name %s not found", @@ -4169,7 +4169,7 @@ status_t ResourceTable::Package::setStrings(const sp<AaptFile>& data, const size_t N = strings->size(); for (size_t i=0; i<N; i++) { size_t len; - mappings->add(String16(strings->stringAt(i, &len)), i); + mappings->add(String16(UnpackOptionalString(strings->stringAt(i), &len)), i); } } return err; diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp index 37b61bfdffbd..6cacd32eb91d 100644 --- a/tools/aapt/StringPool.cpp +++ b/tools/aapt/StringPool.cpp @@ -52,9 +52,9 @@ void printStringPool(const ResStringPool* pool) for (size_t i=0; i<N; i++) { size_t len; if (pool->isUTF8()) { - uniqueStrings.add(pool->string8At(i, &len)); + uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len)); } else { - uniqueStrings.add(pool->stringAt(i, &len)); + uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len)); } } @@ -66,8 +66,8 @@ void printStringPool(const ResStringPool* pool) const size_t NS = pool->size(); for (size_t s=0; s<NS; s++) { - String8 str = pool->string8ObjectAt(s); - printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string()); + auto str = pool->string8ObjectAt(s); + printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->string() : "")); } } diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp index 4f22fa581a88..b7c6bd25a565 100644 --- a/tools/aapt/tests/AaptConfig_test.cpp +++ b/tools/aapt/tests/AaptConfig_test.cpp @@ -20,7 +20,6 @@ #include "AaptConfig.h" #include "ConfigDescription.h" #include "SdkConstants.h" -#include "TestHelper.h" using android::String8; @@ -127,4 +126,4 @@ TEST(AaptConfigTest, HdrQualifier) { config.colorMode & android::ResTable_config::MASK_HDR); EXPECT_EQ(SDK_O, config.sdkVersion); EXPECT_EQ(String8("lowdr-v26"), config.toString()); -}
\ No newline at end of file +} diff --git a/tools/aapt/tests/AaptGroupEntry_test.cpp b/tools/aapt/tests/AaptGroupEntry_test.cpp index 7348a08a022f..bf5ca59a81c8 100644 --- a/tools/aapt/tests/AaptGroupEntry_test.cpp +++ b/tools/aapt/tests/AaptGroupEntry_test.cpp @@ -19,7 +19,6 @@ #include "AaptAssets.h" #include "ResourceFilter.h" -#include "TestHelper.h" using android::String8; diff --git a/tools/aapt/tests/ResourceTable_test.cpp b/tools/aapt/tests/ResourceTable_test.cpp index f2c696b2f87e..0d550df16767 100644 --- a/tools/aapt/tests/ResourceTable_test.cpp +++ b/tools/aapt/tests/ResourceTable_test.cpp @@ -19,7 +19,6 @@ #include "ConfigDescription.h" #include "ResourceTable.h" -#include "TestHelper.h" using android::String16; diff --git a/tools/aapt/tests/TestHelper.h b/tools/aapt/tests/TestHelper.h deleted file mode 100644 index 79174832a54d..000000000000 --- a/tools/aapt/tests/TestHelper.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#ifndef __TEST_HELPER_H -#define __TEST_HELPER_H - -#include <utils/String8.h> - -namespace android { - -/** - * Stream operator for nicely printing String8's in gtest output. - */ -inline std::ostream& operator<<(std::ostream& stream, const String8& str) { - return stream << str.string(); -} - -} - -#endif diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index c1d05e47bc19..5c5b3c32876c 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + toolSources = [ "cmd/Command.cpp", "cmd/Compile.cpp", @@ -47,6 +56,7 @@ cc_defaults { cflags: ["-D_DARWIN_UNLIMITED_STREAMS"], }, }, + header_libs: ["jni_headers"], static_libs: [ "libandroidfw", "libutils", diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 439f231193df..82da24959521 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -436,9 +436,9 @@ void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* for (size_t i=0; i<N; i++) { size_t len; if (pool->isUTF8()) { - uniqueStrings.add(pool->string8At(i, &len)); + uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len)); } else { - uniqueStrings.add(pool->stringAt(i, &len)); + uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len)); } } @@ -450,8 +450,8 @@ void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* const size_t NS = pool->size(); for (size_t s=0; s<NS; s++) { - String8 str = pool->string8ObjectAt(s); - printer->Print(StringPrintf("String #%zd : %s\n", s, str.string())); + auto str = pool->string8ObjectAt(s); + printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->string() : "")); } } diff --git a/tools/aapt2/DominatorTree_test.cpp b/tools/aapt2/DominatorTree_test.cpp index fe4f951a5cd0..52949da1b64f 100644 --- a/tools/aapt2/DominatorTree_test.cpp +++ b/tools/aapt2/DominatorTree_test.cpp @@ -173,4 +173,58 @@ TEST(DominatorTreeTest, LocalesAreNeverDominated) { EXPECT_EQ(expected, printer.ToString(&tree)); } +TEST(DominatorTreeTest, NonZeroDensitiesMatch) { + const ConfigDescription sw600_config = test::ParseConfigOrDie("sw600dp"); + const ConfigDescription sw600_hdpi_config = test::ParseConfigOrDie("sw600dp-hdpi"); + const ConfigDescription sw800_hdpi_config = test::ParseConfigOrDie("sw800dp-hdpi"); + const ConfigDescription sw800_xxhdpi_config = test::ParseConfigOrDie("sw800dp-xxhdpi"); + + std::vector<std::unique_ptr<ResourceConfigValue>> configs; + configs.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), "")); + configs.push_back(util::make_unique<ResourceConfigValue>(sw600_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(sw600_hdpi_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(sw800_hdpi_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(sw800_xxhdpi_config, "")); + + DominatorTree tree(configs); + PrettyPrinter printer; + + std::string expected = + "<default>\n" + " sw600dp-v13\n" + " sw600dp-hdpi-v13\n" + " sw800dp-hdpi-v13\n" + " sw800dp-xxhdpi-v13\n"; + EXPECT_EQ(expected, printer.ToString(&tree)); +} + +TEST(DominatorTreeTest, MccMncIsPeertoLocale) { + const ConfigDescription default_config = {}; + const ConfigDescription de_config = test::ParseConfigOrDie("de"); + const ConfigDescription fr_config = test::ParseConfigOrDie("fr"); + const ConfigDescription mcc_config = test::ParseConfigOrDie("mcc262"); + const ConfigDescription mcc_fr_config = test::ParseConfigOrDie("mcc262-fr"); + const ConfigDescription mnc_config = test::ParseConfigOrDie("mnc2"); + const ConfigDescription mnc_fr_config = test::ParseConfigOrDie("mnc2-fr"); + std::vector<std::unique_ptr<ResourceConfigValue>> configs; + configs.push_back(util::make_unique<ResourceConfigValue>(default_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(de_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(fr_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(mcc_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(mcc_fr_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(mnc_config, "")); + configs.push_back(util::make_unique<ResourceConfigValue>(mnc_fr_config, "")); + DominatorTree tree(configs); + PrettyPrinter printer; + std::string expected = + "<default>\n" + "de\n" + "fr\n" + "mcc262\n" + "mcc262-fr\n" + "mnc2\n" + "mnc2-fr\n"; + EXPECT_EQ(expected, printer.ToString(&tree)); +} + } // namespace aapt diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp index ae01170a6894..b78f48ce7f17 100644 --- a/tools/aapt2/Resource.cpp +++ b/tools/aapt2/Resource.cpp @@ -96,8 +96,6 @@ StringPiece to_string(ResourceType type) { return "styleable"; case ResourceType::kTransition: return "transition"; - case ResourceType::kUnknown: - return "unknown"; case ResourceType::kXml: return "xml"; } diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h index c49c370bcc44..4e051a37f3ed 100644 --- a/tools/aapt2/Resource.h +++ b/tools/aapt2/Resource.h @@ -66,11 +66,6 @@ enum class ResourceType { kStyle, kStyleable, kTransition, - - // Not a parsed type. It is only used when loading resource tables that may have modified type - // names - kUnknown, - kXml, }; diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 234cbc4b37e0..931a14b1f650 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -449,6 +449,7 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) { ParsedResource parsed_resource; parsed_resource.config = config_; parsed_resource.source = source_.WithLine(parser->line_number()); + // NOLINTNEXTLINE(bugprone-use-after-move) move+reset comment parsed_resource.comment = std::move(comment); if (options_.visibility) { parsed_resource.visibility_level = options_.visibility.value(); @@ -979,6 +980,7 @@ bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource child_resource.name.type = *parsed_type; child_resource.name.entry = maybe_name.value().to_string(); child_resource.id = next_id; + // NOLINTNEXTLINE(bugprone-use-after-move) move+reset comment child_resource.comment = std::move(comment); child_resource.source = item_source; child_resource.visibility_level = Visibility::Level::kPublic; @@ -1698,6 +1700,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource child_resource; child_resource.name = child_ref.name.value(); child_resource.source = item_source; + // NOLINTNEXTLINE(bugprone-use-after-move) move+reset comment child_resource.comment = std::move(comment); if (options_.visibility) { child_resource.visibility_level = options_.visibility.value(); diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 469128b1e50b..f26e995aa4f9 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -751,10 +751,12 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config switch (res_value.dataType) { case android::Res_value::TYPE_STRING: { const std::string str = util::GetString(src_pool, data); - const android::ResStringPool_span* spans = src_pool.styleAt(data); + auto spans_result = src_pool.styleAt(data); // Check if the string has a valid style associated with it. - if (spans != nullptr && spans->name.index != android::ResStringPool_span::END) { + if (spans_result.has_value() && + (*spans_result)->name.index != android::ResStringPool_span::END) { + const android::ResStringPool_span* spans = spans_result->unsafe_ptr(); StyleString style_str = {str}; while (spans->name.index != android::ResStringPool_span::END) { style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index), diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index ab9ce66b0ae3..b1e1a77e1224 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -168,6 +168,7 @@ message OverlayableItem { ODM = 6; OEM = 7; ACTOR = 8; + CONFIG_SIGNATURE = 9; } // The location of the <item> declaration in source. diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp index f9faed84f5f0..e8873bf2d81b 100644 --- a/tools/aapt2/SdkConstants.cpp +++ b/tools/aapt2/SdkConstants.cpp @@ -27,7 +27,7 @@ namespace aapt { static ApiVersion sDevelopmentSdkLevel = 10000; static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>({ - "Q", "R" + "Q", "R", "S" }); static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = { diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp index 9a7238b584ba..6e5200bca44c 100644 --- a/tools/aapt2/StringPool_test.cpp +++ b/tools/aapt2/StringPool_test.cpp @@ -223,11 +223,11 @@ TEST(StringPoolTest, FlattenOddCharactersUtf16) { std::unique_ptr<uint8_t[]> data = util::Copy(buffer); ResStringPool test; ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR); - size_t len = 0; - const char16_t* str = test.stringAt(0, &len); - EXPECT_THAT(len, Eq(1u)); - EXPECT_THAT(str, Pointee(Eq(u'\u093f'))); - EXPECT_THAT(str[1], Eq(0u)); + auto str = test.stringAt(0); + ASSERT_TRUE(str.has_value()); + EXPECT_THAT(str->size(), Eq(1u)); + EXPECT_THAT(str->data(), Pointee(Eq(u'\u093f'))); + EXPECT_THAT(str->data()[1], Eq(0u)); } constexpr const char* sLongString = @@ -278,14 +278,15 @@ TEST(StringPoolTest, Flatten) { EXPECT_THAT(util::GetString(test, 3), Eq(sLongString)); EXPECT_THAT(util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString))); - size_t len; - EXPECT_TRUE(test.stringAt(4, &len) != nullptr || test.string8At(4, &len) != nullptr); + EXPECT_TRUE(test.stringAt(4).has_value() || test.string8At(4).has_value()); EXPECT_THAT(util::GetString(test, 0), Eq("style")); EXPECT_THAT(util::GetString16(test, 0), Eq(u"style")); - const ResStringPool_span* span = test.styleAt(0); - ASSERT_THAT(span, NotNull()); + auto span_result = test.styleAt(0); + ASSERT_TRUE(span_result.has_value()); + + const ResStringPool_span* span = span_result->unsafe_ptr(); EXPECT_THAT(util::GetString(test, span->name.index), Eq("b")); EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"b")); EXPECT_THAT(span->firstChar, Eq(0u)); @@ -318,16 +319,17 @@ TEST(StringPoolTest, ModifiedUTF8) { // Check that the codepoints are encoded using two three-byte surrogate pairs ResStringPool test; ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR); - size_t len; - const char* str = test.string8At(0, &len); - ASSERT_THAT(str, NotNull()); - EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80")); - str = test.string8At(1, &len); - ASSERT_THAT(str, NotNull()); - EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar")); - str = test.string8At(2, &len); - ASSERT_THAT(str, NotNull()); - EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7")); + auto str = test.string8At(0); + ASSERT_TRUE(str.has_value()); + EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80")); + + str = test.string8At(1); + ASSERT_TRUE(str.has_value()); + EXPECT_THAT(str->to_string(), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar")); + + str = test.string8At(2); + ASSERT_TRUE(str.has_value()); + EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7")); // Check that retrieving the strings returns the original UTF-8 character bytes EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80")); diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp index fb786a31360e..ae9f7926cf09 100644 --- a/tools/aapt2/cmd/Compile_test.cpp +++ b/tools/aapt2/cmd/Compile_test.cpp @@ -252,5 +252,4 @@ TEST_F(CompilerTest, DoNotTranslateTest) { AssertTranslations(this, "donottranslate", expected_not_translatable); AssertTranslations(this, "donottranslate_foo", expected_not_translatable); } - } // namespace aapt diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 3a3fb2826b74..faabe461648a 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -730,22 +730,6 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path, return true; } -static android::ApkAssetsCookie FindFrameworkAssetManagerCookie( - const android::AssetManager2& assets) { - using namespace android; - - // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so - // we're looking for the first attribute resource in the system package. - Res_value val{}; - ResTable_config config{}; - uint32_t type_spec_flags; - ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */, - 0 /** density_override */, &val, &config, - &type_spec_flags); - - return idx; -} - class Linker { public: Linker(LinkContext* context, const LinkOptions& options) @@ -758,8 +742,12 @@ class Linker { void ExtractCompileSdkVersions(android::AssetManager2* assets) { using namespace android; - android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets); - if (cookie == android::kInvalidCookie) { + // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so + // we're looking for the first attribute resource in the system package. + android::ApkAssetsCookie cookie; + if (auto value = assets->GetResource(0x01010000, true /** may_be_bag */); value.has_value()) { + cookie = value->cookie; + } else { // No Framework assets loaded. Not a failure. return; } @@ -1272,7 +1260,8 @@ class Linker { return false; } - ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout); + ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, + false /* strip_api_annotations */, &fout); fout.Flush(); if (fout.HadError()) { @@ -2334,11 +2323,15 @@ int LinkCommand::Action(const std::vector<std::string>& args) { } // Populate some default no-compress extensions that are already compressed. - options_.extensions_to_not_compress.insert( - {".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp2", ".mp3", ".ogg", - ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl", - ".imy", ".xmf", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2", - ".3gpp2", ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"}); + options_.extensions_to_not_compress.insert({ + // Image extensions + ".jpg", ".jpeg", ".png", ".gif", ".webp", + // Audio extensions + ".wav", ".mp2", ".mp3", ".ogg", ".aac", ".mid", ".midi", ".smf", ".jet", ".rtttl", ".imy", + ".xmf", ".amr", ".awb", + // Audio/video extensions + ".mpg", ".mpeg", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", ".wma", ".wmv", + ".webm", ".mkv"}); // Turn off auto versioning for static-libs. if (context.GetPackageType() == PackageType::kStaticLib) { diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index f362744c0942..cccd9faa9b39 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -352,15 +352,15 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, config.copyFromDtoH(type->config); const std::string type_str = util::GetString(type_pool_, type->id - 1); - - // Be lenient on the name of the type if the table is lenient on resource validation. - auto parsed_type = ResourceType::kUnknown; - if (const ResourceType* parsed = ParseResourceType(type_str)) { - parsed_type = *parsed; - } else if (table_->GetValidateResources()) { - diag_->Error(DiagMessage(source_) << "invalid type name '" << type_str << "' for type with ID " - << (int) type->id); - return false; + const ResourceType* parsed_type = ParseResourceType(type_str); + if (!parsed_type) { + // Be lenient on the name of the type if the table is lenient on resource validation. + bool log_error = table_->GetValidateResources(); + if (log_error) { + diag_->Error(DiagMessage(source_) << "invalid type name '" << type_str + << "' for type with ID " << type->id); + } + return !log_error; } TypeVariant tv(type); @@ -370,9 +370,8 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, continue; } - const ResourceName name(package->name, parsed_type, + const ResourceName name(package->name, *parsed_type, util::GetString(key_pool_, util::DeviceToHost32(entry->key.index))); - const ResourceId res_id(package->id.value(), type->id, static_cast<uint16_t>(it.index())); std::unique_ptr<Value> resource_value; diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index 59627ce579af..f8b8a1c4e35b 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -189,16 +189,16 @@ TEST_F(TableFlattenerTest, FlattenFullyLinkedTable) { ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; - ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); - ASSERT_GE(idx, 0); + auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); + ASSERT_TRUE(idx.has_value()); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {}, - Res_value::TYPE_STRING, (uint32_t)idx, 0u)); + Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); - ASSERT_GE(idx, 0); + ASSERT_TRUE(idx.has_value()); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/bar", ResourceId(0x7f050000), {}, - Res_value::TYPE_STRING, (uint32_t)idx, 0u)); + Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); } TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) { @@ -603,16 +603,16 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoNameCollapseExemptionsSucce 2u, ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; - ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); - ASSERT_GE(idx, 0); + auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); + ASSERT_TRUE(idx.has_value()); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated", - ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); + ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); - ASSERT_GE(idx, 0); + ASSERT_TRUE(idx.has_value()); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated", - ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); + ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); } TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) { @@ -659,16 +659,16 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSuc 2u, ResTable_config::CONFIG_VERSION)); std::u16string foo_str = u"foo"; - ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); - ASSERT_GE(idx, 0); + auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size()); + ASSERT_TRUE(idx.has_value()); EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {}, - Res_value::TYPE_STRING, (uint32_t)idx, 0u)); + Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); std::u16string bar_path = u"res/layout/bar.xml"; idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size()); - ASSERT_GE(idx, 0); + ASSERT_TRUE(idx.has_value()); EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated", - ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); + ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u)); } TEST_F(TableFlattenerTest, FlattenOverlayable) { @@ -776,6 +776,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { OverlayableItem overlayable_item_three(group_one); overlayable_item_three.policies |= PolicyFlags::SIGNATURE; overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; + overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -830,7 +831,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE - | PolicyFlags::ACTOR_SIGNATURE); + | PolicyFlags::ACTOR_SIGNATURE + | PolicyFlags::CONFIG_SIGNATURE); } TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 2fd01d7f3dee..7eb8ebd9a043 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -404,6 +404,9 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, case pb::OverlayableItem::ACTOR: out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE; break; + case pb::OverlayableItem::CONFIG_SIGNATURE: + out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE; + break; default: *out_error = "unknown overlayable policy"; return false; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index ba6df22af9d3..831229ffa383 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -325,6 +325,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); } + if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) { + pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE); + } if (source_pool != nullptr) { SerializeSourceToPb(overlayable_item.source, source_pool, diff --git a/tools/aapt2/integration-tests/AutoVersionTest/Android.bp b/tools/aapt2/integration-tests/AutoVersionTest/Android.bp index 79fb5734cd68..bfd35083366e 100644 --- a/tools/aapt2/integration-tests/AutoVersionTest/Android.bp +++ b/tools/aapt2/integration-tests/AutoVersionTest/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + android_test { name: "AaptAutoVersionTest", sdk_version: "current", diff --git a/tools/aapt2/integration-tests/BasicTest/Android.bp b/tools/aapt2/integration-tests/BasicTest/Android.bp index a94a01f12c9e..7db9d2698cc7 100644 --- a/tools/aapt2/integration-tests/BasicTest/Android.bp +++ b/tools/aapt2/integration-tests/BasicTest/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + android_test { name: "AaptBasicTest", sdk_version: "current", diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk index 7bf8cf84426c..c084849a9d28 100644 --- a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk +++ b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk @@ -20,9 +20,12 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_AAPT_NAMESPACES := true LOCAL_MODULE := AaptTestMergeOnly_LeafLib +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_MIN_SDK_VERSION := 21 LOCAL_AAPT_FLAGS := --merge-only -include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk index ba781c56a913..699ad79ecf1a 100644 --- a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk +++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk @@ -20,9 +20,12 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_AAPT_NAMESPACES := true LOCAL_MODULE := AaptTestMergeOnly_LocalLib +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_MIN_SDK_VERSION := 21 LOCAL_AAPT_FLAGS := --merge-only -include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk index c723d905db5b..dd4170234258 100644 --- a/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk +++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk @@ -20,6 +20,9 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_AAPT_NAMESPACES := true LOCAL_MODULE := AaptTestNamespace_LibOne +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk index 90a7f627e591..0d11bcbda64d 100644 --- a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk +++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk @@ -20,6 +20,9 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_AAPT_NAMESPACES := true LOCAL_MODULE := AaptTestNamespace_LibTwo +LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 +LOCAL_LICENSE_CONDITIONS := notice +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) diff --git a/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp index 9aadff3d619e..80404eeb8d8e 100644 --- a/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp +++ b/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + android_test { name: "AaptTestStaticLib_App", diff --git a/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp index 4c8181343a33..a84da43c70c8 100644 --- a/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + android_library { name: "AaptTestStaticLib_LibOne", sdk_version: "current", diff --git a/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp index 7c4f7ed90e69..d386c3a35d20 100644 --- a/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + android_library { name: "AaptTestStaticLib_LibTwo", sdk_version: "current", diff --git a/tools/aapt2/integration-tests/SymlinkTest/Android.bp b/tools/aapt2/integration-tests/SymlinkTest/Android.bp index 68e6148e480c..1e8cf86ed811 100644 --- a/tools/aapt2/integration-tests/SymlinkTest/Android.bp +++ b/tools/aapt2/integration-tests/SymlinkTest/Android.bp @@ -14,6 +14,15 @@ // 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"], +} + android_test { name: "AaptSymlinkTest", sdk_version: "current", diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp index cec59e75831d..482d91aeb491 100644 --- a/tools/aapt2/java/AnnotationProcessor.cpp +++ b/tools/aapt2/java/AnnotationProcessor.cpp @@ -123,7 +123,7 @@ void AnnotationProcessor::AppendNewLine() { } } -void AnnotationProcessor::Print(Printer* printer) const { +void AnnotationProcessor::Print(Printer* printer, bool strip_api_annotations) const { if (has_comments_) { std::string result = comment_.str(); for (const StringPiece& line : util::Tokenize(result, '\n')) { @@ -137,6 +137,9 @@ void AnnotationProcessor::Print(Printer* printer) const { printer->Println("@Deprecated"); } + if (strip_api_annotations) { + return; + } for (const AnnotationRule& rule : sAnnotationRules) { const auto& it = annotation_parameter_map_.find(rule.bit_mask); if (it != annotation_parameter_map_.end()) { diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h index fdb58468d995..f217afb16f32 100644 --- a/tools/aapt2/java/AnnotationProcessor.h +++ b/tools/aapt2/java/AnnotationProcessor.h @@ -65,7 +65,7 @@ class AnnotationProcessor { void AppendNewLine(); // Writes the comments and annotations to the Printer. - void Print(text::Printer* printer) const; + void Print(text::Printer* printer, bool strip_api_annotations = false) const; private: std::stringstream comment_; diff --git a/tools/aapt2/java/AnnotationProcessor_test.cpp b/tools/aapt2/java/AnnotationProcessor_test.cpp index 7d0a4e9af632..6bc8902a6dcf 100644 --- a/tools/aapt2/java/AnnotationProcessor_test.cpp +++ b/tools/aapt2/java/AnnotationProcessor_test.cpp @@ -91,6 +91,21 @@ TEST(AnnotationProcessorTest, EmitsTestApiAnnotationAndRemovesFromComment) { EXPECT_THAT(annotations, HasSubstr("This is a test API")); } +TEST(AnnotationProcessorTest, NotEmitSystemApiAnnotation) { + AnnotationProcessor processor; + processor.AppendComment("@SystemApi This is a system API"); + + std::string annotations; + StringOutputStream out(&annotations); + Printer printer(&out); + processor.Print(&printer, true /* strip_api_annotations */); + out.Flush(); + + EXPECT_THAT(annotations, Not(HasSubstr("@android.annotation.SystemApi"))); + EXPECT_THAT(annotations, Not(HasSubstr("@SystemApi"))); + EXPECT_THAT(annotations, HasSubstr("This is a system API")); +} + TEST(AnnotationProcessor, ExtractsFirstSentence) { EXPECT_THAT(AnnotationProcessor::ExtractFirstSentence("This is the only sentence"), Eq("This is the only sentence")); diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp index f5f5b05491bb..3163497f0da6 100644 --- a/tools/aapt2/java/ClassDefinition.cpp +++ b/tools/aapt2/java/ClassDefinition.cpp @@ -23,15 +23,15 @@ using ::android::StringPiece; namespace aapt { -void ClassMember::Print(bool /*final*/, Printer* printer) const { - processor_.Print(printer); +void ClassMember::Print(bool /*final*/, Printer* printer, bool strip_api_annotations) const { + processor_.Print(printer, strip_api_annotations); } void MethodDefinition::AppendStatement(const StringPiece& statement) { statements_.push_back(statement.to_string()); } -void MethodDefinition::Print(bool final, Printer* printer) const { +void MethodDefinition::Print(bool final, Printer* printer, bool) const { printer->Print(signature_).Println(" {"); printer->Indent(); for (const auto& statement : statements_) { @@ -74,12 +74,12 @@ bool ClassDefinition::empty() const { return true; } -void ClassDefinition::Print(bool final, Printer* printer) const { +void ClassDefinition::Print(bool final, Printer* printer, bool strip_api_annotations) const { if (empty() && !create_if_empty_) { return; } - ClassMember::Print(final, printer); + ClassMember::Print(final, printer, strip_api_annotations); printer->Print("public "); if (qualifier_ == ClassQualifier::kStatic) { @@ -93,7 +93,7 @@ void ClassDefinition::Print(bool final, Printer* printer) const { // and takes precedence over a previous member with the same name. The overridden member is // set to nullptr. if (member != nullptr) { - member->Print(final, printer); + member->Print(final, printer, strip_api_annotations); printer->Println(); } } @@ -111,11 +111,11 @@ constexpr static const char* sWarningHeader = " */\n\n"; void ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package, - bool final, io::OutputStream* out) { + bool final, bool strip_api_annotations, io::OutputStream* out) { Printer printer(out); printer.Print(sWarningHeader).Print("package ").Print(package).Println(";"); printer.Println(); - def->Print(final, &printer); + def->Print(final, &printer, strip_api_annotations); } } // namespace aapt diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h index fb11266f1761..1e4b6816075a 100644 --- a/tools/aapt2/java/ClassDefinition.h +++ b/tools/aapt2/java/ClassDefinition.h @@ -50,7 +50,7 @@ class ClassMember { // Writes the class member to the Printer. Subclasses should derive this method // to write their own data. Call this base method from the subclass to write out // this member's comments/annotations. - virtual void Print(bool final, text::Printer* printer) const; + virtual void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const; private: AnnotationProcessor processor_; @@ -70,10 +70,11 @@ class PrimitiveMember : public ClassMember { return name_; } - void Print(bool final, text::Printer* printer) const override { + void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) + const override { using std::to_string; - ClassMember::Print(final, printer); + ClassMember::Print(final, printer, strip_api_annotations); printer->Print("public static "); if (final) { @@ -104,8 +105,9 @@ class PrimitiveMember<std::string> : public ClassMember { return name_; } - void Print(bool final, text::Printer* printer) const override { - ClassMember::Print(final, printer); + void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) + const override { + ClassMember::Print(final, printer, strip_api_annotations); printer->Print("public static "); if (final) { @@ -142,8 +144,9 @@ class PrimitiveArrayMember : public ClassMember { return name_; } - void Print(bool final, text::Printer* printer) const override { - ClassMember::Print(final, printer); + void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) + const override { + ClassMember::Print(final, printer, strip_api_annotations); printer->Print("public static final int[] ").Print(name_).Print("={"); printer->Indent(); @@ -195,7 +198,7 @@ class MethodDefinition : public ClassMember { return false; } - void Print(bool final, text::Printer* printer) const override; + void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const override; private: DISALLOW_COPY_AND_ASSIGN(MethodDefinition); @@ -209,7 +212,7 @@ enum class ClassQualifier { kNone, kStatic }; class ClassDefinition : public ClassMember { public: static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package, - bool final, io::OutputStream* out); + bool final, bool strip_api_annotations, io::OutputStream* out); ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty) : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {} @@ -227,7 +230,7 @@ class ClassDefinition : public ClassMember { return name_; } - void Print(bool final, text::Printer* printer) const override; + void Print(bool final, text::Printer* printer, bool strip_api_annotations = false) const override; private: DISALLOW_COPY_AND_ASSIGN(ClassDefinition); diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index bb541fe2490b..dffad3b99c06 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -604,6 +604,8 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, rewrite_method->AppendStatement("final int packageIdBits = p << 24;"); } + const bool is_public = (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic); + for (const auto& package : table_->packages) { for (const auto& type : package->types) { if (type->type == ResourceType::kAttrPrivate) { @@ -612,8 +614,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, } // Stay consistent with AAPT and generate an empty type class if the R class is public. - const bool force_creation_if_empty = - (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic); + const bool force_creation_if_empty = is_public; std::unique_ptr<ClassDefinition> class_def; if (out != nullptr) { @@ -637,8 +638,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, } } - if (out != nullptr && type->type == ResourceType::kStyleable && - options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) { + if (out != nullptr && type->type == ResourceType::kStyleable && is_public) { // When generating a public R class, we don't want Styleable to be part // of the API. It is only emitted for documentation purposes. class_def->GetCommentBuilder()->AppendComment("@doconly"); @@ -657,7 +657,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, if (out != nullptr) { AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder()); - ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out); + ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, !is_public, out); } return true; } diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp index ab7f9a11d971..3858fc7f765e 100644 --- a/tools/aapt2/java/ManifestClassGenerator_test.cpp +++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp @@ -26,6 +26,7 @@ using ::testing::Not; namespace aapt { static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xml::XmlResource* res, + bool strip_api_annotations, std::string* out_str); TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) { @@ -39,7 +40,8 @@ TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) { </manifest>)"); std::string actual; - ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), &actual)); + ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), + false /* strip_api_annotations */, &actual)); ASSERT_THAT(actual, HasSubstr("public static final class permission {")); ASSERT_THAT(actual, HasSubstr("public static final class permission_group {")); @@ -91,7 +93,8 @@ TEST(ManifestClassGeneratorTest, CommentsAndAnnotationsArePresent) { </manifest>)"); std::string actual; - ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), &actual)); + ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), + false /* strip_api_annotations */, &actual)); const char* expected_access_internet = R"( /** * Required to access the internet. @@ -123,6 +126,55 @@ TEST(ManifestClassGeneratorTest, CommentsAndAnnotationsArePresent) { EXPECT_THAT(actual, HasSubstr(expected_test)); } +TEST(ManifestClassGeneratorTest, CommentsAndAnnotationsArePresentButNoApiAnnotations) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"( + <manifest xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Required to access the internet. + Added in API 1. --> + <permission android:name="android.permission.ACCESS_INTERNET" /> + <!-- @deprecated This permission is for playing outside. --> + <permission android:name="android.permission.PLAY_OUTSIDE" /> + <!-- This is a private permission for system only! + @hide + @SystemApi --> + <permission android:name="android.permission.SECRET" /> + <!-- @TestApi This is a test only permission. --> + <permission android:name="android.permission.TEST_ONLY" /> + </manifest>)"); + + std::string actual; + ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), + true /* strip_api_annotations */, &actual)); + + const char* expected_access_internet = R"( /** + * Required to access the internet. + * Added in API 1. + */ + public static final String ACCESS_INTERNET="android.permission.ACCESS_INTERNET";)"; + EXPECT_THAT(actual, HasSubstr(expected_access_internet)); + + const char* expected_play_outside = R"( /** + * @deprecated This permission is for playing outside. + */ + @Deprecated + public static final String PLAY_OUTSIDE="android.permission.PLAY_OUTSIDE";)"; + EXPECT_THAT(actual, HasSubstr(expected_play_outside)); + + const char* expected_secret = R"( /** + * This is a private permission for system only! + * @hide + */ + public static final String SECRET="android.permission.SECRET";)"; + EXPECT_THAT(actual, HasSubstr(expected_secret)); + + const char* expected_test = R"( /** + * This is a test only permission. + */ + public static final String TEST_ONLY="android.permission.TEST_ONLY";)"; + EXPECT_THAT(actual, HasSubstr(expected_test)); +} + // This is bad but part of public API behaviour so we need to preserve it. TEST(ManifestClassGeneratorTest, LastSeenPermissionWithSameLeafNameTakesPrecedence) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); @@ -135,7 +187,8 @@ TEST(ManifestClassGeneratorTest, LastSeenPermissionWithSameLeafNameTakesPreceden </manifest>)"); std::string actual; - ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), &actual)); + ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), + false /* strip_api_annotations */, &actual)); EXPECT_THAT(actual, HasSubstr("ACCESS_INTERNET=\"com.android.aapt.test.ACCESS_INTERNET\";")); EXPECT_THAT(actual, Not(HasSubstr("ACCESS_INTERNET=\"android.permission.ACCESS_INTERNET\";"))); EXPECT_THAT(actual, Not(HasSubstr("ACCESS_INTERNET=\"com.android.sample.ACCESS_INTERNET\";"))); @@ -149,11 +202,13 @@ TEST(ManifestClassGeneratorTest, NormalizePermissionNames) { </manifest>)"); std::string actual; - ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), &actual)); + ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(), + false /* strip_api_annotations */, &actual)); EXPECT_THAT(actual, HasSubstr("access_internet=\"android.permission.access-internet\";")); } static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xml::XmlResource* res, + bool strip_api_annotations, std::string* out_str) { std::unique_ptr<ClassDefinition> manifest_class = GenerateManifestClass(context->GetDiagnostics(), res); @@ -162,7 +217,7 @@ static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xm } StringOutputStream out(out_str); - manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out); + manifest_class->WriteJavaFile(manifest_class.get(), "android", true, strip_api_annotations, &out); out.Flush(); return ::testing::AssertionSuccess(); } diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp index 0db1807c75d9..d9a4caa34e0d 100644 --- a/tools/aapt2/java/ProguardRules.cpp +++ b/tools/aapt2/java/ProguardRules.cpp @@ -115,15 +115,10 @@ class LayoutVisitor : public BaseVisitor { void Visit(xml::Element* node) override { bool is_view = false; - bool is_fragment = false; if (node->namespace_uri.empty()) { if (node->name == "view") { is_view = true; - } else if (node->name == "fragment") { - is_fragment = true; } - } else if (node->namespace_uri == xml::kSchemaAndroid) { - is_fragment = node->name == "fragment"; } for (const auto& attr : node->attributes) { @@ -132,12 +127,12 @@ class LayoutVisitor : public BaseVisitor { if (is_view) { AddClass(node->line_number, attr.value, "android.content.Context, android.util.AttributeSet"); - } else if (is_fragment) { + } else { AddClass(node->line_number, attr.value, ""); } } } else if (attr.namespace_uri == xml::kSchemaAndroid && attr.name == "name") { - if (is_fragment && util::IsJavaClassName(attr.value)) { + if (util::IsJavaClassName(attr.value)) { AddClass(node->line_number, attr.value, ""); } } else if (attr.namespace_uri == xml::kSchemaAndroid && attr.name == "onClick") { diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp index b6e76021ccc1..c7ae0b6a75cc 100644 --- a/tools/aapt2/java/ProguardRules_test.cpp +++ b/tools/aapt2/java/ProguardRules_test.cpp @@ -131,6 +131,61 @@ TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) { EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(); }")); } +TEST(ProguardRulesTest, FragmentContainerViewNameRuleIsEmitted) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"( + <androidx.fragment.app.FragmentContainerView + xmlns:android="http://schemas.android.com/apk/res/android" + android:name="com.foo.Bar"/>)"); + layout->file.name = test::ParseNameOrDie("layout/foo"); + + proguard::KeepSet set; + ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set)); + + std::string actual = GetKeepSetString(set, /** minimal_rules */ false); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }")); + + actual = GetKeepSetString(set, /** minimal_rules */ true); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }")); +} + +TEST(ProguardRulesTest, FragmentContainerViewClassRuleIsEmitted) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + std::unique_ptr<xml::XmlResource> layout = + test::BuildXmlDom(R"(<androidx.fragment.app.FragmentContainerView class="com.foo.Bar"/>)"); + layout->file.name = test::ParseNameOrDie("layout/foo"); + + proguard::KeepSet set; + ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set)); + + std::string actual = GetKeepSetString(set, /** minimal_rules */ false); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }")); + + actual = GetKeepSetString(set, /** minimal_rules */ true); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }")); +} + +TEST(ProguardRulesTest, FragmentContainerViewNameAndClassRulesAreEmitted) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"( + <androidx.fragment.app.FragmentContainerView + xmlns:android="http://schemas.android.com/apk/res/android" + android:name="com.foo.Baz" + class="com.foo.Bar"/>)"); + layout->file.name = test::ParseNameOrDie("layout/foo"); + + proguard::KeepSet set; + ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set)); + + std::string actual = GetKeepSetString(set, /** minimal_rules */ false); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }")); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }")); + + actual = GetKeepSetString(set, /** minimal_rules */ true); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }")); + EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(); }")); +} + TEST(ProguardRulesTest, NavigationFragmentNameAndClassRulesAreEmitted) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .SetCompilationPackage("com.base").Build(); diff --git a/tools/aapt2/optimize/ResourceDeduper_test.cpp b/tools/aapt2/optimize/ResourceDeduper_test.cpp index 048e318d2802..888de40be268 100644 --- a/tools/aapt2/optimize/ResourceDeduper_test.cpp +++ b/tools/aapt2/optimize/ResourceDeduper_test.cpp @@ -52,9 +52,11 @@ TEST(ResourceDeduperTest, SameValuesAreDeduped) { .Build(); ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/dedupe", default_config)); EXPECT_THAT(table, Not(HasValue("android:string/dedupe", ldrtl_config))); EXPECT_THAT(table, Not(HasValue("android:string/dedupe", land_config))); + EXPECT_THAT(table, HasValue("android:string/dedupe2", default_config)); EXPECT_THAT(table, HasValue("android:string/dedupe2", ldrtl_v21_config)); EXPECT_THAT(table, Not(HasValue("android:string/dedupe2", ldrtl_config))); @@ -151,4 +153,24 @@ TEST(ResourceDeduperTest, LocalesValuesAreKept) { EXPECT_THAT(table, HasValue("android:string/keep", fr_rCA_config)); } +TEST(ResourceDeduperTest, MccMncValuesAreKept) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + const ConfigDescription default_config = {}; + const ConfigDescription mcc_config = test::ParseConfigOrDie("mcc262"); + const ConfigDescription mnc_config = test::ParseConfigOrDie("mnc2"); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddString("android:string/keep", ResourceId{}, default_config, "keep") + .AddString("android:string/keep", ResourceId{}, mcc_config, "keep") + .AddString("android:string/keep", ResourceId{}, mnc_config, "keep") + .Build(); + + ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); + EXPECT_THAT(table, HasValue("android:string/keep", mcc_config)); + EXPECT_THAT(table, HasValue("android:string/keep", mnc_config)); +} + + } // namespace aapt diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp index 897fa80ffedb..ad716c78d65d 100644 --- a/tools/aapt2/process/SymbolTable.cpp +++ b/tools/aapt2/process/SymbolTable.cpp @@ -265,21 +265,22 @@ bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId, static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable( android::AssetManager2& am, ResourceId id) { + using namespace android; if (am.GetApkAssets().empty()) { return {}; } - const android::ResolvedBag* bag = am.GetBag(id.id); - if (bag == nullptr) { + auto bag_result = am.GetBag(id.id); + if (!bag_result.has_value()) { return nullptr; } // We found a resource. std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>(id); - + const ResolvedBag* bag = *bag_result; const size_t count = bag->entry_count; for (uint32_t i = 0; i < count; i++) { - if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) { + if (bag->entries[i].key == ResTable_map::ATTR_TYPE) { s->attribute = std::make_shared<Attribute>(bag->entries[i].value.data); break; } @@ -287,25 +288,25 @@ static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable( if (s->attribute) { for (size_t i = 0; i < count; i++) { - const android::ResolvedBag::Entry& map_entry = bag->entries[i]; + const ResolvedBag::Entry& map_entry = bag->entries[i]; if (Res_INTERNALID(map_entry.key)) { switch (map_entry.key) { - case android::ResTable_map::ATTR_MIN: + case ResTable_map::ATTR_MIN: s->attribute->min_int = static_cast<int32_t>(map_entry.value.data); break; - case android::ResTable_map::ATTR_MAX: + case ResTable_map::ATTR_MAX: s->attribute->max_int = static_cast<int32_t>(map_entry.value.data); break; } continue; } - android::AssetManager2::ResourceName name; - if (!am.GetResourceName(map_entry.key, &name)) { + auto name = am.GetResourceName(map_entry.key); + if (!name.has_value()) { return nullptr; } - Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(name); + Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name); if (!parsed_name) { return nullptr; } @@ -328,7 +329,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( bool found = false; ResourceId res_id = 0; - uint32_t type_spec_flags; + uint32_t type_spec_flags = 0; ResourceName real_name; // There can be mangled resources embedded within other packages. Here we will @@ -340,8 +341,19 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( real_name.package = package_name; } - res_id = asset_manager_.GetResourceId(real_name.to_string()); - if (res_id.is_valid_static() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) { + auto real_res_id = asset_manager_.GetResourceId(real_name.to_string()); + if (!real_res_id.has_value()) { + return true; + } + + res_id.id = *real_res_id; + if (!res_id.is_valid_static()) { + return true; + } + + auto value = asset_manager_.GetResource(res_id.id, true /* may_be_bag */); + if (value.has_value()) { + type_spec_flags = value->flags; found = true; return false; } @@ -371,11 +383,11 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName( static Maybe<ResourceName> GetResourceName(android::AssetManager2& am, ResourceId id) { - android::AssetManager2::ResourceName name; - if (!am.GetResourceName(id.id, &name)) { + auto name = am.GetResourceName(id.id); + if (!name.has_value()) { return {}; } - return ResourceUtils::ToResourceName(name); + return ResourceUtils::ToResourceName(*name); } std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( @@ -394,9 +406,8 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( return {}; } - - uint32_t type_spec_flags = 0; - if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) { + auto value = asset_manager_.GetResource(id.id, true /* may_be_bag */); + if (!value.has_value()) { return {}; } @@ -411,7 +422,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById( } if (s) { - s->is_public = (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0; + s->is_public = (value->flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0; return s; } return {}; diff --git a/tools/aapt2/util/BigBuffer_test.cpp b/tools/aapt2/util/BigBuffer_test.cpp index a7776e33ae74..64dcc1dad9a2 100644 --- a/tools/aapt2/util/BigBuffer_test.cpp +++ b/tools/aapt2/util/BigBuffer_test.cpp @@ -62,7 +62,7 @@ TEST(BigBufferTest, AppendAndMoveBlock) { *b1 = 44; buffer.AppendBuffer(std::move(buffer2)); - EXPECT_EQ(0u, buffer2.size()); + EXPECT_EQ(0u, buffer2.size()); // NOLINT EXPECT_EQ(buffer2.begin(), buffer2.end()); } diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index 37ce65e4fe5b..793a2368526b 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -531,19 +531,15 @@ bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix, } StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) { - size_t len; - const char16_t* str = pool.stringAt(idx, &len); - if (str != nullptr) { - return StringPiece16(str, len); + if (auto str = pool.stringAt(idx); str.ok()) { + return *str; } return StringPiece16(); } std::string GetString(const android::ResStringPool& pool, size_t idx) { - size_t len; - const char* str = pool.string8At(idx, &len); - if (str != nullptr) { - return ModifiedUtf8ToUtf8(std::string(str, len)); + if (auto str = pool.string8At(idx); str.ok()) { + return ModifiedUtf8ToUtf8(str->to_string()); } return Utf16ToUtf8(GetString16(pool, idx)); } diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index 9a725fad8727..005eeb936612 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -305,6 +305,8 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string* if (pending_element == nullptr) { pending_element = util::make_unique<Element>(); } + // pending_element is not nullptr + // NOLINTNEXTLINE(bugprone-use-after-move) pending_element->namespace_decls.push_back(std::move(decl)); break; } diff --git a/tools/bit/Android.bp b/tools/bit/Android.bp index a8062719d586..f6aa0fb8f3f0 100644 --- a/tools/bit/Android.bp +++ b/tools/bit/Android.bp @@ -17,6 +17,15 @@ // ========================================================== // Build the host executable: bit // ========================================================== +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"], +} + cc_binary_host { name: "bit", diff --git a/tools/bit/adb.cpp b/tools/bit/adb.cpp index fa7d3d4031d4..f521a63255e1 100644 --- a/tools/bit/adb.cpp +++ b/tools/bit/adb.cpp @@ -200,7 +200,7 @@ skip_bytes(int fd, ssize_t size, char* scratch, int scratchSize) static int skip_unknown_field(int fd, uint64_t tag, char* scratch, int scratchSize) { - bool done; + bool done = false; int err; uint64_t size; switch (tag & 0x7) { diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp index df64a801e213..2a88732b50b1 100644 --- a/tools/bit/make.cpp +++ b/tools/bit/make.cpp @@ -89,8 +89,8 @@ BuildVars::BuildVars(const string& outDir, const string& buildProduct, } Json::Value json; - Json::Reader reader; - if (!reader.parse(stream, json)) { + Json::CharReaderBuilder builder; + if (!Json::parseFromStream(builder, stream, &json, /* errorMessage = */ nullptr)) { return; } @@ -132,8 +132,9 @@ BuildVars::save() return; } - Json::StyledStreamWriter writer(" "); - + Json::StreamWriterBuilder factory; + factory["indentation"] = " "; + std::unique_ptr<Json::StreamWriter> const writer(factory.newStreamWriter()); Json::Value json(Json::objectValue); for (map<string,string>::const_iterator it = m_cache.begin(); it != m_cache.end(); it++) { @@ -141,7 +142,7 @@ BuildVars::save() } std::ofstream stream(m_filename, std::ofstream::binary); - writer.write(stream, json); + writer->write(json, &stream); } string @@ -212,8 +213,8 @@ read_modules(const string& buildOut, const string& device, map<string,Module>* r } Json::Value json; - Json::Reader reader; - if (!reader.parse(stream, json)) { + Json::CharReaderBuilder builder; + if (!Json::parseFromStream(builder, stream, &json, /* errorMessage = */ nullptr)) { json_error(filename, "can't parse json format", quiet); return; } diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp index 677bee2cce81..e53ba3e18a86 100644 --- a/tools/codegen/Android.bp +++ b/tools/codegen/Android.bp @@ -1,3 +1,12 @@ +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"], +} + java_binary_host { name: "codegen_cli", manifest: "manifest.txt", diff --git a/tools/dump-coverage/Android.bp b/tools/dump-coverage/Android.bp index 4519ce3636bf..f38177390972 100644 --- a/tools/dump-coverage/Android.bp +++ b/tools/dump-coverage/Android.bp @@ -15,10 +15,20 @@ // // Build variants {target,host} x {32,64} +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"], +} + cc_library { name: "libdumpcoverage", srcs: ["dump_coverage.cc"], header_libs: [ + "jni_headers", "libopenjdkjvmti_headers", ], diff --git a/tools/fonts/OWNERS b/tools/fonts/OWNERS new file mode 100644 index 000000000000..a538331dd3f4 --- /dev/null +++ b/tools/fonts/OWNERS @@ -0,0 +1 @@ +include /core/java/android/graphics/fonts/OWNERS diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py index 6683e2abb0da..7de706502618 100755 --- a/tools/fonts/fontchain_linter.py +++ b/tools/fonts/fontchain_linter.py @@ -11,6 +11,12 @@ from fontTools import ttLib EMOJI_VS = 0xFE0F +#TODO(179952916): Rename CutiveMono and DancingScript +CANONICAL_NAME_EXCEPTION_LIST = [ + 'CutiveMono.ttf', + 'DancingScript-Regular.ttf', +] + LANG_TO_SCRIPT = { 'as': 'Beng', 'be': 'Cyrl', @@ -286,7 +292,7 @@ def parse_fonts_xml(fonts_xml_path): if not fallback_for: if not name or name == 'sans-serif': - for _, fallback in _fallback_chains.iteritems(): + for _, fallback in _fallback_chains.items(): fallback.append(record) else: _fallback_chains[name].append(record) @@ -327,7 +333,7 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji): assert sequence in all_emoji, ( 'Emoji font should not support %s.' % printable(sequence)) - for first, second in sorted(equivalent_emoji.items()): + for first, second in equivalent_emoji.items(): assert coverage[first] == coverage[second], ( '%s and %s should map to the same glyph.' % ( printable(first), @@ -352,7 +358,7 @@ def check_emoji_font_coverage(emoji_font, all_emoji, equivalent_emoji): def check_emoji_defaults(default_emoji): missing_text_chars = _emoji_properties['Emoji'] - default_emoji - for name, fallback_chain in _fallback_chains.iteritems(): + for name, fallback_chain in _fallback_chains.items(): emoji_font_seen = False for record in fallback_chain: if 'Zsye' in record.scripts: @@ -369,7 +375,7 @@ def check_emoji_defaults(default_emoji): continue # Check default emoji-style characters - assert_font_supports_none_of_chars(record.font, sorted(default_emoji), name) + assert_font_supports_none_of_chars(record.font, default_emoji, name) # Mark default text-style characters appearing in fonts above the emoji # font as seen @@ -412,7 +418,7 @@ def parse_unicode_datafile(file_path, reverse=False): char_start, char_end = chars.split('..') char_start = int(char_start, 16) char_end = int(char_end, 16) - additions = xrange(char_start, char_end+1) + additions = range(char_start, char_end+1) else: # singe character additions = [int(chars, 16)] if reverse: @@ -478,7 +484,7 @@ def parse_ucd(ucd_path): # Unicode 12.0 adds Basic_Emoji in emoji-sequences.txt. We ignore them here since we are already # checking the emoji presentations with emoji-variation-sequences.txt. # Please refer to http://unicode.org/reports/tr51/#def_basic_emoji_set . - _emoji_sequences = {k: v for k, v in _emoji_sequences.iteritems() if not v == 'Basic_Emoji' } + _emoji_sequences = {k: v for k, v in _emoji_sequences.items() if not v == 'Basic_Emoji' } def remove_emoji_variation_exclude(source, items): @@ -551,7 +557,7 @@ def reverse_emoji(seq): rev = list(reversed(seq)) # if there are fitzpatrick modifiers in the sequence, keep them after # the emoji they modify - for i in xrange(1, len(rev)): + for i in range(1, len(rev)): if is_fitzpatrick_modifier(rev[i-1]): rev[i], rev[i-1] = rev[i-1], rev[i] return tuple(rev) @@ -620,7 +626,7 @@ def compute_expected_emoji(): def check_compact_only_fallback(): - for name, fallback_chain in _fallback_chains.iteritems(): + for name, fallback_chain in _fallback_chains.items(): for record in fallback_chain: if record.variant == 'compact': same_script_elegants = [x for x in fallback_chain @@ -650,7 +656,7 @@ def check_vertical_metrics(): def check_cjk_punctuation(): cjk_scripts = {'Hans', 'Hant', 'Jpan', 'Kore'} cjk_punctuation = range(0x3000, 0x301F + 1) - for name, fallback_chain in _fallback_chains.iteritems(): + for name, fallback_chain in _fallback_chains.items(): for record in fallback_chain: if record.scripts.intersection(cjk_scripts): # CJK font seen. Stop checking the rest of the fonts. @@ -658,6 +664,53 @@ def check_cjk_punctuation(): assert_font_supports_none_of_chars(record.font, cjk_punctuation, name) +def getPostScriptName(font): + ttf = open_font(font) + nameTable = ttf['name'] + for name in nameTable.names: + if name.nameID == 6 and name.platformID == 3 and name.platEncID == 1 and name.langID == 0x0409: + return str(name) + + +def getSuffix(font): + file_path, index = font + with open(path.join(_fonts_dir, file_path), 'rb') as f: + tag = f.read(4) + isCollection = tag == b'ttcf' + + ttf = open_font(font) + isType1 = ('CFF ' in ttf or 'CFF2' in ttf) + + if isType1: + if isCollection: + return '.otc' + else: + return '.otf' + else: + if isCollection: + return '.ttc' + else: + return '.ttf' + + +def check_canonical_name(): + for record in _all_fonts: + file_name, index = record.font + if file_name in CANONICAL_NAME_EXCEPTION_LIST: + continue + + if index and index != 0: + continue + + psName = getPostScriptName(record.font) + assert psName, 'PostScript must be defined' + + suffix = getSuffix(record.font) + canonicalName = '%s%s' % (psName, suffix) + + assert file_name == canonicalName, ( + '%s is not a canonical name. Must be %s' % (file_name, canonicalName)) + def main(): global _fonts_dir target_out = sys.argv[1] @@ -675,6 +728,8 @@ def main(): check_cjk_punctuation() + check_canonical_name() + check_emoji = sys.argv[2] if check_emoji == 'true': ucd_path = sys.argv[3] diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp deleted file mode 100644 index e0eb06cbea7f..000000000000 --- a/tools/hiddenapi/Android.bp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -python_binary_host { - name: "merge_csv", - main: "merge_csv.py", - srcs: ["merge_csv.py"], - version: { - py2: { - enabled: false, - }, - py3: { - enabled: true, - embedded_launcher: true - }, - }, -} diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py deleted file mode 100755 index 0b2077d9bba0..000000000000 --- a/tools/hiddenapi/generate_hiddenapi_lists.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2018 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. -""" -Generate API lists for non-SDK API enforcement. -""" -import argparse -from collections import defaultdict -import os -import sys -import re -import functools - -# Names of flags recognized by the `hiddenapi` tool. -FLAG_WHITELIST = "whitelist" -FLAG_GREYLIST = "greylist" -FLAG_BLACKLIST = "blacklist" -FLAG_GREYLIST_MAX_O = "greylist-max-o" -FLAG_GREYLIST_MAX_P = "greylist-max-p" -FLAG_GREYLIST_MAX_Q = "greylist-max-q" -FLAG_CORE_PLATFORM_API = "core-platform-api" -FLAG_PUBLIC_API = "public-api" -FLAG_SYSTEM_API = "system-api" -FLAG_TEST_API = "test-api" - -# List of all known flags. -FLAGS_API_LIST = [ - FLAG_WHITELIST, - FLAG_GREYLIST, - FLAG_BLACKLIST, - FLAG_GREYLIST_MAX_O, - FLAG_GREYLIST_MAX_P, - FLAG_GREYLIST_MAX_Q, -] -ALL_FLAGS = FLAGS_API_LIST + [ - FLAG_CORE_PLATFORM_API, - FLAG_PUBLIC_API, - FLAG_SYSTEM_API, - FLAG_TEST_API, - ] - -FLAGS_API_LIST_SET = set(FLAGS_API_LIST) -ALL_FLAGS_SET = set(ALL_FLAGS) - -# Suffix used in command line args to express that only known and -# otherwise unassigned entries should be assign the given flag. -# For example, the P dark greylist is checked in as it was in P, -# but signatures have changes since then. The flag instructs this -# script to skip any entries which do not exist any more. -FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts" - -# Suffix used in command line args to express that all apis within a given set -# of packages should be assign the given flag. -FLAG_PACKAGES_SUFFIX = "-packages" - -# Regex patterns of fields/methods used in serialization. These are -# considered public API despite being hidden. -SERIALIZATION_PATTERNS = [ - r'readObject\(Ljava/io/ObjectInputStream;\)V', - r'readObjectNoData\(\)V', - r'readResolve\(\)Ljava/lang/Object;', - r'serialVersionUID:J', - r'serialPersistentFields:\[Ljava/io/ObjectStreamField;', - r'writeObject\(Ljava/io/ObjectOutputStream;\)V', - r'writeReplace\(\)Ljava/lang/Object;', -] - -# Single regex used to match serialization API. It combines all the -# SERIALIZATION_PATTERNS into a single regular expression. -SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$') - -# Predicates to be used with filter_apis. -HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags) -IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api) - -def get_args(): - """Parses command line arguments. - - Returns: - Namespace: dictionary of parsed arguments - """ - parser = argparse.ArgumentParser() - parser.add_argument('--output', required=True) - parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE', - help='CSV files to be merged into output') - - for flag in ALL_FLAGS: - ignore_conflicts_flag = flag + FLAG_IGNORE_CONFLICTS_SUFFIX - packages_flag = flag + FLAG_PACKAGES_SUFFIX - parser.add_argument('--' + flag, dest=flag, nargs='*', default=[], metavar='TXT_FILE', - help='lists of entries with flag "' + flag + '"') - parser.add_argument('--' + ignore_conflicts_flag, dest=ignore_conflicts_flag, nargs='*', - default=[], metavar='TXT_FILE', - help='lists of entries with flag "' + flag + - '". skip entry if missing or flag conflict.') - parser.add_argument('--' + packages_flag, dest=packages_flag, nargs='*', - default=[], metavar='TXT_FILE', - help='lists of packages to be added to ' + flag + ' list') - - return parser.parse_args() - -def read_lines(filename): - """Reads entire file and return it as a list of lines. - - Lines which begin with a hash are ignored. - - Args: - filename (string): Path to the file to read from. - - Returns: - Lines of the file as a list of string. - """ - with open(filename, 'r') as f: - lines = f.readlines(); - lines = filter(lambda line: not line.startswith('#'), lines) - lines = map(lambda line: line.strip(), lines) - return set(lines) - -def write_lines(filename, lines): - """Writes list of lines into a file, overwriting the file it it exists. - - Args: - filename (string): Path to the file to be writting into. - lines (list): List of strings to write into the file. - """ - lines = map(lambda line: line + '\n', lines) - with open(filename, 'w') as f: - f.writelines(lines) - -def extract_package(signature): - """Extracts the package from a signature. - - Args: - signature (string): JNI signature of a method or field. - - Returns: - The package name of the class containing the field/method. - """ - full_class_name = signature.split(";->")[0] - # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy - if (full_class_name[0] != "L"): - raise ValueError("Expected to start with 'L': %s" % full_class_name) - full_class_name = full_class_name[1:] - # If full_class_name doesn't contain '/', then package_name will be ''. - package_name = full_class_name.rpartition("/")[0] - return package_name.replace('/', '.') - -class FlagsDict: - def __init__(self): - self._dict_keyset = set() - self._dict = defaultdict(set) - - def _check_entries_set(self, keys_subset, source): - assert isinstance(keys_subset, set) - assert keys_subset.issubset(self._dict_keyset), ( - "Error processing: {}\n" - "The following entries were unexpected:\n" - "{}" - "Please visit go/hiddenapi for more information.").format( - source, "".join(map(lambda x: " " + str(x), keys_subset - self._dict_keyset))) - - def _check_flags_set(self, flags_subset, source): - assert isinstance(flags_subset, set) - assert flags_subset.issubset(ALL_FLAGS_SET), ( - "Error processing: {}\n" - "The following flags were not recognized: \n" - "{}\n" - "Please visit go/hiddenapi for more information.").format( - source, "\n".join(flags_subset - ALL_FLAGS_SET)) - - def filter_apis(self, filter_fn): - """Returns APIs which match a given predicate. - - This is a helper function which allows to filter on both signatures (keys) and - flags (values). The built-in filter() invokes the lambda only with dict's keys. - - Args: - filter_fn : Function which takes two arguments (signature/flags) and returns a boolean. - - Returns: - A set of APIs which match the predicate. - """ - return set(filter(lambda x: filter_fn(x, self._dict[x]), self._dict_keyset)) - - def get_valid_subset_of_unassigned_apis(self, api_subset): - """Sanitizes a key set input to only include keys which exist in the dictionary - and have not been assigned any API list flags. - - Args: - entries_subset (set/list): Key set to be sanitized. - - Returns: - Sanitized key set. - """ - assert isinstance(api_subset, set) - return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED)) - - def generate_csv(self): - """Constructs CSV entries from a dictionary. - - Returns: - List of lines comprising a CSV file. See "parse_and_merge_csv" for format description. - """ - return sorted(map(lambda api: ",".join([api] + sorted(self._dict[api])), self._dict)) - - def parse_and_merge_csv(self, csv_lines, source = "<unknown>"): - """Parses CSV entries and merges them into a given dictionary. - - The expected CSV format is: - <api signature>,<flag1>,<flag2>,...,<flagN> - - Args: - csv_lines (list of strings): Lines read from a CSV file. - source (string): Origin of `csv_lines`. Will be printed in error messages. - - Throws: - AssertionError if parsed flags are invalid. - """ - # Split CSV lines into arrays of values. - csv_values = [ line.split(',') for line in csv_lines ] - - # Update the full set of API signatures. - self._dict_keyset.update([ csv[0] for csv in csv_values ]) - - # Check that all flags are known. - csv_flags = set(functools.reduce( - lambda x, y: set(x).union(y), - [ csv[1:] for csv in csv_values ], - [])) - self._check_flags_set(csv_flags, source) - - # Iterate over all CSV lines, find entry in dict and append flags to it. - for csv in csv_values: - flags = csv[1:] - if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags): - flags.append(FLAG_WHITELIST) - self._dict[csv[0]].update(flags) - - def assign_flag(self, flag, apis, source="<unknown>"): - """Assigns a flag to given subset of entries. - - Args: - flag (string): One of ALL_FLAGS. - apis (set): Subset of APIs to receive the flag. - source (string): Origin of `entries_subset`. Will be printed in error messages. - - Throws: - AssertionError if parsed API signatures of flags are invalid. - """ - # Check that all APIs exist in the dict. - self._check_entries_set(apis, source) - - # Check that the flag is known. - self._check_flags_set(set([ flag ]), source) - - # Iterate over the API subset, find each entry in dict and assign the flag to it. - for api in apis: - self._dict[api].add(flag) - -def main(argv): - # Parse arguments. - args = vars(get_args()) - - # Initialize API->flags dictionary. - flags = FlagsDict() - - # Merge input CSV files into the dictionary. - # Do this first because CSV files produced by parsing API stubs will - # contain the full set of APIs. Subsequent additions from text files - # will be able to detect invalid entries, and/or filter all as-yet - # unassigned entries. - for filename in args["csv"]: - flags.parse_and_merge_csv(read_lines(filename), filename) - - # Combine inputs which do not require any particular order. - # (1) Assign serialization API to whitelist. - flags.assign_flag(FLAG_WHITELIST, flags.filter_apis(IS_SERIALIZATION)) - - # (2) Merge text files with a known flag into the dictionary. - for flag in ALL_FLAGS: - for filename in args[flag]: - flags.assign_flag(flag, read_lines(filename), filename) - - # Merge text files where conflicts should be ignored. - # This will only assign the given flag if: - # (a) the entry exists, and - # (b) it has not been assigned any other flag. - # Because of (b), this must run after all strict assignments have been performed. - for flag in ALL_FLAGS: - for filename in args[flag + FLAG_IGNORE_CONFLICTS_SUFFIX]: - valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(filename)) - flags.assign_flag(flag, valid_entries, filename) - - # All members in the specified packages will be assigned the appropriate flag. - for flag in ALL_FLAGS: - for filename in args[flag + FLAG_PACKAGES_SUFFIX]: - packages_needing_list = set(read_lines(filename)) - should_add_signature_to_list = lambda sig,lists: extract_package( - sig) in packages_needing_list and not lists - valid_entries = flags.filter_apis(should_add_signature_to_list) - flags.assign_flag(flag, valid_entries) - - # Assign all remaining entries to the blacklist. - flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED)) - - # Write output. - write_lines(args["output"], flags.generate_csv()) - -if __name__ == "__main__": - main(sys.argv) diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py deleted file mode 100755 index 55c3a7d718db..000000000000 --- a/tools/hiddenapi/generate_hiddenapi_lists_test.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2018 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. -"""Unit tests for Hidden API list generation.""" -import unittest -from generate_hiddenapi_lists import * - -class TestHiddenapiListGeneration(unittest.TestCase): - - def test_filter_apis(self): - # Initialize flags so that A and B are put on the whitelist and - # C, D, E are left unassigned. Try filtering for the unassigned ones. - flags = FlagsDict() - flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST, - 'C', 'D', 'E']) - filter_set = flags.filter_apis(lambda api, flags: not flags) - self.assertTrue(isinstance(filter_set, set)) - self.assertEqual(filter_set, set([ 'C', 'D', 'E' ])) - - def test_get_valid_subset_of_unassigned_keys(self): - # Create flags where only A is unassigned. - flags = FlagsDict() - flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C']) - flags.assign_flag(FLAG_GREYLIST, set(['C'])) - self.assertEqual(flags.generate_csv(), - [ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ]) - - # Check three things: - # (1) B is selected as valid unassigned - # (2) A is not selected because it is assigned 'whitelist' - # (3) D is not selected because it is not a valid key - self.assertEqual( - flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ])) - - def test_parse_and_merge_csv(self): - flags = FlagsDict() - - # Test empty CSV entry. - self.assertEqual(flags.generate_csv(), []) - - # Test new additions. - flags.parse_and_merge_csv([ - 'A,' + FLAG_GREYLIST, - 'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O, - 'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST, - 'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API, - 'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API, - ]) - self.assertEqual(flags.generate_csv(), [ - 'A,' + FLAG_GREYLIST, - 'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O, - 'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST, - 'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API, - 'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API, - ]) - - # Test unknown flag. - with self.assertRaises(AssertionError): - flags.parse_and_merge_csv([ 'Z,foo' ]) - - def test_assign_flag(self): - flags = FlagsDict() - flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B']) - - # Test new additions. - flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ])) - self.assertEqual(flags.generate_csv(), - [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ]) - - # Test invalid API signature. - with self.assertRaises(AssertionError): - flags.assign_flag(FLAG_WHITELIST, set([ 'C' ])) - - # Test invalid flag. - with self.assertRaises(AssertionError): - flags.assign_flag('foo', set([ 'A' ])) - - def test_extract_package(self): - signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;' - expected_package = 'com.foo.bar' - self.assertEqual(extract_package(signature), expected_package) - - signature = 'Lcom/foo1/bar/MyClass;->method2()V' - expected_package = 'com.foo1.bar' - self.assertEqual(extract_package(signature), expected_package) - - signature = 'Lcom/foo_bar/baz/MyClass;->method3()V' - expected_package = 'com.foo_bar.baz' - self.assertEqual(extract_package(signature), expected_package) - -if __name__ == '__main__': - unittest.main() diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py deleted file mode 100755 index 6a5b0e1347b2..000000000000 --- a/tools/hiddenapi/merge_csv.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2018 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. -""" -Merge multiple CSV files, possibly with different columns. -""" - -import argparse -import csv -import io - -from zipfile import ZipFile - -args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.') -args_parser.add_argument('--header', help='Comma separated field names; ' - 'if missing determines the header from input files.') -args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.') -args_parser.add_argument('--output', help='Output file for merged CSV.', - default='-', type=argparse.FileType('w')) -args_parser.add_argument('files', nargs=argparse.REMAINDER) -args = args_parser.parse_args() - - -def dict_reader(input): - return csv.DictReader(input, delimiter=',', quotechar='|') - - -if args.zip_input and len(args.files) > 0: - raise ValueError('Expecting either a single ZIP with CSV files' - ' or a list of CSV files as input; not both.') - -csv_readers = [] -if len(args.files) > 0: - for file in args.files: - csv_readers.append(dict_reader(open(file, 'r'))) -elif args.zip_input: - with ZipFile(args.zip_input) as zip: - for entry in zip.namelist(): - if entry.endswith('.uau'): - csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r')))) - -headers = set() -if args.header: - fieldnames = args.header.split(',') -else: - # Build union of all columns from source files: - for reader in csv_readers: - headers = headers.union(reader.fieldnames) - fieldnames = sorted(headers) - -# Concatenate all files to output: -writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL, - dialect='unix', fieldnames=fieldnames) -writer.writeheader() -for reader in csv_readers: - for row in reader: - writer.writerow(row) diff --git a/tools/incident_report/Android.bp b/tools/incident_report/Android.bp index f2d0d0f3e553..fe519c7edff4 100644 --- a/tools/incident_report/Android.bp +++ b/tools/incident_report/Android.bp @@ -17,6 +17,15 @@ // ========================================================== // Build the host executable: incident_report // ========================================================== +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"], +} + cc_binary_host { name: "incident_report", diff --git a/tools/incident_report/OWNERS b/tools/incident_report/OWNERS new file mode 100644 index 000000000000..f76611555dbb --- /dev/null +++ b/tools/incident_report/OWNERS @@ -0,0 +1 @@ +include /cmds/incidentd/OWNERS diff --git a/tools/incident_section_gen/Android.bp b/tools/incident_section_gen/Android.bp index 0c7797eacf09..8227b60d6c09 100644 --- a/tools/incident_section_gen/Android.bp +++ b/tools/incident_section_gen/Android.bp @@ -17,6 +17,15 @@ // ========================================================== // Build the host executable: incident-section-gen // ========================================================== +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"], +} + cc_binary_host { name: "incident-section-gen", cflags: [ diff --git a/tools/incident_section_gen/OWNERS b/tools/incident_section_gen/OWNERS new file mode 100644 index 000000000000..f76611555dbb --- /dev/null +++ b/tools/incident_section_gen/OWNERS @@ -0,0 +1 @@ +include /cmds/incidentd/OWNERS diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp index 786223a430ae..dd266ffe0f16 100644 --- a/tools/incident_section_gen/main.cpp +++ b/tools/incident_section_gen/main.cpp @@ -368,10 +368,13 @@ static bool generatePrivacyFlags(const Descriptor* descriptor, const Destination // Don't generate a variable twice if (!hasDefaultFlags[i]) variableNames[fieldName] = false; } + // hasDefaultFlags[i] has been initialized in the above for-loop, + // but clang-tidy analyzer still report uninitized values. + // So we use NOLINT to suppress those false positives. bool allDefaults = true; for (size_t i=0; i<fieldsInOrder.size(); i++) { - allDefaults &= hasDefaultFlags[i]; + allDefaults &= hasDefaultFlags[i]; // NOLINT(clang-analyzer-core.uninitialized.Assign) } parents->erase(messageName); // erase the message type name when exit the message. @@ -384,7 +387,7 @@ static bool generatePrivacyFlags(const Descriptor* descriptor, const Destination printf("Privacy* %s[] = {\n", messageName.c_str()); for (size_t i=0; i<fieldsInOrder.size(); i++) { const FieldDescriptor* field = fieldsInOrder[i]; - if (hasDefaultFlags[i]) continue; + if (hasDefaultFlags[i]) continue; // NOLINT(clang-analyzer-core.uninitialized.Branch) printf(" &%s,\n", getFieldName(field).c_str()); policyCount++; } diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp index 7b2ca9a65242..cabe1398903e 100644 --- a/tools/lock_agent/Android.bp +++ b/tools/lock_agent/Android.bp @@ -1,3 +1,12 @@ +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"], +} + cc_library { name: "liblockagent", host_supported: false, diff --git a/tools/locked_region_code_injection/Android.bp b/tools/locked_region_code_injection/Android.bp index 5f81a2eeb130..98c0e69cbf8e 100644 --- a/tools/locked_region_code_injection/Android.bp +++ b/tools/locked_region_code_injection/Android.bp @@ -1,3 +1,12 @@ +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"], +} + java_binary_host { name: "lockedregioncodeinjection", manifest: "manifest.txt", diff --git a/tools/obbtool/Android.bp b/tools/obbtool/Android.bp index f87965860ce1..1c50d18ed32b 100644 --- a/tools/obbtool/Android.bp +++ b/tools/obbtool/Android.bp @@ -4,6 +4,15 @@ // Opaque Binary Blob (OBB) Tool // +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"], +} + cc_binary_host { name: "obbtool", diff --git a/tools/powermodel/Android.bp b/tools/powermodel/Android.bp index f597aab0f464..35c135614027 100644 --- a/tools/powermodel/Android.bp +++ b/tools/powermodel/Android.bp @@ -1,4 +1,13 @@ +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"], +} + java_library_host { name: "powermodel", srcs: [ @@ -23,4 +32,3 @@ java_test_host { "mockito", ], } - diff --git a/tools/powerstats/OWNERS b/tools/powerstats/OWNERS new file mode 100644 index 000000000000..d68066bb8c40 --- /dev/null +++ b/tools/powerstats/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/power/OWNERS diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp index 87b31d22af32..73caac694cb4 100644 --- a/tools/preload-check/Android.bp +++ b/tools/preload-check/Android.bp @@ -12,10 +12,19 @@ // 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"], +} + java_test_host { name: "PreloadCheck", srcs: ["src/**/*.java"], - java_resources: [":preloaded-classes-blacklist"], + java_resources: [":preloaded-classes-denylist"], libs: ["tradefed"], test_suites: ["general-tests"], required: ["preload-check-device"], diff --git a/tools/preload-check/device/Android.bp b/tools/preload-check/device/Android.bp index f40d8ba5a287..2a866c426336 100644 --- a/tools/preload-check/device/Android.bp +++ b/tools/preload-check/device/Android.bp @@ -12,6 +12,15 @@ // 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"], +} + java_test_helper_library { name: "preload-check-device", host_supported: false, diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java index 00fd414e3ee2..3d851531d7e7 100644 --- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java +++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java @@ -69,13 +69,13 @@ public class PreloadCheck implements IDeviceTest { } /** - * Test the classes mentioned in the embedded preloaded-classes blacklist. + * Test the classes mentioned in the embedded preloaded-classes denylist. */ @Test - public void testBlackList() throws Exception { + public void testDenyList() throws Exception { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass() - .getResourceAsStream("/preloaded-classes-blacklist")))) { + .getResourceAsStream("/preloaded-classes-denylist")))) { String s; while ((s = br.readLine()) != null) { s = s.trim(); diff --git a/tools/preload/Android.bp b/tools/preload/Android.bp index 809ee474969a..fad015ae35e0 100644 --- a/tools/preload/Android.bp +++ b/tools/preload/Android.bp @@ -1,3 +1,13 @@ +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 + // SPDX-license-identifier-MIT + default_applicable_licenses: ["frameworks_base_license"], +} + java_library_host { name: "preload", srcs: [ diff --git a/tools/preload/loadclass/Android.bp b/tools/preload/loadclass/Android.bp index 6f12015dae2b..ba36061e5fb6 100644 --- a/tools/preload/loadclass/Android.bp +++ b/tools/preload/loadclass/Android.bp @@ -1,3 +1,12 @@ +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"], +} + java_test { name: "loadclass", srcs: ["**/*.java"], diff --git a/tools/processors/staledataclass/Android.bp b/tools/processors/staledataclass/Android.bp index 58a7d346ce1f..1e5097662a0a 100644 --- a/tools/processors/staledataclass/Android.bp +++ b/tools/processors/staledataclass/Android.bp @@ -1,4 +1,13 @@ +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"], +} + java_plugin { name: "staledataclass-annotation-processor", processor_class: "android.processor.staledataclass.StaleDataclassProcessor", diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp index 069e61f5b921..ea9974f06a64 100644 --- a/tools/processors/view_inspector/Android.bp +++ b/tools/processors/view_inspector/Android.bp @@ -1,3 +1,12 @@ +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"], +} + java_plugin { name: "view-inspector-annotation-processor", diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp index ce551bd0cc10..ea3cd427a130 100644 --- a/tools/protologtool/Android.bp +++ b/tools/protologtool/Android.bp @@ -1,3 +1,12 @@ +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"], +} + java_library_host { name: "protologtool-lib", srcs: [ @@ -25,9 +34,13 @@ java_test_host { srcs: [ "tests/**/*.kt", ], + test_options: { + unit_test: true, + }, static_libs: [ "protologtool-lib", "junit", "mockito", + "objenesis", ], } diff --git a/tools/sdkparcelables/Android.bp b/tools/sdkparcelables/Android.bp index 00fb8aa20b18..9d773e44faea 100644 --- a/tools/sdkparcelables/Android.bp +++ b/tools/sdkparcelables/Android.bp @@ -1,3 +1,12 @@ +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"], +} + java_binary_host { name: "sdkparcelables", manifest: "manifest.txt", diff --git a/tools/split-select/Android.bp b/tools/split-select/Android.bp index ee822b7d7fa7..c12fc6a7f253 100644 --- a/tools/split-select/Android.bp +++ b/tools/split-select/Android.bp @@ -19,6 +19,15 @@ // targets here. // ========================================================== +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"], +} + cc_defaults { name: "split-select_defaults", diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp index d3eb012a80e9..e6966db0aa00 100644 --- a/tools/split-select/Main.cpp +++ b/tools/split-select/Main.cpp @@ -182,14 +182,18 @@ static bool getAppInfo(const String8& path, AppInfo& outInfo) { if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) { outInfo.minSdkVersion = xml.getAttributeData(idx); } else if (type == Res_value::TYPE_STRING) { - String8 minSdk8(xml.getStrings().string8ObjectAt(idx)); - char* endPtr; - int minSdk = strtol(minSdk8.string(), &endPtr, 10); - if (endPtr != minSdk8.string() + minSdk8.size()) { - fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n", - minSdk8.string()); + auto minSdk8 = xml.getStrings().string8ObjectAt(idx); + if (!minSdk8.has_value()) { + fprintf(stderr, "warning: failed to retrieve android:minSdkVersion.\n"); } else { - outInfo.minSdkVersion = minSdk; + char *endPtr; + int minSdk = strtol(minSdk8->string(), &endPtr, 10); + if (endPtr != minSdk8->string() + minSdk8->size()) { + fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n", + minSdk8->string()); + } else { + outInfo.minSdkVersion = minSdk; + } } } else { fprintf(stderr, "warning: unrecognized value for android:minSdkVersion.\n"); diff --git a/tools/split-select/OWNERS b/tools/split-select/OWNERS new file mode 100644 index 000000000000..6c50ede5bb8c --- /dev/null +++ b/tools/split-select/OWNERS @@ -0,0 +1 @@ +include /core/java/android/content/res/OWNERS
\ No newline at end of file diff --git a/tools/stats_log_api_gen/.clang-format b/tools/stats_log_api_gen/.clang-format deleted file mode 100644 index cead3a079435..000000000000 --- a/tools/stats_log_api_gen/.clang-format +++ /dev/null @@ -1,17 +0,0 @@ -BasedOnStyle: Google -AllowShortIfStatementsOnASingleLine: true -AllowShortFunctionsOnASingleLine: false -AllowShortLoopsOnASingleLine: true -BinPackArguments: true -BinPackParameters: true -ColumnLimit: 100 -CommentPragmas: NOLINT:.* -ContinuationIndentWidth: 8 -DerivePointerAlignment: false -IndentWidth: 4 -PointerAlignment: Left -TabWidth: 4 -AccessModifierOffset: -4 -IncludeCategories: - - Regex: '^"Log\.h"' - Priority: -1 diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp deleted file mode 100644 index e3b6db08c503..000000000000 --- a/tools/stats_log_api_gen/Android.bp +++ /dev/null @@ -1,131 +0,0 @@ -// -// Copyright (C) 2017 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. -// - -// ========================================================== -// Build the host executable: stats-log-api-gen -// ========================================================== -cc_binary_host { - name: "stats-log-api-gen", - srcs: [ - "Collation.cpp", - "java_writer.cpp", - "java_writer_q.cpp", - "main.cpp", - "native_writer.cpp", - "utils.cpp", - ], - cflags: [ - "-Wall", - "-Werror", - ], - - shared_libs: [ - "libstats_proto_host", - "libprotobuf-cpp-full", - "libbase", - ], - - proto: { - type: "full", - }, -} - -// ========================================================== -// Build the host test executable: stats-log-api-gen -// ========================================================== -cc_test_host { - name: "stats-log-api-gen-test", - cflags: [ - "-Wall", - "-Wextra", - "-Werror", - "-g", - "-DUNIT_TEST", - ], - srcs: [ - "Collation.cpp", - "test_collation.cpp", - "test.proto", - ], - - static_libs: [ - "libgmock_host", - ], - - shared_libs: [ - "libstats_proto_host", - "libprotobuf-cpp-full", - ], - - proto: { - type: "full", - include_dirs: [ - "external/protobuf/src", - ], - }, -} - -// ========================================================== -// Native library -// ========================================================== -genrule { - name: "statslog.h", - tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog.h", - out: [ - "statslog.h", - ], -} - -genrule { - name: "statslog.cpp", - tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog.cpp", - out: [ - "statslog.cpp", - ], -} - -cc_library { - name: "libstatslog", - host_supported: true, - generated_sources: [ - "statslog.cpp", - ], - generated_headers: [ - "statslog.h" - ], - cflags: [ - "-Wall", - "-Werror", - ], - export_generated_headers: [ - "statslog.h" - ], - shared_libs: [ - "liblog", - "libcutils", - ], - target: { - android: { - shared_libs: ["libstatssocket"], - }, - host: { - static_libs: ["libstatssocket"], - }, - }, -} - diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp deleted file mode 100644 index a230de46dcf3..000000000000 --- a/tools/stats_log_api_gen/Collation.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (C) 2017, 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 "Collation.h" - -#include <stdio.h> - -#include <map> - -#include "frameworks/base/cmds/statsd/src/atoms.pb.h" - -namespace android { -namespace stats_log_api_gen { - -using google::protobuf::EnumDescriptor; -using google::protobuf::FieldDescriptor; -using google::protobuf::FileDescriptor; -using google::protobuf::SourceLocation; -using std::make_shared; -using std::map; - -const bool dbg = false; - -// -// AtomDecl class -// - -AtomDecl::AtomDecl() : code(0), name() { -} - -AtomDecl::AtomDecl(const AtomDecl& that) - : code(that.code), - name(that.name), - message(that.message), - fields(that.fields), - fieldNumberToAnnotations(that.fieldNumberToAnnotations), - primaryFields(that.primaryFields), - exclusiveField(that.exclusiveField), - defaultState(that.defaultState), - triggerStateReset(that.triggerStateReset), - nested(that.nested), - uidField(that.uidField) { -} - -AtomDecl::AtomDecl(int c, const string& n, const string& m) : code(c), name(n), message(m) { -} - -AtomDecl::~AtomDecl() { -} - -/** - * Print an error message for a FieldDescriptor, including the file name and - * line number. - */ -static void print_error(const FieldDescriptor* field, const char* format, ...) { - const Descriptor* message = field->containing_type(); - const FileDescriptor* file = message->file(); - - SourceLocation loc; - if (field->GetSourceLocation(&loc)) { - // TODO: this will work if we can figure out how to pass - // --include_source_info to protoc - fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line); - } else { - fprintf(stderr, "%s: ", file->name().c_str()); - } - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} - -/** - * Convert a protobuf type into a java type. - */ -static java_type_t java_type(const FieldDescriptor* field) { - int protoType = field->type(); - switch (protoType) { - case FieldDescriptor::TYPE_DOUBLE: - return JAVA_TYPE_DOUBLE; - case FieldDescriptor::TYPE_FLOAT: - return JAVA_TYPE_FLOAT; - case FieldDescriptor::TYPE_INT64: - return JAVA_TYPE_LONG; - case FieldDescriptor::TYPE_UINT64: - return JAVA_TYPE_LONG; - case FieldDescriptor::TYPE_INT32: - return JAVA_TYPE_INT; - case FieldDescriptor::TYPE_FIXED64: - return JAVA_TYPE_LONG; - case FieldDescriptor::TYPE_FIXED32: - return JAVA_TYPE_INT; - case FieldDescriptor::TYPE_BOOL: - return JAVA_TYPE_BOOLEAN; - case FieldDescriptor::TYPE_STRING: - return JAVA_TYPE_STRING; - case FieldDescriptor::TYPE_GROUP: - return JAVA_TYPE_UNKNOWN; - case FieldDescriptor::TYPE_MESSAGE: - // TODO: not the final package name - if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") { - return JAVA_TYPE_ATTRIBUTION_CHAIN; - } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") { - return JAVA_TYPE_KEY_VALUE_PAIR; - } else if (field->options().GetExtension(os::statsd::log_mode) == - os::statsd::LogMode::MODE_BYTES) { - return JAVA_TYPE_BYTE_ARRAY; - } else { - return JAVA_TYPE_OBJECT; - } - case FieldDescriptor::TYPE_BYTES: - return JAVA_TYPE_BYTE_ARRAY; - case FieldDescriptor::TYPE_UINT32: - return JAVA_TYPE_INT; - case FieldDescriptor::TYPE_ENUM: - return JAVA_TYPE_ENUM; - case FieldDescriptor::TYPE_SFIXED32: - return JAVA_TYPE_INT; - case FieldDescriptor::TYPE_SFIXED64: - return JAVA_TYPE_LONG; - case FieldDescriptor::TYPE_SINT32: - return JAVA_TYPE_INT; - case FieldDescriptor::TYPE_SINT64: - return JAVA_TYPE_LONG; - default: - return JAVA_TYPE_UNKNOWN; - } -} - -/** - * Gather the enums info. - */ -void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) { - for (int i = 0; i < enumDescriptor.value_count(); i++) { - atomField->enumValues[enumDescriptor.value(i)->number()] = - enumDescriptor.value(i)->name().c_str(); - } -} - -static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber, - const AnnotationId annotationId, - const AnnotationType annotationType, - const AnnotationValue annotationValue) { - if (dbg) { - printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(), - fieldNumber, annotationId, annotationType); - } - atomDecl->fieldNumberToAnnotations[fieldNumber].insert( - make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue)); -} - -static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field, - const int fieldNumber, const java_type_t& javaType) { - int errorCount = 0; - - if (field->options().HasExtension(os::statsd::state_field_option)) { - const os::statsd::StateAtomFieldOption& stateFieldOption = - field->options().GetExtension(os::statsd::state_field_option); - const bool primaryField = stateFieldOption.primary_field(); - const bool exclusiveState = stateFieldOption.exclusive_state(); - const bool primaryFieldFirstUid = stateFieldOption.primary_field_first_uid(); - - // Check the field is only one of primaryField, exclusiveState, or primaryFieldFirstUid. - if (primaryField + primaryFieldFirstUid + exclusiveState > 1) { - print_error(field, - "Field can be max 1 of primary_field, exclusive_state, " - "or primary_field_first_uid: '%s'\n", - atomDecl->message.c_str()); - errorCount++; - } - - if (primaryField) { - if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || - javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) { - print_error(field, "Invalid primary state field: '%s'\n", - atomDecl->message.c_str()); - errorCount++; - } else { - atomDecl->primaryFields.push_back(fieldNumber); - addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_PRIMARY_FIELD, - ANNOTATION_TYPE_BOOL, AnnotationValue(true)); - } - } - - if (primaryFieldFirstUid) { - if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) { - print_error(field, - "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: " - "'%s'\n", - atomDecl->message.c_str()); - errorCount++; - } else { - atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID); - addAnnotationToAtomDecl(atomDecl, fieldNumber, - ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, ANNOTATION_TYPE_BOOL, - AnnotationValue(true)); - } - } - - if (exclusiveState) { - if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || - javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) { - print_error(field, "Invalid exclusive state field: '%s'\n", - atomDecl->message.c_str()); - errorCount++; - } - - if (atomDecl->exclusiveField != 0) { - print_error(field, - "Cannot have more than one exclusive state field in an " - "atom: '%s'\n", - atomDecl->message.c_str()); - errorCount++; - } else { - atomDecl->exclusiveField = fieldNumber; - addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_EXCLUSIVE_STATE, - ANNOTATION_TYPE_BOOL, AnnotationValue(true)); - } - - if (stateFieldOption.has_default_state_value()) { - const int defaultState = stateFieldOption.default_state_value(); - atomDecl->defaultState = defaultState; - - addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE, - ANNOTATION_TYPE_INT, AnnotationValue(defaultState)); - } - - if (stateFieldOption.has_trigger_state_reset_value()) { - const int triggerStateReset = stateFieldOption.trigger_state_reset_value(); - - atomDecl->triggerStateReset = triggerStateReset; - addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_TRIGGER_STATE_RESET, - ANNOTATION_TYPE_INT, AnnotationValue(triggerStateReset)); - } - - if (stateFieldOption.has_nested()) { - const bool nested = stateFieldOption.nested(); - atomDecl->nested = nested; - - addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED, - ANNOTATION_TYPE_BOOL, AnnotationValue(nested)); - } - } - } - - if (field->options().GetExtension(os::statsd::is_uid) == true) { - if (javaType != JAVA_TYPE_INT) { - print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n", - atomDecl->message.c_str()); - errorCount++; - } - - if (atomDecl->uidField == 0) { - atomDecl->uidField = fieldNumber; - - addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID, - ANNOTATION_TYPE_BOOL, AnnotationValue(true)); - } else { - print_error(field, - "Cannot have more than one field in an atom with is_uid " - "annotation: '%s'\n", - atomDecl->message.c_str()); - errorCount++; - } - } - - return errorCount; -} - -/** - * Gather the info about an atom proto. - */ -int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) { - int errorCount = 0; - - // Build a sorted list of the fields. Descriptor has them in source file - // order. - map<int, const FieldDescriptor*> fields; - for (int j = 0; j < atom->field_count(); j++) { - const FieldDescriptor* field = atom->field(j); - fields[field->number()] = field; - } - - // Check that the parameters start at 1 and go up sequentially. - int expectedNumber = 1; - for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end(); - it++) { - const int number = it->first; - const FieldDescriptor* field = it->second; - if (number != expectedNumber) { - print_error(field, - "Fields must be numbered consecutively starting at 1:" - " '%s' is %d but should be %d\n", - field->name().c_str(), number, expectedNumber); - errorCount++; - expectedNumber = number; - continue; - } - expectedNumber++; - } - - // Check that only allowed types are present. Remove any invalid ones. - for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end(); - it++) { - const FieldDescriptor* field = it->second; - bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) == - os::statsd::LogMode::MODE_BYTES; - - java_type_t javaType = java_type(field); - - if (javaType == JAVA_TYPE_UNKNOWN) { - print_error(field, "Unknown type for field: %s\n", field->name().c_str()); - errorCount++; - continue; - } else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) { - // Allow attribution chain, but only at position 1. - print_error(field, "Message type not allowed for field in pushed atoms: %s\n", - field->name().c_str()); - errorCount++; - continue; - } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) { - print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str()); - errorCount++; - continue; - } - - if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) { - print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str()); - errorCount++; - continue; - } - - // Doubles are not supported yet. - if (javaType == JAVA_TYPE_DOUBLE) { - print_error(field, - "Doubles are not supported in atoms. Please change field %s " - "to float\n", - field->name().c_str()); - errorCount++; - continue; - } - - if (field->is_repeated() && - !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) { - print_error(field, - "Repeated fields are not supported in atoms. Please make " - "field %s not " - "repeated.\n", - field->name().c_str()); - errorCount++; - continue; - } - } - - // Check that if there's an attribution chain, it's at position 1. - for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end(); - it++) { - int number = it->first; - if (number != 1) { - const FieldDescriptor* field = it->second; - java_type_t javaType = java_type(field); - if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - print_error(field, - "AttributionChain fields must have field id 1, in message: '%s'\n", - atom->name().c_str()); - errorCount++; - } - } - } - - // Build the type signature and the atom data. - for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end(); - it++) { - const FieldDescriptor* field = it->second; - java_type_t javaType = java_type(field); - bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) == - os::statsd::LogMode::MODE_BYTES; - - AtomField atField(field->name(), javaType); - - if (javaType == JAVA_TYPE_ENUM) { - // All enums are treated as ints when it comes to function signatures. - collate_enums(*field->enum_type(), &atField); - } - - // Generate signature for pushed atoms - if (atomDecl->code < PULL_ATOM_START_ID) { - if (javaType == JAVA_TYPE_ENUM) { - // All enums are treated as ints when it comes to function signatures. - signature->push_back(JAVA_TYPE_INT); - } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) { - signature->push_back(JAVA_TYPE_BYTE_ARRAY); - } else { - signature->push_back(javaType); - } - } - - atomDecl->fields.push_back(atField); - - errorCount += collate_field_annotations(atomDecl, field, it->first, javaType); - } - - return errorCount; -} - -// This function flattens the fields of the AttributionNode proto in an Atom -// proto and generates the corresponding atom decl and signature. -bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl, - vector<java_type_t>* signature) { - // Build a sorted list of the fields. Descriptor has them in source file - // order. - map<int, const FieldDescriptor*> fields; - for (int j = 0; j < atom->field_count(); j++) { - const FieldDescriptor* field = atom->field(j); - fields[field->number()] = field; - } - - AtomDecl attributionDecl; - vector<java_type_t> attributionSignature; - collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl, - &attributionSignature); - - // Build the type signature and the atom data. - bool has_attribution_node = false; - for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end(); - it++) { - const FieldDescriptor* field = it->second; - java_type_t javaType = java_type(field); - if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(), - attributionDecl.fields.end()); - signature->insert(signature->end(), attributionSignature.begin(), - attributionSignature.end()); - has_attribution_node = true; - - } else { - AtomField atField(field->name(), javaType); - if (javaType == JAVA_TYPE_ENUM) { - // All enums are treated as ints when it comes to function signatures. - signature->push_back(JAVA_TYPE_INT); - collate_enums(*field->enum_type(), &atField); - } else { - signature->push_back(javaType); - } - atomDecl->fields.push_back(atField); - } - } - return has_attribution_node; -} - -static void populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl>& atomDecl, - FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet) { - for (FieldNumberToAnnotations::const_iterator it = atomDecl->fieldNumberToAnnotations.begin(); - it != atomDecl->fieldNumberToAnnotations.end(); it++) { - const int fieldNumber = it->first; - (*fieldNumberToAtomDeclSet)[fieldNumber].insert(atomDecl); - } -} - -/** - * Gather the info about the atoms. - */ -int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) { - int errorCount = 0; - - for (int i = 0; i < descriptor->field_count(); i++) { - const FieldDescriptor* atomField = descriptor->field(i); - - if (moduleName != DEFAULT_MODULE_NAME) { - const int moduleCount = atomField->options().ExtensionSize(os::statsd::module); - int j; - for (j = 0; j < moduleCount; ++j) { - const string atomModuleName = - atomField->options().GetExtension(os::statsd::module, j); - if (atomModuleName == moduleName) { - break; - } - } - - // This atom is not in the module we're interested in; skip it. - if (moduleCount == j) { - if (dbg) { - printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number()); - } - continue; - } - } - - if (dbg) { - printf(" %s (%d)\n", atomField->name().c_str(), atomField->number()); - } - - // StatsEvent only has one oneof, which contains only messages. Don't allow - // other types. - if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) { - print_error(atomField, - "Bad type for atom. StatsEvent can only have message type " - "fields: %s\n", - atomField->name().c_str()); - errorCount++; - continue; - } - - const Descriptor* atom = atomField->message_type(); - shared_ptr<AtomDecl> atomDecl = - make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name()); - - if (atomDecl->code < PULL_ATOM_START_ID && - atomField->options().GetExtension(os::statsd::truncate_timestamp)) { - addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER, - ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL, - AnnotationValue(true)); - if (dbg) { - printf("%s can have timestamp truncated\n", atomField->name().c_str()); - } - } - - vector<java_type_t> signature; - errorCount += collate_atom(atom, atomDecl.get(), &signature); - if (atomDecl->primaryFields.size() != 0 && atomDecl->exclusiveField == 0) { - print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n", - atomField->name().c_str()); - errorCount++; - continue; - } - - FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = atoms->signatureInfoMap[signature]; - populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet); - - atoms->decls.insert(atomDecl); - - shared_ptr<AtomDecl> nonChainedAtomDecl = - make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name()); - vector<java_type_t> nonChainedSignature; - if (get_non_chained_node(atom, nonChainedAtomDecl.get(), &nonChainedSignature)) { - FieldNumberToAtomDeclSet& nonChainedFieldNumberToAtomDeclSet = - atoms->nonChainedSignatureInfoMap[nonChainedSignature]; - populateFieldNumberToAtomDeclSet(nonChainedAtomDecl, - &nonChainedFieldNumberToAtomDeclSet); - - atoms->non_chained_decls.insert(nonChainedAtomDecl); - } - } - - if (dbg) { - printf("signatures = [\n"); - for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin(); - it != atoms->signatureInfoMap.end(); it++) { - printf(" "); - for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end(); - jt++) { - printf(" %d", (int)*jt); - } - printf("\n"); - } - printf("]\n"); - } - - return errorCount; -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h deleted file mode 100644 index 10b34ecf5f54..000000000000 --- a/tools/stats_log_api_gen/Collation.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2017, 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. - */ - -#ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H -#define ANDROID_STATS_LOG_API_GEN_COLLATION_H - -#include <google/protobuf/descriptor.h> -#include <stdint.h> - -#include <map> -#include <set> -#include <vector> - -#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h" - -namespace android { -namespace stats_log_api_gen { - -using google::protobuf::Descriptor; -using google::protobuf::FieldDescriptor; -using std::map; -using std::set; -using std::shared_ptr; -using std::string; -using std::vector; - -const int PULL_ATOM_START_ID = 10000; - -const int FIRST_UID_IN_CHAIN_ID = 0; - -enum AnnotationId : uint8_t { - ANNOTATION_ID_IS_UID = 1, - ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2, - ANNOTATION_ID_PRIMARY_FIELD = 3, - ANNOTATION_ID_EXCLUSIVE_STATE = 4, - ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID = 5, - ANNOTATION_ID_DEFAULT_STATE = 6, - ANNOTATION_ID_TRIGGER_STATE_RESET = 7, - ANNOTATION_ID_STATE_NESTED = 8, -}; - -const int ATOM_ID_FIELD_NUMBER = -1; - -const string DEFAULT_MODULE_NAME = "DEFAULT"; - -/** - * The types for atom parameters. - */ -typedef enum { - JAVA_TYPE_UNKNOWN = 0, - - JAVA_TYPE_ATTRIBUTION_CHAIN = 1, - JAVA_TYPE_BOOLEAN = 2, - JAVA_TYPE_INT = 3, - JAVA_TYPE_LONG = 4, - JAVA_TYPE_FLOAT = 5, - JAVA_TYPE_DOUBLE = 6, - JAVA_TYPE_STRING = 7, - JAVA_TYPE_ENUM = 8, - JAVA_TYPE_KEY_VALUE_PAIR = 9, - - JAVA_TYPE_OBJECT = -1, - JAVA_TYPE_BYTE_ARRAY = -2, -} java_type_t; - -enum AnnotationType { - ANNOTATION_TYPE_UNKNOWN = 0, - ANNOTATION_TYPE_INT = 1, - ANNOTATION_TYPE_BOOL = 2, -}; - -union AnnotationValue { - int intValue; - bool boolValue; - - AnnotationValue(const int value) : intValue(value) { - } - AnnotationValue(const bool value) : boolValue(value) { - } -}; - -struct Annotation { - const AnnotationId annotationId; - const int atomId; - AnnotationType type; - AnnotationValue value; - - inline Annotation(AnnotationId annotationId, int atomId, AnnotationType type, - AnnotationValue value) - : annotationId(annotationId), atomId(atomId), type(type), value(value) { - } - inline ~Annotation() { - } - - inline bool operator<(const Annotation& that) const { - return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId; - } -}; - -struct SharedComparator { - template <typename T> - inline bool operator()(const shared_ptr<T>& lhs, const shared_ptr<T>& rhs) const { - return (*lhs) < (*rhs); - } -}; - -using AnnotationSet = set<shared_ptr<Annotation>, SharedComparator>; - -using FieldNumberToAnnotations = map<int, AnnotationSet>; - -/** - * The name and type for an atom field. - */ -struct AtomField { - string name; - java_type_t javaType; - - // If the field is of type enum, the following map contains the list of enum - // values. - map<int /* numeric value */, string /* value name */> enumValues; - - inline AtomField() : name(), javaType(JAVA_TYPE_UNKNOWN) { - } - inline AtomField(const AtomField& that) - : name(that.name), javaType(that.javaType), enumValues(that.enumValues) { - } - - inline AtomField(string n, java_type_t jt) : name(n), javaType(jt) { - } - inline ~AtomField() { - } -}; - -/** - * The name and code for an atom. - */ -struct AtomDecl { - int code; - string name; - - string message; - vector<AtomField> fields; - - FieldNumberToAnnotations fieldNumberToAnnotations; - - vector<int> primaryFields; - int exclusiveField = 0; - int defaultState = INT_MAX; - int triggerStateReset = INT_MAX; - bool nested = true; - - int uidField = 0; - - AtomDecl(); - AtomDecl(const AtomDecl& that); - AtomDecl(int code, const string& name, const string& message); - ~AtomDecl(); - - inline bool operator<(const AtomDecl& that) const { - return (code == that.code) ? (name < that.name) : (code < that.code); - } -}; - -using AtomDeclSet = set<shared_ptr<AtomDecl>, SharedComparator>; - -// Maps a field number to a set of atoms that have annotation(s) for their field with that field -// number. -using FieldNumberToAtomDeclSet = map<int, AtomDeclSet>; - -using SignatureInfoMap = map<vector<java_type_t>, FieldNumberToAtomDeclSet>; - -struct Atoms { - SignatureInfoMap signatureInfoMap; - AtomDeclSet decls; - AtomDeclSet non_chained_decls; - SignatureInfoMap nonChainedSignatureInfoMap; -}; - -/** - * Gather the information about the atoms. Returns the number of errors. - */ -int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms); -int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature); - -} // namespace stats_log_api_gen -} // namespace android - -#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp deleted file mode 100644 index f4c937c3f599..000000000000 --- a/tools/stats_log_api_gen/java_writer.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (C) 2019, 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 "java_writer.h" - -#include "java_writer_q.h" -#include "utils.h" - -namespace android { -namespace stats_log_api_gen { - -static int write_java_q_logger_class(FILE* out, const SignatureInfoMap& signatureInfoMap, - const AtomDecl& attributionDecl) { - fprintf(out, "\n"); - fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n"); - fprintf(out, " private static class QLogger {\n"); - - write_java_q_logging_constants(out, " "); - - // Print Q write methods. - fprintf(out, "\n"); - fprintf(out, " // Write methods.\n"); - write_java_methods_q_schema(out, signatureInfoMap, attributionDecl, " "); - - fprintf(out, " }\n"); - return 0; -} - -static void write_java_annotation_constants(FILE* out) { - fprintf(out, " // Annotation constants.\n"); - - for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) { - fprintf(out, " public static final byte %s = %hhu;\n", name.c_str(), id); - } - fprintf(out, "\n"); -} - -static void write_annotations(FILE* out, int argIndex, - const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet) { - FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt = - fieldNumberToAtomDeclSet.find(argIndex); - if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) { - return; - } - const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second; - for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) { - const string atomConstant = make_constant_name(atomDecl->name); - fprintf(out, " if (%s == code) {\n", atomConstant.c_str()); - const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex); - int resetState = -1; - int defaultState = -1; - for (const shared_ptr<Annotation>& annotation : annotations) { - const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId); - switch (annotation->type) { - case ANNOTATION_TYPE_INT: - if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) { - resetState = annotation->value.intValue; - } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) { - defaultState = annotation->value.intValue; - } else { - fprintf(out, " builder.addIntAnnotation(%s, %d);\n", - annotationConstant.c_str(), annotation->value.intValue); - } - break; - case ANNOTATION_TYPE_BOOL: - fprintf(out, " builder.addBooleanAnnotation(%s, %s);\n", - annotationConstant.c_str(), - annotation->value.boolValue ? "true" : "false"); - break; - default: - break; - } - } - if (defaultState != -1 && resetState != -1) { - const string& annotationConstant = - ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET); - fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState); - fprintf(out, " builder.addIntAnnotation(%s, %d);\n", - annotationConstant.c_str(), defaultState); - fprintf(out, " }\n"); - } - fprintf(out, " }\n"); - } -} - -static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap, - const AtomDecl& attributionDecl, const bool supportQ) { - for (auto signatureInfoMapIt = signatureInfoMap.begin(); - signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { - // Print method signature. - fprintf(out, " public static void write(int code"); - const vector<java_type_t>& signature = signatureInfoMapIt->first; - const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second; - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), - chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", android.util.SparseArray<Object> valueMap"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // Print method body. - string indent(""); - if (supportQ) { - fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n"); - indent = " "; - } - - // Start StatsEvent.Builder. - fprintf(out, - "%s final StatsEvent.Builder builder = " - "StatsEvent.newBuilder();\n", - indent.c_str()); - - // Write atom code. - fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str()); - write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet); - - // Write the args. - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(), - argIndex); - break; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex); - break; - case JAVA_TYPE_FLOAT: - fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(), - argIndex); - break; - case JAVA_TYPE_LONG: - fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex); - break; - case JAVA_TYPE_STRING: - fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), - argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, - "%s builder.writeByteArray(null == arg%d ? new byte[0] : " - "arg%d);\n", - indent.c_str(), argIndex, argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str()); - fprintf(out, "%s null == %s ? new int[0] : %s,\n", - indent.c_str(), uidName, uidName); - fprintf(out, "%s null == %s ? new String[0] : %s);\n", - indent.c_str(), tagName, tagName); - break; - } - case JAVA_TYPE_KEY_VALUE_PAIR: - fprintf(out, "\n"); - fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str()); - fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str()); - fprintf(out, "%s android.util.SparseIntArray intMap = null;\n", - indent.c_str()); - fprintf(out, "%s android.util.SparseLongArray longMap = null;\n", - indent.c_str()); - fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n", - indent.c_str()); - fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n", - indent.c_str()); - fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str()); - fprintf(out, "%s final int key = valueMap.keyAt(i);\n", - indent.c_str()); - fprintf(out, "%s final Object value = valueMap.valueAt(i);\n", - indent.c_str()); - fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str()); - fprintf(out, "%s if (null == intMap) {\n", indent.c_str()); - fprintf(out, - "%s intMap = new " - "android.util.SparseIntArray();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s intMap.put(key, (Integer) value);\n", - indent.c_str()); - fprintf(out, "%s } else if (value instanceof Long) {\n", - indent.c_str()); - fprintf(out, "%s if (null == longMap) {\n", indent.c_str()); - fprintf(out, - "%s longMap = new " - "android.util.SparseLongArray();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s longMap.put(key, (Long) value);\n", - indent.c_str()); - fprintf(out, "%s } else if (value instanceof String) {\n", - indent.c_str()); - fprintf(out, "%s if (null == stringMap) {\n", indent.c_str()); - fprintf(out, - "%s stringMap = new " - "android.util.SparseArray<>();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s stringMap.put(key, (String) value);\n", - indent.c_str()); - fprintf(out, "%s } else if (value instanceof Float) {\n", - indent.c_str()); - fprintf(out, "%s if (null == floatMap) {\n", indent.c_str()); - fprintf(out, - "%s floatMap = new " - "android.util.SparseArray<>();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s floatMap.put(key, (Float) value);\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, - "%s builder.writeKeyValuePairs(" - "intMap, longMap, stringMap, floatMap);\n", - indent.c_str()); - break; - default: - // Unsupported types: OBJECT, DOUBLE. - fprintf(stderr, "Encountered unsupported type."); - return 1; - } - write_annotations(out, argIndex, fieldNumberToAtomDeclSet); - argIndex++; - } - - fprintf(out, "\n"); - fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str()); - fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str()); - - // Add support for writing using Q schema if this is not the default module. - if (supportQ) { - fprintf(out, " } else {\n"); - fprintf(out, " QLogger.write(code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - fprintf(out, ", %s, %s", uidName, tagName); - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - // Module logging does not yet support key value pair. - fprintf(stderr, "Module logging does not yet support key value pair.\n"); - return 1; - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // if - } - - fprintf(out, " }\n"); // method - fprintf(out, "\n"); - } - return 0; -} - -int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, - const string& javaClass, const string& javaPackage, const bool supportQ, - const bool supportWorkSource) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package %s;\n", javaPackage.c_str()); - fprintf(out, "\n"); - fprintf(out, "\n"); - if (supportQ) { - fprintf(out, "import android.os.Build;\n"); - fprintf(out, "import android.os.SystemClock;\n"); - } - - fprintf(out, "import android.util.StatsEvent;\n"); - fprintf(out, "import android.util.StatsLog;\n"); - - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * Utility class for logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "public class %s {\n", javaClass.c_str()); - - write_java_atom_codes(out, atoms); - write_java_enum_values(out, atoms); - write_java_annotation_constants(out); - - int errors = 0; - - // Print write methods. - fprintf(out, " // Write methods\n"); - errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ); - errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap); - if (supportWorkSource) { - errors += write_java_work_source_methods(out, atoms.signatureInfoMap); - } - - if (supportQ) { - errors += write_java_q_logger_class(out, atoms.signatureInfoMap, attributionDecl); - } - - fprintf(out, "}\n"); - - return errors; -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h deleted file mode 100644 index 8b3b50588efc..000000000000 --- a/tools/stats_log_api_gen/java_writer.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2019, 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 <stdio.h> -#include <string.h> - -#include <map> -#include <set> -#include <vector> - -#include "Collation.h" - -namespace android { -namespace stats_log_api_gen { - -using namespace std; - -int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, - const string& javaClass, const string& javaPackage, const bool supportQ, - const bool supportWorkSource); - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp deleted file mode 100644 index d21e2708b724..000000000000 --- a/tools/stats_log_api_gen/java_writer_q.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) 2019, 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 "java_writer_q.h" - -#include "utils.h" - -namespace android { -namespace stats_log_api_gen { - -void write_java_q_logging_constants(FILE* out, const string& indent) { - fprintf(out, "%s// Payload limits.\n", indent.c_str()); - fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str()); - fprintf(out, - "%sprivate static final int MAX_EVENT_PAYLOAD = " - "LOGGER_ENTRY_MAX_PAYLOAD - 4;\n", - indent.c_str()); - - // Value types. Must match with EventLog.java and log.h. - fprintf(out, "\n"); - fprintf(out, "%s// Value types.\n", indent.c_str()); - fprintf(out, "%sprivate static final byte INT_TYPE = 0;\n", indent.c_str()); - fprintf(out, "%sprivate static final byte LONG_TYPE = 1;\n", indent.c_str()); - fprintf(out, "%sprivate static final byte STRING_TYPE = 2;\n", indent.c_str()); - fprintf(out, "%sprivate static final byte LIST_TYPE = 3;\n", indent.c_str()); - fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str()); - - // Size of each value type. - // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for - // the value. - fprintf(out, "\n"); - fprintf(out, "%s// Size of each value type.\n", indent.c_str()); - fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str()); - fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str()); - // Longs take 9 bytes, 1 for the type and 8 for the value. - fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str()); - // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the - // length. - fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str()); - fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str()); -} - -int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap, - const AtomDecl& attributionDecl, const string& indent) { - int requiredHelpers = 0; - for (auto signatureInfoMapIt = signatureInfoMap.begin(); - signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { - // Print method signature. - vector<java_type_t> signature = signatureInfoMapIt->first; - fprintf(out, "%spublic static void write(int code", indent.c_str()); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), - chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", android.util.SparseArray<Object> valueMap"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // Calculate the size of the buffer. - fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n", - indent.c_str()); - fprintf(out, - "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + " - "INT_TYPE_SIZE;\n", - indent.c_str()); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - case JAVA_TYPE_INT: - case JAVA_TYPE_FLOAT: - case JAVA_TYPE_ENUM: - fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str()); - break; - case JAVA_TYPE_LONG: - // Longs take 9 bytes, 1 for the type and 8 for the value. - fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str()); - break; - case JAVA_TYPE_STRING: - // Strings take 5 metadata bytes + length of byte encoded string. - fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); - fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, - "%s byte[] arg%dBytes = " - "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", - indent.c_str(), argIndex, argIndex); - fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", - indent.c_str(), argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - // Byte arrays take 5 metadata bytes + length of byte array. - fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); - fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", - indent.c_str(), argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - // Null checks on the params. - fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName); - fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName, - java_type_name(attributionDecl.fields.front().javaType)); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName); - fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName, - java_type_name(attributionDecl.fields.back().javaType)); - fprintf(out, "%s }\n", indent.c_str()); - - // First check that the lengths of the uid and tag arrays are the - // same. - fprintf(out, "%s if (%s.length != %s.length) {\n", indent.c_str(), uidName, - tagName); - fprintf(out, "%s return;\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str()); - fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), - tagName); - fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n", - indent.c_str(), argIndex, tagName, tagName); - fprintf(out, - "%s int str%dlen = " - "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8)." - "length;\n", - indent.c_str(), argIndex, argIndex); - fprintf(out, - "%s attrSize += " - "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + " - "str%dlen;\n", - indent.c_str(), argIndex); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s needed += attrSize;\n", indent.c_str()); - break; - } - case JAVA_TYPE_KEY_VALUE_PAIR: { - fprintf(out, "%s // Calculate bytes needed by Key Value Pairs.\n", - indent.c_str()); - fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str()); - fprintf(out, "%s android.util.SparseIntArray intMap = null;\n", - indent.c_str()); - fprintf(out, "%s android.util.SparseLongArray longMap = null;\n", - indent.c_str()); - fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n", - indent.c_str()); - fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n", - indent.c_str()); - fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n", - indent.c_str()); - fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str()); - fprintf(out, "%s final int key = valueMap.keyAt(i);\n", indent.c_str()); - fprintf(out, "%s final Object value = valueMap.valueAt(i);\n", - indent.c_str()); - fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str()); - fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n", - indent.c_str()); - fprintf(out, "%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n", - indent.c_str()); - fprintf(out, "%s if (null == intMap) {\n", indent.c_str()); - fprintf(out, "%s intMap = new android.util.SparseIntArray();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s intMap.put(key, (Integer) value);\n", - indent.c_str()); - fprintf(out, "%s } else if (value instanceof Long) {\n", indent.c_str()); - fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n", - indent.c_str()); - fprintf(out, "%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n", - indent.c_str()); - fprintf(out, "%s if (null == longMap) {\n", indent.c_str()); - fprintf(out, - "%s longMap = new " - "android.util.SparseLongArray();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s longMap.put(key, (Long) value);\n", indent.c_str()); - fprintf(out, "%s } else if (value instanceof String) {\n", - indent.c_str()); - fprintf(out, - "%s final String str = (value == null) ? \"\" : " - "(String) value;\n", - indent.c_str()); - fprintf(out, - "%s final int len = " - "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n", - indent.c_str()); - fprintf(out, - "%s keyValuePairSize += LIST_TYPE_OVERHEAD + " - "INT_TYPE_SIZE\n", - indent.c_str()); - fprintf(out, "%s + STRING_TYPE_OVERHEAD + len;\n", - indent.c_str()); - fprintf(out, "%s if (null == stringMap) {\n", indent.c_str()); - fprintf(out, - "%s stringMap = new " - "android.util.SparseArray<>();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s stringMap.put(key, str);\n", indent.c_str()); - fprintf(out, "%s } else if (value instanceof Float) {\n", - indent.c_str()); - fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n", - indent.c_str()); - fprintf(out, "%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n", - indent.c_str()); - fprintf(out, "%s if (null == floatMap) {\n", indent.c_str()); - fprintf(out, - "%s floatMap = new " - "android.util.SparseArray<>();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s floatMap.put(key, (Float) value);\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str()); - break; - } - default: - // Unsupported types: OBJECT, DOUBLE. - fprintf(stderr, "Module logging does not yet support Object and Double.\n"); - return 1; - } - argIndex++; - } - - // Now we have the size that is needed. Check for overflow and return if - // needed. - fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str()); - fprintf(out, "%s return;\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - - // Create new buffer, and associated data types. - fprintf(out, "%s byte[] buff = new byte[needed];\n", indent.c_str()); - fprintf(out, "%s int pos = 0;\n", indent.c_str()); - - // Initialize the buffer with list data type. - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = %zu;\n", indent.c_str(), signature.size() + 2); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - - // Write timestamp. - fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n", - indent.c_str()); - fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str()); - fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); - - // Write atom code. - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, code);\n", indent.c_str()); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - - // Write the args. - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", indent.c_str(), - argIndex); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - break; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(), - argIndex); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - break; - case JAVA_TYPE_FLOAT: - requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; - fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(), - argIndex); - fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str()); - break; - case JAVA_TYPE_LONG: - fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(), - argIndex); - fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); - break; - case JAVA_TYPE_STRING: - fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n", - indent.c_str(), argIndex); - fprintf(out, - "%s System.arraycopy(" - "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, " - "arg%dBytes.length);\n", - indent.c_str(), argIndex, argIndex); - fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", - indent.c_str(), argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", indent.c_str(), - argIndex); - fprintf(out, - "%s System.arraycopy(" - "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n", - indent.c_str(), argIndex, argIndex); - fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", - indent.c_str(), argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: { - requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION; - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n", - indent.c_str(), uidName, tagName); - fprintf(out, "%s pos += attrSize;\n", indent.c_str()); - break; - } - case JAVA_TYPE_KEY_VALUE_PAIR: - requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; - requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS; - fprintf(out, - "%s writeKeyValuePairs(buff, pos, (byte) count, intMap, " - "longMap, " - "stringMap, floatMap);\n", - indent.c_str()); - fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str()); - break; - default: - // Unsupported types: OBJECT, DOUBLE. - fprintf(stderr, "Object and Double are not supported in module logging"); - return 1; - } - argIndex++; - } - - fprintf(out, "%s StatsLog.writeRaw(buff, pos);\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "\n"); - } - - write_java_helpers_for_q_schema_methods(out, attributionDecl, requiredHelpers, indent); - - return 0; -} - -void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl, - const int requiredHelpers, const string& indent) { - fprintf(out, "\n"); - fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str()); - fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n", - indent.c_str()); - fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str()); - fprintf(out, "%s return;\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "\n"); - - fprintf(out, "%sprivate static void copyLong(byte[] buff, int pos, long val) {\n", - indent.c_str()); - fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 4] = (byte) (val >> 32);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 5] = (byte) (val >> 40);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 6] = (byte) (val >> 48);\n", indent.c_str()); - fprintf(out, "%s buff[pos + 7] = (byte) (val >> 56);\n", indent.c_str()); - fprintf(out, "%s return;\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "\n"); - - if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) { - fprintf(out, "%sprivate static void copyFloat(byte[] buff, int pos, float val) {\n", - indent.c_str()); - fprintf(out, "%s copyInt(buff, pos, Float.floatToIntBits(val));\n", indent.c_str()); - fprintf(out, "%s return;\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "\n"); - } - - if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) { - fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos", - indent.c_str()); - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str()); - } - fprintf(out, ") {\n"); - - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - // Write the first list begin. - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) (%s.length);\n", indent.c_str(), tagName); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - - // Iterate through the attribution chain and write the nodes. - fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName); - // Write the list begin. - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = %lu;\n", indent.c_str(), - attributionDecl.fields.size()); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - - // Write the uid. - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, %s[i]);\n", indent.c_str(), uidName); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - - // Write the tag. - fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", indent.c_str(), - tagName, tagName, tagName); - fprintf(out, - "%s byte[] %sByte = " - "%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", - indent.c_str(), tagName, tagName); - fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName); - fprintf(out, - "%s System.arraycopy(" - "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n", - indent.c_str(), tagName, tagName); - fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", indent.c_str(), - tagName); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "\n"); - } - - if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) { - fprintf(out, - "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, " - "byte numPairs,\n", - indent.c_str()); - fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str()); - fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str()); - fprintf(out, "%s final android.util.SparseArray<String> stringMap,\n", - indent.c_str()); - fprintf(out, "%s final android.util.SparseArray<Float> floatMap) {\n", - indent.c_str()); - - // Start list of lists. - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) numPairs;\n", indent.c_str()); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - - // Write integers. - fprintf(out, "%s final int intMapSize = null == intMap ? 0 : intMap.size();\n", - indent.c_str()); - fprintf(out, "%s for (int i = 0; i < intMapSize; i++) {\n", indent.c_str()); - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str()); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - fprintf(out, "%s final int key = intMap.keyAt(i);\n", indent.c_str()); - fprintf(out, "%s final int value = intMap.valueAt(i);\n", indent.c_str()); - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str()); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, value);\n", indent.c_str()); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - - // Write longs. - fprintf(out, "%s final int longMapSize = null == longMap ? 0 : longMap.size();\n", - indent.c_str()); - fprintf(out, "%s for (int i = 0; i < longMapSize; i++) {\n", indent.c_str()); - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str()); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - fprintf(out, "%s final int key = longMap.keyAt(i);\n", indent.c_str()); - fprintf(out, "%s final long value = longMap.valueAt(i);\n", indent.c_str()); - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str()); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyLong(buff, pos + 1, value);\n", indent.c_str()); - fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - - // Write Strings. - fprintf(out, - "%s final int stringMapSize = null == stringMap ? 0 : " - "stringMap.size();\n", - indent.c_str()); - fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str()); - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str()); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - fprintf(out, "%s final int key = stringMap.keyAt(i);\n", indent.c_str()); - fprintf(out, "%s final String value = stringMap.valueAt(i);\n", indent.c_str()); - fprintf(out, - "%s final byte[] valueBytes = " - "value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", - indent.c_str()); - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str()); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str()); - fprintf(out, - "%s System.arraycopy(" - "valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, " - "valueBytes.length);\n", - indent.c_str()); - fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - - // Write floats. - fprintf(out, - "%s final int floatMapSize = null == floatMap ? 0 : " - "floatMap.size();\n", - indent.c_str()); - fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str()); - fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); - fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str()); - fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); - fprintf(out, "%s final int key = floatMap.keyAt(i);\n", indent.c_str()); - fprintf(out, "%s final float value = floatMap.valueAt(i);\n", indent.c_str()); - fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str()); - fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str()); - fprintf(out, "%s copyFloat(buff, pos + 1, value);\n", indent.c_str()); - fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "\n"); - } -} - -// This method is called in main.cpp to generate StatsLog for modules that's -// compatible with Q at compile-time. -int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& javaClass, - const string& javaPackage, const bool supportWorkSource) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package %s;\n", javaPackage.c_str()); - fprintf(out, "\n"); - fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n"); - fprintf(out, "\n"); - fprintf(out, "import android.util.StatsLog;\n"); - fprintf(out, "import android.os.SystemClock;\n"); - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * Utility class for logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "public class %s {\n", javaClass.c_str()); - - write_java_q_logging_constants(out, " "); - - write_java_atom_codes(out, atoms); - - write_java_enum_values(out, atoms); - - int errors = 0; - // Print write methods - fprintf(out, " // Write methods\n"); - errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, " "); - errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap); - if (supportWorkSource) { - errors += write_java_work_source_methods(out, atoms.signatureInfoMap); - } - - fprintf(out, "}\n"); - - return errors; -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h deleted file mode 100644 index c511a8436416..000000000000 --- a/tools/stats_log_api_gen/java_writer_q.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2019, 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 <stdio.h> -#include <string.h> - -#include <map> -#include <set> -#include <vector> - -#include "Collation.h" - -namespace android { -namespace stats_log_api_gen { - -using namespace std; - -void write_java_q_logging_constants(FILE* out, const string& indent); - -int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap, - const AtomDecl& attributionDecl, const string& indent); - -void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl, - const int requiredHelpers, const string& indent); - -int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& javaClass, - const string& javaPackage, const bool supportWorkSource); - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp deleted file mode 100644 index b888ce904b31..000000000000 --- a/tools/stats_log_api_gen/main.cpp +++ /dev/null @@ -1,264 +0,0 @@ - -#include <getopt.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <map> -#include <set> -#include <vector> - -#include "Collation.h" -#include "frameworks/base/cmds/statsd/src/atoms.pb.h" -#include "java_writer.h" -#include "java_writer_q.h" -#include "native_writer.h" -#include "utils.h" - -using namespace google::protobuf; -using namespace std; - -namespace android { -namespace stats_log_api_gen { - -using android::os::statsd::Atom; - -static void print_usage() { - fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "OPTIONS\n"); - fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n"); - fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n"); - fprintf(stderr, " --help this message\n"); - fprintf(stderr, " --java FILENAME the java file to output\n"); - fprintf(stderr, " --module NAME optional, module name to generate outputs for\n"); - fprintf(stderr, - " --namespace COMMA,SEP,NAMESPACE required for cpp/header with " - "module\n"); - fprintf(stderr, - " comma separated namespace of " - "the files\n"); - fprintf(stderr, - " --importHeader NAME required for cpp/jni to say which header to " - "import " - "for write helpers\n"); - fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n"); - fprintf(stderr, " required for java with module\n"); - fprintf(stderr, " --javaClass CLASS the class name of the java class.\n"); - fprintf(stderr, " Optional for Java with module.\n"); - fprintf(stderr, " Default is \"StatsLogInternal\"\n"); - fprintf(stderr, " --supportQ Include runtime support for Android Q.\n"); - fprintf(stderr, - " --worksource Include support for logging WorkSource " - "objects.\n"); - fprintf(stderr, - " --compileQ Include compile-time support for Android Q " - "(Java only).\n"); -} - -/** - * Do the argument parsing and execute the tasks. - */ -static int run(int argc, char const* const* argv) { - string cppFilename; - string headerFilename; - string javaFilename; - string javaPackage; - string javaClass; - - string moduleName = DEFAULT_MODULE_NAME; - string cppNamespace = DEFAULT_CPP_NAMESPACE; - string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT; - bool supportQ = false; - bool supportWorkSource = false; - bool compileQ = false; - - int index = 1; - while (index < argc) { - if (0 == strcmp("--help", argv[index])) { - print_usage(); - return 0; - } else if (0 == strcmp("--cpp", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - cppFilename = argv[index]; - } else if (0 == strcmp("--header", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - headerFilename = argv[index]; - } else if (0 == strcmp("--java", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - javaFilename = argv[index]; - } else if (0 == strcmp("--module", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - moduleName = argv[index]; - } else if (0 == strcmp("--namespace", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - cppNamespace = argv[index]; - } else if (0 == strcmp("--importHeader", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - cppHeaderImport = argv[index]; - } else if (0 == strcmp("--javaPackage", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - javaPackage = argv[index]; - } else if (0 == strcmp("--javaClass", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - javaClass = argv[index]; - } else if (0 == strcmp("--supportQ", argv[index])) { - supportQ = true; - } else if (0 == strcmp("--worksource", argv[index])) { - supportWorkSource = true; - } else if (0 == strcmp("--compileQ", argv[index])) { - compileQ = true; - } - - index++; - } - - if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0) { - print_usage(); - return 1; - } - - if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) { - // Support for Q schema is not needed for default module. - fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str()); - return 1; - } - - if (supportQ && compileQ) { - // Runtime Q support is redundant if compile-time Q support is required. - fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n"); - return 1; - } - - // Collate the parameters - Atoms atoms; - int errorCount = collate_atoms(Atom::descriptor(), moduleName, &atoms); - if (errorCount != 0) { - return 1; - } - - AtomDecl attributionDecl; - vector<java_type_t> attributionSignature; - collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl, - &attributionSignature); - - // Write the .cpp file - if (cppFilename.size() != 0) { - FILE* out = fopen(cppFilename.c_str(), "w"); - if (out == NULL) { - fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str()); - return 1; - } - // If this is for a specific module, the namespace must also be provided. - if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { - fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); - return 1; - } - // If this is for a specific module, the header file to import must also be - // provided. - if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) { - fprintf(stderr, "Must supply --headerImport if supplying a specific module\n"); - return 1; - } - errorCount = android::stats_log_api_gen::write_stats_log_cpp( - out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ); - fclose(out); - } - - // Write the .h file - if (headerFilename.size() != 0) { - FILE* out = fopen(headerFilename.c_str(), "w"); - if (out == NULL) { - fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str()); - return 1; - } - // If this is for a specific module, the namespace must also be provided. - if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { - fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); - } - errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl, - cppNamespace); - fclose(out); - } - - // Write the .java file - if (javaFilename.size() != 0) { - if (javaClass.size() == 0) { - fprintf(stderr, "Must supply --javaClass if supplying a Java filename"); - return 1; - } - - if (javaPackage.size() == 0) { - fprintf(stderr, "Must supply --javaPackage if supplying a Java filename"); - return 1; - } - - if (moduleName.size() == 0) { - fprintf(stderr, "Must supply --module if supplying a Java filename"); - return 1; - } - - FILE* out = fopen(javaFilename.c_str(), "w"); - if (out == NULL) { - fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str()); - return 1; - } - - if (compileQ) { - errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module( - out, atoms, attributionDecl, javaClass, javaPackage, supportWorkSource); - } else { - errorCount = android::stats_log_api_gen::write_stats_log_java( - out, atoms, attributionDecl, javaClass, javaPackage, supportQ, - supportWorkSource); - } - - fclose(out); - } - - return errorCount; -} - -} // namespace stats_log_api_gen -} // namespace android - -/** - * Main. - */ -int main(int argc, char const* const* argv) { - GOOGLE_PROTOBUF_VERIFY_VERSION; - - return android::stats_log_api_gen::run(argc, argv); -} diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp deleted file mode 100644 index 0c6c0099e459..000000000000 --- a/tools/stats_log_api_gen/native_writer.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2019, 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 "native_writer.h" - -#include "utils.h" - -namespace android { -namespace stats_log_api_gen { - -static void write_native_annotation_constants(FILE* out) { - fprintf(out, "// Annotation constants.\n"); - - for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) { - fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id); - } - fprintf(out, "\n"); -} - -static void write_annotations(FILE* out, int argIndex, - const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet, - const string& methodPrefix, const string& methodSuffix) { - FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt = - fieldNumberToAtomDeclSet.find(argIndex); - if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) { - return; - } - const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second; - for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) { - const string atomConstant = make_constant_name(atomDecl->name); - fprintf(out, " if (%s == code) {\n", atomConstant.c_str()); - const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex); - int resetState = -1; - int defaultState = -1; - for (const shared_ptr<Annotation>& annotation : annotations) { - const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId); - switch (annotation->type) { - case ANNOTATION_TYPE_INT: - if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) { - resetState = annotation->value.intValue; - } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) { - defaultState = annotation->value.intValue; - } else { - fprintf(out, " %saddInt32Annotation(%s%s, %d);\n", - methodPrefix.c_str(), methodSuffix.c_str(), - annotationConstant.c_str(), annotation->value.intValue); - } - break; - case ANNOTATION_TYPE_BOOL: - // TODO(b/151786433): Write annotation constant name instead of - // annotation id literal. - fprintf(out, " %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(), - methodSuffix.c_str(), annotationConstant.c_str(), - annotation->value.boolValue ? "true" : "false"); - break; - default: - break; - } - } - if (defaultState != -1 && resetState != -1) { - const string& annotationConstant = - ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET); - fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState); - fprintf(out, " %saddInt32Annotation(%s%s, %d);\n", methodPrefix.c_str(), - methodSuffix.c_str(), annotationConstant.c_str(), defaultState); - fprintf(out, " }\n"); - } - fprintf(out, " }\n"); - } -} - -static int write_native_stats_write_methods(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const bool supportQ) { - fprintf(out, "\n"); - for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin(); - signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) { - vector<java_type_t> signature = signatureInfoMapIt->first; - const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second; - // Key value pairs not supported in native. - if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) { - continue; - } - write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {"); - - int argIndex = 1; - if (supportQ) { - fprintf(out, " StatsEventCompat event;\n"); - fprintf(out, " event.setAtomId(code);\n"); - write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", ""); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_ATTRIBUTION_CHAIN: { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n", - uidName, uidName, tagName); - break; - } - case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n", - argIndex, argIndex); - break; - case JAVA_TYPE_BOOLEAN: - fprintf(out, " event.writeBool(arg%d);\n", argIndex); - break; - case JAVA_TYPE_INT: // Fall through. - case JAVA_TYPE_ENUM: - fprintf(out, " event.writeInt32(arg%d);\n", argIndex); - break; - case JAVA_TYPE_FLOAT: - fprintf(out, " event.writeFloat(arg%d);\n", argIndex); - break; - case JAVA_TYPE_LONG: - fprintf(out, " event.writeInt64(arg%d);\n", argIndex); - break; - case JAVA_TYPE_STRING: - fprintf(out, " event.writeString(arg%d);\n", argIndex); - break; - default: - // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS. - fprintf(stderr, "Encountered unsupported type."); - return 1; - } - write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", ""); - argIndex++; - } - fprintf(out, " return event.writeToSocket();\n"); - } else { - fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n"); - fprintf(out, " AStatsEvent_setAtomId(event, code);\n"); - write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_", - "event, "); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_ATTRIBUTION_CHAIN: { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - fprintf(out, - " AStatsEvent_writeAttributionChain(event, " - "reinterpret_cast<const uint32_t*>(%s), %s.data(), " - "static_cast<uint8_t>(%s_length));\n", - uidName, tagName, uidName); - break; - } - case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, - " AStatsEvent_writeByteArray(event, " - "reinterpret_cast<const uint8_t*>(arg%d.arg), " - "arg%d.arg_length);\n", - argIndex, argIndex); - break; - case JAVA_TYPE_BOOLEAN: - fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex); - break; - case JAVA_TYPE_INT: // Fall through. - case JAVA_TYPE_ENUM: - fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex); - break; - case JAVA_TYPE_FLOAT: - fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex); - break; - case JAVA_TYPE_LONG: - fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex); - break; - case JAVA_TYPE_STRING: - fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex); - break; - default: - // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS - fprintf(stderr, "Encountered unsupported type."); - return 1; - } - write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_", - "event, "); - argIndex++; - } - fprintf(out, " const int ret = AStatsEvent_write(event);\n"); - fprintf(out, " AStatsEvent_release(event);\n"); - fprintf(out, " return ret;\n"); - } - fprintf(out, "}\n\n"); - } - return 0; -} - -static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl) { - fprintf(out, "\n"); - for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin(); - signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) { - vector<java_type_t> signature = signature_it->first; - // Key value pairs not supported in native. - if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) { - continue; - } - - write_native_method_signature(out, "int stats_write_non_chained", signature, - attributionDecl, " {"); - - vector<java_type_t> newSignature; - - // First two args form the attribution node so size goes down by 1. - newSignature.reserve(signature.size() - 1); - - // First arg is Attribution Chain. - newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN); - - // Followed by the originial signature except the first 2 args. - newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end()); - - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - fprintf(out, " const int32_t* %s = &arg1;\n", uidName); - fprintf(out, " const size_t %s_length = 1;\n", uidName); - fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName); - fprintf(out, " return "); - write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2); - - fprintf(out, "}\n\n"); - } -} - -static void write_native_method_header(FILE* out, const string& methodName, - const SignatureInfoMap& signatureInfoMap, - const AtomDecl& attributionDecl) { - for (auto signatureInfoMapIt = signatureInfoMap.begin(); - signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { - vector<java_type_t> signature = signatureInfoMapIt->first; - - // Key value pairs not supported in native. - if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) { - continue; - } - write_native_method_signature(out, methodName, signature, attributionDecl, ";"); - } -} - -int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, - const string& cppNamespace, const string& importHeader, - const bool supportQ) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - - fprintf(out, "#include <%s>\n", importHeader.c_str()); - if (supportQ) { - fprintf(out, "#include <StatsEventCompat.h>\n"); - } else { - fprintf(out, "#include <stats_event.h>\n"); - } - - fprintf(out, "\n"); - write_namespace(out, cppNamespace); - - write_native_stats_write_methods(out, atoms, attributionDecl, supportQ); - write_native_stats_write_non_chained_methods(out, atoms, attributionDecl); - - // Print footer - fprintf(out, "\n"); - write_closing_namespace(out, cppNamespace); - - return 0; -} - -int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, - const string& cppNamespace) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "#pragma once\n"); - fprintf(out, "\n"); - fprintf(out, "#include <stdint.h>\n"); - fprintf(out, "#include <vector>\n"); - fprintf(out, "#include <map>\n"); - fprintf(out, "#include <set>\n"); - fprintf(out, "\n"); - - write_namespace(out, cppNamespace); - fprintf(out, "\n"); - fprintf(out, "/*\n"); - fprintf(out, " * API For logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "\n"); - - write_native_atom_constants(out, atoms, attributionDecl); - - // Print constants for the enum values. - fprintf(out, "//\n"); - fprintf(out, "// Constants for enum values\n"); - fprintf(out, "//\n\n"); - for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end(); - atomIt++) { - for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin(); - field != (*atomIt)->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ENUM) { - fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(), - field->name.c_str()); - for (map<int, string>::const_iterator value = field->enumValues.begin(); - value != field->enumValues.end(); value++) { - fprintf(out, "const int32_t %s__%s__%s = %d;\n", - make_constant_name((*atomIt)->message).c_str(), - make_constant_name(field->name).c_str(), - make_constant_name(value->second).c_str(), value->first); - } - fprintf(out, "\n"); - } - } - } - - write_native_annotation_constants(out); - - fprintf(out, "struct BytesField {\n"); - fprintf(out, - " BytesField(char const* array, size_t len) : arg(array), " - "arg_length(len) {}\n"); - fprintf(out, " char const* arg;\n"); - fprintf(out, " size_t arg_length;\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); - - // Print write methods - fprintf(out, "//\n"); - fprintf(out, "// Write methods\n"); - fprintf(out, "//\n"); - write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl); - - fprintf(out, "//\n"); - fprintf(out, "// Write flattened methods\n"); - fprintf(out, "//\n"); - write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap, - attributionDecl); - - fprintf(out, "\n"); - write_closing_namespace(out, cppNamespace); - - return 0; -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h deleted file mode 100644 index 264d4db29fc9..000000000000 --- a/tools/stats_log_api_gen/native_writer.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2019, 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 <stdio.h> -#include <string.h> - -#include "Collation.h" - -namespace android { -namespace stats_log_api_gen { - -using namespace std; - -int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, - const string& cppNamespace, const string& importHeader, - const bool supportQ); - -int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, - const string& cppNamespace); - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto deleted file mode 100644 index aaa488e44fee..000000000000 --- a/tools/stats_log_api_gen/test.proto +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -syntax = "proto2"; - -import "frameworks/base/cmds/statsd/src/atoms.proto"; -import "frameworks/base/cmds/statsd/src/atom_field_options.proto"; - -package android.stats_log_api_gen; - -message IntAtom { - optional int32 field1 = 1; -} - -message AnotherIntAtom { - optional int32 field1 = 1; -} - -message OutOfOrderAtom { - optional int32 field2 = 2; - optional int32 field1 = 1; -} - -enum AnEnum { - VALUE0 = 0; - VALUE1 = 1; -} - -message AllTypesAtom { - repeated android.os.statsd.AttributionNode attribution_chain = 1; - optional float float_field = 2; - optional int64 int64_field = 3; - optional uint64 uint64_field = 4; - optional int32 int32_field = 5; - optional fixed64 fixed64_field = 6; - optional fixed32 fixed32_field = 7; - optional bool bool_field = 8; - optional string string_field = 9; - optional uint32 uint32_field = 10; - optional AnEnum enum_field = 11; - optional sfixed32 sfixed32_field = 12; - optional sfixed64 sfixed64_field = 13; - optional sint32 sint32_field = 14; - optional sint64 sint64_field = 15; -} - -message Event { - oneof event { - OutOfOrderAtom out_of_order_atom = 2; - IntAtom int_atom = 1; - AnotherIntAtom another_int_atom = 3; - AllTypesAtom all_types_atom = 4; - } -} - -message BadTypesAtom { - optional IntAtom bad_int_atom = 1; - optional bytes bad_bytes = 2; - repeated int32 repeated_field = 3; - optional double double_field = 4; -} - -message BadTypesEvent { - oneof event { - BadTypesAtom bad_types_atom = 1; - } -} - -message BadSkippedFieldSingleAtom { - optional int32 field2 = 2; -} - -message BadSkippedFieldSingle { - oneof event { - BadSkippedFieldSingleAtom bad = 1; - } -} - -message BadSkippedFieldMultipleAtom { - optional int32 field1 = 1; - optional int32 field3 = 3; - optional int32 field5 = 5; -} - -message BadSkippedFieldMultiple { - oneof event { - BadSkippedFieldMultipleAtom bad = 1; - } -} - -message BadAttributionNodePositionAtom { - optional int32 field1 = 1; - repeated android.os.statsd.AttributionNode attribution = 2; -} - -message BadAttributionNodePosition { - oneof event { BadAttributionNodePositionAtom bad = 1; } -} - -message GoodEventWithBinaryFieldAtom { - oneof event { GoodBinaryFieldAtom field1 = 1; } -} - -message ComplexField { - optional string str = 1; -} - -message GoodBinaryFieldAtom { - optional int32 field1 = 1; - optional ComplexField bf = 2 [(android.os.statsd.log_mode) = MODE_BYTES]; -} - -message BadEventWithBinaryFieldAtom { - oneof event { BadBinaryFieldAtom field1 = 1; } -} - -message BadBinaryFieldAtom { - optional int32 field1 = 1; - optional ComplexField bf = 2; -} - -message BadStateAtoms { - oneof event { - BadStateAtom1 bad1 = 1; - BadStateAtom2 bad2 = 2; - BadStateAtom3 bad3 = 3; - } -} - -message GoodStateAtoms { - oneof event { - GoodStateAtom1 good1 = 1; - GoodStateAtom2 good2 = 2; - } -} - -// The atom has only primary field but no exclusive state field. -message BadStateAtom1 { - optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true]; -} - -// Only primative types can be annotated. -message BadStateAtom2 { - repeated android.os.statsd.AttributionNode attribution = 1 - [(android.os.statsd.state_field_option).primary_field = true]; - optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true]; -} - -// Having 2 exclusive state field in the atom means the atom is badly designed. -// E.g., putting bluetooth state and wifi state in the same atom. -message BadStateAtom3 { - optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true]; - optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true]; - optional int32 state2 = 3 [(android.os.statsd.state_field_option).exclusive_state = true]; -} - -message GoodStateAtom1 { - optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true]; - optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true]; -} - -// Atoms can have exclusive state field, but no primary field. That means -// the state is globally exclusive (e.g., DisplayState). -message GoodStateAtom2 { - optional int32 uid = 1; - optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true]; -} - -// We can have more than one primary fields. That means their combination is a -// primary key. -message GoodStateAtom3 { - optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true]; - optional int32 tid = 2 [(android.os.statsd.state_field_option).primary_field = true]; - optional int32 state = 3 [(android.os.statsd.state_field_option).exclusive_state = true]; -} - -message ModuleOneAtom { - optional int32 field = 1 [(android.os.statsd.is_uid) = true]; -} - -message ModuleTwoAtom { - optional int32 field = 1; -} - -message ModuleOneAndTwoAtom { - optional int32 field = 1 [(android.os.statsd.state_field_option).exclusive_state = true]; -} - -message NoModuleAtom { - optional string field = 1; -} - -message ModuleAtoms { - oneof event { - ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"]; - ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"]; - ModuleOneAndTwoAtom module_one_and_two_atom = 3 [ - (android.os.statsd.module) = "module1", (android.os.statsd.module) = "module2" - ]; - NoModuleAtom no_module_atom = 4; - } -} diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp deleted file mode 100644 index dbae58889333..000000000000 --- a/tools/stats_log_api_gen/test_collation.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (C) 2017, 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 <gtest/gtest.h> -#include <stdio.h> - -#include "Collation.h" -#include "frameworks/base/tools/stats_log_api_gen/test.pb.h" - -namespace android { -namespace stats_log_api_gen { - -using std::map; -using std::set; -using std::vector; - -/** - * Return whether the map contains a vector of the elements provided. - */ -static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) { - va_list args; - vector<java_type_t> v; - - va_start(args, count); - for (int i = 0; i < count; i++) { - v.push_back((java_type_t)va_arg(args, int)); - } - va_end(args); - - return s.find(v) != s.end(); -} - -/** - * Expect that the provided map contains the elements provided. - */ -#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \ - do { \ - int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int); \ - EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \ - } while (0) - -/** Expects that the provided atom has no enum values for any field. */ -#define EXPECT_NO_ENUM_FIELD(atom) \ - do { \ - for (vector<AtomField>::const_iterator field = atom->fields.begin(); \ - field != atom->fields.end(); field++) { \ - EXPECT_TRUE(field->enumValues.empty()); \ - } \ - } while (0) - -/** Expects that exactly one specific field has expected enum values. */ -#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \ - do { \ - for (vector<AtomField>::const_iterator field = atom->fields.begin(); \ - field != atom->fields.end(); field++) { \ - if (field->name == field_name) { \ - EXPECT_EQ(field->enumValues, values); \ - } else { \ - EXPECT_TRUE(field->enumValues.empty()); \ - } \ - } \ - } while (0) - -/** - * Test a correct collation, with all the types. - */ -TEST(CollationTest, CollateStats) { - Atoms atoms; - int errorCount = collate_atoms(Event::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(0, errorCount); - EXPECT_EQ(3ul, atoms.signatureInfoMap.size()); - - // IntAtom, AnotherIntAtom - EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); - - // OutOfOrderAtom - EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT); - - // AllTypesAtom - EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, - JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain - JAVA_TYPE_FLOAT, // float - JAVA_TYPE_LONG, // int64 - JAVA_TYPE_LONG, // uint64 - JAVA_TYPE_INT, // int32 - JAVA_TYPE_LONG, // fixed64 - JAVA_TYPE_INT, // fixed32 - JAVA_TYPE_BOOLEAN, // bool - JAVA_TYPE_STRING, // string - JAVA_TYPE_INT, // uint32 - JAVA_TYPE_INT, // AnEnum - JAVA_TYPE_INT, // sfixed32 - JAVA_TYPE_LONG, // sfixed64 - JAVA_TYPE_INT, // sint32 - JAVA_TYPE_LONG // sint64 - ); - - EXPECT_EQ(4ul, atoms.decls.size()); - - AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); - EXPECT_EQ(1, (*atomIt)->code); - EXPECT_EQ("int_atom", (*atomIt)->name); - EXPECT_EQ("IntAtom", (*atomIt)->message); - EXPECT_NO_ENUM_FIELD((*atomIt)); - atomIt++; - - EXPECT_EQ(2, (*atomIt)->code); - EXPECT_EQ("out_of_order_atom", (*atomIt)->name); - EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message); - EXPECT_NO_ENUM_FIELD((*atomIt)); - atomIt++; - - EXPECT_EQ(3, (*atomIt)->code); - EXPECT_EQ("another_int_atom", (*atomIt)->name); - EXPECT_EQ("AnotherIntAtom", (*atomIt)->message); - EXPECT_NO_ENUM_FIELD((*atomIt)); - atomIt++; - - EXPECT_EQ(4, (*atomIt)->code); - EXPECT_EQ("all_types_atom", (*atomIt)->name); - EXPECT_EQ("AllTypesAtom", (*atomIt)->message); - map<int, string> enumValues; - enumValues[0] = "VALUE0"; - enumValues[1] = "VALUE1"; - EXPECT_HAS_ENUM_FIELD((*atomIt), "enum_field", enumValues); - atomIt++; - - EXPECT_EQ(atoms.decls.end(), atomIt); -} - -/** - * Test that event class that contains stuff other than the atoms is rejected. - */ -TEST(CollationTest, NonMessageTypeFails) { - Atoms atoms; - int errorCount = collate_atoms(IntAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(1, errorCount); -} - -/** - * Test that atoms that have non-primitive types or repeated fields are - * rejected. - */ -TEST(CollationTest, FailOnBadTypes) { - Atoms atoms; - int errorCount = collate_atoms(BadTypesEvent::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(4, errorCount); -} - -/** - * Test that atoms that skip field numbers (in the first position) are rejected. - */ -TEST(CollationTest, FailOnSkippedFieldsSingle) { - Atoms atoms; - int errorCount = - collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(1, errorCount); -} - -/** - * Test that atoms that skip field numbers (not in the first position, and - * multiple times) are rejected. - */ -TEST(CollationTest, FailOnSkippedFieldsMultiple) { - Atoms atoms; - int errorCount = - collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(2, errorCount); -} - -/** - * Test that atoms that have an attribution chain not in the first position are - * rejected. - */ -TEST(CollationTest, FailBadAttributionNodePosition) { - Atoms atoms; - int errorCount = - collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(1, errorCount); -} - -TEST(CollationTest, FailOnBadStateAtomOptions) { - Atoms atoms; - int errorCount = collate_atoms(BadStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); - - EXPECT_EQ(3, errorCount); -} - -TEST(CollationTest, PassOnGoodStateAtomOptions) { - Atoms atoms; - int errorCount = collate_atoms(GoodStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); - EXPECT_EQ(0, errorCount); -} - -TEST(CollationTest, PassOnGoodBinaryFieldAtom) { - Atoms atoms; - int errorCount = - collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); - EXPECT_EQ(0, errorCount); -} - -TEST(CollationTest, FailOnBadBinaryFieldAtom) { - Atoms atoms; - int errorCount = - collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); - EXPECT_TRUE(errorCount > 0); -} - -TEST(CollationTest, PassOnLogFromModuleAtom) { - Atoms atoms; - int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); - EXPECT_EQ(errorCount, 0); - EXPECT_EQ(atoms.decls.size(), 4ul); -} - -TEST(CollationTest, RecognizeModuleAtom) { - Atoms atoms; - int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); - EXPECT_EQ(errorCount, 0); - EXPECT_EQ(atoms.decls.size(), 4ul); - EXPECT_EQ(atoms.signatureInfoMap.size(), 2u); - EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); - EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_STRING); - - SignatureInfoMap::const_iterator signatureInfoMapIt; - const vector<java_type_t>* signature; - const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet; - FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt; - const AtomDeclSet* atomDeclSet; - AtomDeclSet::const_iterator atomDeclSetIt; - AtomDecl* atomDecl; - FieldNumberToAnnotations* fieldNumberToAnnotations; - FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt; - const AnnotationSet* annotationSet; - AnnotationSet::const_iterator annotationSetIt; - Annotation* annotation; - - signatureInfoMapIt = atoms.signatureInfoMap.begin(); - signature = &(signatureInfoMapIt->first); - fieldNumberToAtomDeclSet = &signatureInfoMapIt->second; - EXPECT_EQ(1ul, signature->size()); - EXPECT_EQ(JAVA_TYPE_INT, signature->at(0)); - EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size()); - fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin(); - EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first); - atomDeclSet = &fieldNumberToAtomDeclSetIt->second; - EXPECT_EQ(2ul, atomDeclSet->size()); - atomDeclSetIt = atomDeclSet->begin(); - atomDecl = atomDeclSetIt->get(); - EXPECT_EQ(1, atomDecl->code); - fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; - fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); - EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); - annotationSet = &fieldNumberToAnnotationsIt->second; - EXPECT_EQ(1ul, annotationSet->size()); - annotationSetIt = annotationSet->begin(); - annotation = annotationSetIt->get(); - EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId); - EXPECT_EQ(1, annotation->atomId); - EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); - EXPECT_TRUE(annotation->value.boolValue); - - atomDeclSetIt++; - atomDecl = atomDeclSetIt->get(); - EXPECT_EQ(3, atomDecl->code); - fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; - fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); - EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); - annotationSet = &fieldNumberToAnnotationsIt->second; - EXPECT_EQ(1ul, annotationSet->size()); - annotationSetIt = annotationSet->begin(); - annotation = annotationSetIt->get(); - EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId); - EXPECT_EQ(3, annotation->atomId); - EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); - EXPECT_TRUE(annotation->value.boolValue); - - signatureInfoMapIt++; - signature = &signatureInfoMapIt->first; - fieldNumberToAtomDeclSet = &signatureInfoMapIt->second; - EXPECT_EQ(1ul, signature->size()); - EXPECT_EQ(JAVA_TYPE_STRING, signature->at(0)); - EXPECT_EQ(0ul, fieldNumberToAtomDeclSet->size()); -} - -TEST(CollationTest, RecognizeModule1Atom) { - Atoms atoms; - const string moduleName = "module1"; - int errorCount = collate_atoms(ModuleAtoms::descriptor(), moduleName, &atoms); - EXPECT_EQ(errorCount, 0); - EXPECT_EQ(atoms.decls.size(), 2ul); - EXPECT_EQ(atoms.signatureInfoMap.size(), 1u); - EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); - - SignatureInfoMap::const_iterator signatureInfoMapIt; - const vector<java_type_t>* signature; - const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet; - FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt; - const AtomDeclSet* atomDeclSet; - AtomDeclSet::const_iterator atomDeclSetIt; - AtomDecl* atomDecl; - FieldNumberToAnnotations* fieldNumberToAnnotations; - FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt; - const AnnotationSet* annotationSet; - AnnotationSet::const_iterator annotationSetIt; - Annotation* annotation; - - signatureInfoMapIt = atoms.signatureInfoMap.begin(); - signature = &(signatureInfoMapIt->first); - fieldNumberToAtomDeclSet = &signatureInfoMapIt->second; - EXPECT_EQ(1ul, signature->size()); - EXPECT_EQ(JAVA_TYPE_INT, signature->at(0)); - EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size()); - fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin(); - EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first); - atomDeclSet = &fieldNumberToAtomDeclSetIt->second; - EXPECT_EQ(2ul, atomDeclSet->size()); - atomDeclSetIt = atomDeclSet->begin(); - atomDecl = atomDeclSetIt->get(); - EXPECT_EQ(1, atomDecl->code); - fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; - fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); - EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); - annotationSet = &fieldNumberToAnnotationsIt->second; - EXPECT_EQ(1ul, annotationSet->size()); - annotationSetIt = annotationSet->begin(); - annotation = annotationSetIt->get(); - EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId); - EXPECT_EQ(1, annotation->atomId); - EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); - EXPECT_TRUE(annotation->value.boolValue); - - atomDeclSetIt++; - atomDecl = atomDeclSetIt->get(); - EXPECT_EQ(3, atomDecl->code); - fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; - fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); - EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); - annotationSet = &fieldNumberToAnnotationsIt->second; - EXPECT_EQ(1ul, annotationSet->size()); - annotationSetIt = annotationSet->begin(); - annotation = annotationSetIt->get(); - EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId); - EXPECT_EQ(3, annotation->atomId); - EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); - EXPECT_TRUE(annotation->value.boolValue); -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp deleted file mode 100644 index abb89133e58e..000000000000 --- a/tools/stats_log_api_gen/utils.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) 2019, 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 "utils.h" - -#include "android-base/strings.h" - -namespace android { -namespace stats_log_api_gen { - -static void build_non_chained_decl_map(const Atoms& atoms, - std::map<int, AtomDeclSet::const_iterator>* decl_map) { - for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin(); - atomIt != atoms.non_chained_decls.end(); atomIt++) { - decl_map->insert(std::make_pair((*atomIt)->code, atomIt)); - } -} - -/** - * Turn lower and camel case into upper case with underscores. - */ -string make_constant_name(const string& str) { - string result; - const int N = str.size(); - bool underscore_next = false; - for (int i = 0; i < N; i++) { - char c = str[i]; - if (c >= 'A' && c <= 'Z') { - if (underscore_next) { - result += '_'; - underscore_next = false; - } - } else if (c >= 'a' && c <= 'z') { - c = 'A' + c - 'a'; - underscore_next = true; - } else if (c == '_') { - underscore_next = false; - } - result += c; - } - return result; -} - -const char* cpp_type_name(java_type_t type) { - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "bool"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "int32_t"; - case JAVA_TYPE_LONG: - return "int64_t"; - case JAVA_TYPE_FLOAT: - return "float"; - case JAVA_TYPE_DOUBLE: - return "double"; - case JAVA_TYPE_STRING: - return "char const*"; - case JAVA_TYPE_BYTE_ARRAY: - return "const BytesField&"; - default: - return "UNKNOWN"; - } -} - -const char* java_type_name(java_type_t type) { - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "boolean"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "int"; - case JAVA_TYPE_LONG: - return "long"; - case JAVA_TYPE_FLOAT: - return "float"; - case JAVA_TYPE_DOUBLE: - return "double"; - case JAVA_TYPE_STRING: - return "java.lang.String"; - case JAVA_TYPE_BYTE_ARRAY: - return "byte[]"; - default: - return "UNKNOWN"; - } -} - -// Native -// Writes namespaces for the cpp and header files, returning the number of -// namespaces written. -void write_namespace(FILE* out, const string& cppNamespaces) { - vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); - for (string cppNamespace : cppNamespaceVec) { - fprintf(out, "namespace %s {\n", cppNamespace.c_str()); - } -} - -// Writes namespace closing brackets for cpp and header files. -void write_closing_namespace(FILE* out, const string& cppNamespaces) { - vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); - for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) { - fprintf(out, "} // namespace %s\n", it->c_str()); - } -} - -static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name, - const shared_ptr<AtomDecl> atom, const AtomDecl& attributionDecl) { - fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str()); - - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), chainField.name.c_str(), - chainField.name.c_str()); - } - } - } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, - ", const std::map<int, int32_t>& %s_int" - ", const std::map<int, int64_t>& %s_long" - ", const std::map<int, char const*>& %s_str" - ", const std::map<int, float>& %s_float", - field->name.c_str(), field->name.c_str(), field->name.c_str(), - field->name.c_str()); - } else { - fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); - } - } - fprintf(out, ");\n"); -} - -void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl) { - fprintf(out, "/**\n"); - fprintf(out, " * Constants for atom codes.\n"); - fprintf(out, " */\n"); - fprintf(out, "enum {\n"); - - std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map; - build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); - - size_t i = 0; - // Print atom constants - for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end(); - atomIt++) { - string constant = make_constant_name((*atomIt)->name); - fprintf(out, "\n"); - fprintf(out, " /**\n"); - fprintf(out, " * %s %s\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str()); - write_cpp_usage(out, "stats_write", constant, *atomIt, attributionDecl); - - auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code); - if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { - write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second, - attributionDecl); - } - fprintf(out, " */\n"); - char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; - fprintf(out, " %s = %d%s\n", constant.c_str(), (*atomIt)->code, comma); - i++; - } - fprintf(out, "\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); -} - -void write_native_method_signature(FILE* out, const string& methodName, - const vector<java_type_t>& signature, - const AtomDecl& attributionDecl, const string& closer) { - fprintf(out, "%s(int32_t code", methodName.c_str()); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), chainField.name.c_str(), - chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, - ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ")%s\n", closer.c_str()); -} - -void write_native_method_call(FILE* out, const string& methodName, - const vector<java_type_t>& signature, const AtomDecl& attributionDecl, - int argIndex) { - fprintf(out, "%s(code", methodName.c_str()); - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", %s", chainField.name.c_str()); - } else { - fprintf(out, ", %s, %s_length", chainField.name.c_str(), - chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, argIndex, argIndex, - argIndex); - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); -} - -// Java -void write_java_atom_codes(FILE* out, const Atoms& atoms) { - fprintf(out, " // Constants for atom codes.\n"); - - std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map; - build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); - - // Print constants for the atom codes. - for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end(); - atomIt++) { - string constant = make_constant_name((*atomIt)->name); - fprintf(out, "\n"); - fprintf(out, " /**\n"); - fprintf(out, " * %s %s<br>\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str()); - write_java_usage(out, "write", constant, **atomIt); - auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code); - if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { - write_java_usage(out, "write_non_chained", constant, **(non_chained_decl->second)); - } - fprintf(out, " */\n"); - fprintf(out, " public static final int %s = %d;\n", constant.c_str(), (*atomIt)->code); - } - fprintf(out, "\n"); -} - -void write_java_enum_values(FILE* out, const Atoms& atoms) { - fprintf(out, " // Constants for enum values.\n\n"); - for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end(); - atomIt++) { - for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin(); - field != (*atomIt)->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ENUM) { - fprintf(out, " // Values for %s.%s\n", (*atomIt)->message.c_str(), - field->name.c_str()); - for (map<int, string>::const_iterator value = field->enumValues.begin(); - value != field->enumValues.end(); value++) { - fprintf(out, " public static final int %s__%s__%s = %d;\n", - make_constant_name((*atomIt)->message).c_str(), - make_constant_name(field->name).c_str(), - make_constant_name(value->second).c_str(), value->first); - } - fprintf(out, "\n"); - } - } - } -} - -void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, - const AtomDecl& atom) { - fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(), - atom_code_name.c_str()); - for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end(); - field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(out, ", android.os.WorkSource workSource"); - } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", android.util.SparseArray<Object> value_map"); - } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, ", byte[] %s", field->name.c_str()); - } else { - fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str()); - } - } - fprintf(out, ");<br>\n"); -} - -int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) { - for (auto signatureInfoMapIt = signatureInfoMap.begin(); - signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { - // Print method signature. - fprintf(out, " public static void write_non_chained(int code"); - vector<java_type_t> signature = signatureInfoMapIt->first; - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(stderr, "Non chained signatures should not have attribution chains.\n"); - return 1; - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(stderr, "Module logging does not yet support key value pair.\n"); - return 1; - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - fprintf(out, " write(code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - // First two args are uid and tag of attribution chain. - if (argIndex == 1) { - fprintf(out, ", new int[] {arg%d}", argIndex); - } else if (argIndex == 2) { - fprintf(out, ", new java.lang.String[] {arg%d}", argIndex); - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - return 0; -} - -int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) { - fprintf(out, " // WorkSource methods.\n"); - for (auto signatureInfoMapIt = signatureInfoMap.begin(); - signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { - vector<java_type_t> signature = signatureInfoMapIt->first; - // Determine if there is Attribution in this signature. - int attributionArg = -1; - int argIndexMax = 0; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - argIndexMax++; - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - if (attributionArg > -1) { - fprintf(stderr, "An atom contains multiple AttributionNode fields.\n"); - fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n"); - fprintf(out, - "\n// Invalid for WorkSource: more than one attribution " - "chain.\n"); - return 1; - } - attributionArg = argIndexMax; - } - } - if (attributionArg < 0) { - continue; - } - - fprintf(out, "\n"); - // Method header (signature) - fprintf(out, " public static void write(int code"); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end(); - arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(out, ", android.os.WorkSource ws"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // write_non_chained() component. TODO: Remove when flat uids are no longer - // needed. - fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n"); - fprintf(out, " write_non_chained(code"); - for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { - if (argIndex == attributionArg) { - fprintf(out, ", ws.getUid(i), ws.getPackageName(i)"); - } else { - fprintf(out, ", arg%d", argIndex); - } - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // close for-loop - - // write() component. - fprintf(out, - " java.util.List<android.os.WorkSource.WorkChain> workChains = " - "ws.getWorkChains();\n"); - fprintf(out, " if (workChains != null) {\n"); - fprintf(out, - " for (android.os.WorkSource.WorkChain wc : workChains) " - "{\n"); - fprintf(out, " write(code"); - for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { - if (argIndex == attributionArg) { - fprintf(out, ", wc.getUids(), wc.getTags()"); - } else { - fprintf(out, ", arg%d", argIndex); - } - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // close for-loop - fprintf(out, " }\n"); // close if - fprintf(out, " }\n"); // close method - } - return 0; -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h deleted file mode 100644 index 73e0cb838227..000000000000 --- a/tools/stats_log_api_gen/utils.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2019, 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 <stdio.h> -#include <string.h> - -#include <map> -#include <set> -#include <vector> - -#include "Collation.h" - -namespace android { -namespace stats_log_api_gen { - -using namespace std; - -const string DEFAULT_CPP_NAMESPACE = "android,util"; -const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; - -const int JAVA_MODULE_REQUIRES_FLOAT = 0x01; -const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02; -const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04; - -const map<AnnotationId, string> ANNOTATION_ID_CONSTANTS = { - {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"}, - {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"}, - {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"}, - {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"}, - {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"}, - {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"}, - {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}}; - -string make_constant_name(const string& str); - -const char* cpp_type_name(java_type_t type); - -const char* java_type_name(java_type_t type); - -// Common Native helpers -void write_namespace(FILE* out, const string& cppNamespaces); - -void write_closing_namespace(FILE* out, const string& cppNamespaces); - -void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl); - -void write_native_method_signature(FILE* out, const string& methodName, - const vector<java_type_t>& signature, - const AtomDecl& attributionDecl, const string& closer); - -void write_native_method_call(FILE* out, const string& methodName, - const vector<java_type_t>& signature, const AtomDecl& attributionDecl, - int argIndex = 1); - -// Common Java helpers. -void write_java_atom_codes(FILE* out, const Atoms& atoms); - -void write_java_enum_values(FILE* out, const Atoms& atoms); - -void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, - const AtomDecl& atom); - -int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap); - -int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap); - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp index 1390f63248f9..1ec83a360048 100644 --- a/tools/streaming_proto/Android.bp +++ b/tools/streaming_proto/Android.bp @@ -17,6 +17,15 @@ // ========================================================== // Build the host executable: protoc-gen-javastream // ========================================================== +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"], +} + cc_defaults { name: "protoc-gen-stream-defaults", srcs: [ diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py index afe91cda37b0..15088fc81e88 100644 --- a/tools/stringslint/stringslint.py +++ b/tools/stringslint/stringslint.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 +#-*- coding: utf-8 -*- # Copyright (C) 2018 The Android Open Source Project # @@ -33,9 +34,6 @@ In general: import re, sys, codecs import lxml.etree as ET -reload(sys) -sys.setdefaultencoding('utf8') - BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False): @@ -118,7 +116,7 @@ def lint(path): raw = f.read() if len(raw.strip()) == 0: return warnings - tree = ET.fromstring(raw) + tree = ET.fromstring(bytes(raw, encoding='utf-8')) root = tree #tree.getroot() last_comment = None @@ -231,6 +229,6 @@ for b in before: if len(after) > 0: for a in sorted(after.keys()): - print after[a] - print + print(after[a]) + print() sys.exit(1) diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh index bd80bb4e6f3f..bd0569873197 100755 --- a/tools/stringslint/stringslint_sha.sh +++ b/tools/stringslint/stringslint_sha.sh @@ -1,5 +1,5 @@ #!/bin/bash LOCAL_DIR="$( dirname ${BASH_SOURCE} )" git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do - python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file) + python3 $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file) done diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp index 819e75ba1fed..9fcf034536fc 100644 --- a/tools/validatekeymaps/Android.bp +++ b/tools/validatekeymaps/Android.bp @@ -4,6 +4,15 @@ // Keymap validation tool. // +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"], +} + cc_binary_host { name: "validatekeymaps", diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp index 5ac9dfd2a557..877715a66f6d 100644 --- a/tools/validatekeymaps/Main.cpp +++ b/tools/validatekeymaps/Main.cpp @@ -16,8 +16,8 @@ #include <input/KeyCharacterMap.h> #include <input/KeyLayoutMap.h> +#include <input/PropertyMap.h> #include <input/VirtualKeyMap.h> -#include <utils/PropertyMap.h> #include <stdarg.h> #include <stdio.h> |