AAPT2: Merge-only mode for building static libraries

Add a new option for skipping resource references validation when
building a static library. This pushes resource reference validation
to the final link step (creating an installable APK), but allows a lib
to be linked without having the static libs of its dependencies.

More context: go/autonamespace-transform

Test: MergeOnlyTest + manually verified
Bug: 128824820
Change-Id: I1f3e3b7715a5244b8633c85519d94334c76ff664
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 04d12f8..828e80d 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -269,6 +269,7 @@
   bool keep_raw_values = false;
   bool do_not_compress_anything = false;
   bool update_proguard_spec = false;
+  bool do_not_fail_on_missing_resources = false;
   OutputFormat output_format = OutputFormat::kApk;
   std::unordered_set<std::string> extensions_to_not_compress;
   Maybe<std::regex> regex_to_not_compress;
@@ -435,7 +436,7 @@
   xml::StripAndroidStudioAttributes(doc->root.get());
 
   XmlReferenceLinker xml_linker;
-  if (!xml_linker.Consume(context_, doc)) {
+  if (!options_.do_not_fail_on_missing_resources && !xml_linker.Consume(context_, doc)) {
     return {};
   }
 
@@ -1579,6 +1580,7 @@
     file_flattener_options.update_proguard_spec =
         static_cast<bool>(options_.generate_proguard_rules_path);
     file_flattener_options.output_format = options_.output_format;
+    file_flattener_options.do_not_fail_on_missing_resources = options_.merge_only;
 
     ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set);
 
@@ -1807,7 +1809,7 @@
     }
 
     ReferenceLinker linker;
-    if (!linker.Consume(context_, &final_table_)) {
+    if (!options_.merge_only && !linker.Consume(context_, &final_table_)) {
       context_->GetDiagnostics()->Error(DiagMessage() << "failed linking references");
       return 1;
     }
@@ -1959,7 +1961,7 @@
       manifest_xml->file.name.package = context_->GetCompilationPackage();
 
       XmlReferenceLinker manifest_linker;
-      if (manifest_linker.Consume(context_, manifest_xml.get())) {
+      if (options_.merge_only || manifest_linker.Consume(context_, manifest_xml.get())) {
         if (options_.generate_proguard_rules_path &&
             !proguard::CollectProguardRulesForManifest(manifest_xml.get(), &proguard_keep_set)) {
           error = true;
@@ -2093,6 +2095,12 @@
     return 1;
   }
 
+  if (options_.merge_only && !static_lib_) {
+    context.GetDiagnostics()->Error(
+        DiagMessage() << "the --merge-only flag can be only used when building a static library");
+    return 1;
+  }
+
   // The default build type.
   context.SetPackageType(PackageType::kApp);
   context.SetPackageId(kAppPackageId);
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 37765f6..324807c 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -71,6 +71,7 @@
 
   // Static lib options.
   bool no_static_lib_packages = false;
+  bool merge_only = false;
 
   // AndroidManifest.xml massaging options.
   ManifestFixerOptions manifest_fixer_options;
@@ -285,6 +286,10 @@
     AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
     AddOptionalFlag("--trace-folder", "Generate systrace json trace fragment to specified folder.",
                     &trace_folder_);
+    AddOptionalSwitch("--merge-only",
+          "Only merge the resources, without verifying resource references. This flag\n"
+          "should only be used together with the --static-lib flag.",
+          &options_.merge_only);
   }
 
   int Action(const std::vector<std::string>& args) override;
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/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/MergeOnlyTest/App/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/App/Android.mk
new file mode 100644
index 0000000..6bc2064
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/App/Android.mk
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_NAMESPACES := true
+LOCAL_PACKAGE_NAME := AaptTestMergeOnly_App
+LOCAL_SDK_VERSION := current
+LOCAL_EXPORT_PACKAGE_RESOURCES := true
+LOCAL_MODULE_TAGS := tests
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    AaptTestMergeOnly_LeafLib \
+    AaptTestMergeOnly_LocalLib
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/App/AndroidManifest.xml b/tools/aapt2/integration-tests/MergeOnlyTest/App/AndroidManifest.xml
new file mode 100644
index 0000000..bc3a7e5
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/App/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.app">
+
+    <application
+        android:label="@*com.local.lib:string/lib_string"/>
+
+</manifest>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk
new file mode 100644
index 0000000..7bf8cf8
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/Android.mk
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_NAMESPACES := true
+LOCAL_MODULE := AaptTestMergeOnly_LeafLib
+LOCAL_SDK_VERSION := current
+LOCAL_MODULE_TAGS := tests
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_AAPT_FLAGS := --merge-only
+include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/AndroidManifest.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/AndroidManifest.xml
new file mode 100644
index 0000000..9907bd9
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest package="com.leaf.lib" />
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/res/layout/activity.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/res/layout/activity.xml
new file mode 100644
index 0000000..07de87f
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/res/layout/activity.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:leaf="http://schemas.android.com/apk/res/com.leaf.lib">
+
+    <TextView android:text="@string/leaf_string"
+        leaf:leaf_attr="hello"
+        style="@style/LeafChildStyle"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/res/values/values.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/res/values/values.xml
new file mode 100644
index 0000000..7f94c26
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LeafLib/res/values/values.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <attr format="string" name="leaf_attr"/>
+    <attr format="string" name="leaf_attr2"/>
+
+    <string name="leaf_string">I am a leaf</string>
+
+    <style name="LeafParentStyle">
+        <item type="attr" name="leaf_attr"/>
+        <item type="attr" name="leaf_attr2"/>
+    </style>
+
+    <style name="LeafChildStyle" parent="LeafParentStyle">
+        <item type="attr" name="leaf_attr2">hello</item>
+    </style>
+
+    <style name="LeafParentStyle.DottedChild"/>
+
+    <declare-styleable name="leaf_ds">
+        <attr name="leaf_attr">hello</attr>
+    </declare-styleable>
+
+    <public type="attr" name="leaf_attr"/>
+    <public type="attr" name="leaf_attr2"/>
+    <public type="style" name="LeafParentStyle"/>
+    <public type="style" name="LeafChildStyle"/>
+    <public type="style" name="LeafParentStyle.DottedChild"/>
+</resources>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk
new file mode 100644
index 0000000..ba781c5
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/Android.mk
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_NAMESPACES := true
+LOCAL_MODULE := AaptTestMergeOnly_LocalLib
+LOCAL_SDK_VERSION := current
+LOCAL_MODULE_TAGS := tests
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_AAPT_FLAGS := --merge-only
+include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/AndroidManifest.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/AndroidManifest.xml
new file mode 100644
index 0000000..aa0ff5d
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.local.lib">
+
+    <application>
+
+    <activity
+        android:name="com.myapp.MyActivity"
+        android:theme="@com.leaf.lib:style/LeafParentStyle.DottedChild"/>
+
+    </application>
+
+</manifest>
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/layout/activity.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/layout/activity.xml
new file mode 100644
index 0000000..80d2fd6
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/layout/activity.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:leaf="http://schemas.android.com/apk/res/com.leaf.lib">
+
+    <TextView android:text="@*com.leaf.lib:string/leaf_string"
+        leaf:leaf_attr="hello"
+        style="@com.leaf.lib:style/LeafChildStyle"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/layout/includer.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/layout/includer.xml
new file mode 100644
index 0000000..f063718
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/layout/includer.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:leaf="http://schemas.android.com/apk/res/com.leaf.lib">
+
+    <include layout="@layout/activity"/>
+
+    <include layout="@*com.leaf.lib:layout/activity"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/values/values.xml b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/values/values.xml
new file mode 100644
index 0000000..2f9704d
--- /dev/null
+++ b/tools/aapt2/integration-tests/MergeOnlyTest/LocalLib/res/values/values.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="lib_string">@*com.leaf.lib:string/leaf_string</string>
+
+    <style name="lib_style" parent="@com.leaf.lib:style/LeafChildStyle">
+        <item name="com.leaf.lib:leaf_attr">hello</item>
+    </style>
+
+    <style name="LeafParentStyle.DottedChild.LocalLibStyle" 
+        parent="@com.leaf.lib:style/LeafParentStyle.DottedChild"/>
+
+    <public type="style" name="LeafParentStyle.DottedChild.LocalLibStyle"/>
+
+</resources>
\ No newline at end of file