diff options
author | Adam Lesinski <adamlesinski@google.com> | 2017-08-29 17:32:24 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-08-29 17:32:24 +0000 |
commit | 123a19bc3af1c4da4faa9f781eaabcd0e9135f9c (patch) | |
tree | 819cddace5365a06b9b786272d6871b5e48b233a | |
parent | f5ff39f0bdfedb19d994b0e97403ff5b90ec6511 (diff) | |
parent | 1ef0fa9d7242b1926543bc49e35905d1be02a781 (diff) |
Merge "AAPT2: Fixup namespace implementation"
76 files changed, 824 insertions, 508 deletions
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h index 1305a4cf0710..f1aad29a5c58 100644 --- a/tools/aapt2/NameMangler.h +++ b/tools/aapt2/NameMangler.h @@ -69,8 +69,7 @@ class NameMangler { * The mangled name should contain symbols that are illegal to define in XML, * so that there will never be name mangling collisions. */ - static std::string MangleEntry(const std::string& package, - const std::string& name) { + static std::string MangleEntry(const std::string& package, const std::string& name) { return package + "$" + name; } @@ -86,8 +85,8 @@ class NameMangler { } out_package->assign(out_name->data(), pivot); - out_name->assign(out_name->data() + pivot + 1, - out_name->size() - (pivot + 1)); + std::string new_name = out_name->substr(pivot + 1); + *out_name = std::move(new_name); return true; } diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 1c3ac2ad4f17..47549f01f8ca 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -605,7 +605,7 @@ std::unique_ptr<Item> ResourceParser::ParseXml(xml::XmlPullParser* parser, if (processed_item) { // Fix up the reference. if (Reference* ref = ValueCast<Reference>(processed_item.get())) { - TransformReferenceFromNamespace(parser, "", ref); + ResolvePackage(parser, ref); } return processed_item; } @@ -1074,15 +1074,13 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) { return false; } - Maybe<Reference> maybe_key = - ResourceUtils::ParseXmlAttributeName(maybe_name.value()); + Maybe<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value()); if (!maybe_key) { - diag_->Error(DiagMessage(source) << "invalid attribute name '" - << maybe_name.value() << "'"); + diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'"); return false; } - TransformReferenceFromNamespace(parser, "", &maybe_key.value()); + ResolvePackage(parser, &maybe_key.value()); maybe_key.value().SetSource(source); std::unique_ptr<Item> value = ParseXml(parser, 0, kAllowRawString); @@ -1091,8 +1089,7 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) { return false; } - style->entries.push_back( - Style::Entry{std::move(maybe_key.value()), std::move(value)}); + style->entries.push_back(Style::Entry{std::move(maybe_key.value()), std::move(value)}); return true; } @@ -1104,21 +1101,18 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par Maybe<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent"); if (maybe_parent) { - // If the parent is empty, we don't have a parent, but we also don't infer - // either. + // If the parent is empty, we don't have a parent, but we also don't infer either. if (!maybe_parent.value().empty()) { std::string err_str; - style->parent = ResourceUtils::ParseStyleParentReference( - maybe_parent.value(), &err_str); + style->parent = ResourceUtils::ParseStyleParentReference(maybe_parent.value(), &err_str); if (!style->parent) { diag_->Error(DiagMessage(out_resource->source) << err_str); return false; } - // Transform the namespace prefix to the actual package name, and mark the - // reference as + // Transform the namespace prefix to the actual package name, and mark the reference as // private if appropriate. - TransformReferenceFromNamespace(parser, "", &style->parent.value()); + ResolvePackage(parser, &style->parent.value()); } } else { @@ -1127,8 +1121,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par size_t pos = style_name.find_last_of(u'.'); if (pos != std::string::npos) { style->parent_inferred = true; - style->parent = Reference( - ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos))); + style->parent = Reference(ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos))); } } @@ -1373,7 +1366,7 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, } Reference& child_ref = maybe_ref.value(); - xml::TransformReferenceFromNamespace(parser, "", &child_ref); + xml::ResolvePackage(parser, &child_ref); // Create the ParsedResource that will add the attribute to the table. ParsedResource child_resource; diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index d4ff6188d48d..3a2faa9f0368 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -457,7 +457,8 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer const Source& src = doc->file.source; if (context_->IsVerbose()) { - context_->GetDiagnostics()->Note(DiagMessage() << "linking " << src.path); + context_->GetDiagnostics()->Note(DiagMessage() + << "linking " << src.path << " (" << doc->file.name << ")"); } XmlReferenceLinker xml_linker; @@ -505,6 +506,8 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files; for (auto& pkg : table->packages) { + CHECK(!pkg->name.empty()) << "Packages must have names when being linked"; + for (auto& type : pkg->types) { // Sort by config and name, so that we get better locality in the zip file. config_sorted_files.clear(); @@ -701,7 +704,7 @@ class LinkCommand { util::make_unique<AssetManagerSymbolSource>(); for (const std::string& path : options_.include_paths) { if (context_->IsVerbose()) { - context_->GetDiagnostics()->Note(DiagMessage(path) << "loading include path"); + context_->GetDiagnostics()->Note(DiagMessage() << "including " << path); } // First try to load the file as a static lib. @@ -819,11 +822,9 @@ class LinkCommand { return app_info; } - /** - * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked. - * Postcondition: ResourceTable has only one package left. All others are - * stripped, or there is an error and false is returned. - */ + // Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked. + // Postcondition: ResourceTable has only one package left. All others are + // stripped, or there is an error and false is returned. bool VerifyNoExternalPackages() { auto is_ext_package_func = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool { return context_->GetCompilationPackage() != pkg->name || !pkg->id || @@ -965,7 +966,91 @@ class LinkCommand { context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path << "': " << android::base::SystemErrorCodeToString(errno)); + return false; + } + return true; + } + + bool GenerateJavaClasses() { + // The set of packages whose R class to call in the main classes onResourcesLoaded callback. + std::vector<std::string> packages_to_callback; + + JavaClassGeneratorOptions template_options; + template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; + template_options.javadoc_annotations = options_.javadoc_annotations; + + if (context_->GetPackageType() == PackageType::kStaticLib || options_.generate_non_final_ids) { + template_options.use_final = false; + } + + if (context_->GetPackageType() == PackageType::kSharedLib) { + template_options.use_final = false; + template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{}; + } + + const StringPiece actual_package = context_->GetCompilationPackage(); + StringPiece output_package = context_->GetCompilationPackage(); + if (options_.custom_java_package) { + // Override the output java package to the custom one. + output_package = options_.custom_java_package.value(); + } + + // Generate the private symbols if required. + if (options_.private_symbols) { + packages_to_callback.push_back(options_.private_symbols.value()); + + // If we defined a private symbols package, we only emit Public symbols + // to the original package, and private and public symbols to the private package. + JavaClassGeneratorOptions options = template_options; + options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate; + if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(), + options)) { + return false; + } + } + + // Generate copies of the original package R class but with different package names. + // This is to support non-namespaced builds. + for (const std::string& extra_package : options_.extra_java_packages) { + packages_to_callback.push_back(extra_package); + + JavaClassGeneratorOptions options = template_options; + options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; + if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) { + return false; + } + } + + // Generate R classes for each package that was merged (static library). + // Use the actual package's resources only. + for (const std::string& package : table_merger_->merged_packages()) { + packages_to_callback.push_back(package); + + JavaClassGeneratorOptions options = template_options; + options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; + if (!WriteJavaFile(&final_table_, package, package, options)) { + return false; + } } + + // Generate the main public R class. + JavaClassGeneratorOptions options = template_options; + + // Only generate public symbols if we have a private package. + if (options_.private_symbols) { + options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic; + } + + if (options.rewrite_callback_options) { + options.rewrite_callback_options.value().packages_to_callback = + std::move(packages_to_callback); + } + + if (!WriteJavaFile(&final_table_, actual_package, output_package, options, + options_.generate_text_symbols_path)) { + return false; + } + return true; } @@ -1097,15 +1182,17 @@ class LinkCommand { bool result; if (options_.no_static_lib_packages) { - // Merge all resources as if they were in the compilation package. This is - // the old behavior of aapt. + // Merge all resources as if they were in the compilation package. This is the old behavior + // of aapt. - // Add the package to the set of --extra-packages so we emit an R.java for - // each library package. + // Add the package to the set of --extra-packages so we emit an R.java for each library + // package. if (!pkg->name.empty()) { options_.extra_java_packages.insert(pkg->name); } + // Clear the package name, so as to make the resources look like they are coming from the + // local package. pkg->name = ""; if (override) { result = table_merger_->MergeOverlay(Source(input), table.get(), collection.get()); @@ -1673,8 +1760,7 @@ class LinkCommand { bool error = false; { - // AndroidManifest.xml has no resource name, but the CallSite is built - // from the name + // AndroidManifest.xml has no resource name, but the CallSite is built from the name // (aka, which package the AndroidManifest.xml is coming from). // So we give it a package name so it can see local resources. manifest_xml->file.name.package = context_->GetCompilationPackage(); @@ -1727,72 +1813,7 @@ class LinkCommand { } if (options_.generate_java_class_path) { - // The set of packages whose R class to call in the main classes - // onResourcesLoaded callback. - std::vector<std::string> packages_to_callback; - - JavaClassGeneratorOptions template_options; - template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; - template_options.javadoc_annotations = options_.javadoc_annotations; - - if (context_->GetPackageType() == PackageType::kStaticLib || - options_.generate_non_final_ids) { - template_options.use_final = false; - } - - if (context_->GetPackageType() == PackageType::kSharedLib) { - template_options.use_final = false; - template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{}; - } - - const StringPiece actual_package = context_->GetCompilationPackage(); - StringPiece output_package = context_->GetCompilationPackage(); - if (options_.custom_java_package) { - // Override the output java package to the custom one. - output_package = options_.custom_java_package.value(); - } - - // Generate the private symbols if required. - if (options_.private_symbols) { - packages_to_callback.push_back(options_.private_symbols.value()); - - // If we defined a private symbols package, we only emit Public symbols - // to the original package, and private and public symbols to the - // private package. - JavaClassGeneratorOptions options = template_options; - options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate; - if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(), - options)) { - return 1; - } - } - - // Generate all the symbols for all extra packages. - for (const std::string& extra_package : options_.extra_java_packages) { - packages_to_callback.push_back(extra_package); - - JavaClassGeneratorOptions options = template_options; - options.types = JavaClassGeneratorOptions::SymbolTypes::kAll; - if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) { - return 1; - } - } - - // Generate the main public R class. - JavaClassGeneratorOptions options = template_options; - - // Only generate public symbols if we have a private package. - if (options_.private_symbols) { - options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic; - } - - if (options.rewrite_callback_options) { - options.rewrite_callback_options.value().packages_to_callback = - std::move(packages_to_callback); - } - - if (!WriteJavaFile(&final_table_, actual_package, output_package, options, - options_.generate_text_symbols_path)) { + if (!GenerateJavaClasses()) { return 1; } } diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp index 857cdd5365a0..a17926067a0b 100644 --- a/tools/aapt2/compile/InlineXmlFormatParser.cpp +++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp @@ -69,10 +69,10 @@ class Visitor : public xml::PackageAwareVisitor { // Use an empty string for the compilation package because we don't want to default to // the local package if the user specified name="style" or something. This should just // be the default namespace. - Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package, {}); + Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package); if (!maybe_pkg) { - context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid namespace prefix '" - << name.package << "'"); + context_->GetDiagnostics()->Error(DiagMessage(src) + << "invalid namespace prefix '" << name.package << "'"); error_ = true; return; } diff --git a/tools/aapt2/integration-tests/NamespaceTest/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/Android.mk new file mode 100644 index 000000000000..6361f9b8ae7d --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/Android.mk @@ -0,0 +1,2 @@ +LOCAL_PATH := $(call my-dir) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk new file mode 100644 index 000000000000..6ed07b0c5c73 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk @@ -0,0 +1,29 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_USE_AAPT2 := true +LOCAL_AAPT_NAMESPACES := true +LOCAL_PACKAGE_NAME := AaptTestNamespace_App +LOCAL_MODULE_TAGS := tests +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_STATIC_ANDROID_LIBRARIES := \ + AaptTestNamespace_LibOne \ + AaptTestNamespace_LibTwo +LOCAL_AAPT_FLAGS := -v +include $(BUILD_PACKAGE) diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/AndroidManifest.xml b/tools/aapt2/integration-tests/NamespaceTest/App/AndroidManifest.xml new file mode 100644 index 000000000000..6398a83ea1d2 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/App/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.aapt.namespace.app"> + + <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/> + + <application android:theme="@style/AppTheme" android:label="@string/app_name"> + <activity android:name=".MainActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/res/layout/activity_main.xml b/tools/aapt2/integration-tests/NamespaceTest/App/res/layout/activity_main.xml new file mode 100644 index 000000000000..19bfd942a5bd --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/App/res/layout/activity_main.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:libone="http://schemas.android.com/apk/res/com.android.aapt.namespace.libone" + xmlns:libtwo="http://schemas.android.com/apk/res/com.android.aapt.namespace.libtwo" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <com.android.aapt.namespace.libtwo.TextView + android:id="@+id/textview" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="@bool/always_true" + android:text="@libone:string/textview_text" + libtwo:textview_attr="?libone:theme_attr" /> +</RelativeLayout>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/res/values/values.xml b/tools/aapt2/integration-tests/NamespaceTest/App/res/values/values.xml new file mode 100644 index 000000000000..1b80d9542881 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/App/res/values/values.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <string name="app_name">Namespace App</string> + <bool name="always_true">true</bool> + + <style name="AppTheme" parent="com.android.aapt.namespace.libone:style/Theme"> + <item name="android:colorPrimary">#3F51B5</item> + <item name="android:colorPrimaryDark">#303F9F</item> + <item name="android:colorAccent">#FF4081</item> + <item name="com.android.aapt.namespace.libone:theme_attr"> + @com.android.aapt.namespace.libtwo:string/public_string + </item> + </style> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/src/com/android/aapt/namespace/app/MainActivity.java b/tools/aapt2/integration-tests/NamespaceTest/App/src/com/android/aapt/namespace/app/MainActivity.java new file mode 100644 index 000000000000..fcb4c3c12f81 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/App/src/com/android/aapt/namespace/app/MainActivity.java @@ -0,0 +1,34 @@ +/* + * 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. + */ +package com.android.aapt.namespace.app; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.Toast; + +public class MainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + com.android.aapt.namespace.libtwo.TextView tv = findViewById(R.id.textview); + + + + Toast.makeText(this, tv.getTextViewAttr(), Toast.LENGTH_LONG).show(); + } +} diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk new file mode 100644 index 000000000000..b1cac68dae7a --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk @@ -0,0 +1,28 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_USE_AAPT2 := true +LOCAL_AAPT_NAMESPACES := true +LOCAL_MODULE := AaptTestNamespace_LibOne +LOCAL_MODULE_TAGS := tests +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +# We need this to retain the R.java generated for this library. +LOCAL_JAR_EXCLUDE_FILES := none +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/NamespaceTest/LibOne/AndroidManifest.xml new file mode 100644 index 000000000000..70b4b226624b --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.aapt.namespace.libone"> + + <uses-sdk android:minSdkVersion="21" /> +</manifest> diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibOne/res/values/values.xml b/tools/aapt2/integration-tests/NamespaceTest/LibOne/res/values/values.xml new file mode 100644 index 000000000000..d2dcea0c0b1e --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/res/values/values.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <public type="string" name="textview_text" /> + <string name="textview_text">LibOne\'s textview_text string!</string> + + <public type="attr" name="theme_attr" /> + <attr name="theme_attr" format="string" /> + + <public type="style" name="Theme" /> + <style name="Theme" parent="android:Theme.Material.Light.DarkActionBar"> + <item name="theme_attr">[Please override with your own value]</item> + </style> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk new file mode 100644 index 000000000000..dc16d1bbb420 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk @@ -0,0 +1,29 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_USE_AAPT2 := true +LOCAL_AAPT_NAMESPACES := true +LOCAL_MODULE := AaptTestNamespace_LibTwo +LOCAL_MODULE_TAGS := tests +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +# We need this to retain the R.java generated for this library. +LOCAL_JAR_EXCLUDE_FILES := none +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/AndroidManifest.xml new file mode 100644 index 000000000000..32944a9b8f0b --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.aapt.namespace.libtwo"> + + <uses-sdk android:minSdkVersion="21" /> +</manifest> diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/res/values/values.xml b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/res/values/values.xml new file mode 100644 index 000000000000..0c5f5d8d55e0 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/res/values/values.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <public type="string" name="public_string" /> + <string name="public_string">LibTwo\'s public string!</string> + + <public type="attr" name="textview_attr" /> + <attr name="textview_attr" format="string" /> + + <declare-styleable name="TextView"> + <attr name="textview_attr" /> + </declare-styleable> +</resources>
\ No newline at end of file diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/src/com/android/aapt/namespace/libtwo/TextView.java b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/src/com/android/aapt/namespace/libtwo/TextView.java new file mode 100644 index 000000000000..0f8024e58797 --- /dev/null +++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/src/com/android/aapt/namespace/libtwo/TextView.java @@ -0,0 +1,53 @@ +/* + * 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. + */ +package com.android.aapt.namespace.libtwo; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; + +public class TextView extends android.widget.TextView { + + private String mTextViewAttr; + + public TextView(Context context) { + this(context, null); + } + + public TextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TextView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + final TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TextView, + 0, 0); + try { + mTextViewAttr = ta.getString(R.styleable.TextView_textview_attr); + } finally { + ta.recycle(); + } + } + + public String getTextViewAttr() { + return mTextViewAttr; + } +} diff --git a/tools/aapt2/integration-tests/StaticLibTest/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/Android.mk new file mode 100644 index 000000000000..6361f9b8ae7d --- /dev/null +++ b/tools/aapt2/integration-tests/StaticLibTest/Android.mk @@ -0,0 +1,2 @@ +LOCAL_PATH := $(call my-dir) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/App/Android.mk index 38bd5b5e3275..4d0c01d565a5 100644 --- a/tools/aapt2/integration-tests/AppOne/Android.mk +++ b/tools/aapt2/integration-tests/StaticLibTest/App/Android.mk @@ -18,12 +18,12 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true -LOCAL_PACKAGE_NAME := AaptTestAppOne +LOCAL_PACKAGE_NAME := AaptTestStaticLib_App LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets $(LOCAL_PATH)/assets2 LOCAL_STATIC_ANDROID_LIBRARIES := \ - AaptTestStaticLibOne \ - AaptTestStaticLibTwo + AaptTestStaticLib_LibOne \ + AaptTestStaticLib_LibTwo LOCAL_AAPT_FLAGS := --no-version-vectors --no-version-transitions include $(BUILD_PACKAGE) diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml index a5f202dd22fc..a5f202dd22fc 100644 --- a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml diff --git a/tools/aapt2/integration-tests/AppOne/assets/subdir/subsubdir/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets/subdir/subsubdir/test.txt index 125194943ec8..125194943ec8 100644 --- a/tools/aapt2/integration-tests/AppOne/assets/subdir/subsubdir/test.txt +++ b/tools/aapt2/integration-tests/StaticLibTest/App/assets/subdir/subsubdir/test.txt diff --git a/tools/aapt2/integration-tests/AppOne/assets/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets/test.txt index 88266de2b4d4..88266de2b4d4 100644 --- a/tools/aapt2/integration-tests/AppOne/assets/test.txt +++ b/tools/aapt2/integration-tests/StaticLibTest/App/assets/test.txt diff --git a/tools/aapt2/integration-tests/AppOne/assets2/new.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets2/new.txt index f4963a95503a..f4963a95503a 100644 --- a/tools/aapt2/integration-tests/AppOne/assets2/new.txt +++ b/tools/aapt2/integration-tests/StaticLibTest/App/assets2/new.txt diff --git a/tools/aapt2/integration-tests/AppOne/assets2/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets2/test.txt index 5d8b36c0d52d..5d8b36c0d52d 100644 --- a/tools/aapt2/integration-tests/AppOne/assets2/test.txt +++ b/tools/aapt2/integration-tests/StaticLibTest/App/assets2/test.txt diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/cheap_transparency.png Binary files differindex 0522a9979db9..0522a9979db9 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/cheap_transparency.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/complex.9.png Binary files differindex baf9fff13ab5..baf9fff13ab5 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/complex.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/icon.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/icon.png Binary files differindex 4bff9b900643..4bff9b900643 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/icon.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/icon.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/image.xml index 6132a75d85d0..6132a75d85d0 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/image.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/outline_8x8.9.png Binary files differindex 7b331e16fcbd..7b331e16fcbd 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/outline_8x8.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_off_center_outline_32x16.9.png Binary files differindex 0ec6c70a2b9f..0ec6c70a2b9f 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_off_center_outline_32x16.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_outline_32x16.9.png Binary files differindex e05708a089a3..e05708a089a3 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_outline_32x16.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/test.9.png Binary files differindex 33daa117ea9d..33daa117ea9d 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/test.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_3x3.9.png Binary files differindex a11377a0d670..a11377a0d670 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_3x3.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_optical_bounds_3x3.9.png Binary files differindex 6803e4243484..6803e4243484 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_optical_bounds_3x3.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_3x3.9.png Binary files differindex 1a3731bbc8b8..1a3731bbc8b8 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_3x3.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_optical_bounds_3x3.9.png Binary files differindex 489ace292e1f..489ace292e1f 100644 --- a/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_optical_bounds_3x3.9.png diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-italic.ttf index e69de29bb2d1..e69de29bb2d1 100644 --- a/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-italic.ttf diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-normal.ttf index e69de29bb2d1..e69de29bb2d1 100644 --- a/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-normal.ttf diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont.xml index 1fb67914894e..1fb67914894e 100644 --- a/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout-v21/main.xml index 9f5a4a85cbcf..724bfe4a9536 100644 --- a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout-v21/main.xml @@ -15,7 +15,6 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:support="http://schemas.android.com/apk/res/android.appcompat" android:id="@+id/view" android:layout_width="match_parent" android:layout_height="wrap_content"> diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/main.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml index ab1a251a7d56..aaa884bf7084 100644 --- a/tools/aapt2/integration-tests/AppOne/res/layout/main.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml @@ -15,7 +15,6 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:support="http://schemas.android.com/apk/res/android.appcompat" android:id="@+id/view" android:layout_width="match_parent" android:layout_height="wrap_content"> diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/special.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/special.xml index 28c85ca92019..28c85ca92019 100644 --- a/tools/aapt2/integration-tests/AppOne/res/layout/special.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/special.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/navigation/home.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/navigation/home.xml index ade271d60ab6..ade271d60ab6 100644 --- a/tools/aapt2/integration-tests/AppOne/res/navigation/home.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/navigation/home.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/raw/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/res/raw/test.txt index b14df6442ea5..b14df6442ea5 100644 --- a/tools/aapt2/integration-tests/AppOne/res/raw/test.txt +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/raw/test.txt diff --git a/tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/transition/transition_set.xml index e10e6c2f53da..e10e6c2f53da 100644 --- a/tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/transition/transition_set.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values-v4/styles.xml index d8c11e210eda..d8c11e210eda 100644 --- a/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/values-v4/styles.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/values/colors.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/colors.xml index 4df5077051d2..4df5077051d2 100644 --- a/tools/aapt2/integration-tests/AppOne/res/values/colors.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/colors.xml diff --git a/tools/aapt2/integration-tests/AppOne/res/values/styles.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/styles.xml index 19d96c0809db..a088e5d0e1a2 100644 --- a/tools/aapt2/integration-tests/AppOne/res/values/styles.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/styles.xml @@ -14,7 +14,7 @@ limitations under the License. --> -<resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat"> +<resources> <style name="App"> <item name="android:background">@color/primary</item> <item name="android:colorPrimary">@color/primary</item> diff --git a/tools/aapt2/integration-tests/AppOne/res/values/test.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/test.xml index 2c9e8b877565..2c9e8b877565 100644 --- a/tools/aapt2/integration-tests/AppOne/res/values/test.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/test.xml diff --git a/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java b/tools/aapt2/integration-tests/StaticLibTest/App/src/com/android/aapt/app/one/AppOne.java index 472b35a781fe..472b35a781fe 100644 --- a/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java +++ b/tools/aapt2/integration-tests/StaticLibTest/App/src/com/android/aapt/app/one/AppOne.java diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.mk index 0b7129aa0d38..0c828b80b3b3 100644 --- a/tools/aapt2/integration-tests/StaticLibOne/Android.mk +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.mk @@ -18,11 +18,11 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true -LOCAL_MODULE := AaptTestStaticLibOne +LOCAL_MODULE := AaptTestStaticLib_LibOne LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res -# We need this to compile the Java sources of AaptTestStaticLibTwo using javac. +# We need this to compile the Java sources of AaptTestStaticLib_LibTwo using javac. LOCAL_JAR_EXCLUDE_FILES := none include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/LibOne/AndroidManifest.xml index 705047e71300..705047e71300 100644 --- a/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/AndroidManifest.xml diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml b/tools/aapt2/integration-tests/StaticLibTest/LibOne/res/layout/layout.xml index 683c91cd9cf5..683c91cd9cf5 100644 --- a/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/res/layout/layout.xml diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTest/LibOne/res/values/values.xml index b4dc90b3e640..b4dc90b3e640 100644 --- a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/res/values/values.xml diff --git a/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java b/tools/aapt2/integration-tests/StaticLibTest/LibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java index cf48f67056cf..cf48f67056cf 100644 --- a/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java diff --git a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.mk index 8b6eb41b08cd..538d5251b203 100644 --- a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.mk @@ -18,10 +18,10 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true -LOCAL_MODULE := AaptTestStaticLibTwo +LOCAL_MODULE := AaptTestStaticLib_LibTwo LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res -LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLibOne +LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLib_LibOne include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/AndroidManifest.xml index 28f069932452..28f069932452 100644 --- a/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/AndroidManifest.xml diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/drawable/vector.xml index dd5979f7e838..dd5979f7e838 100644 --- a/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/drawable/vector.xml diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/layout/layout_two.xml index ba9830708eb0..ba9830708eb0 100644 --- a/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/layout/layout_two.xml diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/values/values.xml index 97bb2a53d9f6..97bb2a53d9f6 100644 --- a/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/values/values.xml diff --git a/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java index 7110dcdd017a..7110dcdd017a 100644 --- a/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index 44fa0f19a0e5..8da9106aa8d7 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -480,7 +480,7 @@ Maybe<std::string> JavaClassGenerator::UnmangleResource(const StringPiece& packa if (NameMangler::Unmangle(&unmangled_name, &unmangled_package)) { // The entry name was mangled, and we successfully unmangled it. // Check that we want to emit this symbol. - if (package_name != unmangled_package) { + if (package_name_to_generate != unmangled_package) { // Skip the entry if it doesn't belong to the package we're writing. return {}; } @@ -579,8 +579,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, continue; } - // Stay consistent with AAPT and generate an empty type class if the R class - // is public. + // 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); diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h index 5527f9092c87..3c9c4767b3d1 100644 --- a/tools/aapt2/link/Linkers.h +++ b/tools/aapt2/link/Linkers.h @@ -21,6 +21,7 @@ #include <unordered_set> #include "android-base/macros.h" +#include "androidfw/StringPiece.h" #include "Resource.h" #include "SdkConstants.h" @@ -33,18 +34,15 @@ class ResourceTable; class ResourceEntry; struct ConfigDescription; -/** - * Defines the location in which a value exists. This determines visibility of - * other package's private symbols. - */ +// Defines the context in which a resource value is defined. Most resources are defined with the +// implicit package name of their compilation context. Understanding the package name of a resource +// allows to determine visibility of other symbols which may or may not have their packages defined. struct CallSite { - ResourceNameRef resource; + std::string package; }; -/** - * Determines whether a versioned resource should be created. If a versioned - * resource already exists, it takes precedence. - */ +// Determines whether a versioned resource should be created. If a versioned resource already +// exists, it takes precedence. bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config, const ApiVersion sdk_version_to_generate); @@ -62,39 +60,26 @@ class AutoVersioner : public IResourceTableConsumer { DISALLOW_COPY_AND_ASSIGN(AutoVersioner); }; -/** - * If any attribute resource values are defined as public, this consumer will - * move all private - * attribute resource values to a private ^private-attr type, avoiding backwards - * compatibility - * issues with new apps running on old platforms. - * - * The Android platform ignores resource attributes it doesn't recognize, so an - * app developer can - * use new attributes in their layout XML files without worrying about - * versioning. This assumption - * actually breaks on older platforms. OEMs may add private attributes that are - * used internally. - * AAPT originally assigned all private attributes IDs immediately proceeding - * the public attributes' - * IDs. - * - * This means that on a newer Android platform, an ID previously assigned to a - * private attribute - * may end up assigned to a public attribute. - * - * App developers assume using the newer attribute is safe on older platforms - * because it will - * be ignored. Instead, the platform thinks the new attribute is an older, - * private attribute and - * will interpret it as such. This leads to unintended styling and exceptions - * thrown due to - * unexpected types. - * - * By moving the private attributes to a completely different type, this ID - * conflict will never - * occur. - */ +// If any attribute resource values are defined as public, this consumer will move all private +// attribute resource values to a private ^private-attr type, avoiding backwards compatibility +// issues with new apps running on old platforms. +// +// The Android platform ignores resource attributes it doesn't recognize, so an app developer can +// use new attributes in their layout XML files without worrying about versioning. This assumption +// actually breaks on older platforms. OEMs may add private attributes that are used internally. +// AAPT originally assigned all private attributes IDs immediately proceeding the public attributes' +// IDs. +// +// This means that on a newer Android platform, an ID previously assigned to a private attribute +// may end up assigned to a public attribute. +// +// App developers assume using the newer attribute is safe on older platforms because it will +// be ignored. Instead, the platform thinks the new attribute is an older, private attribute and +// will interpret it as such. This leads to unintended styling and exceptions thrown due to +// unexpected types. +// +// By moving the private attributes to a completely different type, this ID conflict will never +// occur. class PrivateAttributeMover : public IResourceTableConsumer { public: PrivateAttributeMover() = default; @@ -126,14 +111,10 @@ class ProductFilter : public IResourceTableConsumer { std::unordered_set<std::string> products_; }; -/** - * Removes namespace nodes and URI information from the XmlResource. - * - * Once an XmlResource is processed by this consumer, it is no longer able to - * have its attributes - * parsed. As such, this XmlResource must have already been processed by - * XmlReferenceLinker. - */ +// Removes namespace nodes and URI information from the XmlResource. +// +// Once an XmlResource is processed by this consumer, it is no longer able to have its attributes +// parsed. As such, this XmlResource must have already been processed by XmlReferenceLinker. class XmlNamespaceRemover : public IXmlResourceConsumer { public: explicit XmlNamespaceRemover(bool keep_uris = false) : keep_uris_(keep_uris){}; @@ -146,11 +127,8 @@ class XmlNamespaceRemover : public IXmlResourceConsumer { bool keep_uris_; }; -/** - * Resolves attributes in the XmlResource and compiles string values to resource - * values. - * Once an XmlResource is processed by this linker, it is ready to be flattened. - */ +// Resolves attributes in the XmlResource and compiles string values to resource values. +// Once an XmlResource is processed by this linker, it is ready to be flattened. class XmlReferenceLinker : public IXmlResourceConsumer { public: XmlReferenceLinker() = default; diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp index 414e56eb5dcc..71e828b039e1 100644 --- a/tools/aapt2/link/ReferenceLinker.cpp +++ b/tools/aapt2/link/ReferenceLinker.cpp @@ -30,23 +30,18 @@ #include "util/Util.h" #include "xml/XmlUtil.h" -using android::StringPiece; +using ::android::StringPiece; namespace aapt { namespace { -/** - * The ReferenceLinkerVisitor will follow all references and make sure they - * point - * to resources that actually exist, either in the local resource table, or as - * external - * symbols. Once the target resource has been found, the ID of the resource will - * be assigned - * to the reference object. - * - * NOTE: All of the entries in the ResourceTable must be assigned IDs. - */ +// The ReferenceLinkerVisitor will follow all references and make sure they point +// to resources that actually exist, either in the local resource table, or as external +// symbols. Once the target resource has been found, the ID of the resource will be assigned +// to the reference object. +// +// NOTE: All of the entries in the ResourceTable must be assigned IDs. class ReferenceLinkerVisitor : public ValueVisitor { public: using ValueVisitor::Visit; @@ -65,14 +60,9 @@ class ReferenceLinkerVisitor : public ValueVisitor { } } - /** - * We visit the Style specially because during this phase, values of - * attributes are - * all RawString values. Now that we are expected to resolve all symbols, we - * can - * lookup the attributes to find out which types are allowed for the - * attributes' values. - */ + // We visit the Style specially because during this phase, values of attributes are + // all RawString values. Now that we are expected to resolve all symbols, we can + // lookup the attributes to find out which types are allowed for the attributes' values. void Visit(Style* style) override { if (style->parent) { Visit(&style->parent.value()); @@ -81,28 +71,21 @@ class ReferenceLinkerVisitor : public ValueVisitor { for (Style::Entry& entry : style->entries) { std::string err_str; - // Transform the attribute reference so that it is using the fully - // qualified package - // name. This will also mark the reference as being able to see private - // resources if - // there was a '*' in the reference or if the package came from the - // private namespace. + // Transform the attribute reference so that it is using the fully qualified package + // name. This will also mark the reference as being able to see private resources if + // there was a '*' in the reference or if the package came from the private namespace. Reference transformed_reference = entry.key; - TransformReferenceFromNamespace(package_decls_, - context_->GetCompilationPackage(), - &transformed_reference); + ResolvePackage(package_decls_, &transformed_reference); - // Find the attribute in the symbol table and check if it is visible from - // this callsite. + // Find the attribute in the symbol table and check if it is visible from this callsite. const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility( transformed_reference, callsite_, symbols_, &err_str); if (symbol) { - // Assign our style key the correct ID. - // The ID may not exist. + // Assign our style key the correct ID. The ID may not exist. entry.key.id = symbol->id; - // Try to convert the value to a more specific, typed value based on the - // attribute it is set to. + // Try to convert the value to a more specific, typed value based on the attribute it is + // set to. entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get()); // Link/resolve the final value (mostly if it's a reference). @@ -115,8 +98,8 @@ class ReferenceLinkerVisitor : public ValueVisitor { // The actual type of this item is incompatible with the attribute. DiagMessage msg(entry.key.GetSource()); - // Call the matches method again, this time with a DiagMessage so we - // fill in the actual error message. + // Call the matches method again, this time with a DiagMessage so we fill in the actual + // error message. symbol->attribute->Matches(*entry.value, &msg); context_->GetDiagnostics()->Error(msg); error_ = true; @@ -125,7 +108,7 @@ class ReferenceLinkerVisitor : public ValueVisitor { } else { DiagMessage msg(entry.key.GetSource()); msg << "style attribute '"; - ReferenceLinker::WriteResourceName(&msg, entry.key, transformed_reference); + ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg); msg << "' " << err_str; context_->GetDiagnostics()->Error(msg); error_ = true; @@ -133,17 +116,15 @@ class ReferenceLinkerVisitor : public ValueVisitor { } } - bool HasError() { return error_; } + bool HasError() { + return error_; + } private: DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor); - /** - * Transform a RawString value into a more specific, appropriate value, based - * on the - * Attribute. If a non RawString value is passed in, this is an identity - * transform. - */ + // Transform a RawString value into a more specific, appropriate value, based on the + // Attribute. If a non RawString value is passed in, this is an identity transform. std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value, const Attribute* attr) { if (RawString* raw_string = ValueCast<RawString>(value.get())) { @@ -178,11 +159,9 @@ class EmptyDeclStack : public xml::IPackageDeclStack { public: EmptyDeclStack() = default; - Maybe<xml::ExtractedPackage> TransformPackageAlias( - const StringPiece& alias, - const StringPiece& local_package) const override { + Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override { if (alias.empty()) { - return xml::ExtractedPackage{local_package.to_string(), true /* private */}; + return xml::ExtractedPackage{{}, true /*private*/}; } return {}; } @@ -191,32 +170,44 @@ class EmptyDeclStack : public xml::IPackageDeclStack { DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack); }; -} // namespace +// The symbol is visible if it is public, or if the reference to it is requesting private access +// or if the callsite comes from the same package. +bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref, + const CallSite& callsite) { + if (symbol.is_public || ref.private_reference) { + return true; + } -/** - * The symbol is visible if it is public, or if the reference to it is - * requesting private access - * or if the callsite comes from the same package. - */ -bool ReferenceLinker::IsSymbolVisible(const SymbolTable::Symbol& symbol, - const Reference& ref, - const CallSite& callsite) { - if (!symbol.is_public && !ref.private_reference) { - if (ref.name) { - return callsite.resource.package == ref.name.value().package; - } else if (ref.id && symbol.id) { - return ref.id.value().package_id() == symbol.id.value().package_id(); - } else { - return false; + if (ref.name) { + const ResourceName& name = ref.name.value(); + if (name.package.empty()) { + // If the symbol was found, and the package is empty, that means it was found in the local + // scope, which is always visible (private local). + return true; } + + // The symbol is visible if the reference is local to the same package it is defined in. + return callsite.package == name.package; } - return true; + + if (ref.id && symbol.id) { + return ref.id.value().package_id() == symbol.id.value().package_id(); + } + return false; } +} // namespace + const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference, + const CallSite& callsite, SymbolTable* symbols) { if (reference.name) { - return symbols->FindByName(reference.name.value()); + const ResourceName& name = reference.name.value(); + if (name.package.empty()) { + // Use the callsite's package name if no package name was defined. + return symbols->FindByName(ResourceName(callsite.package, name.type, name.entry)); + } + return symbols->FindByName(name); } else if (reference.id) { return symbols->FindById(reference.id.value()); } else { @@ -228,7 +219,7 @@ const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const R const CallSite& callsite, SymbolTable* symbols, std::string* out_error) { - const SymbolTable::Symbol* symbol = ResolveSymbol(reference, symbols); + const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols); if (!symbol) { if (out_error) *out_error = "not found"; return nullptr; @@ -274,24 +265,62 @@ Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& return xml::AaptAttribute(*symbol->attribute, symbol->id); } -void ReferenceLinker::WriteResourceName(DiagMessage* out_msg, - const Reference& orig, - const Reference& transformed) { +void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite, + const xml::IPackageDeclStack* decls, DiagMessage* out_msg) { CHECK(out_msg != nullptr); + if (!ref.name) { + *out_msg << ref.id.value(); + return; + } - if (orig.name) { - *out_msg << orig.name.value(); - if (transformed.name.value() != orig.name.value()) { - *out_msg << " (aka " << transformed.name.value() << ")"; - } - } else { - *out_msg << orig.id.value(); + *out_msg << ref.name.value(); + + Reference fully_qualified = ref; + xml::ResolvePackage(decls, &fully_qualified); + + ResourceName& full_name = fully_qualified.name.value(); + if (full_name.package.empty()) { + full_name.package = callsite.package; + } + + if (full_name != ref.name.value()) { + *out_msg << " (aka " << full_name << ")"; + } +} + +void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite, + const xml::IPackageDeclStack* decls, + DiagMessage* out_msg) { + CHECK(out_msg != nullptr); + if (!ref.name) { + *out_msg << ref.id.value(); + return; + } + + const ResourceName& ref_name = ref.name.value(); + CHECK_EQ(ref_name.type, ResourceType::kAttr); + + if (!ref_name.package.empty()) { + *out_msg << ref_name.package << ":"; + } + *out_msg << ref_name.entry; + + Reference fully_qualified = ref; + xml::ResolvePackage(decls, &fully_qualified); + + ResourceName& full_name = fully_qualified.name.value(); + if (full_name.package.empty()) { + full_name.package = callsite.package; + } + + if (full_name != ref.name.value()) { + *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")"; } } bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference, IAaptContext* context, SymbolTable* symbols, - xml::IPackageDeclStack* decls) { + const xml::IPackageDeclStack* decls) { CHECK(reference != nullptr); if (!reference->name && !reference->id) { // This is @null. @@ -299,7 +328,7 @@ bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* referen } Reference transformed_reference = *reference; - TransformReferenceFromNamespace(decls, context->GetCompilationPackage(), &transformed_reference); + xml::ResolvePackage(decls, &transformed_reference); std::string err_str; const SymbolTable::Symbol* s = @@ -314,7 +343,7 @@ bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* referen DiagMessage error_msg(reference->GetSource()); error_msg << "resource "; - WriteResourceName(&error_msg, *reference, transformed_reference); + WriteResourceName(*reference, callsite, decls, &error_msg); error_msg << " " << err_str; context->GetDiagnostics()->Error(error_msg); return false; @@ -324,21 +353,24 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) { EmptyDeclStack decl_stack; bool error = false; for (auto& package : table->packages) { + // Since we're linking, each package must have a name. + CHECK(!package->name.empty()) << "all packages being linked must have a name"; + for (auto& type : package->types) { for (auto& entry : type->entries) { - // Symbol state information may be lost if there is no value for the - // resource. - if (entry->symbol_status.state != SymbolState::kUndefined && - entry->values.empty()) { - context->GetDiagnostics()->Error( - DiagMessage(entry->symbol_status.source) - << "no definition for declared symbol '" - << ResourceNameRef(package->name, type->type, entry->name) - << "'"); + // First, unmangle the name if necessary. + ResourceName name(package->name, type->type, entry->name); + NameMangler::Unmangle(&name.entry, &name.package); + + // Symbol state information may be lost if there is no value for the resource. + if (entry->symbol_status.state != SymbolState::kUndefined && entry->values.empty()) { + context->GetDiagnostics()->Error(DiagMessage(entry->symbol_status.source) + << "no definition for declared symbol '" << name << "'"); error = true; } - CallSite callsite = {ResourceNameRef(package->name, type->type, entry->name)}; + // The context of this resource is the package in which it is defined. + const CallSite callsite{name.package}; ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(), &table->string_pool, &decl_stack); diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h index b3d0196d9e7c..3b11bee0acc9 100644 --- a/tools/aapt2/link/ReferenceLinker.h +++ b/tools/aapt2/link/ReferenceLinker.h @@ -29,83 +29,58 @@ namespace aapt { -/** - * Resolves all references to resources in the ResourceTable and assigns them - * IDs. - * The ResourceTable must already have IDs assigned to each resource. - * Once the ResourceTable is processed by this linker, it is ready to be - * flattened. - */ +// Resolves all references to resources in the ResourceTable and assigns them IDs. +// The ResourceTable must already have IDs assigned to each resource. +// Once the ResourceTable is processed by this linker, it is ready to be flattened. class ReferenceLinker : public IResourceTableConsumer { public: ReferenceLinker() = default; - /** - * Returns true if the symbol is visible by the reference and from the - * callsite. - */ - static bool IsSymbolVisible(const SymbolTable::Symbol& symbol, - const Reference& ref, const CallSite& callsite); - - /** - * Performs name mangling and looks up the resource in the symbol table. - * Returns nullptr if the symbol was not found. - */ - static const SymbolTable::Symbol* ResolveSymbol(const Reference& reference, SymbolTable* symbols); - - /** - * Performs name mangling and looks up the resource in the symbol table. If - * the symbol is not visible by the reference at the callsite, nullptr is - * returned. out_error holds the error message. - */ + // Performs name mangling and looks up the resource in the symbol table. Uses the callsite's + // package if the reference has no package name defined (implicit). + // Returns nullptr if the symbol was not found. + static const SymbolTable::Symbol* ResolveSymbol(const Reference& reference, + const CallSite& callsite, SymbolTable* symbols); + + // Performs name mangling and looks up the resource in the symbol table. If the symbol is not + // visible by the reference at the callsite, nullptr is returned. + // `out_error` holds the error message. static const SymbolTable::Symbol* ResolveSymbolCheckVisibility(const Reference& reference, const CallSite& callsite, SymbolTable* symbols, std::string* out_error); - /** - * Same as resolveSymbolCheckVisibility(), but also makes sure the symbol is - * an attribute. - * That is, the return value will have a non-null value for - * ISymbolTable::Symbol::attribute. - */ + // Same as ResolveSymbolCheckVisibility(), but also makes sure the symbol is an attribute. + // That is, the return value will have a non-null value for ISymbolTable::Symbol::attribute. static const SymbolTable::Symbol* ResolveAttributeCheckVisibility(const Reference& reference, const CallSite& callsite, SymbolTable* symbols, std::string* out_error); - /** - * Resolves the attribute reference and returns an xml::AaptAttribute if - * successful. - * If resolution fails, outError holds the error message. - */ + // Resolves the attribute reference and returns an xml::AaptAttribute if successful. + // If resolution fails, outError holds the error message. static Maybe<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference, const CallSite& callsite, SymbolTable* symbols, std::string* out_error); - /** - * Writes the resource name to the DiagMessage, using the - * "orig_name (aka <transformed_name>)" syntax. - */ - static void WriteResourceName(DiagMessage* out_msg, const Reference& orig, - const Reference& transformed); - - /** - * Transforms the package name of the reference to the fully qualified package - * name using - * the xml::IPackageDeclStack, then mangles and looks up the symbol. If the - * symbol is visible - * to the reference at the callsite, the reference is updated with an ID. - * Returns false on failure, and an error message is logged to the - * IDiagnostics in the context. - */ + // Writes the resource name to the DiagMessage, using the + // "orig_name (aka <transformed_name>)" syntax. + static void WriteResourceName(const Reference& orig, const CallSite& callsite, + const xml::IPackageDeclStack* decls, DiagMessage* out_msg); + + // Same as WriteResourceName but omits the 'attr' part. + static void WriteAttributeName(const Reference& ref, const CallSite& callsite, + const xml::IPackageDeclStack* decls, DiagMessage* out_msg); + + // Transforms the package name of the reference to the fully qualified package name using + // the xml::IPackageDeclStack, then mangles and looks up the symbol. If the symbol is visible + // to the reference at the callsite, the reference is updated with an ID. + // Returns false on failure, and an error message is logged to the IDiagnostics in the context. static bool LinkReference(const CallSite& callsite, Reference* reference, IAaptContext* context, - SymbolTable* symbols, xml::IPackageDeclStack* decls); + SymbolTable* symbols, const xml::IPackageDeclStack* decls); - /** - * Links all references in the ResourceTable. - */ + // Links all references in the ResourceTable. bool Consume(IAaptContext* context, ResourceTable* table) override; private: diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp index 72a91689e392..be38b967c986 100644 --- a/tools/aapt2/link/ReferenceLinker_test.cpp +++ b/tools/aapt2/link/ReferenceLinker_test.cpp @@ -18,7 +18,9 @@ #include "test/Test.h" -using android::ResTable_map; +using ::android::ResTable_map; +using ::testing::Eq; +using ::testing::IsNull; using ::testing::NotNull; namespace aapt { @@ -263,7 +265,7 @@ TEST(ReferenceLinkerTest, AppsWithSamePackageButDifferentIdAreVisibleNonPublic) .Build()); std::string error; - const CallSite call_site{ResourceNameRef("com.app.test", ResourceType::kString, "foo")}; + const CallSite call_site{"com.app.test"}; const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility( *test::BuildReference("com.app.test:string/foo"), call_site, &table, &error); ASSERT_THAT(symbol, NotNull()); @@ -281,7 +283,7 @@ TEST(ReferenceLinkerTest, AppsWithDifferentPackageCanNotUseEachOthersAttribute) .Build()); std::string error; - const CallSite call_site{ResourceNameRef("com.app.ext", ResourceType::kLayout, "foo")}; + const CallSite call_site{"com.app.ext"}; EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute( *test::BuildReference("com.app.test:attr/foo"), call_site, &table, &error)); @@ -293,4 +295,27 @@ TEST(ReferenceLinkerTest, AppsWithDifferentPackageCanNotUseEachOthersAttribute) EXPECT_TRUE(error.empty()); } +TEST(ReferenceLinkerTest, ReferenceWithNoPackageUsesCallSitePackage) { + NameMangler mangler(NameManglerPolicy{"com.app.test"}); + SymbolTable table(&mangler); + table.AppendSource(test::StaticSymbolSourceBuilder() + .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000)) + .AddSymbol("com.app.lib:string/foo", ResourceId(0x7f010001)) + .Build()); + + const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), + CallSite{"com.app.test"}, &table); + ASSERT_THAT(s, NotNull()); + EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000))); + + s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"}, + &table); + ASSERT_THAT(s, NotNull()); + EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001))); + + EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), + CallSite{"com.app.bad"}, &table), + IsNull()); +} + } // namespace aapt diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index 10e837c725e5..93c904f1a743 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -24,7 +24,7 @@ #include "ValueVisitor.h" #include "util/Util.h" -using android::StringPiece; +using ::android::StringPiece; namespace aapt { @@ -32,27 +32,23 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table, const TableMergerOptions& options) : context_(context), master_table_(out_table), options_(options) { // Create the desired package that all tables will be merged into. - master_package_ = master_table_->CreatePackage( - context_->GetCompilationPackage(), context_->GetPackageId()); + master_package_ = + master_table_->CreatePackage(context_->GetCompilationPackage(), context_->GetPackageId()); CHECK(master_package_ != nullptr) << "package name or ID already taken"; } -bool TableMerger::Merge(const Source& src, ResourceTable* table, - io::IFileCollection* collection) { - return MergeImpl(src, table, collection, false /* overlay */, true /* allow new */); +bool TableMerger::Merge(const Source& src, ResourceTable* table, io::IFileCollection* collection) { + return MergeImpl(src, table, collection, false /*overlay*/, true /*allow_new*/); } bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table, io::IFileCollection* collection) { - return MergeImpl(src, table, collection, true /* overlay */, options_.auto_add_overlay); + return MergeImpl(src, table, collection, true /*overlay*/, options_.auto_add_overlay); } -/** - * This will merge packages with the same package name (or no package name). - */ +// This will merge packages with the same package name (or no package name). bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, - io::IFileCollection* collection, bool overlay, - bool allow_new) { + io::IFileCollection* collection, bool overlay, bool allow_new) { bool error = false; for (auto& package : table->packages) { // Only merge an empty package or the package we're building. @@ -62,9 +58,8 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, if (package->name.empty() || context_->GetCompilationPackage() == package->name) { FileMergeCallback callback; if (collection) { - callback = [&](const ResourceNameRef& name, - const ConfigDescription& config, FileReference* new_file, - FileReference* old_file) -> bool { + callback = [&](const ResourceNameRef& name, const ConfigDescription& config, + FileReference* new_file, FileReference* old_file) -> bool { // The old file's path points inside the APK, so we can use it as is. io::IFile* f = collection->FindFile(*old_file->path); if (!f) { @@ -78,45 +73,38 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, }; } - // Merge here. Once the entries are merged and mangled, any references to - // them are still valid. This is because un-mangled references are - // mangled, then looked up at resolution time. - // Also, when linking, we convert references with no package name to use - // the compilation package name. - error |= !DoMerge(src, table, package.get(), false /* mangle */, overlay, - allow_new, callback); + // Merge here. Once the entries are merged and mangled, any references to them are still + // valid. This is because un-mangled references are mangled, then looked up at resolution + // time. Also, when linking, we convert references with no package name to use the compilation + // package name. + error |= + !DoMerge(src, table, package.get(), false /* mangle */, overlay, allow_new, callback); } } return !error; } -/** - * This will merge and mangle resources from a static library. - */ -bool TableMerger::MergeAndMangle(const Source& src, - const StringPiece& package_name, - ResourceTable* table, - io::IFileCollection* collection) { +// This will merge and mangle resources from a static library. +bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_name, + ResourceTable* table, io::IFileCollection* collection) { bool error = false; for (auto& package : table->packages) { // Warn of packages with an unrelated ID. if (package_name != package->name) { - context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " - << package->name); + context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " << package->name); continue; } bool mangle = package_name != context_->GetCompilationPackage(); merged_packages_.insert(package->name); - auto callback = [&]( - const ResourceNameRef& name, const ConfigDescription& config, - FileReference* new_file, FileReference* old_file) -> bool { + auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config, + FileReference* new_file, FileReference* old_file) -> bool { // The old file's path points inside the APK, so we can use it as is. io::IFile* f = collection->FindFile(*old_file->path); if (!f) { - context_->GetDiagnostics()->Error( - DiagMessage(src) << "file '" << *old_file->path << "' not found"); + context_->GetDiagnostics()->Error(DiagMessage(src) + << "file '" << *old_file->path << "' not found"); return false; } @@ -124,21 +112,18 @@ bool TableMerger::MergeAndMangle(const Source& src, return true; }; - error |= !DoMerge(src, table, package.get(), mangle, false /* overlay */, - true /* allow new */, callback); + error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/, + callback); } return !error; } -static bool MergeType(IAaptContext* context, const Source& src, - ResourceTableType* dst_type, +static bool MergeType(IAaptContext* context, const Source& src, ResourceTableType* dst_type, ResourceTableType* src_type) { if (dst_type->symbol_status.state < src_type->symbol_status.state) { - // The incoming type's visibility is stronger, so we should override - // the visibility. + // The incoming type's visibility is stronger, so we should override the visibility. if (src_type->symbol_status.state == SymbolState::kPublic) { - // Only copy the ID if the source is public, or else the ID is - // meaningless. + // Only copy the ID if the source is public, or else the ID is meaningless. dst_type->id = src_type->id; } dst_type->symbol_status = std::move(src_type->symbol_status); @@ -155,14 +140,12 @@ static bool MergeType(IAaptContext* context, const Source& src, return true; } -static bool MergeEntry(IAaptContext* context, const Source& src, - ResourceEntry* dst_entry, ResourceEntry* src_entry) { +static bool MergeEntry(IAaptContext* context, const Source& src, ResourceEntry* dst_entry, + ResourceEntry* src_entry) { if (dst_entry->symbol_status.state < src_entry->symbol_status.state) { - // The incoming type's visibility is stronger, so we should override - // the visibility. + // The incoming type's visibility is stronger, so we should override the visibility. if (src_entry->symbol_status.state == SymbolState::kPublic) { - // Only copy the ID if the source is public, or else the ID is - // meaningless. + // Only copy the ID if the source is public, or else the ID is meaningless. dst_entry->id = src_entry->id; } dst_entry->symbol_status = std::move(src_entry->symbol_status); @@ -171,9 +154,8 @@ static bool MergeEntry(IAaptContext* context, const Source& src, dst_entry->id && src_entry->id && dst_entry->id.value() != src_entry->id.value()) { // Both entries are public and have different IDs. - context->GetDiagnostics()->Error( - DiagMessage(src) << "cannot merge entry '" << src_entry->name - << "': conflicting public IDs"); + context->GetDiagnostics()->Error(DiagMessage(src) << "cannot merge entry '" << src_entry->name + << "': conflicting public IDs"); return false; } return true; @@ -181,12 +163,10 @@ static bool MergeEntry(IAaptContext* context, const Source& src, // Modified CollisionResolver which will merge Styleables and Styles. Used with overlays. // -// Styleables are not actual resources, but they are treated as such during the -// compilation phase. +// Styleables are not actual resources, but they are treated as such during the compilation phase. // -// Styleables and Styles don't simply overlay each other, their definitions merge -// and accumulate. If both values are Styleables/Styles, we just merge them into the -// existing value. +// Styleables and Styles don't simply overlay each other, their definitions merge and accumulate. +// If both values are Styleables/Styles, we just merge them into the existing value. static ResourceTable::CollisionResult ResolveMergeCollision(Value* existing, Value* incoming, StringPool* pool) { if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) { diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h index c96b1b0b4dfb..81518ffb2441 100644 --- a/tools/aapt2/link/TableMerger.h +++ b/tools/aapt2/link/TableMerger.h @@ -33,81 +33,49 @@ namespace aapt { struct TableMergerOptions { - /** - * If true, resources in overlays can be added without previously having - * existed. - */ + // If true, resources in overlays can be added without previously having existed. bool auto_add_overlay = false; }; -/** - * TableMerger takes resource tables and merges all packages within the tables - * that have the same - * package ID. - * - * If a package has a different name, all the entries in that table have their - * names mangled - * to include the package name. This way there are no collisions. In order to do - * this correctly, - * the TableMerger needs to also mangle any FileReference paths. Once these are - * mangled, - * the original source path of the file, along with the new destination path is - * recorded in the - * queue returned from getFileMergeQueue(). - * - * Once the merging is complete, a separate process can go collect the files - * from the various - * source APKs and either copy or process their XML and put them in the correct - * location in - * the final APK. - */ +// TableMerger takes resource tables and merges all packages within the tables that have the same +// package ID. +// +// If a package has a different name, all the entries in that table have their names mangled +// to include the package name. This way there are no collisions. In order to do this correctly, +// the TableMerger needs to also mangle any FileReference paths. Once these are mangled, the +// `IFile` pointer in `FileReference` will point to the original file. +// +// Once the merging is complete, a separate phase can go collect the files from the various +// source APKs and either copy or process their XML and put them in the correct location in the +// final APK. class TableMerger { public: - /** - * Note: The out_table ResourceTable must live longer than this TableMerger. - * References are made to this ResourceTable for efficiency reasons. - */ - TableMerger(IAaptContext* context, ResourceTable* out_table, - const TableMergerOptions& options); - - const std::set<std::string>& merged_packages() const { + // Note: The out_table ResourceTable must live longer than this TableMerger. + // References are made to this ResourceTable for efficiency reasons. + TableMerger(IAaptContext* context, ResourceTable* out_table, const TableMergerOptions& options); + + inline const std::set<std::string>& merged_packages() const { return merged_packages_; } - /** - * Merges resources from the same or empty package. This is for local sources. - * An io::IFileCollection is optional and used to find the referenced Files - * and process them. - */ - bool Merge(const Source& src, ResourceTable* table, - io::IFileCollection* collection = nullptr); - - /** - * Merges resources from an overlay ResourceTable. - * An io::IFileCollection is optional and used to find the referenced Files - * and process them. - */ + // Merges resources from the same or empty package. This is for local sources. + // An io::IFileCollection is optional and used to find the referenced Files and process them. + bool Merge(const Source& src, ResourceTable* table, io::IFileCollection* collection = nullptr); + + // Merges resources from an overlay ResourceTable. + // An io::IFileCollection is optional and used to find the referenced Files and process them. bool MergeOverlay(const Source& src, ResourceTable* table, io::IFileCollection* collection = nullptr); - /** - * Merges resources from the given package, mangling the name. This is for - * static libraries. - * An io::IFileCollection is needed in order to find the referenced Files and - * process them. - */ + // Merges resources from the given package, mangling the name. This is for static libraries. + // An io::IFileCollection is needed in order to find the referenced Files and process them. bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table, io::IFileCollection* collection); - /** - * Merges a compiled file that belongs to this same or empty package. This is - * for local sources. - */ + // Merges a compiled file that belongs to this same or empty package. This is for local sources. bool MergeFile(const ResourceFile& fileDesc, io::IFile* file); - /** - * Merges a compiled file from an overlay, overriding an existing definition. - */ + // Merges a compiled file from an overlay, overriding an existing definition. bool MergeFileOverlay(const ResourceFile& fileDesc, io::IFile* file); private: diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp index bcecd2003846..6ebb80f4be8f 100644 --- a/tools/aapt2/link/XmlReferenceLinker.cpp +++ b/tools/aapt2/link/XmlReferenceLinker.cpp @@ -31,13 +31,9 @@ namespace aapt { namespace { -/** - * Visits all references (including parents of styles, references in styles, - * arrays, etc) and - * links their symbolic name to their Resource ID, performing mangling and - * package aliasing - * as needed. - */ +// Visits all references (including parents of styles, references in styles, arrays, etc) and +// links their symbolic name to their Resource ID, performing mangling and package aliasing +// as needed. class ReferenceVisitor : public ValueVisitor { public: using ValueVisitor::Visit; @@ -52,7 +48,9 @@ class ReferenceVisitor : public ValueVisitor { } } - bool HasError() const { return error_; } + bool HasError() const { + return error_; + } private: DISALLOW_COPY_AND_ASSIGN(ReferenceVisitor); @@ -64,9 +62,7 @@ class ReferenceVisitor : public ValueVisitor { bool error_; }; -/** - * Visits each xml Element and compiles the attributes within. - */ +// Visits each xml Element and compiles the attributes within. class XmlVisitor : public xml::PackageAwareVisitor { public: using xml::PackageAwareVisitor::Visit; @@ -92,18 +88,12 @@ class XmlVisitor : public xml::PackageAwareVisitor { // they were assigned to the default Attribute. const Attribute* attribute = &kDefaultAttribute; - std::string attribute_package; if (Maybe<xml::ExtractedPackage> maybe_package = xml::ExtractPackageFromNamespace(attr.namespace_uri)) { // There is a valid package name for this attribute. We will look this up. - attribute_package = maybe_package.value().package; - if (attribute_package.empty()) { - // Empty package means the 'current' or 'local' package. - attribute_package = context_->GetCompilationPackage(); - } - - Reference attr_ref(ResourceNameRef(attribute_package, ResourceType::kAttr, attr.name)); + Reference attr_ref( + ResourceNameRef(maybe_package.value().package, ResourceType::kAttr, attr.name)); attr_ref.private_reference = maybe_package.value().private_namespace; std::string err_str; @@ -111,9 +101,11 @@ class XmlVisitor : public xml::PackageAwareVisitor { ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, symbols_, &err_str); if (!attr.compiled_attribute) { - context_->GetDiagnostics()->Error(DiagMessage(source) << "attribute '" - << attribute_package << ":" - << attr.name << "' " << err_str); + DiagMessage error_msg(source); + error_msg << "attribute "; + ReferenceLinker::WriteAttributeName(attr_ref, callsite_, this, &error_msg); + error_msg << " " << err_str; + context_->GetDiagnostics()->Error(error_msg); error_ = true; continue; } @@ -129,12 +121,8 @@ class XmlVisitor : public xml::PackageAwareVisitor { } else if ((attribute->type_mask & android::ResTable_map::TYPE_STRING) == 0) { // We won't be able to encode this as a string. DiagMessage msg(source); - msg << "'" << attr.value << "' " - << "is incompatible with attribute "; - if (!attribute_package.empty()) { - msg << attribute_package << ":"; - } - msg << attr.name << " " << *attribute; + msg << "'" << attr.value << "' is incompatible with attribute " << attr.name << " " + << *attribute; context_->GetDiagnostics()->Error(msg); error_ = true; } @@ -163,7 +151,17 @@ class XmlVisitor : public xml::PackageAwareVisitor { } // namespace bool XmlReferenceLinker::Consume(IAaptContext* context, xml::XmlResource* resource) { - const CallSite callsite = {resource->file.name}; + CallSite callsite{resource->file.name.package}; + + std::string out_name = resource->file.name.entry; + NameMangler::Unmangle(&out_name, &callsite.package); + + if (callsite.package.empty()) { + // Assume an empty package means that the XML file is local. This is true of AndroidManifest.xml + // for example. + callsite.package = context->GetCompilationPackage(); + } + XmlVisitor visitor(resource->file.source, callsite, context, context->GetExternalSymbols()); if (resource->root) { resource->root->Accept(&visitor); diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index cbb652ed9a1a..19de3afb9d62 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -274,6 +274,8 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos switch (code) { case ResXMLParser::START_NAMESPACE: { NamespaceDecl decl; + decl.line_number = tree.getLineNumber(); + size_t len; const char16_t* str16 = tree.getNamespacePrefix(&len); if (str16) { @@ -288,6 +290,7 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos if (pending_element == nullptr) { pending_element = util::make_unique<Element>(); } + pending_element->namespace_decls.push_back(std::move(decl)); break; } @@ -297,8 +300,8 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos el = std::move(pending_element); } else { el = util::make_unique<Element>(); - ; } + el->line_number = tree.getLineNumber(); size_t len; const char16_t* str16 = tree.getElementNamespace(&len); @@ -479,10 +482,9 @@ void PackageAwareVisitor::AfterVisitElement(Element* el) { package_decls_.pop_back(); } -Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias( - const StringPiece& alias, const StringPiece& local_package) const { +Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const { if (alias.empty()) { - return ExtractedPackage{local_package.to_string(), false /* private */}; + return ExtractedPackage{{}, false /*private*/}; } const auto rend = package_decls_.rend(); @@ -493,7 +495,7 @@ Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias( const PackageDecl& decl = *iter2; if (alias == decl.prefix) { if (decl.package.package.empty()) { - return ExtractedPackage{local_package.to_string(), decl.package.private_namespace}; + return ExtractedPackage{{}, decl.package.private_namespace}; } return decl.package; } diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h index 154224381626..9a9151da4ab7 100644 --- a/tools/aapt2/xml/XmlDom.h +++ b/tools/aapt2/xml/XmlDom.h @@ -185,8 +185,7 @@ class PackageAwareVisitor : public Visitor, public IPackageDeclStack { public: using Visitor::Visit; - Maybe<ExtractedPackage> TransformPackageAlias( - const android::StringPiece& alias, const android::StringPiece& local_package) const override; + Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override; protected: PackageAwareVisitor() = default; diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp index 6ed2d616f782..10a45870e556 100644 --- a/tools/aapt2/xml/XmlDom_test.cpp +++ b/tools/aapt2/xml/XmlDom_test.cpp @@ -86,19 +86,14 @@ class TestVisitor : public PackageAwareVisitor { void Visit(Element* el) override { if (el->name == "View1") { - EXPECT_THAT(TransformPackageAlias("one", "local"), - Eq(make_value(ExtractedPackage{"com.one", false}))); + EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); } else if (el->name == "View2") { - EXPECT_THAT(TransformPackageAlias("one", "local"), - Eq(make_value(ExtractedPackage{"com.one", false}))); - EXPECT_THAT(TransformPackageAlias("two", "local"), - Eq(make_value(ExtractedPackage{"com.two", false}))); + EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); + EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); } else if (el->name == "View3") { - EXPECT_THAT(TransformPackageAlias("one", "local"), - Eq(make_value(ExtractedPackage{"com.one", false}))); - EXPECT_THAT(TransformPackageAlias("two", "local"), - Eq(make_value(ExtractedPackage{"com.two", false}))); - EXPECT_THAT(TransformPackageAlias("three", "local"), + EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false}))); + EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false}))); + EXPECT_THAT(TransformPackageAlias("three"), Eq(make_value(ExtractedPackage{"com.three", false}))); } } @@ -112,7 +107,6 @@ TEST(XmlDomTest, PackageAwareXmlVisitor) { </View2> </View1>)"); - Debug::DumpXml(doc.get()); TestVisitor visitor; doc->root->Accept(&visitor); } diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp index 30bdc507303b..402e5a459f4e 100644 --- a/tools/aapt2/xml/XmlPullParser.cpp +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -141,17 +141,16 @@ const std::string& XmlPullParser::namespace_uri() const { return event_queue_.front().data2; } -Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias( - const StringPiece& alias, const StringPiece& local_package) const { +Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(const StringPiece& alias) const { if (alias.empty()) { - return ExtractedPackage{local_package.to_string(), false /* private */}; + return ExtractedPackage{{}, false /*private*/}; } const auto end_iter = package_aliases_.rend(); for (auto iter = package_aliases_.rbegin(); iter != end_iter; ++iter) { if (alias == iter->prefix) { if (iter->package.package.empty()) { - return ExtractedPackage{local_package.to_string(), iter->package.private_namespace}; + return ExtractedPackage{{}, iter->package.private_namespace}; } return iter->package; } diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h index a00caa139061..63db66f0b2b7 100644 --- a/tools/aapt2/xml/XmlPullParser.h +++ b/tools/aapt2/xml/XmlPullParser.h @@ -119,8 +119,7 @@ class XmlPullParser : public IPackageDeclStack { * If xmlns:app="http://schemas.android.com/apk/res-auto", then * 'package' will be set to 'defaultPackage'. */ - Maybe<ExtractedPackage> TransformPackageAlias( - const android::StringPiece& alias, const android::StringPiece& local_package) const override; + Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override; // // Remaining methods are for retrieving information about attributes diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp index fb8cee8b5634..c1186e83369c 100644 --- a/tools/aapt2/xml/XmlUtil.cpp +++ b/tools/aapt2/xml/XmlUtil.cpp @@ -62,19 +62,15 @@ Maybe<ExtractedPackage> ExtractPackageFromNamespace( return {}; } -void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack, - const StringPiece& local_package, - Reference* in_ref) { +void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref) { if (in_ref->name) { if (Maybe<ExtractedPackage> transformed_package = - decl_stack->TransformPackageAlias(in_ref->name.value().package, - local_package)) { + decl_stack->TransformPackageAlias(in_ref->name.value().package)) { ExtractedPackage& extracted_package = transformed_package.value(); in_ref->name.value().package = std::move(extracted_package.package); // If the reference was already private (with a * prefix) and the - // namespace is public, - // we keep the reference private. + // namespace is public, we keep the reference private. in_ref->private_reference |= extracted_package.private_namespace; } } diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h index 866b6dcd7a88..4eb359a9eed4 100644 --- a/tools/aapt2/xml/XmlUtil.h +++ b/tools/aapt2/xml/XmlUtil.h @@ -35,7 +35,7 @@ constexpr const char* kSchemaAapt = "http://schemas.android.com/aapt"; // Result of extracting a package name from a namespace URI declaration. struct ExtractedPackage { // The name of the package. This can be the empty string, which means that the package - // should be assumed to be the package being compiled. + // should be assumed to be the same as the CallSite it was defined in. std::string package; // True if the package's private namespace was declared. This means that private resources @@ -51,8 +51,8 @@ struct ExtractedPackage { // http://schemas.android.com/apk/res/<package> or // http://schemas.android.com/apk/prv/res/<package> // -// Special case: if namespaceUri is http://schemas.android.com/apk/res-auto, -// returns an empty package name. +// Special case: if namespaceUri is http://schemas.android.com/apk/res-auto, returns an empty +// package name. Maybe<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri); // Returns an XML Android namespace for the given package of the form: @@ -63,21 +63,20 @@ Maybe<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace std::string BuildPackageNamespace(const android::StringPiece& package, bool private_reference = false); -// Interface representing a stack of XML namespace declarations. When looking up the package -// for a namespace prefix, the stack is checked from top to bottom. +// Interface representing a stack of XML namespace declarations. When looking up the package for a +// namespace prefix, the stack is checked from top to bottom. struct IPackageDeclStack { virtual ~IPackageDeclStack() = default; // Returns an ExtractedPackage struct if the alias given corresponds with a package declaration. virtual Maybe<ExtractedPackage> TransformPackageAlias( - const android::StringPiece& alias, const android::StringPiece& local_package) const = 0; + const android::StringPiece& alias) const = 0; }; // Helper function for transforming the original Reference inRef to a fully qualified reference // via the IPackageDeclStack. This will also mark the Reference as private if the namespace of the // package declaration was private. -void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack, - const android::StringPiece& local_package, Reference* in_ref); +void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref); } // namespace xml } // namespace aapt |