diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/aapt2/Debug.cpp | 92 | ||||
| -rw-r--r-- | tools/aapt2/Debug.h | 1 | ||||
| -rw-r--r-- | tools/aapt2/Main.cpp | 5 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Dump.cpp | 11 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Dump.h | 12 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Optimize.cpp | 50 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Optimize.h | 15 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Optimize_test.cpp | 68 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/TableFlattener.cpp | 14 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/TableFlattener.h | 5 | ||||
| -rw-r--r-- | tools/aapt2/format/binary/TableFlattener_test.cpp | 15 | ||||
| -rwxr-xr-x | tools/codegen/src/com/android/codegen/Main.kt | 2 | ||||
| -rw-r--r-- | tools/codegen/src/com/android/codegen/SharedConstants.kt | 2 | ||||
| -rw-r--r-- | tools/protologtool/Android.bp | 23 | ||||
| -rw-r--r-- | tools/protologtool/manifest.txt | 2 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt (renamed from tools/protologtool/src/com/android/protologtool/CodeUtils.kt) | 68 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt (renamed from tools/protologtool/src/com/android/protologtool/CommandOptions.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/Constants.kt (renamed from tools/protologtool/src/com/android/protologtool/Constants.kt) | 5 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/LogGroup.kt (renamed from tools/protologtool/src/com/android/protologtool/LogGroup.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/LogLevel.kt (renamed from tools/protologtool/src/com/android/protologtool/LogLevel.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/LogParser.kt (renamed from tools/protologtool/src/com/android/protologtool/LogParser.kt) | 25 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt (renamed from tools/protologtool/src/com/android/protologtool/ProtoLogCallProcessor.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/ProtoLogCallVisitor.kt (renamed from tools/protologtool/src/com/android/protologtool/ProtoLogCallVisitor.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt (renamed from tools/protologtool/src/com/android/protologtool/ProtoLogGroupReader.kt) | 24 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt (renamed from tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt) | 29 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt (renamed from tools/protologtool/src/com/android/protologtool/SourceTransformer.kt) | 104 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt (renamed from tools/protologtool/src/com/android/protologtool/ViewerConfigBuilder.kt) | 33 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt (renamed from tools/protologtool/src/com/android/protologtool/ViewerConfigParser.kt) | 11 | ||||
| -rw-r--r-- | tools/protologtool/src/com/android/protolog/tool/exceptions.kt (renamed from tools/protologtool/src/com/android/protologtool/exceptions.kt) | 14 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/CodeUtilsTest.kt) | 62 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/CommandOptionsTest.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/LogParserTest.kt) | 30 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/ProtoLogCallProcessorTest.kt) | 2 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt) | 139 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/ViewerConfigBuilderTest.kt) | 47 | ||||
| -rw-r--r-- | tools/protologtool/tests/com/android/protolog/tool/ViewerConfigParserTest.kt (renamed from tools/protologtool/tests/com/android/protologtool/ViewerConfigParserTest.kt) | 6 | ||||
| -rw-r--r-- | tools/validatekeymaps/Main.cpp | 1 |
37 files changed, 590 insertions, 339 deletions
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 7ffa5ffc09fe..137fbd671865 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -246,6 +246,36 @@ class ValueBodyPrinter : public ConstValueVisitor { Printer* printer_; }; +std::string OverlayablePoliciesToString(OverlayableItem::PolicyFlags policies) { + static const std::map<OverlayableItem::PolicyFlags, std::string> kFlagToString = { + {OverlayableItem::kPublic, "public"}, + {OverlayableItem::kSystem, "system"}, + {OverlayableItem::kVendor, "vendor"}, + {OverlayableItem::kProduct, "product"}, + {OverlayableItem::kSignature, "signature"}, + {OverlayableItem::kOdm, "odm"}, + {OverlayableItem::kOem, "oem"}, + }; + std::string str; + for (auto const& policy : kFlagToString) { + if ((policies & policy.first) != policy.first) { + continue; + } + if (!str.empty()) { + str.append("|"); + } + str.append(policy.second); + policies &= ~policy.first; + } + if (policies != 0) { + if (!str.empty()) { + str.append("|"); + } + str.append(StringPrintf("0x%08x", policies)); + } + return !str.empty() ? str : "none"; +} + } // namespace void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options, @@ -312,6 +342,10 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& break; } + if (entry->overlayable_item) { + printer->Print(" OVERLAYABLE"); + } + printer->Println(); if (options.show_values) { @@ -525,4 +559,62 @@ void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) { doc.root->Accept(&xml_visitor); } +struct DumpOverlayableEntry { + std::string overlayable_section; + std::string policy_subsection; + std::string resource_name; +}; + +void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer) { + std::vector<DumpOverlayableEntry> items; + for (const auto& package : table.packages) { + for (const auto& type : package->types) { + for (const auto& entry : type->entries) { + if (entry->overlayable_item) { + const auto& overlayable_item = entry->overlayable_item.value(); + const auto overlayable_section = StringPrintf(R"(name="%s" actor="%s")", + overlayable_item.overlayable->name.c_str(), + overlayable_item.overlayable->actor.c_str()); + const auto policy_subsection = StringPrintf(R"(policies="%s")", + OverlayablePoliciesToString(overlayable_item.policies).c_str()); + const auto value = + StringPrintf("%s/%s", to_string(type->type).data(), entry->name.c_str()); + items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value}); + } + } + } + } + + std::sort(items.begin(), items.end(), + [](const DumpOverlayableEntry& a, const DumpOverlayableEntry& b) { + if (a.overlayable_section != b.overlayable_section) { + return a.overlayable_section < b.overlayable_section; + } + if (a.policy_subsection != b.policy_subsection) { + return a.policy_subsection < b.policy_subsection; + } + return a.resource_name < b.resource_name; + }); + + std::string last_overlayable_section; + std::string last_policy_subsection; + for (const auto& item : items) { + if (last_overlayable_section != item.overlayable_section) { + printer->Println(item.overlayable_section); + last_overlayable_section = item.overlayable_section; + } + if (last_policy_subsection != item.policy_subsection) { + printer->Indent(); + printer->Println(item.policy_subsection); + last_policy_subsection = item.policy_subsection; + printer->Undent(); + } + printer->Indent(); + printer->Indent(); + printer->Println(item.resource_name); + printer->Undent(); + printer->Undent(); + } +} + } // namespace aapt diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h index a43197cacf7b..9443d606d7e5 100644 --- a/tools/aapt2/Debug.h +++ b/tools/aapt2/Debug.h @@ -39,6 +39,7 @@ struct Debug { static void DumpHex(const void* data, size_t len); static void DumpXml(const xml::XmlResource& doc, text::Printer* printer); static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer); + static void DumpOverlayable(const ResourceTable& table, text::Printer* printer); }; } // namespace aapt diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 213bdd2372ec..7966ba27ebd8 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -177,6 +177,11 @@ int MainImpl(int argc, char** argv) { return main_command->Execute(args, &std::cerr); } +// TODO(b/141312058) stop leaks +extern "C" const char *__asan_default_options() { + return "detect_leaks=0"; +} + int main(int argc, char** argv) { #ifdef _WIN32 LPWSTR* wide_argv = CommandLineToArgvW(GetCommandLineW(), &argc); diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 429aff1ff594..3982d12f6036 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -394,6 +394,17 @@ int DumpXmlTreeCommand::Dump(LoadedApk* apk) { return 0; } +int DumpOverlayableCommand::Dump(LoadedApk* apk) { + ResourceTable* table = apk->GetResourceTable(); + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); + return 1; + } + + Debug::DumpOverlayable(*table, GetPrinter()); + return 0; +} + const char DumpBadgerCommand::kBadgerData[2925] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 7ded9bcf8470..cd51f7a7718c 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -240,6 +240,16 @@ class DumpXmlTreeCommand : public DumpApkCommand { std::vector<std::string> files_; }; +class DumpOverlayableCommand : public DumpApkCommand { + public: + explicit DumpOverlayableCommand(text::Printer* printer, IDiagnostics* diag) + : DumpApkCommand("overlayable", printer, diag) { + SetDescription("Print the <overlayable> resources of an APK."); + } + + int Dump(LoadedApk* apk) override; +}; + /** The default dump command. Performs no action because a subcommand is required. */ class DumpCommand : public Command { public: @@ -255,8 +265,8 @@ class DumpCommand : public Command { AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_)); AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_)); AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_)); + AddOptionalSubcommand(util::make_unique<DumpOverlayableCommand>(printer, diag_)); AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true); - // TODO(b/120609160): Add aapt2 overlayable dump command } int Action(const std::vector<std::string>& args) override { diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index 5e06818d7a13..e36668e5a043 100644 --- a/tools/aapt2/cmd/Optimize.cpp +++ b/tools/aapt2/cmd/Optimize.cpp @@ -53,9 +53,9 @@ using ::android::ConfigDescription; using ::android::ResTable_config; using ::android::StringPiece; using ::android::base::ReadFileToString; -using ::android::base::WriteStringToFile; using ::android::base::StringAppendF; using ::android::base::StringPrintf; +using ::android::base::WriteStringToFile; namespace aapt { @@ -300,29 +300,7 @@ class Optimizer { OptimizeContext* context_; }; -bool ExtractObfuscationWhitelistFromConfig(const std::string& path, OptimizeContext* context, - OptimizeOptions* options) { - std::string contents; - if (!ReadFileToString(path, &contents, true)) { - context->GetDiagnostics()->Error(DiagMessage() - << "failed to parse whitelist from config file: " << path); - return false; - } - for (StringPiece resource_name : util::Tokenize(contents, ',')) { - options->table_flattener_options.whitelisted_resources.insert( - resource_name.to_string()); - } - return true; -} - -bool ExtractConfig(const std::string& path, OptimizeContext* context, - OptimizeOptions* options) { - std::string content; - if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) { - context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading whitelist"); - return false; - } - +bool ParseConfig(const std::string& content, IAaptContext* context, OptimizeOptions* options) { size_t line_no = 0; for (StringPiece line : util::Tokenize(content, '\n')) { line_no++; @@ -351,15 +329,24 @@ bool ExtractConfig(const std::string& path, OptimizeContext* context, for (StringPiece directive : util::Tokenize(directives, ',')) { if (directive == "remove") { options->resources_blacklist.insert(resource_name.ToResourceName()); - } else if (directive == "no_obfuscate") { - options->table_flattener_options.whitelisted_resources.insert( - resource_name.entry.to_string()); + } else if (directive == "no_collapse" || directive == "no_obfuscate") { + options->table_flattener_options.name_collapse_exemptions.insert( + resource_name.ToResourceName()); } } } return true; } +bool ExtractConfig(const std::string& path, IAaptContext* context, OptimizeOptions* options) { + std::string content; + if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) { + context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading config file"); + return false; + } + return ParseConfig(content, context, options); +} + bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk, OptimizeOptions* out_options) { const xml::XmlResource* manifest = apk->GetManifest(); @@ -467,15 +454,6 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) { } } - if (options_.table_flattener_options.collapse_key_stringpool) { - if (whitelist_path_) { - std::string& path = whitelist_path_.value(); - if (!ExtractObfuscationWhitelistFromConfig(path, &context, &options_)) { - return 1; - } - } - } - if (resources_config_path_) { std::string& path = resources_config_path_.value(); if (!ExtractConfig(path, &context, &options_)) { diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h index 0be7dad18380..5070ccc8afbf 100644 --- a/tools/aapt2/cmd/Optimize.h +++ b/tools/aapt2/cmd/Optimize.h @@ -78,10 +78,6 @@ class OptimizeCommand : public Command { "All the resources that would be unused on devices of the given densities will be \n" "removed from the APK.", &target_densities_); - AddOptionalFlag("--whitelist-path", - "Path to the whitelist.cfg file containing whitelisted resources \n" - "whose names should not be altered in final resource tables.", - &whitelist_path_); AddOptionalFlag("--resources-config-path", "Path to the resources.cfg file containing the list of resources and \n" "directives to each resource. \n" @@ -104,11 +100,13 @@ class OptimizeCommand : public Command { "Enables encoding sparse entries using a binary search tree.\n" "This decreases APK size at the cost of resource retrieval performance.", &options_.table_flattener_options.use_sparse_entries); - AddOptionalSwitch("--enable-resource-obfuscation", - "Enables obfuscation of key string pool to single value", + AddOptionalSwitch("--collapse-resource-names", + "Collapses resource names to a single value in the key string pool. Resources can \n" + "be exempted using the \"no_collapse\" directive in a file specified by " + "--resources-config-path.", &options_.table_flattener_options.collapse_key_stringpool); - AddOptionalSwitch("--enable-resource-path-shortening", - "Enables shortening of the path of the resources inside the APK.", + AddOptionalSwitch("--shorten-resource-paths", + "Shortens the paths of resources inside the APK.", &options_.shorten_resource_paths); AddOptionalFlag("--resource-path-shortening-map", "Path to output the map of old resource paths to shortened paths.", @@ -125,7 +123,6 @@ class OptimizeCommand : public Command { const std::string &file_path); Maybe<std::string> config_path_; - Maybe<std::string> whitelist_path_; Maybe<std::string> resources_config_path_; Maybe<std::string> target_densities_; std::vector<std::string> configs_; diff --git a/tools/aapt2/cmd/Optimize_test.cpp b/tools/aapt2/cmd/Optimize_test.cpp new file mode 100644 index 000000000000..ac681e85b3d6 --- /dev/null +++ b/tools/aapt2/cmd/Optimize_test.cpp @@ -0,0 +1,68 @@ +/* + * 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 "Optimize.h" + +#include "AppInfo.h" +#include "Diagnostics.h" +#include "LoadedApk.h" +#include "Resource.h" +#include "test/Test.h" + +using testing::Contains; +using testing::Eq; + +namespace aapt { + +bool ParseConfig(const std::string&, IAaptContext*, OptimizeOptions*); + +using OptimizeTest = CommandTestFixture; + +TEST_F(OptimizeTest, ParseConfigWithNoCollapseExemptions) { + const std::string& content = R"( +string/foo#no_collapse +dimen/bar#no_collapse +)"; + aapt::test::Context context; + OptimizeOptions options; + ParseConfig(content, &context, &options); + + const std::set<ResourceName>& name_collapse_exemptions = + options.table_flattener_options.name_collapse_exemptions; + + ASSERT_THAT(name_collapse_exemptions.size(), Eq(2)); + EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kString, "foo"))); + EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kDimen, "bar"))); +} + +TEST_F(OptimizeTest, ParseConfigWithNoObfuscateExemptions) { + const std::string& content = R"( +string/foo#no_obfuscate +dimen/bar#no_obfuscate +)"; + aapt::test::Context context; + OptimizeOptions options; + ParseConfig(content, &context, &options); + + const std::set<ResourceName>& name_collapse_exemptions = + options.table_flattener_options.name_collapse_exemptions; + + ASSERT_THAT(name_collapse_exemptions.size(), Eq(2)); + EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kString, "foo"))); + EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kDimen, "bar"))); +} + +} // namespace aapt diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index b9321174100b..58e232c33985 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -228,14 +228,15 @@ class PackageFlattener { public: PackageFlattener(IAaptContext* context, ResourceTablePackage* package, const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries, - bool collapse_key_stringpool, const std::set<std::string>& whitelisted_resources) + bool collapse_key_stringpool, + const std::set<ResourceName>& name_collapse_exemptions) : context_(context), diag_(context->GetDiagnostics()), package_(package), shared_libs_(shared_libs), use_sparse_entries_(use_sparse_entries), collapse_key_stringpool_(collapse_key_stringpool), - whitelisted_resources_(whitelisted_resources) { + name_collapse_exemptions_(name_collapse_exemptions) { } bool FlattenPackage(BigBuffer* buffer) { @@ -652,11 +653,12 @@ class PackageFlattener { for (ResourceEntry* entry : sorted_entries) { uint32_t local_key_index; + ResourceName resource_name({}, type->type, entry->name); if (!collapse_key_stringpool_ || - whitelisted_resources_.find(entry->name) != whitelisted_resources_.end()) { + name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) { local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index(); } else { - // resource isn't whitelisted, add it as obfuscated value + // resource isn't exempt from collapse, add it as obfuscated value local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index(); } // Group values by configuration. @@ -712,7 +714,7 @@ class PackageFlattener { StringPool type_pool_; StringPool key_pool_; bool collapse_key_stringpool_; - const std::set<std::string>& whitelisted_resources_; + const std::set<ResourceName>& name_collapse_exemptions_; }; } // namespace @@ -760,7 +762,7 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { PackageFlattener flattener(context, package.get(), &table->included_packages_, options_.use_sparse_entries, options_.collapse_key_stringpool, - options_.whitelisted_resources); + options_.name_collapse_exemptions); if (!flattener.FlattenPackage(&package_buffer)) { return false; } diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h index 73c17295556b..4360db190146 100644 --- a/tools/aapt2/format/binary/TableFlattener.h +++ b/tools/aapt2/format/binary/TableFlattener.h @@ -19,6 +19,7 @@ #include "android-base/macros.h" +#include "Resource.h" #include "ResourceTable.h" #include "process/IResourceTableConsumer.h" #include "util/BigBuffer.h" @@ -41,8 +42,8 @@ struct TableFlattenerOptions { // have name indices that point to this single value bool collapse_key_stringpool = false; - // Set of whitelisted resource names to avoid altering in key stringpool - std::set<std::string> whitelisted_resources; + // Set of resources to avoid collapsing to a single entry in key stringpool. + std::set<ResourceName> name_collapse_exemptions; // Map from original resource paths to shortened resource paths. std::map<std::string, std::string> shortened_path_map; diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index a9409235e07a..8fbdd7f27041 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -518,7 +518,7 @@ TEST_F(TableFlattenerTest, LongSharedLibraryPackageNameIsIllegal) { ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result)); } -TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) { +TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoNameCollapseExemptionsSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) @@ -572,7 +572,7 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoWhitelistSucceeds) { ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u)); } -TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { +TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) { std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) @@ -591,21 +591,22 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) { TableFlattenerOptions options; options.collapse_key_stringpool = true; - options.whitelisted_resources.insert("test"); - options.whitelisted_resources.insert("three"); + options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kId, "one")); + options.name_collapse_exemptions.insert(ResourceName({}, ResourceType::kString, "test")); ResTable res_table; ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table)); - EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated", + EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f020000), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated", ResourceId(0x7f020001), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u)); - EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three", ResourceId(0x7f020002), {}, - Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); + EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated", + ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u)); + // Note that this resource is also named "one", but it's a different type, so gets obfuscated. EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated", ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION)); diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt index 0f932f3c34e1..fa2b41adcacb 100755 --- a/tools/codegen/src/com/android/codegen/Main.kt +++ b/tools/codegen/src/com/android/codegen/Main.kt @@ -107,7 +107,7 @@ fun main(args: Array<String>) { println(CODEGEN_VERSION) System.exit(0) } - val file = File(args.last()) + val file = File(args.last()).absoluteFile val sourceLinesNoClosingBrace = file.readLines().dropLastWhile { it.startsWith("}") || it.all(Char::isWhitespace) } diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 7d50ad10de00..b2cc81391510 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.0" +const val CODEGEN_VERSION = "1.0.1" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp index a86c226c2179..d1a86c245dec 100644 --- a/tools/protologtool/Android.bp +++ b/tools/protologtool/Android.bp @@ -1,27 +1,32 @@ -java_binary_host { - name: "protologtool", - manifest: "manifest.txt", +java_library_host { + name: "protologtool-lib", srcs: [ - "src/**/*.kt", + "src/com/android/protolog/tool/**/*.kt", ], static_libs: [ + "protolog-common", "javaparser", - "windowmanager-log-proto", + "protolog-proto", "jsonlib", ], } +java_binary_host { + name: "protologtool", + manifest: "manifest.txt", + static_libs: [ + "protologtool-lib", + ], +} + java_test_host { name: "protologtool-tests", test_suites: ["general-tests"], srcs: [ - "src/**/*.kt", "tests/**/*.kt", ], static_libs: [ - "javaparser", - "windowmanager-log-proto", - "jsonlib", + "protologtool-lib", "junit", "mockito", ], diff --git a/tools/protologtool/manifest.txt b/tools/protologtool/manifest.txt index f5e53c450f2a..cabebd51a2fa 100644 --- a/tools/protologtool/manifest.txt +++ b/tools/protologtool/manifest.txt @@ -1 +1 @@ -Main-class: com.android.protologtool.ProtoLogTool +Main-class: com.android.protolog.tool.ProtoLogTool diff --git a/tools/protologtool/src/com/android/protologtool/CodeUtils.kt b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt index facca6290c91..2e48d97d6349 100644 --- a/tools/protologtool/src/com/android/protologtool/CodeUtils.kt +++ b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt @@ -14,28 +14,22 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool -import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.ImportDeclaration -import com.github.javaparser.ast.NodeList import com.github.javaparser.ast.expr.BinaryExpr import com.github.javaparser.ast.expr.Expression -import com.github.javaparser.ast.expr.MethodCallExpr -import com.github.javaparser.ast.expr.SimpleName import com.github.javaparser.ast.expr.StringLiteralExpr -import com.github.javaparser.ast.expr.TypeExpr -import com.github.javaparser.ast.type.PrimitiveType -import com.github.javaparser.ast.type.Type object CodeUtils { /** * Returns a stable hash of a string. * We reimplement String::hashCode() for readability reasons. */ - fun hash(str: String, level: LogLevel): Int { - return (level.name + str).map { c -> c.toInt() }.reduce { h, c -> h * 31 + c } + fun hash(position: String, messageString: String, logLevel: LogLevel, logGroup: LogGroup): Int { + return (position + messageString + logLevel.name + logGroup.name) + .map { c -> c.toInt() }.reduce { h, c -> h * 31 + c } } fun isWildcardStaticImported(code: CompilationUnit, className: String): Boolean { @@ -79,57 +73,9 @@ object CodeUtils { } } - enum class LogDataTypes( - val type: Type, - val toType: (Expression) -> Expression = { expr -> expr } - ) { - // When adding new LogDataType make sure to update {@code logDataTypesToBitMask} accordingly - STRING(StaticJavaParser.parseClassOrInterfaceType("String"), - { expr -> - MethodCallExpr(TypeExpr(StaticJavaParser.parseClassOrInterfaceType("String")), - SimpleName("valueOf"), NodeList(expr)) - }), - LONG(PrimitiveType.longType()), - DOUBLE(PrimitiveType.doubleType()), - BOOLEAN(PrimitiveType.booleanType()); - } - - fun parseFormatString(messageString: String): List<LogDataTypes> { - val types = mutableListOf<LogDataTypes>() - var i = 0 - while (i < messageString.length) { - if (messageString[i] == '%') { - if (i + 1 >= messageString.length) { - throw InvalidFormatStringException("Invalid format string in config") - } - when (messageString[i + 1]) { - 'b' -> types.add(CodeUtils.LogDataTypes.BOOLEAN) - 'd', 'o', 'x' -> types.add(CodeUtils.LogDataTypes.LONG) - 'f', 'e', 'g' -> types.add(CodeUtils.LogDataTypes.DOUBLE) - 's' -> types.add(CodeUtils.LogDataTypes.STRING) - '%' -> { - } - else -> throw InvalidFormatStringException("Invalid format string field" + - " %${messageString[i + 1]}") - } - i += 2 - } else { - i += 1 - } - } - return types - } - - fun logDataTypesToBitMask(types: List<LogDataTypes>): Int { - if (types.size > 16) { - throw InvalidFormatStringException("Too many log call parameters " + - "- max 16 parameters supported") - } - var mask = 0 - types.forEachIndexed { idx, type -> - val x = LogDataTypes.values().indexOf(type) - mask = mask or (x shl (idx * 2)) + fun getPositionString(fileName: String): String { + return when { + else -> fileName } - return mask } } diff --git a/tools/protologtool/src/com/android/protologtool/CommandOptions.kt b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt index df49e1566fbc..3dfa4d216cc2 100644 --- a/tools/protologtool/src/com/android/protologtool/CommandOptions.kt +++ b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import java.util.regex.Pattern diff --git a/tools/protologtool/src/com/android/protologtool/Constants.kt b/tools/protologtool/src/com/android/protolog/tool/Constants.kt index 2ccfc4d20182..aa3e00f2f4db 100644 --- a/tools/protologtool/src/com/android/protologtool/Constants.kt +++ b/tools/protologtool/src/com/android/protolog/tool/Constants.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool object Constants { const val NAME = "protologtool" const val VERSION = "1.0.0" const val IS_ENABLED_METHOD = "isEnabled" - const val IS_LOG_TO_LOGCAT_METHOD = "isLogToLogcat" - const val IS_LOG_TO_ANY_METHOD = "isLogToAny" - const val GET_TAG_METHOD = "getTag" const val ENUM_VALUES_METHOD = "values" } diff --git a/tools/protologtool/src/com/android/protologtool/LogGroup.kt b/tools/protologtool/src/com/android/protolog/tool/LogGroup.kt index 42a37a26e08a..587f7b9db016 100644 --- a/tools/protologtool/src/com/android/protologtool/LogGroup.kt +++ b/tools/protologtool/src/com/android/protolog/tool/LogGroup.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool data class LogGroup( val name: String, diff --git a/tools/protologtool/src/com/android/protologtool/LogLevel.kt b/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt index dc29557ef440..7759f35b33fe 100644 --- a/tools/protologtool/src/com/android/protologtool/LogLevel.kt +++ b/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.ast.Node diff --git a/tools/protologtool/src/com/android/protologtool/LogParser.kt b/tools/protologtool/src/com/android/protolog/tool/LogParser.kt index 4d0eb0e4a705..a59038fc99a0 100644 --- a/tools/protologtool/src/com/android/protologtool/LogParser.kt +++ b/tools/protologtool/src/com/android/protolog/tool/LogParser.kt @@ -14,11 +14,13 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.android.json.stream.JsonReader -import com.android.server.wm.ProtoLogMessage -import com.android.server.wm.WindowManagerLogFileProto +import com.android.server.protolog.common.InvalidFormatStringException +import com.android.server.protolog.common.LogDataType +import com.android.server.protolog.ProtoLogMessage +import com.android.server.protolog.ProtoLogFileProto import java.io.BufferedReader import java.io.InputStream import java.io.InputStreamReader @@ -36,8 +38,8 @@ class LogParser(private val configParser: ViewerConfigParser) { companion object { private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US) private val magicNumber = - WindowManagerLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or - WindowManagerLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong() + ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or + ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong() } private fun printTime(time: Long, offset: Long, ps: PrintStream) { @@ -55,14 +57,15 @@ class LogParser(private val configParser: ViewerConfigParser) { val boolParamsIt = protoLogMessage.booleanParamsList.iterator() val args = mutableListOf<Any>() val format = configEntry.messageString - val argTypes = CodeUtils.parseFormatString(format) + val argTypes = LogDataType.parseFormatString(format) try { argTypes.forEach { when (it) { - CodeUtils.LogDataTypes.BOOLEAN -> args.add(boolParamsIt.next()) - CodeUtils.LogDataTypes.LONG -> args.add(longParamsIt.next()) - CodeUtils.LogDataTypes.DOUBLE -> args.add(doubleParamsIt.next()) - CodeUtils.LogDataTypes.STRING -> args.add(strParmIt.next()) + LogDataType.BOOLEAN -> args.add(boolParamsIt.next()) + LogDataType.LONG -> args.add(longParamsIt.next()) + LogDataType.DOUBLE -> args.add(doubleParamsIt.next()) + LogDataType.STRING -> args.add(strParmIt.next()) + null -> throw NullPointerException() } } } catch (ex: NoSuchElementException) { @@ -85,7 +88,7 @@ class LogParser(private val configParser: ViewerConfigParser) { fun parse(protoLogInput: InputStream, jsonConfigInput: InputStream, ps: PrintStream) { val jsonReader = JsonReader(BufferedReader(InputStreamReader(jsonConfigInput))) val config = configParser.parseConfig(jsonReader) - val protoLog = WindowManagerLogFileProto.parseFrom(protoLogInput) + val protoLog = ProtoLogFileProto.parseFrom(protoLogInput) if (protoLog.magicNumber != magicNumber) { throw InvalidInputException("ProtoLog file magic number is invalid.") diff --git a/tools/protologtool/src/com/android/protologtool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt index 29d8ae5c6694..eae63962161c 100644 --- a/tools/protologtool/src/com/android/protologtool/ProtoLogCallProcessor.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.expr.Expression diff --git a/tools/protologtool/src/com/android/protologtool/ProtoLogCallVisitor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallVisitor.kt index 42a75f8cc22f..aa58b69d61cb 100644 --- a/tools/protologtool/src/com/android/protologtool/ProtoLogCallVisitor.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallVisitor.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.ast.expr.MethodCallExpr diff --git a/tools/protologtool/src/com/android/protologtool/ProtoLogGroupReader.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt index 664c8a6506b2..75493b6427cb 100644 --- a/tools/protologtool/src/com/android/protologtool/ProtoLogGroupReader.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool -import com.android.protologtool.Constants.ENUM_VALUES_METHOD -import com.android.protologtool.Constants.GET_TAG_METHOD -import com.android.protologtool.Constants.IS_ENABLED_METHOD -import com.android.protologtool.Constants.IS_LOG_TO_LOGCAT_METHOD +import com.android.protolog.tool.Constants.ENUM_VALUES_METHOD +import com.android.server.protolog.common.IProtoLogGroup import java.io.File -import java.lang.RuntimeException import java.net.URLClassLoader class ProtoLogGroupReader { @@ -31,18 +28,10 @@ class ProtoLogGroupReader { return URLClassLoader(arrayOf(url), ProtoLogGroupReader::class.java.classLoader) } - private fun getEnumValues(clazz: Class<*>): List<Enum<*>> { + private fun getEnumValues(clazz: Class<*>): List<IProtoLogGroup> { val valuesMethod = clazz.getMethod(ENUM_VALUES_METHOD) @Suppress("UNCHECKED_CAST") - return (valuesMethod.invoke(null) as Array<Enum<*>>).toList() - } - - private fun getLogGroupFromEnumValue(group: Any, clazz: Class<*>): LogGroup { - val enabled = clazz.getMethod(IS_ENABLED_METHOD).invoke(group) as Boolean - val textEnabled = clazz.getMethod(IS_LOG_TO_LOGCAT_METHOD).invoke(group) as Boolean - val tag = clazz.getMethod(GET_TAG_METHOD).invoke(group) as String - val name = (group as Enum<*>).name - return LogGroup(name, enabled, textEnabled, tag) + return (valuesMethod.invoke(null) as Array<IProtoLogGroup>).toList() } fun loadFromJar(jarPath: String, className: String): Map<String, LogGroup> { @@ -51,7 +40,8 @@ class ProtoLogGroupReader { val clazz = classLoader.loadClass(className) val values = getEnumValues(clazz) return values.map { group -> - group.name to getLogGroupFromEnumValue(group, clazz) + group.name() to + LogGroup(group.name(), group.isEnabled, group.isLogToLogcat, group.tag) }.toMap() } catch (ex: ReflectiveOperationException) { throw RuntimeException("Unable to load ProtoLogGroup enum class", ex) diff --git a/tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index 485a0479cbd9..53834a69ef9f 100644 --- a/tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool -import com.android.protologtool.CommandOptions.Companion.USAGE +import com.android.protolog.tool.CommandOptions.Companion.USAGE import com.github.javaparser.StaticJavaParser import java.io.File import java.io.FileInputStream @@ -31,6 +31,11 @@ object ProtoLogTool { exitProcess(-1) } + private fun containsProtoLogText(source: String, protoLogClassName: String): Boolean { + val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.') + return source.contains(protoLogSimpleClassName) + } + private fun processClasses(command: CommandOptions) { val groups = ProtoLogGroupReader() .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) @@ -42,11 +47,16 @@ object ProtoLogTool { command.javaSourceArgs.forEach { path -> val file = File(path) - val code = StaticJavaParser.parse(file) - val outSrc = transformer.processClass(code) + val text = file.readText() + val code = StaticJavaParser.parse(text) val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val newPath = pack.replace('.', '/') + '/' + file.name + val outSrc = when { + containsProtoLogText(text, command.protoLogClassNameArg) -> + transformer.processClass(text, newPath, code) + else -> text + } outJar.putNextEntry(ZipEntry(newPath)) outJar.write(outSrc.toByteArray()) outJar.closeEntry() @@ -64,14 +74,21 @@ object ProtoLogTool { val builder = ViewerConfigBuilder(processor) command.javaSourceArgs.forEach { path -> val file = File(path) - builder.processClass(StaticJavaParser.parse(file)) + val text = file.readText() + if (containsProtoLogText(text, command.protoLogClassNameArg)) { + val code = StaticJavaParser.parse(text) + val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration + .get().nameAsString else "" + val newPath = pack.replace('.', '/') + '/' + file.name + builder.processClass(code, newPath) + } } val out = FileOutputStream(command.viewerConfigJsonArg) out.write(builder.build().toByteArray()) out.close() } - fun read(command: CommandOptions) { + private fun read(command: CommandOptions) { LogParser(ViewerConfigParser()) .parse(FileInputStream(command.logProtofileArg), FileInputStream(command.viewerConfigJsonArg), System.out) diff --git a/tools/protologtool/src/com/android/protologtool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index 319a8170dca8..c2964a3dad7e 100644 --- a/tools/protologtool/src/com/android/protologtool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -14,26 +14,32 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool -import com.android.protologtool.Constants.IS_LOG_TO_ANY_METHOD +import com.android.protolog.tool.Constants.IS_ENABLED_METHOD +import com.android.server.protolog.common.LogDataType import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.NodeList import com.github.javaparser.ast.body.VariableDeclarator import com.github.javaparser.ast.expr.BooleanLiteralExpr import com.github.javaparser.ast.expr.CastExpr +import com.github.javaparser.ast.expr.Expression import com.github.javaparser.ast.expr.FieldAccessExpr import com.github.javaparser.ast.expr.IntegerLiteralExpr import com.github.javaparser.ast.expr.MethodCallExpr import com.github.javaparser.ast.expr.NameExpr import com.github.javaparser.ast.expr.NullLiteralExpr import com.github.javaparser.ast.expr.SimpleName +import com.github.javaparser.ast.expr.TypeExpr import com.github.javaparser.ast.expr.VariableDeclarationExpr import com.github.javaparser.ast.stmt.BlockStmt import com.github.javaparser.ast.stmt.ExpressionStmt import com.github.javaparser.ast.stmt.IfStmt import com.github.javaparser.ast.type.ArrayType +import com.github.javaparser.ast.type.ClassOrInterfaceType +import com.github.javaparser.ast.type.PrimitiveType +import com.github.javaparser.ast.type.Type import com.github.javaparser.printer.PrettyPrinter import com.github.javaparser.printer.PrettyPrinterConfiguration import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter @@ -67,7 +73,8 @@ class SourceTransformer( } val ifStmt: IfStmt if (group.enabled) { - val hash = CodeUtils.hash(messageString, level) + val position = CodeUtils.getPositionString(fileName) + val hash = CodeUtils.hash(position, messageString, level, group) val newCall = call.clone() if (!group.textEnabled) { // Remove message string if text logging is not enabled by default. @@ -77,19 +84,19 @@ class SourceTransformer( // Insert message string hash as a second argument. // Out: ProtoLog.e(GROUP, 1234, null, arg) newCall.arguments.add(1, IntegerLiteralExpr(hash)) - val argTypes = CodeUtils.parseFormatString(messageString) - val typeMask = CodeUtils.logDataTypesToBitMask(argTypes) + val argTypes = LogDataType.parseFormatString(messageString) + val typeMask = LogDataType.logDataTypesToBitMask(argTypes) // Insert bitmap representing which Number parameters are to be considered as // floating point numbers. // Out: ProtoLog.e(GROUP, 1234, 0, null, arg) newCall.arguments.add(2, IntegerLiteralExpr(typeMask)) // Replace call to a stub method with an actual implementation. - // Out: com.android.server.wm.ProtoLogImpl.e(GROUP, 1234, null, arg) + // Out: com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, null, arg) newCall.setScope(protoLogImplClassNode) - // Create a call to GROUP.isLogAny() - // Out: GROUP.isLogAny() - val isLogAnyExpr = MethodCallExpr(newCall.arguments[0].clone(), - SimpleName(IS_LOG_TO_ANY_METHOD)) + // Create a call to ProtoLogImpl.isEnabled(GROUP) + // Out: com.android.server.protolog.ProtoLogImpl.isEnabled(GROUP) + val isLogEnabled = MethodCallExpr(protoLogImplClassNode, IS_ENABLED_METHOD, + NodeList<Expression>(newCall.arguments[0].clone())) if (argTypes.size != call.arguments.size - 2) { throw InvalidProtoLogCallException( "Number of arguments does not mach format string", call) @@ -101,8 +108,8 @@ class SourceTransformer( // Out: long protoLogParam0 = arg argTypes.forEachIndexed { idx, type -> val varName = "protoLogParam$idx" - val declaration = VariableDeclarator(type.type, varName, - type.toType(newCall.arguments[idx + 4].clone())) + val declaration = VariableDeclarator(getASTTypeForDataType(type), varName, + getConversionForType(type)(newCall.arguments[idx + 4].clone())) blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration))) newCall.setArgument(idx + 4, NameExpr(SimpleName(varName))) } @@ -114,11 +121,11 @@ class SourceTransformer( } blockStmt.addStatement(ExpressionStmt(newCall)) // Create an IF-statement with the previously created condition. - // Out: if (GROUP.isLogAny()) { + // Out: if (com.android.server.protolog.ProtoLogImpl.isEnabled(GROUP)) { // long protoLogParam0 = arg; - // com.android.server.wm.ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); + // com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); // } - ifStmt = IfStmt(isLogAnyExpr, blockStmt, null) + ifStmt = IfStmt(isLogEnabled, blockStmt, null) } else { // Surround with if (false). val newCall = parentStmt.clone() @@ -130,6 +137,8 @@ class SourceTransformer( // Append blank lines to preserve line numbering in file (to allow debugging) val newLines = LexicalPreservingPrinter.print(parentStmt).count { c -> c == '\n' } val newStmt = printedIfStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}' + // pre-workaround code, see explanation below + /* val inlinedIfStmt = StaticJavaParser.parseStatement(newStmt) LexicalPreservingPrinter.setup(inlinedIfStmt) // Replace the original call. @@ -138,6 +147,27 @@ class SourceTransformer( throw RuntimeException("Unable to process log call $call " + "- unable to replace the call.") } + */ + /** Workaround for a bug in JavaParser (AST tree invalid after replacing a node when using + * LexicalPreservingPrinter (https://github.com/javaparser/javaparser/issues/2290). + * Replace the code below with the one commended-out above one the issue is resolved. */ + if (!parentStmt.range.isPresent) { + // Should never happen + throw RuntimeException("Unable to process log call $call " + + "- unable to replace the call.") + } + val range = parentStmt.range.get() + val begin = range.begin.line - 1 + val oldLines = processedCode.subList(begin, range.end.line) + val oldCode = oldLines.joinToString("\n") + val newCode = oldCode.replaceRange( + offsets[begin] + range.begin.column - 1, + oldCode.length - oldLines.lastOrNull()!!.length + + range.end.column + offsets[range.end.line - 1], newStmt) + newCode.split("\n").forEachIndexed { idx, line -> + offsets[begin + idx] += line.length - processedCode[begin + idx].length + processedCode[begin + idx] = line + } } private val inlinePrinter: PrettyPrinter @@ -151,12 +181,52 @@ class SourceTransformer( inlinePrinter = PrettyPrinter(config) } + companion object { + private val stringType: ClassOrInterfaceType = + StaticJavaParser.parseClassOrInterfaceType("String") + + fun getASTTypeForDataType(type: Int): Type { + return when (type) { + LogDataType.STRING -> stringType.clone() + LogDataType.LONG -> PrimitiveType.longType() + LogDataType.DOUBLE -> PrimitiveType.doubleType() + LogDataType.BOOLEAN -> PrimitiveType.booleanType() + else -> { + // Should never happen. + throw RuntimeException("Invalid LogDataType") + } + } + } + + fun getConversionForType(type: Int): (Expression) -> Expression { + return when (type) { + LogDataType.STRING -> { expr -> + MethodCallExpr(TypeExpr(StaticJavaParser.parseClassOrInterfaceType("String")), + SimpleName("valueOf"), NodeList(expr)) + } + else -> { expr -> expr } + } + } + } + private val protoLogImplClassNode = StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName) + private var processedCode: MutableList<String> = mutableListOf() + private var offsets: IntArray = IntArray(0) + private var fileName: String = "" - fun processClass(compilationUnit: CompilationUnit): String { + fun processClass( + code: String, + path: String, + compilationUnit: CompilationUnit = + StaticJavaParser.parse(code) + ): String { + fileName = path + processedCode = code.split('\n').toMutableList() + offsets = IntArray(processedCode.size) LexicalPreservingPrinter.setup(compilationUnit) protoLogCallProcessor.process(compilationUnit, this) - return LexicalPreservingPrinter.print(compilationUnit) + // return LexicalPreservingPrinter.print(compilationUnit) + return processedCode.joinToString("\n") } } diff --git a/tools/protologtool/src/com/android/protologtool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt index 8ce9a49c0302..172de0e9d4d0 100644 --- a/tools/protologtool/src/com/android/protologtool/ViewerConfigBuilder.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.android.json.stream.JsonWriter import com.github.javaparser.ast.CompilationUnit -import com.android.protologtool.Constants.VERSION +import com.android.protolog.tool.Constants.VERSION import com.github.javaparser.ast.expr.MethodCallExpr import java.io.StringWriter @@ -32,24 +32,28 @@ class ViewerConfigBuilder( group: LogGroup ) { if (group.enabled) { - val key = CodeUtils.hash(messageString, level) + val position = CodeUtils.getPositionString(fileName) + val key = CodeUtils.hash(position, messageString, level, group) if (statements.containsKey(key)) { - if (statements[key] != Triple(messageString, level, group)) { + if (statements[key] != LogCall(messageString, level, group, position)) { throw HashCollisionException( "Please modify the log message \"$messageString\" " + "or \"${statements[key]}\" - their hashes are equal.") } } else { groups.add(group) - statements[key] = Triple(messageString, level, group) + statements[key] = LogCall(messageString, level, group, position) + call.range.isPresent } } } - private val statements: MutableMap<Int, Triple<String, LogLevel, LogGroup>> = mutableMapOf() + private val statements: MutableMap<Int, LogCall> = mutableMapOf() private val groups: MutableSet<LogGroup> = mutableSetOf() + private var fileName: String = "" - fun processClass(unit: CompilationUnit) { + fun processClass(unit: CompilationUnit, fileName: String) { + this.fileName = fileName protoLogCallVisitor.process(unit, this) } @@ -66,11 +70,13 @@ class ViewerConfigBuilder( writer.name(key.toString()) writer.beginObject() writer.name("message") - writer.value(value.first) + writer.value(value.messageString) writer.name("level") - writer.value(value.second.name) + writer.value(value.logLevel.name) writer.name("group") - writer.value(value.third.name) + writer.value(value.logGroup.name) + writer.name("at") + writer.value(value.position) writer.endObject() } writer.endObject() @@ -88,4 +94,11 @@ class ViewerConfigBuilder( stringWriter.buffer.append('\n') return stringWriter.toString() } + + data class LogCall( + val messageString: String, + val logLevel: LogLevel, + val logGroup: LogGroup, + val position: String + ) } diff --git a/tools/protologtool/src/com/android/protologtool/ViewerConfigParser.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt index 69cf92d4d228..7278db0094e6 100644 --- a/tools/protologtool/src/com/android/protologtool/ViewerConfigParser.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.android.json.stream.JsonReader @@ -31,8 +31,7 @@ open class ViewerConfigParser { var level: String? = null var groupName: String? = null while (jsonReader.hasNext()) { - val key = jsonReader.nextName() - when (key) { + when (jsonReader.nextName()) { "message" -> message = jsonReader.nextString() "level" -> level = jsonReader.nextString() "group" -> groupName = jsonReader.nextString() @@ -52,8 +51,7 @@ open class ViewerConfigParser { jsonReader.beginObject() var tag: String? = null while (jsonReader.hasNext()) { - val key = jsonReader.nextName() - when (key) { + when (jsonReader.nextName()) { "tag" -> tag = jsonReader.nextString() else -> jsonReader.skipValue() } @@ -98,8 +96,7 @@ open class ViewerConfigParser { jsonReader.beginObject() while (jsonReader.hasNext()) { - val key = jsonReader.nextName() - when (key) { + when (jsonReader.nextName()) { "messages" -> messages = parseMessages(jsonReader) "groups" -> groups = parseGroups(jsonReader) "version" -> version = jsonReader.nextString() diff --git a/tools/protologtool/src/com/android/protologtool/exceptions.kt b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt index 2199785a335b..0401d8f8baa0 100644 --- a/tools/protologtool/src/com/android/protologtool/exceptions.kt +++ b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.ast.Node import java.lang.Exception @@ -27,17 +27,7 @@ class IllegalImportException(message: String) : Exception(message) class InvalidProtoLogCallException(message: String, node: Node) : RuntimeException("$message\nAt: $node") -class InvalidViewerConfigException : Exception { - constructor(message: String) : super(message) - - constructor(message: String, ex: Exception) : super(message, ex) -} - -class InvalidFormatStringException : Exception { - constructor(message: String) : super(message) - - constructor(message: String, ex: Exception) : super(message, ex) -} +class InvalidViewerConfigException(message: String) : Exception(message) class InvalidInputException(message: String) : Exception(message) diff --git a/tools/protologtool/tests/com/android/protologtool/CodeUtilsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt index 82daa736e1bc..0acbc9074857 100644 --- a/tools/protologtool/tests/com/android/protologtool/CodeUtilsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.expr.BinaryExpr @@ -27,17 +27,32 @@ import org.junit.Test class CodeUtilsTest { @Test fun hash() { - assertEquals(-1704685243, CodeUtils.hash("test", LogLevel.DEBUG)) + assertEquals(-1259556708, CodeUtils.hash("Test.java:50", "test", + LogLevel.DEBUG, LogGroup("test", true, true, "TAG"))) + } + + @Test + fun hash_changeLocation() { + assertEquals(15793504, CodeUtils.hash("Test.java:10", "test2", + LogLevel.DEBUG, LogGroup("test", true, true, "TAG"))) } @Test fun hash_changeLevel() { - assertEquals(-1176900998, CodeUtils.hash("test", LogLevel.ERROR)) + assertEquals(-731772463, CodeUtils.hash("Test.java:50", "test", + LogLevel.ERROR, LogGroup("test", true, true, "TAG"))) } @Test fun hash_changeMessage() { - assertEquals(-1305634931, CodeUtils.hash("test2", LogLevel.DEBUG)) + assertEquals(-2026343204, CodeUtils.hash("Test.java:50", "test2", + LogLevel.DEBUG, LogGroup("test", true, true, "TAG"))) + } + + @Test + fun hash_changeGroup() { + assertEquals(1607870166, CodeUtils.hash("Test.java:50", "test2", + LogLevel.DEBUG, LogGroup("test2", true, true, "TAG"))) } @Test @@ -164,43 +179,4 @@ class CodeUtilsTest { val out = CodeUtils.concatMultilineString(code) assertEquals("testabc1234test", out) } - - @Test - fun parseFormatString() { - val str = "%b %d %o %x %f %e %g %s %%" - val out = CodeUtils.parseFormatString(str) - assertEquals(listOf( - CodeUtils.LogDataTypes.BOOLEAN, - CodeUtils.LogDataTypes.LONG, - CodeUtils.LogDataTypes.LONG, - CodeUtils.LogDataTypes.LONG, - CodeUtils.LogDataTypes.DOUBLE, - CodeUtils.LogDataTypes.DOUBLE, - CodeUtils.LogDataTypes.DOUBLE, - CodeUtils.LogDataTypes.STRING - ), out) - } - - @Test(expected = InvalidFormatStringException::class) - fun parseFormatString_invalid() { - val str = "%q" - CodeUtils.parseFormatString(str) - } - - @Test - fun logDataTypesToBitMask() { - val types = listOf(CodeUtils.LogDataTypes.STRING, CodeUtils.LogDataTypes.DOUBLE, - CodeUtils.LogDataTypes.LONG, CodeUtils.LogDataTypes.BOOLEAN) - val mask = CodeUtils.logDataTypesToBitMask(types) - assertEquals(0b11011000, mask) - } - - @Test(expected = InvalidFormatStringException::class) - fun logDataTypesToBitMask_toManyParams() { - val types = mutableListOf<CodeUtils.LogDataTypes>() - for (i in 0..16) { - types.add(CodeUtils.LogDataTypes.STRING) - } - CodeUtils.logDataTypesToBitMask(types) - } } diff --git a/tools/protologtool/tests/com/android/protologtool/CommandOptionsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt index c1cd473574c2..615712e10bcf 100644 --- a/tools/protologtool/tests/com/android/protologtool/CommandOptionsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import org.junit.Assert.assertEquals import org.junit.Test diff --git a/tools/protologtool/tests/com/android/protologtool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt index 7106ea6fa168..04a3bfa499d8 100644 --- a/tools/protologtool/tests/com/android/protologtool/LogParserTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.android.json.stream.JsonReader -import com.android.server.wm.ProtoLogMessage -import com.android.server.wm.WindowManagerLogFileProto +import com.android.server.protolog.ProtoLogMessage +import com.android.server.protolog.ProtoLogFileProto import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -51,11 +51,11 @@ class LogParserTest { return "".byteInputStream() } - private fun buildProtoInput(logBuilder: WindowManagerLogFileProto.Builder): InputStream { + private fun buildProtoInput(logBuilder: ProtoLogFileProto.Builder): InputStream { logBuilder.setVersion(Constants.VERSION) logBuilder.magicNumber = - WindowManagerLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or - WindowManagerLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong() + ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or + ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong() return logBuilder.build().toByteArray().inputStream() } @@ -68,7 +68,7 @@ class LogParserTest { config[70933285] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b", "ERROR", "WindowManager") - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() val logMessageBuilder = ProtoLogMessage.newBuilder() logMessageBuilder .setMessageHash(70933285) @@ -87,7 +87,7 @@ class LogParserTest { config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %% %o" + " %x %e %g %s %f", "ERROR", "WindowManager") - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() val logMessageBuilder = ProtoLogMessage.newBuilder() logMessageBuilder .setMessageHash(123) @@ -110,7 +110,7 @@ class LogParserTest { config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %% %o", "ERROR", "WindowManager") - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() val logMessageBuilder = ProtoLogMessage.newBuilder() logMessageBuilder .setMessageHash(123) @@ -132,7 +132,7 @@ class LogParserTest { config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %% %o" + " %x %e %g %s %f", "ERROR", "WindowManager") - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() val logMessageBuilder = ProtoLogMessage.newBuilder() logMessageBuilder .setMessageHash(123) @@ -149,7 +149,7 @@ class LogParserTest { @Test(expected = InvalidInputException::class) fun parse_invalidMagicNumber() { - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() logBuilder.setVersion(Constants.VERSION) logBuilder.magicNumber = 0 val stream = logBuilder.build().toByteArray().inputStream() @@ -159,11 +159,11 @@ class LogParserTest { @Test(expected = InvalidInputException::class) fun parse_invalidVersion() { - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() logBuilder.setVersion("invalid") logBuilder.magicNumber = - WindowManagerLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or - WindowManagerLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong() + ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or + ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong() val stream = logBuilder.build().toByteArray().inputStream() parser.parse(stream, getConfigDummyStream(), printStream) @@ -171,7 +171,7 @@ class LogParserTest { @Test fun parse_noConfig() { - val logBuilder = WindowManagerLogFileProto.newBuilder() + val logBuilder = ProtoLogFileProto.newBuilder() val logMessageBuilder = ProtoLogMessage.newBuilder() logMessageBuilder .setMessageHash(70933285) diff --git a/tools/protologtool/tests/com/android/protologtool/ProtoLogCallProcessorTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt index dcb1f7fe3366..d20ce7ec4dcb 100644 --- a/tools/protologtool/tests/com/android/protologtool/ProtoLogCallProcessorTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.expr.MethodCallExpr diff --git a/tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt index 7b8dd9a73fa9..18504b684006 100644 --- a/tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit @@ -28,6 +28,8 @@ import org.mockito.Mockito class SourceTransformerTest { companion object { private const val PROTO_LOG_IMPL_PATH = "org.example.ProtoLogImpl" + + /* ktlint-disable max-line-length */ private val TEST_CODE = """ package org.example; @@ -50,6 +52,17 @@ class SourceTransformerTest { } """.trimIndent() + private val TEST_CODE_MULTICALLS = """ + package org.example; + + class Test { + void test() { + ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); + ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); + } + } + """.trimIndent() + private val TEST_CODE_NO_PARAMS = """ package org.example; @@ -60,13 +73,12 @@ class SourceTransformerTest { } """.trimIndent() - /* ktlint-disable max-line-length */ private val TRANSFORMED_CODE_TEXT_ENABLED = """ package org.example; class Test { void test() { - if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 835524026, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -76,19 +88,30 @@ class SourceTransformerTest { class Test { void test() { - if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -986393606, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); } } } """.trimIndent() + private val TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED = """ + package org.example; + + class Test { + void test() { + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } + } + } + """.trimIndent() + private val TRANSFORMED_CODE_NO_PARAMS = """ package org.example; class Test { void test() { - if (TEST_GROUP.isLogToAny()) { org.example.ProtoLogImpl.w(TEST_GROUP, 1282022424, 0, "test", (Object[]) null); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { org.example.ProtoLogImpl.w(TEST_GROUP, -1741986185, 0, "test", (Object[]) null); } } } """.trimIndent() @@ -98,7 +121,7 @@ class SourceTransformerTest { class Test { void test() { - if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 835524026, 9, null, protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, null, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -108,7 +131,7 @@ class SourceTransformerTest { class Test { void test() { - if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -986393606, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); } } @@ -137,16 +160,19 @@ class SourceTransformerTest { } """.trimIndent() /* ktlint-enable max-line-length */ + + private const val PATH = "com.example.Test.java" } private val processor: ProtoLogCallProcessor = Mockito.mock(ProtoLogCallProcessor::class.java) - private val sourceJarWriter = SourceTransformer("org.example.ProtoLogImpl", processor) + private val implPath = "org.example.ProtoLogImpl" + private val sourceJarWriter = SourceTransformer(implPath, processor) private fun <T> any(type: Class<T>): T = Mockito.any<T>(type) @Test fun processClass_textEnabled() { - val code = StaticJavaParser.parse(TEST_CODE) + var code = StaticJavaParser.parse(TEST_CODE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -158,12 +184,13 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) val ifStmt = ifStmts[0] - assertEquals("TEST_GROUP.${Constants.IS_LOG_TO_ANY_METHOD}()", + assertEquals("$implPath.${Constants.IS_ENABLED_METHOD}(TEST_GROUP)", ifStmt.condition.toString()) assertFalse(ifStmt.elseStmt.isPresent) assertEquals(3, ifStmt.thenStmt.childNodes.size) @@ -172,7 +199,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("835524026", methodCall.arguments[1].toString()) + assertEquals("1698911065", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -181,8 +208,50 @@ class SourceTransformerTest { } @Test + fun processClass_textEnabledMulticalls() { + var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS) + + Mockito.`when`(processor.process(any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + val visitor = invocation.arguments[1] as ProtoLogCallVisitor + + val calls = code.findAll(MethodCallExpr::class.java) + visitor.processCall(calls[0], "test %d %f", + LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST")) + visitor.processCall(calls[1], "test %d %f", + LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST")) + visitor.processCall(calls[2], "test %d %f", + LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST")) + + invocation.arguments[0] as CompilationUnit + } + + val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, code) + code = StaticJavaParser.parse(out) + + val ifStmts = code.findAll(IfStmt::class.java) + assertEquals(3, ifStmts.size) + val ifStmt = ifStmts[1] + assertEquals("$implPath.${Constants.IS_ENABLED_METHOD}(TEST_GROUP)", + ifStmt.condition.toString()) + assertFalse(ifStmt.elseStmt.isPresent) + assertEquals(3, ifStmt.thenStmt.childNodes.size) + val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr + assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + assertEquals("w", methodCall.name.asString()) + assertEquals(6, methodCall.arguments.size) + assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) + assertEquals("1698911065", methodCall.arguments[1].toString()) + assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) + assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) + assertEquals("protoLogParam0", methodCall.arguments[4].toString()) + assertEquals("protoLogParam1", methodCall.arguments[5].toString()) + assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED, out) + } + + @Test fun processClass_textEnabledMultiline() { - val code = StaticJavaParser.parse(TEST_CODE_MULTILINE) + var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -195,12 +264,13 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) val ifStmt = ifStmts[0] - assertEquals("TEST_GROUP.${Constants.IS_LOG_TO_ANY_METHOD}()", + assertEquals("$implPath.${Constants.IS_ENABLED_METHOD}(TEST_GROUP)", ifStmt.condition.toString()) assertFalse(ifStmt.elseStmt.isPresent) assertEquals(4, ifStmt.thenStmt.childNodes.size) @@ -209,7 +279,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(7, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("-986393606", methodCall.arguments[1].toString()) + assertEquals("1780316587", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) assertEquals("protoLogParam1", methodCall.arguments[5].toString()) @@ -219,7 +289,7 @@ class SourceTransformerTest { @Test fun processClass_noParams() { - val code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS) + var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -231,12 +301,13 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) val ifStmt = ifStmts[0] - assertEquals("TEST_GROUP.${Constants.IS_LOG_TO_ANY_METHOD}()", + assertEquals("$implPath.${Constants.IS_ENABLED_METHOD}(TEST_GROUP)", ifStmt.condition.toString()) assertFalse(ifStmt.elseStmt.isPresent) assertEquals(1, ifStmt.thenStmt.childNodes.size) @@ -245,14 +316,14 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(5, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1282022424", methodCall.arguments[1].toString()) + assertEquals("-1741986185", methodCall.arguments[1].toString()) assertEquals(0.toString(), methodCall.arguments[2].toString()) assertEquals(TRANSFORMED_CODE_NO_PARAMS, out) } @Test fun processClass_textDisabled() { - val code = StaticJavaParser.parse(TEST_CODE) + var code = StaticJavaParser.parse(TEST_CODE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -264,12 +335,13 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) val ifStmt = ifStmts[0] - assertEquals("TEST_GROUP.${Constants.IS_LOG_TO_ANY_METHOD}()", + assertEquals("$implPath.${Constants.IS_ENABLED_METHOD}(TEST_GROUP)", ifStmt.condition.toString()) assertFalse(ifStmt.elseStmt.isPresent) assertEquals(3, ifStmt.thenStmt.childNodes.size) @@ -278,7 +350,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("835524026", methodCall.arguments[1].toString()) + assertEquals("1698911065", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("null", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -288,7 +360,7 @@ class SourceTransformerTest { @Test fun processClass_textDisabledMultiline() { - val code = StaticJavaParser.parse(TEST_CODE_MULTILINE) + var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -301,12 +373,13 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) val ifStmt = ifStmts[0] - assertEquals("TEST_GROUP.${Constants.IS_LOG_TO_ANY_METHOD}()", + assertEquals("$implPath.${Constants.IS_ENABLED_METHOD}(TEST_GROUP)", ifStmt.condition.toString()) assertFalse(ifStmt.elseStmt.isPresent) assertEquals(4, ifStmt.thenStmt.childNodes.size) @@ -315,7 +388,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(7, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("-986393606", methodCall.arguments[1].toString()) + assertEquals("1780316587", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) assertEquals("null", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -326,7 +399,7 @@ class SourceTransformerTest { @Test fun processClass_disabled() { - val code = StaticJavaParser.parse(TEST_CODE) + var code = StaticJavaParser.parse(TEST_CODE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -338,7 +411,8 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) @@ -349,7 +423,7 @@ class SourceTransformerTest { @Test fun processClass_disabledMultiline() { - val code = StaticJavaParser.parse(TEST_CODE_MULTILINE) + var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> @@ -362,7 +436,8 @@ class SourceTransformerTest { invocation.arguments[0] as CompilationUnit } - val out = sourceJarWriter.processClass(code) + val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code) + code = StaticJavaParser.parse(out) val ifStmts = code.findAll(IfStmt::class.java) assertEquals(1, ifStmts.size) diff --git a/tools/protologtool/tests/com/android/protologtool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt index 53d2e8b0f4fa..d3f8c767e8b1 100644 --- a/tools/protologtool/tests/com/android/protologtool/ViewerConfigBuilderTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.android.json.stream.JsonReader import com.github.javaparser.ast.CompilationUnit @@ -31,6 +31,10 @@ class ViewerConfigBuilderTest { private val TEST1 = ViewerConfigParser.ConfigEntry("test1", LogLevel.INFO.name, TAG1) private val TEST2 = ViewerConfigParser.ConfigEntry("test2", LogLevel.DEBUG.name, TAG2) private val TEST3 = ViewerConfigParser.ConfigEntry("test3", LogLevel.ERROR.name, TAG2) + private val GROUP1 = LogGroup("TEST_GROUP", true, true, TAG1) + private val GROUP2 = LogGroup("DEBUG_GROUP", true, true, TAG2) + private val GROUP3 = LogGroup("DEBUG_GROUP", true, true, TAG2) + private const val PATH = "/tmp/test.java" } private val processor: ProtoLogCallProcessor = Mockito.mock(ProtoLogCallProcessor::class.java) @@ -50,25 +54,25 @@ class ViewerConfigBuilderTest { val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, - LogGroup("TEST_GROUP", true, true, TAG1)) + GROUP1) visitor.processCall(MethodCallExpr(), TEST2.messageString, LogLevel.DEBUG, - LogGroup("DEBUG_GROUP", true, true, TAG2)) + GROUP2) visitor.processCall(MethodCallExpr(), TEST3.messageString, LogLevel.ERROR, - LogGroup("DEBUG_GROUP", true, true, TAG2)) + GROUP3) invocation.arguments[0] as CompilationUnit } - configBuilder.processClass(dummyCompilationUnit) + configBuilder.processClass(dummyCompilationUnit, PATH) val parsedConfig = parseConfig(configBuilder.build()) assertEquals(3, parsedConfig.size) - assertEquals(TEST1, parsedConfig[CodeUtils.hash(TEST1.messageString, - LogLevel.INFO)]) - assertEquals(TEST2, parsedConfig[CodeUtils.hash(TEST2.messageString, - LogLevel.DEBUG)]) - assertEquals(TEST3, parsedConfig[CodeUtils.hash(TEST3.messageString, - LogLevel.ERROR)]) + assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, + TEST1.messageString, LogLevel.INFO, GROUP1)]) + assertEquals(TEST2, parsedConfig[CodeUtils.hash(PATH, TEST2.messageString, + LogLevel.DEBUG, GROUP2)]) + assertEquals(TEST3, parsedConfig[CodeUtils.hash(PATH, TEST3.messageString, + LogLevel.ERROR, GROUP3)]) } @Test @@ -78,20 +82,21 @@ class ViewerConfigBuilderTest { val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, - LogGroup("TEST_GROUP", true, true, TAG1)) + GROUP1) visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, - LogGroup("TEST_GROUP", true, true, TAG1)) + GROUP1) visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, - LogGroup("TEST_GROUP", true, true, TAG1)) + GROUP1) invocation.arguments[0] as CompilationUnit } - configBuilder.processClass(dummyCompilationUnit) + configBuilder.processClass(dummyCompilationUnit, PATH) val parsedConfig = parseConfig(configBuilder.build()) assertEquals(1, parsedConfig.size) - assertEquals(TEST1, parsedConfig[CodeUtils.hash(TEST1.messageString, LogLevel.INFO)]) + assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString, + LogLevel.INFO, GROUP1)]) } @Test @@ -101,7 +106,7 @@ class ViewerConfigBuilderTest { val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, - LogGroup("TEST_GROUP", true, true, TAG1)) + GROUP1) visitor.processCall(MethodCallExpr(), TEST2.messageString, LogLevel.DEBUG, LogGroup("DEBUG_GROUP", false, true, TAG2)) visitor.processCall(MethodCallExpr(), TEST3.messageString, LogLevel.ERROR, @@ -110,11 +115,13 @@ class ViewerConfigBuilderTest { invocation.arguments[0] as CompilationUnit } - configBuilder.processClass(dummyCompilationUnit) + configBuilder.processClass(dummyCompilationUnit, PATH) val parsedConfig = parseConfig(configBuilder.build()) assertEquals(2, parsedConfig.size) - assertEquals(TEST1, parsedConfig[CodeUtils.hash(TEST1.messageString, LogLevel.INFO)]) - assertEquals(TEST3, parsedConfig[CodeUtils.hash(TEST3.messageString, LogLevel.ERROR)]) + assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString, + LogLevel.INFO, GROUP1)]) + assertEquals(TEST3, parsedConfig[CodeUtils.hash(PATH, TEST3.messageString, + LogLevel.ERROR, LogGroup("DEBUG_GROUP", true, false, TAG2))]) } } diff --git a/tools/protologtool/tests/com/android/protologtool/ViewerConfigParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigParserTest.kt index c0cea733eadd..dc3ef7c57b35 100644 --- a/tools/protologtool/tests/com/android/protologtool/ViewerConfigParserTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigParserTest.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.android.protologtool +package com.android.protolog.tool import com.android.json.stream.JsonReader +import org.junit.Assert.assertEquals import org.junit.Test import java.io.StringReader -import org.junit.Assert.assertEquals class ViewerConfigParserTest { private val parser = ViewerConfigParser() @@ -322,6 +322,6 @@ class ViewerConfigParserTest { } } """ - val config = parser.parseConfig(getJSONReader(json)) + parser.parseConfig(getJSONReader(json)) } } diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp index 56a242f1daaf..5ac9dfd2a557 100644 --- a/tools/validatekeymaps/Main.cpp +++ b/tools/validatekeymaps/Main.cpp @@ -137,7 +137,6 @@ static bool validateFile(const char* filename) { } } - log("No errors.\n\n"); return true; } |