summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/ResourceTable.cpp8
-rw-r--r--tools/aapt/SdkConstants.h1
-rw-r--r--tools/aapt2/Android.bp12
-rw-r--r--tools/aapt2/ApkInfo.proto340
-rw-r--r--tools/aapt2/Configuration.proto10
-rw-r--r--tools/aapt2/Debug.cpp126
-rw-r--r--tools/aapt2/Debug.h3
-rw-r--r--tools/aapt2/Diagnostics.h100
-rw-r--r--tools/aapt2/LoadedApk.cpp62
-rw-r--r--tools/aapt2/LoadedApk.h19
-rw-r--r--tools/aapt2/Main.cpp18
-rw-r--r--tools/aapt2/NameMangler.h8
-rw-r--r--tools/aapt2/Resource.cpp10
-rw-r--r--tools/aapt2/Resource.h52
-rw-r--r--tools/aapt2/ResourceMetadata.proto49
-rw-r--r--tools/aapt2/ResourceParser.cpp355
-rw-r--r--tools/aapt2/ResourceParser.h25
-rw-r--r--tools/aapt2/ResourceParser_test.cpp10
-rw-r--r--tools/aapt2/ResourceTable.cpp91
-rw-r--r--tools/aapt2/ResourceTable.h80
-rw-r--r--tools/aapt2/ResourceTable_test.cpp17
-rw-r--r--tools/aapt2/ResourceUtils.cpp148
-rw-r--r--tools/aapt2/ResourceUtils.h56
-rw-r--r--tools/aapt2/ResourceUtils_test.cpp2
-rw-r--r--tools/aapt2/ResourceValues.cpp39
-rw-r--r--tools/aapt2/ResourceValues.h47
-rw-r--r--tools/aapt2/ResourceValues_test.cpp22
-rw-r--r--tools/aapt2/Resource_test.cpp10
-rw-r--r--tools/aapt2/Resources.proto11
-rw-r--r--tools/aapt2/SdkConstants.cpp2
-rw-r--r--tools/aapt2/SdkConstants.h3
-rw-r--r--tools/aapt2/Source.h89
-rw-r--r--tools/aapt2/StringPool.cpp511
-rw-r--r--tools/aapt2/StringPool.h227
-rw-r--r--tools/aapt2/StringPool_test.cpp388
-rw-r--r--tools/aapt2/ValueTransformer.h8
-rw-r--r--tools/aapt2/ValueTransformer_inline.h4
-rw-r--r--tools/aapt2/cmd/ApkInfo.cpp94
-rw-r--r--tools/aapt2/cmd/ApkInfo.h49
-rw-r--r--tools/aapt2/cmd/ApkInfo_test.cpp78
-rw-r--r--tools/aapt2/cmd/Command.cpp47
-rw-r--r--tools/aapt2/cmd/Command.h45
-rw-r--r--tools/aapt2/cmd/Compile.cpp152
-rw-r--r--tools/aapt2/cmd/Compile.h16
-rw-r--r--tools/aapt2/cmd/Compile_test.cpp4
-rw-r--r--tools/aapt2/cmd/Convert.cpp115
-rw-r--r--tools/aapt2/cmd/Convert.h36
-rw-r--r--tools/aapt2/cmd/Convert_test.cpp80
-rw-r--r--tools/aapt2/cmd/Diff.cpp34
-rw-r--r--tools/aapt2/cmd/Dump.cpp52
-rw-r--r--tools/aapt2/cmd/Dump.h58
-rw-r--r--tools/aapt2/cmd/Dump_test.cpp128
-rw-r--r--tools/aapt2/cmd/Link.cpp495
-rw-r--r--tools/aapt2/cmd/Link.h19
-rw-r--r--tools/aapt2/cmd/Link_test.cpp222
-rw-r--r--tools/aapt2/cmd/Optimize.cpp138
-rw-r--r--tools/aapt2/cmd/Optimize.h45
-rw-r--r--tools/aapt2/cmd/Optimize_test.cpp68
-rw-r--r--tools/aapt2/cmd/Util.cpp93
-rw-r--r--tools/aapt2/cmd/Util.h25
-rw-r--r--tools/aapt2/cmd/Util_test.cpp73
-rw-r--r--tools/aapt2/compile/IdAssigner.cpp37
-rw-r--r--tools/aapt2/compile/IdAssigner_test.cpp4
-rw-r--r--tools/aapt2/compile/InlineXmlFormatParser.cpp18
-rw-r--r--tools/aapt2/compile/NinePatch.cpp8
-rw-r--r--tools/aapt2/compile/Png.cpp84
-rw-r--r--tools/aapt2/compile/Png.h19
-rw-r--r--tools/aapt2/compile/PngChunkFilter.cpp2
-rw-r--r--tools/aapt2/compile/PngCrunch.cpp36
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.cpp30
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator.h7
-rw-r--r--tools/aapt2/compile/PseudolocaleGenerator_test.cpp40
-rw-r--r--tools/aapt2/compile/Pseudolocalizer.cpp70
-rw-r--r--tools/aapt2/compile/Pseudolocalizer.h11
-rw-r--r--tools/aapt2/compile/XmlIdCollector.cpp13
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.cpp184
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.h17
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.internal.h35
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp1296
-rw-r--r--tools/aapt2/dump/DumpManifest.h10
-rw-r--r--tools/aapt2/filter/AbiFilter.cpp10
-rw-r--r--tools/aapt2/filter/AbiFilter.h8
-rw-r--r--tools/aapt2/filter/Filter.h7
-rw-r--r--tools/aapt2/format/Archive.cpp34
-rw-r--r--tools/aapt2/format/Archive.h17
-rw-r--r--tools/aapt2/format/Archive_test.cpp2
-rw-r--r--tools/aapt2/format/Container.h7
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp216
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.h21
-rw-r--r--tools/aapt2/format/binary/ChunkWriter.h19
-rw-r--r--tools/aapt2/format/binary/ResChunkPullParser.cpp18
-rw-r--r--tools/aapt2/format/binary/ResChunkPullParser.h9
-rw-r--r--tools/aapt2/format/binary/ResEntryWriter.cpp256
-rw-r--r--tools/aapt2/format/binary/ResEntryWriter.h184
-rw-r--r--tools/aapt2/format/binary/ResEntryWriter_test.cpp191
-rw-r--r--tools/aapt2/format/binary/TableFlattener.cpp486
-rw-r--r--tools/aapt2/format/binary/TableFlattener.h61
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp258
-rw-r--r--tools/aapt2/format/binary/XmlFlattener.cpp76
-rw-r--r--tools/aapt2/format/binary/XmlFlattener.h7
-rw-r--r--tools/aapt2/format/binary/XmlFlattener_test.cpp7
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.cpp60
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.h21
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize.cpp65
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize.h15
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize_test.cpp125
-rw-r--r--tools/aapt2/integration-tests/CommandTests/android-33.jar (renamed from tools/aapt2/integration-tests/CommandTests/android-28.jar)bin31949393 -> 27128945 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/built_with_aapt.apkbin0 -> 930 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt11
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components.apkbin0 -> 92659 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_expected.txt57
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt167
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_full_proto.txt2312
-rw-r--r--tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt5
-rw-r--r--tools/aapt2/integration-tests/DumpTest/minimal.apkbin0 -> 214221 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/minimal_expected.txt92
-rw-r--r--tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apkbin0 -> 34459 bytes
-rw-r--r--tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt23
-rw-r--r--tools/aapt2/io/BigBufferStream.h12
-rw-r--r--tools/aapt2/io/File.h9
-rw-r--r--tools/aapt2/io/FileSystem.cpp31
-rw-r--r--tools/aapt2/io/FileSystem.h15
-rw-r--r--tools/aapt2/io/StringStream.cpp2
-rw-r--r--tools/aapt2/io/StringStream.h2
-rw-r--r--tools/aapt2/io/Util.cpp32
-rw-r--r--tools/aapt2/io/Util.h17
-rw-r--r--tools/aapt2/io/ZipArchive.cpp25
-rw-r--r--tools/aapt2/io/ZipArchive.h12
-rw-r--r--tools/aapt2/java/AnnotationProcessor.cpp14
-rw-r--r--tools/aapt2/java/AnnotationProcessor.h4
-rw-r--r--tools/aapt2/java/ClassDefinition.cpp8
-rw-r--r--tools/aapt2/java/ClassDefinition.h26
-rw-r--r--tools/aapt2/java/JavaClassGenerator.cpp56
-rw-r--r--tools/aapt2/java/JavaClassGenerator.h17
-rw-r--r--tools/aapt2/java/ManifestClassGenerator.cpp24
-rw-r--r--tools/aapt2/java/ManifestClassGenerator.h5
-rw-r--r--tools/aapt2/java/ProguardRules.cpp2
-rw-r--r--tools/aapt2/java/ProguardRules.h7
-rw-r--r--tools/aapt2/link/AutoVersioner.cpp2
-rw-r--r--tools/aapt2/link/Linkers.h7
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp205
-rw-r--r--tools/aapt2/link/ManifestFixer.h8
-rw-r--r--tools/aapt2/link/ManifestFixer_test.cpp423
-rw-r--r--tools/aapt2/link/NoDefaultResourceRemover.cpp12
-rw-r--r--tools/aapt2/link/PrivateAttributeMover.cpp5
-rw-r--r--tools/aapt2/link/PrivateAttributeMover_test.cpp12
-rw-r--r--tools/aapt2/link/ProductFilter.cpp30
-rw-r--r--tools/aapt2/link/ProductFilter_test.cpp40
-rw-r--r--tools/aapt2/link/ReferenceLinker.cpp42
-rw-r--r--tools/aapt2/link/ReferenceLinker.h5
-rw-r--r--tools/aapt2/link/ResourceExcluder.cpp9
-rw-r--r--tools/aapt2/link/TableMerger.cpp84
-rw-r--r--tools/aapt2/link/TableMerger.h14
-rw-r--r--tools/aapt2/link/TableMerger_test.cpp2
-rw-r--r--tools/aapt2/link/XmlCompatVersioner.cpp10
-rw-r--r--tools/aapt2/link/XmlCompatVersioner.h6
-rw-r--r--tools/aapt2/link/XmlReferenceLinker.cpp18
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.cpp67
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.h10
-rw-r--r--tools/aapt2/optimize/Obfuscator.cpp237
-rw-r--r--tools/aapt2/optimize/Obfuscator.h65
-rw-r--r--tools/aapt2/optimize/Obfuscator_test.cpp338
-rw-r--r--tools/aapt2/optimize/ResourceDeduper.cpp11
-rw-r--r--tools/aapt2/optimize/ResourceFilter.cpp2
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener.cpp123
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener.h44
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener_test.cpp166
-rw-r--r--tools/aapt2/optimize/VersionCollapser_test.cpp2
-rw-r--r--tools/aapt2/process/IResourceTableConsumer.h6
-rw-r--r--tools/aapt2/process/SymbolTable.cpp2
-rw-r--r--tools/aapt2/process/SymbolTable.h2
-rw-r--r--tools/aapt2/process/SymbolTable_test.cpp2
-rw-r--r--tools/aapt2/split/TableSplitter.cpp16
-rw-r--r--tools/aapt2/test/Builders.cpp72
-rw-r--r--tools/aapt2/test/Builders.h76
-rw-r--r--tools/aapt2/test/Common.cpp11
-rw-r--r--tools/aapt2/test/Common.h28
-rw-r--r--tools/aapt2/test/Context.h18
-rw-r--r--tools/aapt2/test/Fixture.cpp35
-rw-r--r--tools/aapt2/test/Fixture.h15
-rw-r--r--tools/aapt2/text/Printer.cpp6
-rw-r--r--tools/aapt2/text/Printer.h4
-rw-r--r--tools/aapt2/text/Unicode.cpp4
-rw-r--r--tools/aapt2/text/Unicode.h4
-rw-r--r--tools/aapt2/text/Utf8Iterator.cpp2
-rw-r--r--tools/aapt2/text/Utf8Iterator.h2
-rw-r--r--tools/aapt2/trace/TraceBuffer.cpp4
-rw-r--r--tools/aapt2/util/BigBuffer.cpp87
-rw-r--r--tools/aapt2/util/BigBuffer.h189
-rw-r--r--tools/aapt2/util/BigBuffer_test.cpp100
-rw-r--r--tools/aapt2/util/Files.cpp46
-rw-r--r--tools/aapt2/util/Files.h32
-rw-r--r--tools/aapt2/util/Util.cpp202
-rw-r--r--tools/aapt2/util/Util.h92
-rw-r--r--tools/aapt2/util/Util_test.cpp8
-rw-r--r--tools/aapt2/xml/XmlActionExecutor.cpp24
-rw-r--r--tools/aapt2/xml/XmlActionExecutor.h11
-rw-r--r--tools/aapt2/xml/XmlDom.cpp60
-rw-r--r--tools/aapt2/xml/XmlDom.h44
-rw-r--r--tools/aapt2/xml/XmlDom_test.cpp6
-rw-r--r--tools/aapt2/xml/XmlPullParser.cpp8
-rw-r--r--tools/aapt2/xml/XmlPullParser.h7
-rw-r--r--tools/aapt2/xml/XmlUtil.cpp6
-rw-r--r--tools/aapt2/xml/XmlUtil.h5
-rw-r--r--tools/codegen/src/com/android/codegen/Generators.kt14
-rwxr-xr-xtools/codegen/src/com/android/codegen/Main.kt3
-rw-r--r--tools/fonts/font-scaling-array-generator.js196
-rwxr-xr-xtools/fonts/fontchain_linter.py3
-rw-r--r--tools/preload-check/device/src/com/android/preload/check/Util.java4
-rw-r--r--tools/processors/immutability/Android.bp80
-rw-r--r--tools/processors/immutability/AndroidTestTemplate.xml32
-rw-r--r--tools/processors/immutability/OWNERS1
-rw-r--r--tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt424
-rw-r--r--tools/processors/immutability/src/android/processor/immutability/Immutable.java74
-rw-r--r--tools/processors/immutability/src/android/processor/immutability/MessageUtils.kt45
-rw-r--r--tools/processors/immutability/test/android/processor/ImmutabilityProcessorTest.kt411
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt16
-rw-r--r--tools/validatekeymaps/Android.bp2
-rw-r--r--tools/validatekeymaps/Main.cpp4
219 files changed, 11270 insertions, 5491 deletions
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 3abb89acd23b..23440074a326 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3743,15 +3743,15 @@ ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp<AaptFile>&
size_t amt = 0;
ResTable_entry header;
memset(&header, 0, sizeof(header));
- header.size = htods(sizeof(header));
+ header.full.size = htods(sizeof(header));
const type ty = mType;
if (ty == TYPE_BAG) {
- header.flags |= htods(header.FLAG_COMPLEX);
+ header.full.flags |= htods(header.FLAG_COMPLEX);
}
if (isPublic) {
- header.flags |= htods(header.FLAG_PUBLIC);
+ header.full.flags |= htods(header.FLAG_PUBLIC);
}
- header.key.index = htodl(mNameIndex);
+ header.full.key.index = htodl(mNameIndex);
if (ty != TYPE_BAG) {
status_t err = data->writeData(&header, sizeof(header));
if (err != NO_ERROR) {
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index a146466402f6..e2c161482857 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -49,6 +49,7 @@ enum {
SDK_S = 31,
SDK_S_V2 = 32,
SDK_TIRAMISU = 33,
+ SDK_UPSIDE_DOWN_CAKE = 34,
SDK_CUR_DEVELOPMENT = 10000,
};
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index bfb32854a374..0d6dc3522d24 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -24,6 +24,7 @@ package {
}
toolSources = [
+ "cmd/ApkInfo.cpp",
"cmd/Command.cpp",
"cmd/Compile.cpp",
"cmd/Convert.cpp",
@@ -36,6 +37,7 @@ toolSources = [
cc_defaults {
name: "aapt2_defaults",
+ cpp_std: "gnu++2b",
cflags: [
"-Wall",
"-Werror",
@@ -48,6 +50,7 @@ cc_defaults {
],
target: {
windows: {
+ compile_multilib: "64",
enabled: true,
cflags: ["-Wno-maybe-uninitialized"],
ldflags: ["-static"],
@@ -103,6 +106,7 @@ cc_library_host_static {
"format/Container.cpp",
"format/binary/BinaryResourceParser.cpp",
"format/binary/ResChunkPullParser.cpp",
+ "format/binary/ResEntryWriter.cpp",
"format/binary/TableFlattener.cpp",
"format/binary/XmlFlattener.cpp",
"format/proto/ProtoDeserialize.cpp",
@@ -128,14 +132,13 @@ cc_library_host_static {
"optimize/MultiApkGenerator.cpp",
"optimize/ResourceDeduper.cpp",
"optimize/ResourceFilter.cpp",
- "optimize/ResourcePathShortener.cpp",
+ "optimize/Obfuscator.cpp",
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
"split/TableSplitter.cpp",
"text/Printer.cpp",
"text/Unicode.cpp",
"text/Utf8Iterator.cpp",
- "util/BigBuffer.cpp",
"util/Files.cpp",
"util/Util.cpp",
"Debug.cpp",
@@ -152,14 +155,15 @@ cc_library_host_static {
"ResourceUtils.cpp",
"ResourceValues.cpp",
"SdkConstants.cpp",
- "StringPool.cpp",
"trace/TraceBuffer.cpp",
"xml/XmlActionExecutor.cpp",
"xml/XmlDom.cpp",
"xml/XmlPullParser.cpp",
"xml/XmlUtil.cpp",
+ "ApkInfo.proto",
"Configuration.proto",
"Resources.proto",
+ "ResourceMetadata.proto",
"ResourcesInternal.proto",
"ValueTransformer.cpp",
],
@@ -190,6 +194,7 @@ cc_test_host {
"integration-tests/CompileTest/**/*",
"integration-tests/CommandTests/**/*",
"integration-tests/ConvertTest/**/*",
+ "integration-tests/DumpTest/**/*",
],
}
@@ -216,6 +221,7 @@ genrule {
srcs: [
"Configuration.proto",
"ResourcesInternal.proto",
+ "ResourceMetadata.proto",
"Resources.proto",
],
out: ["aapt2-protos.zip"],
diff --git a/tools/aapt2/ApkInfo.proto b/tools/aapt2/ApkInfo.proto
new file mode 100644
index 000000000000..b5ff71fa5935
--- /dev/null
+++ b/tools/aapt2/ApkInfo.proto
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+import "frameworks/base/tools/aapt2/Resources.proto";
+
+package aapt.pb;
+
+option java_package = "com.android.aapt";
+
+// Top level message representing data extracted from the APK for 'apkinfo'
+// command.
+message ApkInfo {
+ message XmlFile {
+ string path = 1;
+ XmlNode root = 2;
+ }
+
+ Badging badging = 1;
+ ResourceTable resource_table = 2;
+ repeated XmlFile xml_files = 3;
+}
+
+// Data extracted from the manifest of the APK.
+message Badging {
+ PackageInfo package = 1;
+ Application application = 2;
+ UsesSdk uses_sdk = 3;
+ // Previously: UsesConfiguration uses_configuration = 4;
+ reserved 4;
+ SupportsScreen supports_screen = 5;
+ SupportsInput supports_input = 6;
+ LaunchableActivity launchable_activity = 7;
+ LeanbackLaunchableActivity leanback_launchable_activity = 8;
+ StaticLibrary static_library = 9;
+ SdkLibrary sdk_library = 10;
+ Overlay overlay = 11;
+ PackageVerifier package_verifier = 12;
+ CompatibleScreens compatible_screens = 13;
+ Architectures architectures = 14;
+ SupportsGlTexture supports_gl_texture = 15;
+ Components components = 16;
+
+ repeated string locales = 17;
+ repeated int32 densities = 18;
+
+ repeated UsesPackage uses_packages = 51;
+ repeated UsesConfiguration uses_configurations = 52;
+ repeated FeatureGroup feature_groups = 53;
+ repeated UsesPermission uses_permissions = 54;
+ repeated Permission permissions = 55;
+ repeated UsesLibrary uses_libraries = 56;
+ repeated UsesStaticLibrary uses_static_libraries = 57;
+ repeated UsesSdkLibrary uses_sdk_libraries = 58;
+ repeated UsesNativeLibrary uses_native_libraries = 59;
+
+ repeated Metadata metadata = 62;
+ repeated Property properties = 63;
+}
+
+// Information extracted about package from <manifest> and
+// <original-package> tags.
+message PackageInfo {
+ enum InstallLocation {
+ DEFAULT_INSTALL_LOCATION = 0;
+ AUTO = 1;
+ INTERNAL_ONLY = 2;
+ PREFER_EXTERNAL = 3;
+ }
+
+ string package = 1;
+ int32 version_code = 2;
+ string version_name = 3;
+
+ string split = 4;
+
+ string platform_version_name = 5;
+ string platform_version_code = 6;
+
+ int32 compile_sdk_version = 7;
+ string compile_sdk_version_codename = 8;
+
+ InstallLocation install_location = 9;
+
+ string original_package = 10;
+}
+
+// Information extracted from <application> element.
+message Application {
+ string label = 1;
+ string icon = 2;
+ string banner = 3;
+
+ bool test_only = 4;
+ bool game = 5;
+ bool debuggable = 6;
+
+ map<string, string> locale_labels = 8;
+ map<int32, string> density_icons = 9;
+}
+
+// Components defined in the APK.
+message Components {
+ bool main = 1;
+ bool other_activities = 2;
+ bool other_receivers = 3;
+ bool other_services = 4;
+
+ repeated string provided_components = 5;
+}
+
+// Application's min and target SDKs.
+message UsesSdk {
+ oneof min_sdk {
+ int32 min_sdk_version = 2;
+ string min_sdk_version_name = 3;
+ }
+ int32 max_sdk_version = 4;
+ oneof target_sdk {
+ int32 target_sdk_version = 5;
+ string target_sdk_version_name = 6;
+ }
+}
+
+message UsesConfiguration {
+ int32 req_touch_screen = 1;
+ int32 req_keyboard_type = 2;
+ int32 req_hard_keyboard = 3;
+ int32 req_navigation = 4;
+ int32 req_five_way_nav = 5;
+}
+
+// Screens supported by this application.
+message SupportsScreen {
+ enum ScreenType {
+ UNSPECIFIED_SCREEN_TYPE = 0;
+ SMALL = 1;
+ NORMAL = 2;
+ LARGE = 3;
+ XLARGE = 4;
+ }
+ repeated ScreenType screens = 1;
+ bool supports_any_densities = 2;
+ int32 requires_smallest_width_dp = 3;
+ int32 compatible_width_limit_dp = 4;
+ int32 largest_width_limit_dp = 5;
+}
+
+// Inputs supported by this application.
+message SupportsInput {
+ repeated string inputs = 1;
+}
+
+// Information about used features which is extracted from <uses-permission>
+// elements or implied from permissions.
+message Feature {
+ message ImpliedData {
+ bool from_sdk_23_permission = 1;
+ repeated string reasons = 2;
+ }
+
+ string name = 1;
+ bool required = 2;
+ int32 version = 3;
+
+ ImpliedData implied_data = 4;
+}
+
+message FeatureGroup {
+ string label = 1;
+ int32 open_gles_version = 2;
+ repeated Feature features = 3;
+}
+
+// Information about permission requested by the application.
+message UsesPermission {
+ message PermissionFlags {
+ bool never_for_location = 1;
+ }
+
+ string name = 1;
+ int32 max_sdk_version = 2;
+ bool required = 3;
+ bool implied = 4;
+ bool sdk23_and_above = 5;
+
+ repeated string required_features = 6;
+ repeated string required_not_features = 7;
+
+ PermissionFlags permission_flags = 8;
+}
+
+// Permission defined by the application.
+message Permission {
+ string name = 1;
+}
+
+// Data extracted about launchable activity. Launchable activity is an entry
+// point on phone and tablet devices.
+message LaunchableActivity {
+ string name = 1;
+ string icon = 2;
+ string label = 3;
+}
+
+// Data extracted about leanback launchable activity. Leanback launchable
+// activity is an entry point on TV devices.
+message LeanbackLaunchableActivity {
+ string name = 1;
+ string icon = 2;
+ string label = 3;
+ string banner = 4;
+}
+
+// Library used by the application.
+message UsesLibrary {
+ string name = 1;
+ bool required = 2;
+}
+
+// Static library this APK declares.
+message StaticLibrary {
+ string name = 1;
+ int32 version = 2;
+ int32 version_major = 3;
+}
+
+// Static library used by the application.
+message UsesStaticLibrary {
+ string name = 1;
+ int32 version = 2;
+ int32 version_major = 3;
+ repeated string certificates = 4;
+}
+
+// SDK library this APK declares.
+message SdkLibrary {
+ string name = 1;
+ int32 version_major = 2;
+}
+
+// SDK library used by the application.
+message UsesSdkLibrary {
+ string name = 1;
+ int32 version_major = 2;
+ repeated string certificates = 3;
+}
+
+// Native library used by the application.
+message UsesNativeLibrary {
+ string name = 1;
+ bool required = 2;
+}
+
+// Information extracted from <meta-data> elements defined across
+// AndroidManifest.xml.
+message Metadata {
+ string name = 1;
+ oneof value {
+ string value_string = 2;
+ int32 value_int = 3;
+ }
+ oneof resource {
+ string resource_string = 4;
+ int32 resource_int = 5;
+ }
+}
+
+// Information about overlay that is declared in the APK.
+message Overlay {
+ string target_package = 1;
+ int32 priority = 2;
+ bool static = 3;
+ string required_property_name = 4;
+ string required_property_value = 5;
+}
+
+// Data extracted from <package-verifier> element.
+message PackageVerifier {
+ string name = 1;
+ string public_key = 2;
+}
+
+// External packages used by the application
+message UsesPackage {
+ string name = 1;
+ string package_type = 2;
+ int32 version = 3;
+ int32 version_major = 4;
+ repeated string certificates = 5;
+}
+
+// Open GL textures format supported by the current application.
+message SupportsGlTexture {
+ repeated string name = 1;
+}
+
+// Screens compatible with the application.
+message CompatibleScreens {
+ message Screen {
+ int32 size = 1;
+ int32 density = 2;
+ }
+
+ repeated Screen screens = 1;
+}
+
+// Architectures supported by the application.
+message Architectures {
+ repeated string architectures = 1;
+ repeated string alt_architectures = 2;
+}
+
+// Information extracted from <property> elements defined across
+// AndroidManifest.xml.
+message Property {
+ string name = 1;
+ oneof value {
+ string value_string = 2;
+ int32 value_int = 3;
+ }
+ oneof resource {
+ string resource_string = 4;
+ int32 resource_int = 5;
+ }
+} \ No newline at end of file
diff --git a/tools/aapt2/Configuration.proto b/tools/aapt2/Configuration.proto
index 8a4644c9a219..48838445f8c1 100644
--- a/tools/aapt2/Configuration.proto
+++ b/tools/aapt2/Configuration.proto
@@ -120,6 +120,13 @@ message Configuration {
NAVIGATION_WHEEL = 4;
}
+ enum GrammaticalGender {
+ GRAM_GENDER_USET = 0;
+ GRAM_GENDER_NEUTER = 1;
+ GRAM_GENDER_FEMININE = 2;
+ GRAM_GENDER_MASCULINE = 3;
+ }
+
//
// Axis/dimensions that are understood by the runtime.
//
@@ -198,6 +205,9 @@ message Configuration {
// The minimum SDK version of the device.
uint32 sdk_version = 24;
+ // Grammatical gender.
+ GrammaticalGender grammatical_gender = 26;
+
//
// Build-time only dimensions.
//
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 3fa39009971c..9cfb85d7cd73 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -17,6 +17,7 @@
#include "Debug.h"
#include <androidfw/TypeWrappers.h>
+#include <androidfw/Util.h>
#include <format/binary/ResChunkPullParser.h>
#include <algorithm>
@@ -32,6 +33,7 @@
#include "ValueVisitor.h"
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
+#include "androidfw/ResourceTypes.h"
#include "idmap2/Policies.h"
#include "text/Printer.h"
#include "util/Util.h"
@@ -273,7 +275,7 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
printer->Indent();
for (const auto& type : package.types) {
printer->Print("type ");
- printer->Print(to_string(type.type));
+ printer->Print(type.named_type.to_string());
if (type.id) {
printer->Print(StringPrintf(" id=%02x", type.id.value()));
}
@@ -287,7 +289,7 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
printer->Print(" ");
// Write the name without the package (this is obvious and too verbose).
- printer->Print(to_string(type.type));
+ printer->Print(type.named_type.to_string());
printer->Print("/");
printer->Print(entry.name);
@@ -514,7 +516,8 @@ class XmlPrinter : public xml::ConstVisitor {
}
void Visit(const xml::Text* text) override {
- printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
+ printer_->Println(
+ StringPrintf("T: '%s'", android::ResTable::normalizeForOutput(text->text.c_str()).c_str()));
}
private:
@@ -547,7 +550,7 @@ void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer)
const auto policy_subsection = StringPrintf(R"(policies="%s")",
android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
const auto value =
- StringPrintf("%s/%s", to_string(type->type).data(), entry->name.c_str());
+ StringPrintf("%s/%s", type->named_type.to_string().data(), entry->name.c_str());
items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
}
}
@@ -592,12 +595,12 @@ using namespace android;
class ChunkPrinter {
public:
- ChunkPrinter(const void* data, size_t len, Printer* printer, IDiagnostics* diag)
+ ChunkPrinter(const void* data, size_t len, Printer* printer, android::IDiagnostics* diag)
: data_(data), data_len_(len), printer_(printer), diag_(diag) {
}
void PrintChunkHeader(const ResChunk_header* chunk) {
- switch (util::DeviceToHost16(chunk->type)) {
+ switch (android::util::DeviceToHost16(chunk->type)) {
case RES_STRING_POOL_TYPE:
printer_->Print("[RES_STRING_POOL_TYPE]");
break;
@@ -620,13 +623,14 @@ class ChunkPrinter {
break;
}
- printer_->Print(StringPrintf(" chunkSize: %u", util::DeviceToHost32(chunk->size)));
- printer_->Print(StringPrintf(" headerSize: %u", util::DeviceToHost32(chunk->headerSize)));
+ printer_->Print(StringPrintf(" chunkSize: %u", android::util::DeviceToHost32(chunk->size)));
+ printer_->Print(
+ StringPrintf(" headerSize: %u", android::util::DeviceToHost32(chunk->headerSize)));
}
bool PrintTable(const ResTable_header* chunk) {
printer_->Print(
- StringPrintf(" Package count: %u\n", util::DeviceToHost32(chunk->packageCount)));
+ StringPrintf(" Package count: %u\n", android::util::DeviceToHost32(chunk->packageCount)));
// Print the chunks contained within the table
printer_->Indent();
@@ -639,9 +643,10 @@ class ChunkPrinter {
void PrintResValue(const Res_value* value, const ConfigDescription& config,
const ResourceType* type) {
printer_->Print("[Res_value]");
- printer_->Print(StringPrintf(" size: %u", util::DeviceToHost32(value->size)));
- printer_->Print(StringPrintf(" dataType: 0x%02x", util::DeviceToHost32(value->dataType)));
- printer_->Print(StringPrintf(" data: 0x%08x", util::DeviceToHost32(value->data)));
+ printer_->Print(StringPrintf(" size: %u", android::util::DeviceToHost32(value->size)));
+ printer_->Print(
+ StringPrintf(" dataType: 0x%02x", android::util::DeviceToHost32(value->dataType)));
+ printer_->Print(StringPrintf(" data: 0x%08x", android::util::DeviceToHost32(value->data)));
if (type) {
auto item =
@@ -655,19 +660,23 @@ class ChunkPrinter {
}
bool PrintTableType(const ResTable_type* chunk) {
- printer_->Print(StringPrintf(" id: 0x%02x", util::DeviceToHost32(chunk->id)));
+ printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
printer_->Print(StringPrintf(
- " name: %s", util::GetString(type_pool_, util::DeviceToHost32(chunk->id) - 1).c_str()));
- printer_->Print(StringPrintf(" flags: 0x%02x", util::DeviceToHost32(chunk->flags)));
- printer_->Print(StringPrintf(" entryCount: %u", util::DeviceToHost32(chunk->entryCount)));
- printer_->Print(StringPrintf(" entryStart: %u", util::DeviceToHost32(chunk->entriesStart)));
+ " name: %s",
+ android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1)
+ .c_str()));
+ printer_->Print(StringPrintf(" flags: 0x%02x", android::util::DeviceToHost32(chunk->flags)));
+ printer_->Print(
+ StringPrintf(" entryCount: %u", android::util::DeviceToHost32(chunk->entryCount)));
+ printer_->Print(
+ StringPrintf(" entryStart: %u", android::util::DeviceToHost32(chunk->entriesStart)));
ConfigDescription config;
config.copyFromDtoH(chunk->config);
printer_->Print(StringPrintf(" config: %s\n", config.to_string().c_str()));
- const ResourceType* type =
- ParseResourceType(util::GetString(type_pool_, util::DeviceToHost32(chunk->id) - 1));
+ const ResourceType* type = ParseResourceType(
+ android::util::GetString(type_pool_, android::util::DeviceToHost32(chunk->id) - 1));
printer_->Indent();
@@ -678,40 +687,46 @@ class ChunkPrinter {
continue;
}
- printer_->Print((entry->flags & ResTable_entry::FLAG_COMPLEX) ? "[ResTable_map_entry]"
- : "[ResTable_entry]");
+ if (entry->is_complex()) {
+ printer_->Print("[ResTable_map_entry]");
+ } else if (entry->is_compact()) {
+ printer_->Print("[ResTable_entry_compact]");
+ } else {
+ printer_->Print("[ResTable_entry]");
+ }
+
printer_->Print(StringPrintf(" id: 0x%04x", it.index()));
printer_->Print(StringPrintf(
- " name: %s", util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)).c_str()));
- printer_->Print(StringPrintf(" keyIndex: %u", util::DeviceToHost32(entry->key.index)));
- printer_->Print(StringPrintf(" size: %u", util::DeviceToHost32(entry->size)));
- printer_->Print(StringPrintf(" flags: 0x%04x", util::DeviceToHost32(entry->flags)));
+ " name: %s", android::util::GetString(key_pool_, entry->key()).c_str()));
+ printer_->Print(StringPrintf(" keyIndex: %u", entry->key()));
+ printer_->Print(StringPrintf(" size: %zu", entry->size()));
+ printer_->Print(StringPrintf(" flags: 0x%04x", entry->flags()));
printer_->Indent();
- if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
- auto map_entry = (const ResTable_map_entry*)entry;
- printer_->Print(StringPrintf(" count: 0x%04x", util::DeviceToHost32(map_entry->count)));
- printer_->Print(
- StringPrintf(" parent: 0x%08x\n", util::DeviceToHost32(map_entry->parent.ident)));
+ if (auto map_entry = entry->map_entry()) {
+ uint32_t map_entry_count = android::util::DeviceToHost32(map_entry->count);
+ printer_->Print(StringPrintf(" count: 0x%04x", map_entry_count));
+ printer_->Print(StringPrintf(" parent: 0x%08x\n",
+ android::util::DeviceToHost32(map_entry->parent.ident)));
// Print the name and value mappings
- auto maps =
- (const ResTable_map*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
- for (size_t i = 0, count = util::DeviceToHost32(map_entry->count); i < count; i++) {
+ auto maps = (const ResTable_map*)((const uint8_t*)entry + entry->size());
+ for (size_t i = 0; i < map_entry_count; i++) {
PrintResValue(&(maps[i].value), config, type);
printer_->Print(StringPrintf(
" name: %s name-id:%d\n",
- util::GetString(key_pool_, util::DeviceToHost32(maps[i].name.ident)).c_str(),
- util::DeviceToHost32(maps[i].name.ident)));
+ android::util::GetString(key_pool_, android::util::DeviceToHost32(maps[i].name.ident))
+ .c_str(),
+ android::util::DeviceToHost32(maps[i].name.ident)));
}
} else {
printer_->Print("\n");
// Print the value of the entry
- auto value = (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
- PrintResValue(value, config, type);
+ Res_value value = entry->value();
+ PrintResValue(&value, config, type);
}
printer_->Undent();
@@ -735,33 +750,37 @@ class ChunkPrinter {
return;
}
- pool->setTo(chunk,
- util::DeviceToHost32((reinterpret_cast<const ResChunk_header*>(chunk))->size));
+ pool->setTo(chunk, android::util::DeviceToHost32(
+ (reinterpret_cast<const ResChunk_header*>(chunk))->size));
printer_->Print("\n");
for (size_t i = 0; i < pool->size(); i++) {
- printer_->Print(StringPrintf("#%zd : %s\n", i, util::GetString(*pool, i).c_str()));
+ printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str()));
}
}
bool PrintPackage(const ResTable_package* chunk) {
- printer_->Print(StringPrintf(" id: 0x%02x", util::DeviceToHost32(chunk->id)));
+ printer_->Print(StringPrintf(" id: 0x%02x", android::util::DeviceToHost32(chunk->id)));
size_t len = strnlen16((const char16_t*)chunk->name, std::size(chunk->name));
std::u16string package_name(len, u'\0');
package_name.resize(len);
for (size_t i = 0; i < len; i++) {
- package_name[i] = util::DeviceToHost16(chunk->name[i]);
+ package_name[i] = android::util::DeviceToHost16(chunk->name[i]);
}
printer_->Print(StringPrintf("name: %s", String8(package_name.c_str()).c_str()));
- printer_->Print(StringPrintf(" typeStrings: %u", util::DeviceToHost32(chunk->typeStrings)));
printer_->Print(
- StringPrintf(" lastPublicType: %u", util::DeviceToHost32(chunk->lastPublicType)));
- printer_->Print(StringPrintf(" keyStrings: %u", util::DeviceToHost32(chunk->keyStrings)));
- printer_->Print(StringPrintf(" lastPublicKey: %u", util::DeviceToHost32(chunk->lastPublicKey)));
- printer_->Print(StringPrintf(" typeIdOffset: %u\n", util::DeviceToHost32(chunk->typeIdOffset)));
+ StringPrintf(" typeStrings: %u", android::util::DeviceToHost32(chunk->typeStrings)));
+ printer_->Print(
+ StringPrintf(" lastPublicType: %u", android::util::DeviceToHost32(chunk->lastPublicType)));
+ printer_->Print(
+ StringPrintf(" keyStrings: %u", android::util::DeviceToHost32(chunk->keyStrings)));
+ printer_->Print(
+ StringPrintf(" lastPublicKey: %u", android::util::DeviceToHost32(chunk->lastPublicKey)));
+ printer_->Print(
+ StringPrintf(" typeIdOffset: %u\n", android::util::DeviceToHost32(chunk->typeIdOffset)));
// Print the chunks contained within the table
printer_->Indent();
@@ -776,7 +795,7 @@ class ChunkPrinter {
auto chunk = parser.chunk();
PrintChunkHeader(chunk);
- switch (util::DeviceToHost16(chunk->type)) {
+ switch (android::util::DeviceToHost16(chunk->type)) {
case RES_STRING_POOL_TYPE:
PrintStringPool(reinterpret_cast<const ResStringPool_header*>(chunk));
break;
@@ -802,7 +821,7 @@ class ChunkPrinter {
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
return false;
}
@@ -815,11 +834,11 @@ class ChunkPrinter {
}
private:
- const Source source_;
+ const android::Source source_;
const void* data_;
const size_t data_len_;
Printer* printer_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
// The standard value string pool for resource values.
ResStringPool value_pool_;
@@ -832,12 +851,13 @@ class ChunkPrinter {
// in this table.
ResStringPool key_pool_;
- StringPool out_pool_;
+ android::StringPool out_pool_;
};
} // namespace
-void Debug::DumpChunks(const void* data, size_t len, Printer* printer, IDiagnostics* diag) {
+void Debug::DumpChunks(const void* data, size_t len, Printer* printer,
+ android::IDiagnostics* diag) {
ChunkPrinter chunk_printer(data, len, printer, diag);
chunk_printer.Print();
}
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 4da92044cf2a..8015249e7d36 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -40,7 +40,8 @@ struct Debug {
static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer);
static void DumpOverlayable(const ResourceTable& table, text::Printer* printer);
- static void DumpChunks(const void* data, size_t len, text::Printer* printer, IDiagnostics* diag);
+ static void DumpChunks(const void* data, size_t len, text::Printer* printer,
+ android::IDiagnostics* diag);
};
} // namespace aapt
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index 30deb5555b21..c89db725e6f2 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -13,86 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#ifndef AAPT_DIAGNOSTICS_H
-#define AAPT_DIAGNOSTICS_H
+#ifndef AAPT_DIAGNOSTICS_H_
+#define AAPT_DIAGNOSTICS_H_
#include <iostream>
#include <sstream>
#include <string>
#include "android-base/macros.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
-
-#include "Source.h"
#include "util/Util.h"
namespace aapt {
-
-struct DiagMessageActual {
- Source source;
- std::string message;
-};
-
-struct DiagMessage {
- public:
- DiagMessage() = default;
-
- explicit DiagMessage(const android::StringPiece& src) : source_(src) {}
-
- explicit DiagMessage(const Source& src) : source_(src) {}
-
- explicit DiagMessage(size_t line) : source_(Source().WithLine(line)) {}
-
- template <typename T>
- DiagMessage& operator<<(const T& value) {
- message_ << value;
- return *this;
- }
-
- DiagMessageActual Build() const {
- return DiagMessageActual{source_, message_.str()};
- }
-
- private:
- Source source_;
- std::stringstream message_;
-};
-
-template <>
-inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) {
- message_ << android::StringPiece16(value);
- return *this;
-}
-
-struct IDiagnostics {
- virtual ~IDiagnostics() = default;
-
- enum class Level { Note, Warn, Error };
-
- virtual void Log(Level level, DiagMessageActual& actualMsg) = 0;
-
- virtual void Error(const DiagMessage& message) {
- DiagMessageActual actual = message.Build();
- Log(Level::Error, actual);
- }
-
- virtual void Warn(const DiagMessage& message) {
- DiagMessageActual actual = message.Build();
- Log(Level::Warn, actual);
- }
-
- virtual void Note(const DiagMessage& message) {
- DiagMessageActual actual = message.Build();
- Log(Level::Note, actual);
- }
-};
-
-class StdErrDiagnostics : public IDiagnostics {
+class StdErrDiagnostics : public android::IDiagnostics {
public:
StdErrDiagnostics() = default;
- void Log(Level level, DiagMessageActual& actual_msg) override {
+ void Log(Level level, android::DiagMessageActual& actual_msg) override {
const char* tag;
switch (level) {
@@ -125,31 +64,6 @@ class StdErrDiagnostics : public IDiagnostics {
DISALLOW_COPY_AND_ASSIGN(StdErrDiagnostics);
};
-class SourcePathDiagnostics : public IDiagnostics {
- public:
- SourcePathDiagnostics(const Source& src, IDiagnostics* diag)
- : source_(src), diag_(diag) {}
-
- void Log(Level level, DiagMessageActual& actual_msg) override {
- actual_msg.source.path = source_.path;
- diag_->Log(level, actual_msg);
- if (level == Level::Error) {
- error = true;
- }
- }
-
- bool HadError() {
- return error;
- }
-
- private:
- Source source_;
- IDiagnostics* diag_;
- bool error = false;
-
- DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
-};
-
} // namespace aapt
-#endif /* AAPT_DIAGNOSTICS_H */
+#endif /* AAPT_DIAGNOSTICS_H_ */
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 830bc5fa36aa..6b1fd9ff11eb 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -72,12 +72,13 @@ static ApkFormat DetermineApkFormat(io::IFileCollection* apk) {
}
}
-std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) {
- Source source(path);
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(StringPiece path,
+ android::IDiagnostics* diag) {
+ android::Source source(path);
std::string error;
std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error);
if (apk == nullptr) {
- diag->Error(DiagMessage(path) << "failed opening zip: " << error);
+ diag->Error(android::DiagMessage(path) << "failed opening zip: " << error);
return {};
}
@@ -88,13 +89,14 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, I
case ApkFormat::kProto:
return LoadProtoApkFromFileCollection(source, std::move(apk), diag);
default:
- diag->Error(DiagMessage(path) << "could not identify format of APK");
+ diag->Error(android::DiagMessage(path) << "could not identify format of APK");
return {};
}
}
std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
- const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ const android::Source& source, unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag) {
std::unique_ptr<ResourceTable> table;
io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
@@ -102,20 +104,20 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
pb::ResourceTable pb_table;
std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
if (in == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
return {};
}
io::ProtoInputStreamReader proto_reader(in.get());
if (!proto_reader.ReadMessage(&pb_table)) {
- diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
+ diag->Error(android::DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
return {};
}
std::string error;
table = util::make_unique<ResourceTable>(ResourceTable::Validation::kDisabled);
if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "failed to deserialize " << kProtoResourceTablePath << ": " << error);
return {};
}
@@ -123,27 +125,27 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
if (manifest_file == nullptr) {
- diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to find " << kAndroidManifestPath);
return {};
}
std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
if (manifest_in == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kAndroidManifestPath);
return {};
}
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(manifest_in.get());
if (!proto_reader.ReadMessage(&pb_node)) {
- diag->Error(DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
return {};
}
std::string error;
std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error);
if (manifest == nullptr) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "failed to deserialize proto " << kAndroidManifestPath << ": " << error);
return {};
}
@@ -152,7 +154,8 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
}
std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
- const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ const android::Source& source, unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag) {
std::unique_ptr<ResourceTable> table;
io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
@@ -160,7 +163,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
table = util::make_unique<ResourceTable>(ResourceTable::Validation::kDisabled);
std::unique_ptr<io::IData> data = table_file->OpenAsData();
if (data == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kApkResourceTablePath);
return {};
}
BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
@@ -172,13 +175,13 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
if (manifest_file == nullptr) {
- diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to find " << kAndroidManifestPath);
return {};
}
std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
if (manifest_data == nullptr) {
- diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ diag->Error(android::DiagMessage(source) << "failed to open " << kAndroidManifestPath);
return {};
}
@@ -186,7 +189,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
std::unique_ptr<xml::XmlResource> manifest =
xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
if (manifest == nullptr) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "failed to parse binary " << kAndroidManifestPath << ": " << error);
return {};
}
@@ -235,7 +238,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
// Skip resources that are not referenced if requested.
if (is_resource && referenced_resources.find(output_path) == referenced_resources.end()) {
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage()
+ context->GetDiagnostics()->Note(android::DiagMessage()
<< "Removing resource '" << path << "' from APK.");
}
continue;
@@ -243,14 +246,15 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
if (!filters->Keep(path)) {
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage() << "Filtered '" << path << "' from APK.");
+ context->GetDiagnostics()->Note(android::DiagMessage()
+ << "Filtered '" << path << "' from APK.");
}
continue;
}
// The resource table needs to be re-serialized since it might have changed.
if (format_ == ApkFormat::kBinary && path == kApkResourceTablePath) {
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
// TODO(adamlesinski): How to determine if there were sparse entries (and if to encode
// with sparse entries) b/35389232.
TableFlattener flattener(options, &buffer);
@@ -282,12 +286,12 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
return false;
}
} else if (manifest != nullptr && path == "AndroidManifest.xml") {
- BigBuffer buffer(8192);
+ android::BigBuffer buffer(8192);
XmlFlattenerOptions xml_flattener_options;
xml_flattener_options.use_utf16 = true;
XmlFlattener xml_flattener(&buffer, xml_flattener_options);
if (!xml_flattener.Consume(context, manifest)) {
- context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
+ context->GetDiagnostics()->Error(android::DiagMessage(path) << "flattening failed");
return false;
}
@@ -308,10 +312,10 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
}
std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_path,
- IDiagnostics* diag) const {
+ android::IDiagnostics* diag) const {
io::IFile* file = apk_->FindFile(file_path);
if (file == nullptr) {
- diag->Error(DiagMessage() << "failed to find file");
+ diag->Error(android::DiagMessage() << "failed to find file");
return nullptr;
}
@@ -319,34 +323,34 @@ std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_pat
if (format_ == ApkFormat::kProto) {
std::unique_ptr<io::InputStream> in = file->OpenInputStream();
if (!in) {
- diag->Error(DiagMessage() << "failed to open file");
+ diag->Error(android::DiagMessage() << "failed to open file");
return nullptr;
}
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(in.get());
if (!proto_reader.ReadMessage(&pb_node)) {
- diag->Error(DiagMessage() << "failed to parse file as proto XML");
+ diag->Error(android::DiagMessage() << "failed to parse file as proto XML");
return nullptr;
}
std::string err;
doc = DeserializeXmlResourceFromPb(pb_node, &err);
if (!doc) {
- diag->Error(DiagMessage() << "failed to deserialize proto XML: " << err);
+ diag->Error(android::DiagMessage() << "failed to deserialize proto XML: " << err);
return nullptr;
}
} else if (format_ == ApkFormat::kBinary) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- diag->Error(DiagMessage() << "failed to open file");
+ diag->Error(android::DiagMessage() << "failed to open file");
return nullptr;
}
std::string err;
doc = xml::Inflate(data->data(), data->size(), &err);
if (!doc) {
- diag->Error(DiagMessage() << "failed to parse file as binary XML: " << err);
+ diag->Error(android::DiagMessage() << "failed to parse file as binary XML: " << err);
return nullptr;
}
}
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 5b6f45ebb38d..4cd7eae0a5e2 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -45,18 +45,20 @@ class LoadedApk {
virtual ~LoadedApk() = default;
// Loads both binary and proto APKs from disk.
- static std::unique_ptr<LoadedApk> LoadApkFromPath(const ::android::StringPiece& path,
- IDiagnostics* diag);
+ static std::unique_ptr<LoadedApk> LoadApkFromPath(android::StringPiece path,
+ android::IDiagnostics* diag);
// Loads a proto APK from the given file collection.
static std::unique_ptr<LoadedApk> LoadProtoApkFromFileCollection(
- const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+ const android::Source& source, std::unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag);
// Loads a binary APK from the given file collection.
static std::unique_ptr<LoadedApk> LoadBinaryApkFromFileCollection(
- const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+ const android::Source& source, std::unique_ptr<io::IFileCollection> collection,
+ android::IDiagnostics* diag);
- LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
+ LoadedApk(const android::Source& source, std::unique_ptr<io::IFileCollection> apk,
std::unique_ptr<ResourceTable> table, std::unique_ptr<xml::XmlResource> manifest,
const ApkFormat& format)
: source_(source),
@@ -82,7 +84,7 @@ class LoadedApk {
return table_.get();
}
- const Source& GetSource() {
+ const android::Source& GetSource() {
return source_;
}
@@ -111,12 +113,13 @@ class LoadedApk {
IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
/** Loads the file as an xml document. */
- std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag) const;
+ std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path,
+ android::IDiagnostics* diag) const;
private:
DISALLOW_COPY_AND_ASSIGN(LoadedApk);
- Source source_;
+ android::Source source_;
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index b249c6c128e1..a0b4dab9b8e5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -24,11 +24,12 @@
#include <iostream>
#include <vector>
+#include "Diagnostics.h"
#include "android-base/stringprintf.h"
#include "android-base/utf8.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
+#include "cmd/ApkInfo.h"
#include "cmd/Command.h"
#include "cmd/Compile.h"
#include "cmd/Convert.h"
@@ -63,7 +64,7 @@ class VersionCommand : public Command {
/** The main entry point of AAPT. */
class MainCommand : public Command {
public:
- explicit MainCommand(text::Printer* printer, IDiagnostics* diagnostics)
+ explicit MainCommand(text::Printer* printer, android::IDiagnostics* diagnostics)
: Command("aapt2"), diagnostics_(diagnostics) {
AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
@@ -72,13 +73,14 @@ class MainCommand : public Command {
AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
AddOptionalSubcommand(util::make_unique<ConvertCommand>());
AddOptionalSubcommand(util::make_unique<VersionCommand>());
+ AddOptionalSubcommand(util::make_unique<ApkInfoCommand>(diagnostics));
}
int Action(const std::vector<std::string>& args) override {
if (args.size() == 0) {
- diagnostics_->Error(DiagMessage() << "no subcommand specified");
+ diagnostics_->Error(android::DiagMessage() << "no subcommand specified");
} else {
- diagnostics_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+ diagnostics_->Error(android::DiagMessage() << "unknown subcommand '" << args[0] << "'");
}
Usage(&std::cerr);
@@ -86,7 +88,7 @@ class MainCommand : public Command {
}
private:
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
};
/*
@@ -97,7 +99,7 @@ class MainCommand : public Command {
*/
class DaemonCommand : public Command {
public:
- explicit DaemonCommand(io::FileOutputStream* out, IDiagnostics* diagnostics)
+ explicit DaemonCommand(io::FileOutputStream* out, android::IDiagnostics* diagnostics)
: Command("daemon", "m"), out_(out), diagnostics_(diagnostics) {
SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
"command. The end of an invocation is signaled by providing an empty line.");
@@ -146,7 +148,7 @@ class DaemonCommand : public Command {
private:
io::FileOutputStream* out_;
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
std::optional<std::string> trace_folder_;
};
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h
index 0b4905253d20..0b08c3276cb5 100644
--- a/tools/aapt2/NameMangler.h
+++ b/tools/aapt2/NameMangler.h
@@ -36,7 +36,7 @@ struct NameManglerPolicy {
* We must know which references to mangle, and which to keep (android vs.
* com.android.support).
*/
- std::set<std::string> packages_to_mangle;
+ std::set<std::string, std::less<>> packages_to_mangle;
};
class NameMangler {
@@ -54,7 +54,7 @@ class NameMangler {
mangled_entry_name);
}
- bool ShouldMangle(const std::string& package) const {
+ bool ShouldMangle(std::string_view package) const {
if (package.empty() || policy_.target_package_name == package) {
return false;
}
@@ -68,8 +68,8 @@ 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) {
- return package + "$" + name;
+ static std::string MangleEntry(std::string_view package, std::string_view name) {
+ return (std::string(package) += '$') += name;
}
/**
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 0bb330e26e6f..cfcb2bb4f99d 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -138,11 +138,11 @@ ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t) {
return {to_string(t), t};
}
-std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s) {
- auto colon = std::find(s.begin(), s.end(), ':');
+std::optional<ResourceNamedTypeRef> ParseResourceNamedType(android::StringPiece s) {
+ auto dot = std::find(s.begin(), s.end(), '.');
const ResourceType* parsedType;
- if (colon != s.end() && colon != std::prev(s.end())) {
- parsedType = ParseResourceType(s.substr(s.begin(), colon));
+ if (dot != s.end() && dot != std::prev(s.end())) {
+ parsedType = ParseResourceType(android::StringPiece(s.begin(), dot - s.begin()));
} else {
parsedType = ParseResourceType(s);
}
@@ -152,7 +152,7 @@ std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::String
return ResourceNamedTypeRef(s, *parsedType);
}
-const ResourceType* ParseResourceType(const StringPiece& str) {
+const ResourceType* ParseResourceType(StringPiece str) {
auto iter = sResourceTypeMap.find(str);
if (iter == std::end(sResourceTypeMap)) {
return nullptr;
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index b41d8514230b..7ba3277d2093 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -25,8 +25,8 @@
#include <tuple>
#include <vector>
-#include "Source.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
#include "utils/JenkinsHash.h"
@@ -74,7 +74,7 @@ android::StringPiece to_string(ResourceType type);
/**
* Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
*/
-const ResourceType* ParseResourceType(const android::StringPiece& str);
+const ResourceType* ParseResourceType(android::StringPiece str);
/**
* Pair of type name as in ResourceTable and actual resource type.
@@ -87,7 +87,7 @@ struct ResourceNamedType {
ResourceType type = ResourceType::kRaw;
ResourceNamedType() = default;
- ResourceNamedType(const android::StringPiece& n, ResourceType t);
+ ResourceNamedType(android::StringPiece n, ResourceType t);
int compare(const ResourceNamedType& other) const;
@@ -108,19 +108,19 @@ struct ResourceNamedTypeRef {
ResourceNamedTypeRef(const ResourceNamedTypeRef&) = default;
ResourceNamedTypeRef(ResourceNamedTypeRef&&) = default;
ResourceNamedTypeRef(const ResourceNamedType& rhs); // NOLINT(google-explicit-constructor)
- ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t);
+ ResourceNamedTypeRef(android::StringPiece n, ResourceType t);
ResourceNamedTypeRef& operator=(const ResourceNamedTypeRef& rhs) = default;
ResourceNamedTypeRef& operator=(ResourceNamedTypeRef&& rhs) = default;
ResourceNamedTypeRef& operator=(const ResourceNamedType& rhs);
ResourceNamedType ToResourceNamedType() const;
- std::string to_string() const;
+ std::string_view to_string() const;
};
ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t);
-std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s);
+std::optional<ResourceNamedTypeRef> ParseResourceNamedType(android::StringPiece s);
/**
* A resource's name. This can uniquely identify
@@ -132,9 +132,8 @@ struct ResourceName {
std::string entry;
ResourceName() = default;
- ResourceName(const android::StringPiece& p, const ResourceNamedTypeRef& t,
- const android::StringPiece& e);
- ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
+ ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t, android::StringPiece e);
+ ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e);
int compare(const ResourceName& other) const;
@@ -157,9 +156,8 @@ struct ResourceNameRef {
ResourceNameRef(const ResourceNameRef&) = default;
ResourceNameRef(ResourceNameRef&&) = default;
ResourceNameRef(const ResourceName& rhs); // NOLINT(google-explicit-constructor)
- ResourceNameRef(const android::StringPiece& p, const ResourceNamedTypeRef& t,
- const android::StringPiece& e);
- ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
+ ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t, android::StringPiece e);
+ ResourceNameRef(android::StringPiece p, ResourceType t, android::StringPiece e);
ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
ResourceNameRef& operator=(const ResourceName& rhs);
@@ -228,7 +226,7 @@ struct ResourceFile {
Type type;
// Source
- Source source;
+ android::Source source;
// Exported symbols
std::vector<SourcedResourceName> exported_symbols;
@@ -346,8 +344,8 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val)
//
// ResourceNamedType implementation.
//
-inline ResourceNamedType::ResourceNamedType(const android::StringPiece& n, ResourceType t)
- : name(n.to_string()), type(t) {
+inline ResourceNamedType::ResourceNamedType(android::StringPiece n, ResourceType t)
+ : name(n), type(t) {
}
inline int ResourceNamedType::compare(const ResourceNamedType& other) const {
@@ -380,7 +378,7 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedType&
//
// ResourceNamedTypeRef implementation.
//
-inline ResourceNamedTypeRef::ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t)
+inline ResourceNamedTypeRef::ResourceNamedTypeRef(android::StringPiece n, ResourceType t)
: name(n), type(t) {
}
@@ -398,8 +396,8 @@ inline ResourceNamedType ResourceNamedTypeRef::ToResourceNamedType() const {
return ResourceNamedType(name, type);
}
-inline std::string ResourceNamedTypeRef::to_string() const {
- return name.to_string();
+inline std::string_view ResourceNamedTypeRef::to_string() const {
+ return name;
}
inline bool operator<(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
@@ -422,13 +420,12 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNamedTypeRe
// ResourceName implementation.
//
-inline ResourceName::ResourceName(const android::StringPiece& p, const ResourceNamedTypeRef& t,
- const android::StringPiece& e)
- : package(p.to_string()), type(t.ToResourceNamedType()), entry(e.to_string()) {
+inline ResourceName::ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t,
+ android::StringPiece e)
+ : package(p), type(t.ToResourceNamedType()), entry(e) {
}
-inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
- const android::StringPiece& e)
+inline ResourceName::ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e)
: ResourceName(p, ResourceNamedTypeWithDefaultName(t), e) {
}
@@ -471,14 +468,13 @@ inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name)
inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
: package(rhs.package), type(rhs.type), entry(rhs.entry) {}
-inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p,
- const ResourceNamedTypeRef& t,
- const android::StringPiece& e)
+inline ResourceNameRef::ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t,
+ android::StringPiece e)
: package(p), type(t), entry(e) {
}
-inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
- const android::StringPiece& e)
+inline ResourceNameRef::ResourceNameRef(android::StringPiece p, ResourceType t,
+ android::StringPiece e)
: ResourceNameRef(p, ResourceNamedTypeWithDefaultName(t), e) {
}
diff --git a/tools/aapt2/ResourceMetadata.proto b/tools/aapt2/ResourceMetadata.proto
new file mode 100644
index 000000000000..8eca54c4da5e
--- /dev/null
+++ b/tools/aapt2/ResourceMetadata.proto
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package aapt.pb;
+
+option java_package = "com.android.aapt";
+option java_multiple_files = true;
+
+message ResourceMappings {
+ ShortenedPathsMap shortened_paths = 1;
+ CollapsedNamesMap collapsed_names = 2;
+}
+
+// Metadata relating to "aapt2 optimize --shorten-resource-paths"
+message ShortenedPathsMap {
+ // Maps shorted paths (e.g. "res/foo.xml") to their original names (e.g.
+ // "res/xml/file_with_long_name.xml").
+ message ResourcePathMapping {
+ string shortened_path = 1;
+ string original_path = 2;
+ }
+ repeated ResourcePathMapping resource_paths = 1;
+}
+
+// Metadata relating to "aapt2 optimize --collapse-resource-names"
+message CollapsedNamesMap {
+ // Maps resource IDs (e.g. 0x7f123456) to their original names (e.g.
+ // "package:type/entry").
+ message ResourceNameMapping {
+ uint32 id = 1;
+ string name = 2;
+ }
+ repeated ResourceNameMapping resource_names = 1;
+}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 8d35eeec2a93..fa9a98f136cb 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -50,11 +50,11 @@ constexpr const char* kStagingPublicGroupFinalTag = "staging-public-group-final"
constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
// Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
-static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) {
+static bool ShouldIgnoreElement(StringPiece ns, StringPiece name) {
return ns.empty() && (name == "skip" || name == "eat-comment");
}
-static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) {
+static uint32_t ParseFormatTypeNoEnumsOrFlags(StringPiece piece) {
if (piece == "reference") {
return android::ResTable_map::TYPE_REFERENCE;
} else if (piece == "string") {
@@ -75,7 +75,7 @@ static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) {
return 0;
}
-static uint32_t ParseFormatType(const StringPiece& piece) {
+static uint32_t ParseFormatType(StringPiece piece) {
if (piece == "enum") {
return android::ResTable_map::TYPE_ENUM;
} else if (piece == "flags") {
@@ -84,9 +84,9 @@ static uint32_t ParseFormatType(const StringPiece& piece) {
return ParseFormatTypeNoEnumsOrFlags(piece);
}
-static uint32_t ParseFormatAttribute(const StringPiece& str) {
+static uint32_t ParseFormatAttribute(StringPiece str) {
uint32_t mask = 0;
- for (const StringPiece& part : util::Tokenize(str, '|')) {
+ for (StringPiece part : util::Tokenize(str, '|')) {
StringPiece trimmed_part = util::TrimWhitespace(part);
uint32_t type = ParseFormatType(trimmed_part);
if (type == 0) {
@@ -102,7 +102,7 @@ struct ParsedResource {
ResourceName name;
ConfigDescription config;
std::string product;
- Source source;
+ android::Source source;
ResourceId id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
@@ -117,11 +117,12 @@ struct ParsedResource {
};
// Recursively adds resources to the ResourceTable.
-static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
+static bool AddResourcesToTable(ResourceTable* table, android::IDiagnostics* diag,
+ ParsedResource* res) {
StringPiece trimmed_comment = util::TrimWhitespace(res->comment);
if (trimmed_comment.size() != res->comment.size()) {
// Only if there was a change do we re-assign.
- res->comment = trimmed_comment.to_string();
+ res->comment = std::string(trimmed_comment);
}
NewResourceBuilder res_builder(res->name);
@@ -175,15 +176,11 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed
// Convenient aliases for more readable function calls.
enum { kAllowRawString = true, kNoRawString = false };
-ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table,
- const Source& source,
- const ConfigDescription& config,
+ResourceParser::ResourceParser(android::IDiagnostics* diag, ResourceTable* table,
+ const android::Source& source, const ConfigDescription& config,
const ResourceParserOptions& options)
- : diag_(diag),
- table_(table),
- source_(source),
- config_(config),
- options_(options) {}
+ : diag_(diag), table_(table), source_(source), config_(config), options_(options) {
+}
// Base class Node for representing the various Spans and UntranslatableSections of an XML string.
// This will be used to traverse and flatten the XML string into a single std::string, with all
@@ -245,7 +242,7 @@ class UntranslatableNode : public Node {
// Build a string from XML that converts nested elements into Span objects.
bool ResourceParser::FlattenXmlSubtree(
- xml::XmlPullParser* parser, std::string* out_raw_string, StyleString* out_style_string,
+ xml::XmlPullParser* parser, std::string* out_raw_string, android::StyleString* out_style_string,
std::vector<UntranslatableSection>* out_untranslatable_sections) {
std::string raw_string;
std::string current_text;
@@ -308,7 +305,7 @@ bool ResourceParser::FlattenXmlSubtree(
// Check that an 'untranslatable' tag is not already being processed. Nested
// <xliff:g> tags are illegal.
if (untranslatable_start_depth) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "illegal nested XLIFF 'g' tag");
return false;
} else {
@@ -323,7 +320,7 @@ bool ResourceParser::FlattenXmlSubtree(
}
} else {
// Besides XLIFF, any other namespaced tag is unsupported and ignored.
- diag_->Warn(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Warn(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "ignoring element '" << parser->element_name()
<< "' with unknown namespace '" << parser->element_namespace() << "'");
node_stack.push_back(node_stack.back()->AddChild(util::make_unique<Node>()));
@@ -365,7 +362,7 @@ bool ResourceParser::FlattenXmlSubtree(
// Trim leading whitespace.
StringPiece trimmed = util::TrimLeadingWhitespace(first_segment->data);
if (trimmed.size() != first_segment->data.size()) {
- first_segment->data = trimmed.to_string();
+ first_segment->data = std::string(trimmed);
}
}
@@ -373,7 +370,7 @@ bool ResourceParser::FlattenXmlSubtree(
// Trim trailing whitespace.
StringPiece trimmed = util::TrimTrailingWhitespace(last_segment->data);
if (trimmed.size() != last_segment->data.size()) {
- last_segment->data = trimmed.to_string();
+ last_segment->data = std::string(trimmed);
}
}
}
@@ -383,7 +380,8 @@ bool ResourceParser::FlattenXmlSubtree(
StringBuilder builder;
root.Build(&builder);
if (!builder) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) << builder.GetError());
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+ << builder.GetError());
return false;
}
@@ -405,7 +403,7 @@ bool ResourceParser::Parse(xml::XmlPullParser* parser) {
}
if (!parser->element_namespace().empty() || parser->element_name() != "resources") {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "root element must be <resources>");
return false;
}
@@ -415,7 +413,7 @@ bool ResourceParser::Parse(xml::XmlPullParser* parser) {
};
if (parser->event() == xml::XmlPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "xml parser error: " << parser->error());
return false;
}
@@ -437,7 +435,7 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) {
if (event == xml::XmlPullParser::Event::kText) {
if (!util::TrimWhitespace(parser->text()).empty()) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "plain text not allowed here");
error = true;
}
@@ -468,7 +466,7 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) {
// Extract the product name if it exists.
if (std::optional<StringPiece> maybe_product = xml::FindNonEmptyAttribute(parser, "product")) {
- parsed_resource.product = maybe_product.value().to_string();
+ parsed_resource.product = std::string(maybe_product.value());
}
// Parse the resource regardless of product.
@@ -486,8 +484,9 @@ bool ResourceParser::ParseResources(xml::XmlPullParser* parser) {
for (const ResourceName& stripped_resource : stripped_resources) {
if (!table_->FindResource(stripped_resource)) {
// Failed to find the resource.
- diag_->Error(DiagMessage(source_) << "resource '" << stripped_resource
- << "' was filtered out but no product variant remains");
+ diag_->Error(android::DiagMessage(source_)
+ << "resource '" << stripped_resource
+ << "' was filtered out but no product variant remains");
error = true;
}
}
@@ -560,9 +559,9 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// Items have their type encoded in the type attribute.
if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
- resource_type = maybe_type.value().to_string();
+ resource_type = std::string(maybe_type.value());
} else {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "<item> must have a 'type' attribute");
return false;
}
@@ -573,9 +572,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// overridden.
resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value());
if (!resource_format) {
- diag_->Error(DiagMessage(out_resource->source)
- << "'" << maybe_format.value()
- << "' is an invalid format");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "'" << maybe_format.value() << "' is an invalid format");
return false;
}
}
@@ -584,9 +582,9 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// Bags have their type encoded in the type attribute.
if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
- resource_type = maybe_type.value().to_string();
+ resource_type = std::string(maybe_type.value());
} else {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "<bag> must have a 'type' attribute");
return false;
}
@@ -598,15 +596,14 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
if (resource_type == "id") {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> missing 'name' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
out_resource->name.type =
ResourceNamedTypeWithDefaultName(ResourceType::kId).ToResourceNamedType();
- out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->name.entry = std::string(maybe_name.value());
// Ids either represent a unique resource id or reference another resource id
auto item = ParseItem(parser, out_resource, resource_format);
@@ -626,9 +623,9 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
out_resource->value = util::make_unique<Id>();
} else if (!ref || ref->name.value().type.type != ResourceType::kId) {
// If an inner element exists, the inner element must be a reference to another resource id
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> inner element must either be a resource reference or empty");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name()
+ << "> inner element must either be a resource reference or empty");
return false;
}
}
@@ -636,14 +633,14 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
return true;
} else if (resource_type == "macro") {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
out_resource->name.type =
ResourceNamedTypeWithDefaultName(ResourceType::kMacro).ToResourceNamedType();
- out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->name.entry = std::string(maybe_name.value());
return ParseMacro(parser, out_resource);
}
@@ -653,14 +650,14 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// This is an item, record its type and format and start parsing.
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
out_resource->name.type =
ResourceNamedTypeWithDefaultName(item_iter->second.type).ToResourceNamedType();
- out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->name.entry = std::string(maybe_name.value());
// Only use the implied format of the type when there is no explicit format.
if (resource_format == 0u) {
@@ -682,12 +679,12 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
if (resource_type != kPublicGroupTag && resource_type != kStagingPublicGroupTag &&
resource_type != kStagingPublicGroupFinalTag && resource_type != "overlayable") {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
- out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->name.entry = std::string(maybe_name.value());
}
// Call the associated parse method. The type will be filled in by the
@@ -705,17 +702,16 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(resource_type);
if (parsed_type) {
if (!maybe_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> missing 'name' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> missing 'name' attribute");
return false;
}
out_resource->name.type = parsed_type->ToResourceNamedType();
- out_resource->name.entry = maybe_name.value().to_string();
+ out_resource->name.entry = std::string(maybe_name.value());
out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for type '" << *parsed_type << "'. Expected a reference");
return false;
}
@@ -724,8 +720,8 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
}
// If the resource type was not recognized, write the error and return false.
- diag_->Error(DiagMessage(out_resource->source)
- << "unknown resource type '" << resource_type << "'");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "unknown resource type '" << resource_type << "'");
return false;
}
@@ -738,8 +734,8 @@ bool ResourceParser::ParseItem(xml::XmlPullParser* parser,
out_resource->value = ParseXml(parser, format, kNoRawString);
if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source) << "invalid "
- << out_resource->name.type);
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "invalid " << out_resource->name.type);
return false;
}
return true;
@@ -750,7 +746,7 @@ std::optional<FlattenedXmlSubTree> ResourceParser::CreateFlattenSubTree(
const size_t begin_xml_line = parser->line_number();
std::string raw_value;
- StyleString style_string;
+ android::StyleString style_string;
std::vector<UntranslatableSection> untranslatable_sections;
if (!FlattenXmlSubtree(parser, &raw_value, &style_string, &untranslatable_sections)) {
return {};
@@ -783,13 +779,13 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
const uint32_t type_mask, const bool allow_raw_value,
ResourceTable& table,
const android::ConfigDescription& config,
- IDiagnostics& diag) {
+ android::IDiagnostics& diag) {
if (!xmlsub_tree.style_string.spans.empty()) {
// This can only be a StyledString.
std::unique_ptr<StyledString> styled_string =
util::make_unique<StyledString>(table.string_pool.MakeRef(
xmlsub_tree.style_string,
- StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
styled_string->untranslatable_sections = xmlsub_tree.untranslatable_sections;
return std::move(styled_string);
}
@@ -817,8 +813,8 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
// Try making a regular string.
if (type_mask & android::ResTable_map::TYPE_STRING) {
// Use the trimmed, escaped string.
- std::unique_ptr<String> string = util::make_unique<String>(
- table.string_pool.MakeRef(xmlsub_tree.style_string.str, StringPool::Context(config)));
+ std::unique_ptr<String> string = util::make_unique<String>(table.string_pool.MakeRef(
+ xmlsub_tree.style_string.str, android::StringPool::Context(config)));
string->untranslatable_sections = xmlsub_tree.untranslatable_sections;
return std::move(string);
}
@@ -826,7 +822,7 @@ std::unique_ptr<Item> ResourceParser::ParseXml(const FlattenedXmlSubTree& xmlsub
if (allow_raw_value) {
// We can't parse this so return a RawString if we are allowed.
return util::make_unique<RawString>(table.string_pool.MakeRef(
- util::TrimWhitespace(xmlsub_tree.raw_value), StringPool::Context(config)));
+ util::TrimWhitespace(xmlsub_tree.raw_value), android::StringPool::Context(config)));
} else if (util::TrimWhitespace(xmlsub_tree.raw_value).empty()) {
// If the text is empty, and the value is not allowed to be a string, encode it as a @null.
return ResourceUtils::MakeNull();
@@ -840,7 +836,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
if (std::optional<StringPiece> formatted_attr = xml::FindAttribute(parser, "formatted")) {
std::optional<bool> maybe_formatted = ResourceUtils::ParseBool(formatted_attr.value());
if (!maybe_formatted) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for 'formatted'. Must be a boolean");
return false;
}
@@ -851,7 +847,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
if (!maybe_translatable) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for 'translatable'. Must be a boolean");
return false;
}
@@ -861,7 +857,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
out_resource->value =
ParseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
if (!out_resource->value) {
- diag_->Error(DiagMessage(out_resource->source) << "not a valid string");
+ diag_->Error(android::DiagMessage(out_resource->source) << "not a valid string");
return false;
}
@@ -870,7 +866,7 @@ bool ResourceParser::ParseString(xml::XmlPullParser* parser,
if (formatted && translatable) {
if (!util::VerifyJavaStringFormat(*string_value->value)) {
- DiagMessage msg(out_resource->source);
+ android::DiagMessage msg(out_resource->source);
msg << "multiple substitutions specified in non-positional format; "
"did you mean to add the formatted=\"false\" attribute?";
if (options_.error_on_positional_arguments) {
@@ -895,7 +891,7 @@ bool ResourceParser::ParseMacro(xml::XmlPullParser* parser, ParsedResource* out_
}
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<macro> tags cannot be declared in configurations other than the default "
"configuration'");
return false;
@@ -919,28 +915,27 @@ bool ResourceParser::ParseMacro(xml::XmlPullParser* parser, ParsedResource* out_
bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<public> tag not allowed with --visibility flag");
return false;
}
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
+ diag_->Warn(android::DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config << "' for <public> tag");
}
std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<public> must have a 'type' attribute");
return false;
}
std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(maybe_type.value());
if (!parsed_type) {
- diag_->Error(DiagMessage(out_resource->source) << "invalid resource type '"
- << maybe_type.value()
- << "' in <public>");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "invalid resource type '" << maybe_type.value() << "' in <public>");
return false;
}
@@ -949,7 +944,7 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out
if (std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) {
std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
if (!maybe_id) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid resource ID '" << maybe_id_str.value() << "' in <public>");
return false;
}
@@ -967,37 +962,39 @@ bool ResourceParser::ParsePublic(xml::XmlPullParser* parser, ParsedResource* out
template <typename Func>
bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resource,
- const char* tag_name, IDiagnostics* diag, Func&& func) {
+ const char* tag_name, android::IDiagnostics* diag, Func&& func) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag->Warn(DiagMessage(out_resource->source)
+ diag->Warn(android::DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config << "' for <" << tag_name
<< "> tag");
}
std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag->Error(DiagMessage(out_resource->source)
+ diag->Error(android::DiagMessage(out_resource->source)
<< "<" << tag_name << "> must have a 'type' attribute");
return false;
}
- std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(maybe_type.value());
- if (!parsed_type) {
- diag->Error(DiagMessage(out_resource->source)
+ std::optional<ResourceNamedTypeRef> maybe_parsed_type =
+ ParseResourceNamedType(maybe_type.value());
+ if (!maybe_parsed_type) {
+ diag->Error(android::DiagMessage(out_resource->source)
<< "invalid resource type '" << maybe_type.value() << "' in <" << tag_name << ">");
return false;
}
+ auto parsed_type = maybe_parsed_type->ToResourceNamedType();
std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id");
if (!maybe_id_str) {
- diag->Error(DiagMessage(out_resource->source)
+ diag->Error(android::DiagMessage(out_resource->source)
<< "<" << tag_name << "> must have a 'first-id' attribute");
return false;
}
std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
if (!maybe_id) {
- diag->Error(DiagMessage(out_resource->source)
+ diag->Error(android::DiagMessage(out_resource->source)
<< "invalid resource ID '" << maybe_id_str.value() << "' in <" << tag_name << ">");
return false;
}
@@ -1008,32 +1005,34 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
const size_t depth = parser->depth();
while (xml::XmlPullParser::NextChildNode(parser, depth)) {
if (parser->event() == xml::XmlPullParser::Event::kComment) {
- comment = util::TrimWhitespace(parser->comment()).to_string();
+ comment = std::string(util::TrimWhitespace(parser->comment()));
continue;
} else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
// Skip text.
continue;
}
- const Source item_source = out_resource->source.WithLine(parser->line_number());
+ const android::Source item_source = out_resource->source.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "public") {
auto maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag->Error(DiagMessage(item_source) << "<public> must have a 'name' attribute");
+ diag->Error(android::DiagMessage(item_source) << "<public> must have a 'name' attribute");
error = true;
continue;
}
if (xml::FindNonEmptyAttribute(parser, "id")) {
- diag->Error(DiagMessage(item_source) << "'id' is ignored within <" << tag_name << ">");
+ diag->Error(android::DiagMessage(item_source)
+ << "'id' is ignored within <" << tag_name << ">");
error = true;
continue;
}
if (xml::FindNonEmptyAttribute(parser, "type")) {
- diag->Error(DiagMessage(item_source) << "'type' is ignored within <" << tag_name << ">");
+ diag->Error(android::DiagMessage(item_source)
+ << "'type' is ignored within <" << tag_name << ">");
error = true;
continue;
}
@@ -1046,7 +1045,7 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
}
ParsedResource& entry_res = out_resource->child_resources.emplace_back(ParsedResource{
- .name = ResourceName{{}, *parsed_type, maybe_name.value().to_string()},
+ .name = ResourceName{{}, parsed_type, std::string(maybe_name.value())},
.source = item_source,
.comment = std::move(comment),
});
@@ -1057,7 +1056,7 @@ bool static ParseGroupImpl(xml::XmlPullParser* parser, ParsedResource* out_resou
next_id.id++;
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag->Error(android::DiagMessage(item_source) << ":" << element_name << ">");
error = true;
}
}
@@ -1084,7 +1083,7 @@ bool ResourceParser::ParseStagingPublicGroupFinal(xml::XmlPullParser* parser,
bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<" << kPublicGroupTag << "> tag not allowed with --visibility flag");
return false;
}
@@ -1100,15 +1099,14 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
ParsedResource* out_resource) {
std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
if (!maybe_type) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<" << parser->element_name()
- << "> must have a 'type' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<" << parser->element_name() << "> must have a 'type' attribute");
return false;
}
std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(maybe_type.value());
if (!parsed_type) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid resource type '" << maybe_type.value() << "' in <"
<< parser->element_name() << ">");
return false;
@@ -1120,12 +1118,12 @@ bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (options_.visibility) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "<java-symbol> and <symbol> tags not allowed with --visibility flag");
return false;
}
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
+ diag_->Warn(android::DiagMessage(out_resource->source)
<< "ignoring configuration '" << out_resource->config << "' for <"
<< parser->element_name() << "> tag");
}
@@ -1140,15 +1138,14 @@ bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out
bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for <overlayable> tag");
+ diag_->Warn(android::DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag");
}
std::optional<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name");
if (!overlayable_name) {
- diag_->Error(DiagMessage(out_resource->source)
- << "<overlayable> tag must have a 'name' attribute");
+ diag_->Error(android::DiagMessage(out_resource->source)
+ << "<overlayable> tag must have a 'name' attribute");
return false;
}
@@ -1156,7 +1153,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
android::base::StringPrintf("%s://", Overlayable::kActorScheme);
std::optional<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor");
if (overlayable_actor && !util::StartsWith(overlayable_actor.value(), kActorUriScheme)) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "specified <overlayable> tag 'actor' attribute must use the scheme '"
<< Overlayable::kActorScheme << "'");
return false;
@@ -1190,13 +1187,13 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
continue;
}
- const Source element_source = source_.WithLine(parser->line_number());
+ const android::Source element_source = source_.WithLine(parser->line_number());
const std::string& element_name = parser->element_name();
const std::string& element_namespace = parser->element_namespace();
if (element_namespace.empty() && element_name == "item") {
if (current_policies == PolicyFlags::NONE) {
- diag_->Error(DiagMessage(element_source)
- << "<item> within an <overlayable> must be inside a <policy> block");
+ diag_->Error(android::DiagMessage(element_source)
+ << "<item> within an <overlayable> must be inside a <policy> block");
error = true;
continue;
}
@@ -1204,7 +1201,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
// Items specify the name and type of resource that should be overlayable
std::optional<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
if (!item_name) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<item> within an <overlayable> must have a 'name' attribute");
error = true;
continue;
@@ -1212,7 +1209,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
std::optional<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type");
if (!item_type) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<item> within an <overlayable> must have a 'type' attribute");
error = true;
continue;
@@ -1220,7 +1217,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
std::optional<ResourceNamedTypeRef> type = ParseResourceNamedType(item_type.value());
if (!type) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "invalid resource type '" << item_type.value()
<< "' in <item> within an <overlayable>");
error = true;
@@ -1234,21 +1231,22 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
ParsedResource child_resource{};
child_resource.name.type = type->ToResourceNamedType();
- child_resource.name.entry = item_name.value().to_string();
+ child_resource.name.entry = std::string(item_name.value());
child_resource.overlayable_item = overlayable_item;
out_resource->child_resources.push_back(std::move(child_resource));
} else if (element_namespace.empty() && element_name == "policy") {
if (current_policies != PolicyFlags::NONE) {
// If the policy list is not empty, then we are currently inside a policy element
- diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested");
+ diag_->Error(android::DiagMessage(element_source)
+ << "<policy> blocks cannot be recursively nested");
error = true;
break;
} else if (std::optional<StringPiece> maybe_type =
xml::FindNonEmptyAttribute(parser, "type")) {
// Parse the polices separated by vertical bar characters to allow for specifying multiple
// policies. Items within the policy tag will have the specified policy.
- for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) {
+ for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
StringPiece trimmed_part = util::TrimWhitespace(part);
const auto policy = std::find_if(kPolicyStringToFlag.begin(),
kPolicyStringToFlag.end(),
@@ -1256,7 +1254,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
return trimmed_part == it.first;
});
if (policy == kPolicyStringToFlag.end()) {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<policy> has unsupported type '" << trimmed_part << "'");
error = true;
continue;
@@ -1265,14 +1263,15 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource
current_policies |= policy->second;
}
} else {
- diag_->Error(DiagMessage(element_source)
+ diag_->Error(android::DiagMessage(element_source)
<< "<policy> must have a 'type' attribute");
error = true;
continue;
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
- << " in <overlayable>");
+ diag_->Error(android::DiagMessage(element_source)
+ << "invalid element <" << element_name << "> "
+ << " in <overlayable>");
error = true;
break;
}
@@ -1304,9 +1303,9 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
// Attributes only end up in default configuration.
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for attribute " << out_resource->name);
+ diag_->Warn(android::DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for attribute "
+ << out_resource->name);
out_resource->config = ConfigDescription::DefaultConfig();
}
@@ -1316,7 +1315,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (maybe_format) {
type_mask = ParseFormatAttribute(maybe_format.value());
if (type_mask == 0) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "invalid attribute format '" << maybe_format.value() << "'");
return false;
}
@@ -1327,7 +1326,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (std::optional<StringPiece> maybe_min_str = xml::FindAttribute(parser, "min")) {
StringPiece min_str = util::TrimWhitespace(maybe_min_str.value());
if (!min_str.empty()) {
- std::u16string min_str16 = util::Utf8ToUtf16(min_str);
+ std::u16string min_str16 = android::util::Utf8ToUtf16(min_str);
android::Res_value value;
if (android::ResTable::stringToInt(min_str16.data(), min_str16.size(), &value)) {
maybe_min = static_cast<int32_t>(value.data);
@@ -1335,7 +1334,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
}
if (!maybe_min) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "invalid 'min' value '" << min_str << "'");
return false;
}
@@ -1344,7 +1343,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if (std::optional<StringPiece> maybe_max_str = xml::FindAttribute(parser, "max")) {
StringPiece max_str = util::TrimWhitespace(maybe_max_str.value());
if (!max_str.empty()) {
- std::u16string max_str16 = util::Utf8ToUtf16(max_str);
+ std::u16string max_str16 = android::util::Utf8ToUtf16(max_str);
android::Res_value value;
if (android::ResTable::stringToInt(max_str16.data(), max_str16.size(), &value)) {
maybe_max = static_cast<int32_t>(value.data);
@@ -1352,7 +1351,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
}
if (!maybe_max) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "invalid 'max' value '" << max_str << "'");
return false;
}
@@ -1360,7 +1359,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
if ((maybe_min || maybe_max) &&
(type_mask & android::ResTable_map::TYPE_INTEGER) == 0) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "'min' and 'max' can only be used when format='integer'");
return false;
}
@@ -1378,20 +1377,20 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
const size_t depth = parser->depth();
while (xml::XmlPullParser::NextChildNode(parser, depth)) {
if (parser->event() == xml::XmlPullParser::Event::kComment) {
- comment = util::TrimWhitespace(parser->comment()).to_string();
+ comment = std::string(util::TrimWhitespace(parser->comment()));
continue;
} else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
// Skip text.
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && (element_name == "flag" || element_name == "enum")) {
if (element_name == "enum") {
if (type_mask & android::ResTable_map::TYPE_FLAGS) {
- diag_->Error(DiagMessage(item_source)
+ diag_->Error(android::DiagMessage(item_source)
<< "can not define an <enum>; already defined a <flag>");
error = true;
continue;
@@ -1400,7 +1399,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
} else if (element_name == "flag") {
if (type_mask & android::ResTable_map::TYPE_ENUM) {
- diag_->Error(DiagMessage(item_source)
+ diag_->Error(android::DiagMessage(item_source)
<< "can not define a <flag>; already defined an <enum>");
error = true;
continue;
@@ -1425,11 +1424,10 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
auto insert_result = items.insert(std::move(symbol));
if (!insert_result.second) {
const Attribute::Symbol& existing_symbol = *insert_result.first;
- diag_->Error(DiagMessage(item_source)
- << "duplicate symbol '"
- << existing_symbol.symbol.name.value().entry << "'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "duplicate symbol '" << existing_symbol.symbol.name.value().entry << "'");
- diag_->Note(DiagMessage(existing_symbol.symbol.GetSource())
+ diag_->Note(android::DiagMessage(existing_symbol.symbol.GetSource())
<< "first defined here");
error = true;
}
@@ -1437,7 +1435,7 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
error = true;
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag_->Error(android::DiagMessage(item_source) << ":" << element_name << ">");
error = true;
}
@@ -1459,29 +1457,28 @@ bool ResourceParser::ParseAttrImpl(xml::XmlPullParser* parser,
}
std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPullParser* parser,
- const StringPiece& tag) {
- const Source source = source_.WithLine(parser->line_number());
+ StringPiece tag) {
+ const android::Source source = source_.WithLine(parser->line_number());
std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(source) << "no attribute 'name' found for tag <"
- << tag << ">");
+ diag_->Error(android::DiagMessage(source)
+ << "no attribute 'name' found for tag <" << tag << ">");
return {};
}
std::optional<StringPiece> maybe_value = xml::FindNonEmptyAttribute(parser, "value");
if (!maybe_value) {
- diag_->Error(DiagMessage(source) << "no attribute 'value' found for tag <"
- << tag << ">");
+ diag_->Error(android::DiagMessage(source)
+ << "no attribute 'value' found for tag <" << tag << ">");
return {};
}
- std::u16string value16 = util::Utf8ToUtf16(maybe_value.value());
+ std::u16string value16 = android::util::Utf8ToUtf16(maybe_value.value());
android::Res_value val;
if (!android::ResTable::stringToInt(value16.data(), value16.size(), &val)) {
- diag_->Error(DiagMessage(source) << "invalid value '" << maybe_value.value()
- << "' for <" << tag
- << ">; must be an integer");
+ diag_->Error(android::DiagMessage(source) << "invalid value '" << maybe_value.value()
+ << "' for <" << tag << ">; must be an integer");
return {};
}
@@ -1492,17 +1489,18 @@ std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPul
}
bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
- const Source source = source_.WithLine(parser->line_number());
+ const android::Source source = source_.WithLine(parser->line_number());
std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(source) << "<item> must have a 'name' attribute");
+ diag_->Error(android::DiagMessage(source) << "<item> must have a 'name' attribute");
return false;
}
std::optional<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
if (!maybe_key) {
- diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'");
+ diag_->Error(android::DiagMessage(source)
+ << "invalid attribute name '" << maybe_name.value() << "'");
return false;
}
@@ -1511,7 +1509,7 @@ bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
std::unique_ptr<Item> value = ParseXml(parser, 0, kAllowRawString);
if (!value) {
- diag_->Error(DiagMessage(source) << "could not parse style item");
+ diag_->Error(android::DiagMessage(source) << "could not parse style item");
return false;
}
@@ -1532,7 +1530,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
std::string err_str;
style->parent = ResourceUtils::ParseStyleParentReference(maybe_parent.value(), &err_str);
if (!style->parent) {
- diag_->Error(DiagMessage(out_resource->source) << err_str);
+ diag_->Error(android::DiagMessage(out_resource->source) << err_str);
return false;
}
@@ -1566,7 +1564,7 @@ bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* par
error |= !ParseStyleItem(parser, style.get());
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< ":" << element_name << ">");
error = true;
}
@@ -1585,7 +1583,7 @@ bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_
if (std::optional<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value());
if (resource_format == 0u) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
<< "'" << format_attr.value() << "' is an invalid format");
return false;
}
@@ -1613,7 +1611,7 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
if (!maybe_translatable) {
- diag_->Error(DiagMessage(out_resource->source)
+ diag_->Error(android::DiagMessage(out_resource->source)
<< "invalid value for 'translatable'. Must be a boolean");
return false;
}
@@ -1629,13 +1627,13 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "item") {
std::unique_ptr<Item> item = ParseXml(parser, typeMask, kNoRawString);
if (!item) {
- diag_->Error(DiagMessage(item_source) << "could not parse array item");
+ diag_->Error(android::DiagMessage(item_source) << "could not parse array item");
error = true;
continue;
}
@@ -1643,9 +1641,8 @@ bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
array->elements.emplace_back(std::move(item));
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
- << "unknown tag <" << element_namespace << ":"
- << element_name << ">");
+ diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+ << "unknown tag <" << element_namespace << ":" << element_name << ">");
error = true;
}
}
@@ -1673,15 +1670,14 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser,
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "item") {
std::optional<StringPiece> maybe_quantity = xml::FindNonEmptyAttribute(parser, "quantity");
if (!maybe_quantity) {
- diag_->Error(DiagMessage(item_source)
- << "<item> in <plurals> requires attribute "
- << "'quantity'");
+ diag_->Error(android::DiagMessage(item_source) << "<item> in <plurals> requires attribute "
+ << "'quantity'");
error = true;
continue;
}
@@ -1702,16 +1698,16 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser,
} else if (trimmed_quantity == "other") {
index = Plural::Other;
} else {
- diag_->Error(DiagMessage(item_source)
- << "<item> in <plural> has invalid value '"
- << trimmed_quantity << "' for attribute 'quantity'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "<item> in <plural> has invalid value '" << trimmed_quantity
+ << "' for attribute 'quantity'");
error = true;
continue;
}
if (plural->values[index]) {
- diag_->Error(DiagMessage(item_source) << "duplicate quantity '"
- << trimmed_quantity << "'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "duplicate quantity '" << trimmed_quantity << "'");
error = true;
continue;
}
@@ -1725,9 +1721,8 @@ bool ResourceParser::ParsePlural(xml::XmlPullParser* parser,
plural->values[index]->SetSource(item_source);
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << "unknown tag <"
- << element_namespace << ":"
- << element_name << ">");
+ diag_->Error(android::DiagMessage(item_source)
+ << "unknown tag <" << element_namespace << ":" << element_name << ">");
error = true;
}
}
@@ -1756,9 +1751,9 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
// Declare-styleable only ends up in default config;
if (out_resource->config != ConfigDescription::DefaultConfig()) {
- diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config
- << "' for styleable " << out_resource->name.entry);
+ diag_->Warn(android::DiagMessage(out_resource->source)
+ << "ignoring configuration '" << out_resource->config << "' for styleable "
+ << out_resource->name.entry);
out_resource->config = ConfigDescription::DefaultConfig();
}
@@ -1769,20 +1764,21 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
const size_t depth = parser->depth();
while (xml::XmlPullParser::NextChildNode(parser, depth)) {
if (parser->event() == xml::XmlPullParser::Event::kComment) {
- comment = util::TrimWhitespace(parser->comment()).to_string();
+ comment = std::string(util::TrimWhitespace(parser->comment()));
continue;
} else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
// Ignore text.
continue;
}
- const Source item_source = source_.WithLine(parser->line_number());
+ const android::Source item_source = source_.WithLine(parser->line_number());
const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
if (element_namespace.empty() && element_name == "attr") {
std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
if (!maybe_name) {
- diag_->Error(DiagMessage(item_source) << "<attr> tag must have a 'name' attribute");
+ diag_->Error(android::DiagMessage(item_source)
+ << "<attr> tag must have a 'name' attribute");
error = true;
continue;
}
@@ -1792,8 +1788,8 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
// Eg. <attr name="android:text" />
std::optional<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
if (!maybe_ref) {
- diag_->Error(DiagMessage(item_source) << "<attr> tag has invalid name '"
- << maybe_name.value() << "'");
+ diag_->Error(android::DiagMessage(item_source)
+ << "<attr> tag has invalid name '" << maybe_name.value() << "'");
error = true;
continue;
}
@@ -1831,9 +1827,8 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser,
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << "unknown tag <"
- << element_namespace << ":"
- << element_name << ">");
+ diag_->Error(android::DiagMessage(item_source)
+ << "unknown tag <" << element_namespace << ":" << element_name << ">");
error = true;
}
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 548f5f9531fd..012a056dccf3 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -20,14 +20,13 @@
#include <memory>
#include <optional>
+#include "ResourceTable.h"
+#include "ResourceValues.h"
#include "android-base/macros.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
-#include "ResourceTable.h"
-#include "ResourceValues.h"
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
#include "xml/XmlPullParser.h"
namespace aapt {
@@ -59,10 +58,10 @@ struct ResourceParserOptions {
struct FlattenedXmlSubTree {
std::string raw_value;
- StyleString style_string;
+ android::StyleString style_string;
std::vector<UntranslatableSection> untranslatable_sections;
xml::IPackageDeclStack* namespace_resolver;
- Source source;
+ android::Source source;
};
/*
@@ -70,7 +69,7 @@ struct FlattenedXmlSubTree {
*/
class ResourceParser {
public:
- ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
+ ResourceParser(android::IDiagnostics* diag, ResourceTable* table, const android::Source& source,
const android::ConfigDescription& config,
const ResourceParserOptions& options = {});
bool Parse(xml::XmlPullParser* parser);
@@ -78,7 +77,7 @@ class ResourceParser {
static std::unique_ptr<Item> ParseXml(const FlattenedXmlSubTree& xmlsub_tree, uint32_t type_mask,
bool allow_raw_value, ResourceTable& table,
const android::ConfigDescription& config,
- IDiagnostics& diag);
+ android::IDiagnostics& diag);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceParser);
@@ -93,7 +92,7 @@ class ResourceParser {
// `out_untranslatable_sections` contains the sections of the string that should not be
// translated.
bool FlattenXmlSubtree(xml::XmlPullParser* parser, std::string* out_raw_string,
- StyleString* out_style_string,
+ android::StyleString* out_style_string,
std::vector<UntranslatableSection>* out_untranslatable_sections);
/*
@@ -123,7 +122,7 @@ class ResourceParser {
bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak);
std::optional<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
- const android::StringPiece& tag);
+ android::StringPiece tag);
bool ParseStyle(ResourceType type, xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
bool ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource);
@@ -133,9 +132,9 @@ class ResourceParser {
bool ParseArrayImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, uint32_t typeMask);
bool ParsePlural(xml::XmlPullParser* parser, ParsedResource* out_resource);
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
ResourceTable* table_;
- Source source_;
+ android::Source source_;
android::ConfigDescription config_;
ResourceParserOptions options_;
};
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 556ffa221db5..b59b16574c42 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -50,7 +50,7 @@ constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>
TEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
ResourceTable table;
- ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
+ ResourceParser parser(context->GetDiagnostics(), &table, android::Source{"test"}, {});
std::string input = kXmlPreamble;
input += R"(<attr name="foo"/>)";
@@ -65,13 +65,13 @@ class ResourceParserTest : public ::testing::Test {
context_ = test::ContextBuilder().Build();
}
- ::testing::AssertionResult TestParse(const StringPiece& str) {
+ ::testing::AssertionResult TestParse(StringPiece str) {
return TestParse(str, ConfigDescription{});
}
- ::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) {
+ ::testing::AssertionResult TestParse(StringPiece str, const ConfigDescription& config) {
ResourceParserOptions parserOptions;
- ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, config,
+ ResourceParser parser(context_->GetDiagnostics(), &table_, android::Source{"test"}, config,
parserOptions);
std::string input = kXmlPreamble;
@@ -711,7 +711,7 @@ TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) {
</declare-styleable>
<public type="styleable" name="bar" />
</resources>)");
- ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"},
+ ResourceParser parser(context_->GetDiagnostics(), &table_, android::Source{"test"},
ConfigDescription::DefaultConfig(),
ResourceParserOptions{.preserve_visibility_of_styleables = true});
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 98cce268e213..a3b0b45df5c3 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -43,26 +43,27 @@ namespace aapt {
const char* Overlayable::kActorScheme = "overlay";
namespace {
-bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
- return lhs->type < rhs;
+bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs,
+ const ResourceNamedTypeRef& rhs) {
+ return lhs->named_type < rhs;
}
template <typename T>
-bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
+bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, StringPiece rhs) {
return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
}
template <typename T>
-bool greater_than_struct_with_name(const StringPiece& lhs, const std::unique_ptr<T>& rhs) {
+bool greater_than_struct_with_name(StringPiece lhs, const std::unique_ptr<T>& rhs) {
return rhs->name.compare(0, rhs->name.size(), lhs.data(), lhs.size()) > 0;
}
template <typename T>
struct NameEqualRange {
- bool operator()(const std::unique_ptr<T>& lhs, const StringPiece& rhs) const {
+ bool operator()(const std::unique_ptr<T>& lhs, StringPiece rhs) const {
return less_than_struct_with_name<T>(lhs, rhs);
}
- bool operator()(const StringPiece& lhs, const std::unique_ptr<T>& rhs) const {
+ bool operator()(StringPiece lhs, const std::unique_ptr<T>& rhs) const {
return greater_than_struct_with_name<T>(lhs, rhs);
}
};
@@ -77,7 +78,7 @@ bool less_than_struct_with_name_and_id(const T& lhs,
}
template <typename T, typename Func, typename Elements>
-T* FindElementsRunAction(const android::StringPiece& name, Elements& entries, Func action) {
+T* FindElementsRunAction(android::StringPiece name, Elements& entries, Func action) {
const auto iter =
std::lower_bound(entries.begin(), entries.end(), name, less_than_struct_with_name<T>);
const bool found = iter != entries.end() && name == (*iter)->name;
@@ -86,7 +87,7 @@ T* FindElementsRunAction(const android::StringPiece& name, Elements& entries, Fu
struct ConfigKey {
const ConfigDescription* config;
- const StringPiece& product;
+ StringPiece product;
};
template <typename T>
@@ -103,47 +104,53 @@ bool lt_config_key_ref(const T& lhs, const ConfigKey& rhs) {
ResourceTable::ResourceTable(ResourceTable::Validation validation) : validation_(validation) {
}
-ResourceTablePackage* ResourceTable::FindPackage(const android::StringPiece& name) const {
+ResourceTablePackage* ResourceTable::FindPackage(android::StringPiece name) const {
return FindElementsRunAction<ResourceTablePackage>(
name, packages, [&](bool found, auto& iter) { return found ? iter->get() : nullptr; });
}
-ResourceTablePackage* ResourceTable::FindOrCreatePackage(const android::StringPiece& name) {
+ResourceTablePackage* ResourceTable::FindOrCreatePackage(android::StringPiece name) {
return FindElementsRunAction<ResourceTablePackage>(name, packages, [&](bool found, auto& iter) {
return found ? iter->get() : packages.emplace(iter, new ResourceTablePackage(name))->get();
});
}
template <typename Func, typename Elements>
-static ResourceTableType* FindTypeRunAction(ResourceType type, Elements& entries, Func action) {
+static ResourceTableType* FindTypeRunAction(const ResourceNamedTypeRef& type, Elements& entries,
+ Func action) {
const auto iter = std::lower_bound(entries.begin(), entries.end(), type, less_than_type);
- const bool found = iter != entries.end() && type == (*iter)->type;
+ const bool found = iter != entries.end() && type == (*iter)->named_type;
return action(found, iter);
}
-ResourceTableType* ResourceTablePackage::FindType(ResourceType type) const {
+ResourceTableType* ResourceTablePackage::FindTypeWithDefaultName(const ResourceType type) const {
+ auto named_type = ResourceNamedTypeWithDefaultName(type);
+ return FindType(named_type);
+}
+
+ResourceTableType* ResourceTablePackage::FindType(const ResourceNamedTypeRef& type) const {
return FindTypeRunAction(type, types,
[&](bool found, auto& iter) { return found ? iter->get() : nullptr; });
}
-ResourceTableType* ResourceTablePackage::FindOrCreateType(ResourceType type) {
+ResourceTableType* ResourceTablePackage::FindOrCreateType(const ResourceNamedTypeRef& type) {
return FindTypeRunAction(type, types, [&](bool found, auto& iter) {
return found ? iter->get() : types.emplace(iter, new ResourceTableType(type))->get();
});
}
-ResourceEntry* ResourceTableType::CreateEntry(const android::StringPiece& name) {
+ResourceEntry* ResourceTableType::CreateEntry(android::StringPiece name) {
return FindElementsRunAction<ResourceEntry>(name, entries, [&](bool found, auto& iter) {
return entries.emplace(iter, new ResourceEntry(name))->get();
});
}
-ResourceEntry* ResourceTableType::FindEntry(const android::StringPiece& name) const {
+ResourceEntry* ResourceTableType::FindEntry(android::StringPiece name) const {
return FindElementsRunAction<ResourceEntry>(
name, entries, [&](bool found, auto& iter) { return found ? iter->get() : nullptr; });
}
-ResourceEntry* ResourceTableType::FindOrCreateEntry(const android::StringPiece& name) {
+ResourceEntry* ResourceTableType::FindOrCreateEntry(android::StringPiece name) {
return FindElementsRunAction<ResourceEntry>(name, entries, [&](bool found, auto& iter) {
return found ? iter->get() : entries.emplace(iter, new ResourceEntry(name))->get();
});
@@ -176,7 +183,7 @@ const ResourceConfigValue* ResourceEntry::FindValue(const android::ConfigDescrip
}
ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
- const StringPiece& product) {
+ StringPiece product) {
auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>);
if (iter != values.end()) {
@@ -329,7 +336,7 @@ struct PackageViewComparer {
struct TypeViewComparer {
bool operator()(const ResourceTableTypeView& lhs, const ResourceTableTypeView& rhs) {
- return lhs.id != rhs.id ? lhs.id < rhs.id : lhs.type < rhs.type;
+ return lhs.id != rhs.id ? lhs.id < rhs.id : lhs.named_type < rhs.named_type;
}
};
@@ -355,7 +362,8 @@ void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePacka
id ? id.value().package_id() : std::optional<uint8_t>{}};
auto view_package = package_inserter.Insert(table.packages, std::move(new_package));
- ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : std::optional<uint8_t>{}};
+ ResourceTableTypeView new_type{type->named_type,
+ id ? id.value().type_id() : std::optional<uint8_t>{}};
auto view_type = type_inserter.Insert(view_package->types, std::move(new_type));
if (visibility.level == Visibility::Level::kPublic) {
@@ -420,13 +428,14 @@ ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptio
// we can reuse those packages for other types that need to be extracted from this package.
// `start_index` is the index of the first newly created package that can be reused.
const size_t start_index = new_packages.size();
- std::map<ResourceType, size_t> type_new_package_index;
+ std::map<ResourceNamedType, size_t> type_new_package_index;
for (auto type_it = package.types.begin(); type_it != package.types.end();) {
auto& type = *type_it;
- auto type_index_iter = type_new_package_index.find(type.type);
+ auto type_index_iter = type_new_package_index.find(type.named_type);
if (type_index_iter == type_new_package_index.end()) {
// First occurrence of the resource type in this package. Keep it in this package.
- type_new_package_index.insert(type_index_iter, std::make_pair(type.type, start_index));
+ type_new_package_index.insert(type_index_iter,
+ std::make_pair(type.named_type, start_index));
++type_it;
continue;
}
@@ -440,7 +449,7 @@ ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptio
// Move the type into a new package
auto& other_package = new_packages[index];
- type_new_package_index[type.type] = index + 1;
+ type_new_package_index[type.named_type] = index + 1;
type_inserter.Insert(other_package.types, std::move(type));
type_it = package.types.erase(type_it);
}
@@ -455,25 +464,26 @@ ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptio
return view;
}
-bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
+bool ResourceTable::AddResource(NewResource&& res, android::IDiagnostics* diag) {
CHECK(diag != nullptr) << "Diagnostic pointer is null";
const bool validate = validation_ == Validation::kEnabled;
- const Source source = res.value ? res.value->GetSource() : Source{};
+ const android::Source source = res.value ? res.value->GetSource() : android::Source{};
if (validate && !res.allow_mangled && !IsValidResourceEntryName(res.name.entry)) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "resource '" << res.name << "' has invalid entry name '" << res.name.entry);
return false;
}
if (res.id.has_value() && !res.id->first.is_valid()) {
- diag->Error(DiagMessage(source) << "trying to add resource '" << res.name << "' with ID "
- << res.id->first << " but that ID is invalid");
+ diag->Error(android::DiagMessage(source)
+ << "trying to add resource '" << res.name << "' with ID " << res.id->first
+ << " but that ID is invalid");
return false;
}
auto package = FindOrCreatePackage(res.name.package);
- auto type = package->FindOrCreateType(res.name.type.type);
+ auto type = package->FindOrCreateType(res.name.type);
auto entry_it = std::equal_range(type->entries.begin(), type->entries.end(), res.name.entry,
NameEqualRange<ResourceEntry>{});
const size_t entry_count = std::distance(entry_it.first, entry_it.second);
@@ -504,7 +514,7 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
if (res.id.has_value()) {
if (entry->id && entry->id.value() != res.id->first) {
if (res.id->second != OnIdConflict::CREATE_ENTRY) {
- diag->Error(DiagMessage(source)
+ diag->Error(android::DiagMessage(source)
<< "trying to add resource '" << res.name << "' with ID " << res.id->first
<< " but resource already has ID " << entry->id.value());
return false;
@@ -532,9 +542,9 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
if (res.overlayable.has_value()) {
if (entry->overlayable_item) {
- diag->Error(DiagMessage(res.overlayable->source)
+ diag->Error(android::DiagMessage(res.overlayable->source)
<< "duplicate overlayable declaration for resource '" << res.name << "'");
- diag->Error(DiagMessage(entry->overlayable_item.value().source)
+ diag->Error(android::DiagMessage(entry->overlayable_item.value().source)
<< "previous declaration here");
return false;
}
@@ -572,9 +582,10 @@ bool ResourceTable::AddResource(NewResource&& res, IDiagnostics* diag) {
break;
case CollisionResult::kConflict:
- diag->Error(DiagMessage(source) << "duplicate value for resource '" << res.name << "' "
- << "with config '" << res.config << "'");
- diag->Error(DiagMessage(source) << "resource previously defined here");
+ diag->Error(android::DiagMessage(source)
+ << "duplicate value for resource '" << res.name << "' "
+ << "with config '" << res.config << "'");
+ diag->Error(android::DiagMessage(source) << "resource previously defined here");
return false;
case CollisionResult::kKeepOriginal:
@@ -593,7 +604,7 @@ std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(
return {};
}
- ResourceTableType* type = package->FindType(name.type.type);
+ ResourceTableType* type = package->FindType(name.type);
if (type == nullptr) {
return {};
}
@@ -612,7 +623,7 @@ std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(const Res
return {};
}
- ResourceTableType* type = package->FindType(name.type.type);
+ ResourceTableType* type = package->FindType(name.type);
if (type == nullptr) {
return {};
}
@@ -633,7 +644,7 @@ bool ResourceTable::RemoveResource(const ResourceNameRef& name, ResourceId id) c
return {};
}
- ResourceTableType* type = package->FindType(name.type.type);
+ ResourceTableType* type = package->FindType(name.type);
if (type == nullptr) {
return {};
}
@@ -655,7 +666,7 @@ std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
for (const auto& pkg : packages) {
ResourceTablePackage* new_pkg = new_table->FindOrCreatePackage(pkg->name);
for (const auto& type : pkg->types) {
- ResourceTableType* new_type = new_pkg->FindOrCreateType(type->type);
+ ResourceTableType* new_type = new_pkg->FindOrCreateType(type->named_type);
new_type->visibility_level = type->visibility_level;
for (const auto& entry : type->entries) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 2e17659b0679..bb286a8abdaa 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -17,17 +17,6 @@
#ifndef AAPT_RESOURCE_TABLE_H
#define AAPT_RESOURCE_TABLE_H
-#include "Diagnostics.h"
-#include "Resource.h"
-#include "ResourceValues.h"
-#include "Source.h"
-#include "StringPool.h"
-#include "io/File.h"
-
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/StringPiece.h"
-
#include <functional>
#include <map>
#include <memory>
@@ -36,6 +25,16 @@
#include <unordered_map>
#include <vector>
+#include "Resource.h"
+#include "ResourceValues.h"
+#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
+#include "androidfw/StringPiece.h"
+#include "androidfw/StringPool.h"
+#include "io/File.h"
+
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace aapt {
@@ -49,7 +48,7 @@ struct Visibility {
};
Level level = Level::kUndefined;
- Source source;
+ android::Source source;
std::string comment;
// Indicates that the resource id may change across builds and that the public R.java identifier
@@ -60,28 +59,28 @@ struct Visibility {
// Represents <add-resource> in an overlay.
struct AllowNew {
- Source source;
+ android::Source source;
std::string comment;
};
// Represents the staged resource id of a finalized resource.
struct StagedId {
ResourceId id;
- Source source;
+ android::Source source;
};
struct Overlayable {
Overlayable() = default;
- Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
- : name(name.to_string()), actor(actor.to_string()) {}
- Overlayable(const android::StringPiece& name, const android::StringPiece& actor,
- const Source& source)
- : name(name.to_string()), actor(actor.to_string()), source(source ){}
+ Overlayable(android::StringPiece name, android::StringPiece actor) : name(name), actor(actor) {
+ }
+ Overlayable(android::StringPiece name, android::StringPiece actor, const android::Source& source)
+ : name(name), actor(actor), source(source) {
+ }
static const char* kActorScheme;
std::string name;
std::string actor;
- Source source;
+ android::Source source;
};
// Represents a declaration that a resource is overlayable at runtime.
@@ -91,7 +90,7 @@ struct OverlayableItem {
std::shared_ptr<Overlayable> overlayable;
PolicyFlags policies = PolicyFlags::NONE;
std::string comment;
- Source source;
+ android::Source source;
};
class ResourceConfigValue {
@@ -105,8 +104,9 @@ class ResourceConfigValue {
// The actual Value.
std::unique_ptr<Value> value;
- ResourceConfigValue(const android::ConfigDescription& config, const android::StringPiece& product)
- : config(config), product(product.to_string()) {}
+ ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product)
+ : config(config), product(product) {
+ }
private:
DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
@@ -136,7 +136,8 @@ class ResourceEntry {
// The resource's values for each configuration.
std::vector<std::unique_ptr<ResourceConfigValue>> values;
- explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
+ explicit ResourceEntry(android::StringPiece name) : name(name) {
+ }
ResourceConfigValue* FindValue(const android::ConfigDescription& config,
android::StringPiece product = {});
@@ -144,7 +145,7 @@ class ResourceEntry {
android::StringPiece product = {}) const;
ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config,
- const android::StringPiece& product);
+ android::StringPiece product);
std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config);
template <typename Func>
@@ -168,7 +169,7 @@ class ResourceEntry {
class ResourceTableType {
public:
// The logical type of resource (string, drawable, layout, etc.).
- const ResourceType type;
+ const ResourceNamedType named_type;
// Whether this type is public (and must maintain the same type ID across builds).
Visibility::Level visibility_level = Visibility::Level::kUndefined;
@@ -176,11 +177,13 @@ class ResourceTableType {
// List of resources for this type.
std::vector<std::unique_ptr<ResourceEntry>> entries;
- explicit ResourceTableType(const ResourceType type) : type(type) {}
+ explicit ResourceTableType(const ResourceNamedTypeRef& type)
+ : named_type(type.ToResourceNamedType()) {
+ }
- ResourceEntry* CreateEntry(const android::StringPiece& name);
- ResourceEntry* FindEntry(const android::StringPiece& name) const;
- ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
+ ResourceEntry* CreateEntry(android::StringPiece name);
+ ResourceEntry* FindEntry(android::StringPiece name) const;
+ ResourceEntry* FindOrCreateEntry(android::StringPiece name);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
@@ -192,12 +195,13 @@ class ResourceTablePackage {
std::vector<std::unique_ptr<ResourceTableType>> types;
- explicit ResourceTablePackage(const android::StringPiece& name) : name(name.to_string()) {
+ explicit ResourceTablePackage(android::StringPiece name) : name(name) {
}
ResourceTablePackage() = default;
- ResourceTableType* FindType(ResourceType type) const;
- ResourceTableType* FindOrCreateType(ResourceType type);
+ ResourceTableType* FindTypeWithDefaultName(const ResourceType type) const;
+ ResourceTableType* FindType(const ResourceNamedTypeRef& type) const;
+ ResourceTableType* FindOrCreateType(const ResourceNamedTypeRef& type);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
@@ -217,7 +221,7 @@ struct ResourceTableEntryView {
};
struct ResourceTableTypeView {
- ResourceType type;
+ ResourceNamedType named_type;
std::optional<uint8_t> id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
@@ -297,7 +301,7 @@ class ResourceTable {
ResourceTable() = default;
explicit ResourceTable(Validation validation);
- bool AddResource(NewResource&& res, IDiagnostics* diag);
+ bool AddResource(NewResource&& res, android::IDiagnostics* diag);
// Retrieves a sorted a view of the packages, types, and entries sorted in ascending resource id
// order.
@@ -316,8 +320,8 @@ class ResourceTable {
// Returns the package struct with the given name, or nullptr if such a package does not
// exist. The empty string is a valid package and typically is used to represent the
// 'current' package before it is known to the ResourceTable.
- ResourceTablePackage* FindPackage(const android::StringPiece& name) const;
- ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name);
+ ResourceTablePackage* FindPackage(android::StringPiece name) const;
+ ResourceTablePackage* FindOrCreatePackage(android::StringPiece name);
std::unique_ptr<ResourceTable> Clone() const;
@@ -330,7 +334,7 @@ class ResourceTable {
// When `string_pool` references are destroyed (as they will be when `packages` is destroyed),
// they decrement a refCount, which would cause invalid memory access if the pool was already
// destroyed.
- StringPool string_pool;
+ android::StringPool string_pool;
// The list of packages in this table, sorted alphabetically by package name and increasing
// package ID (missing ID being the lowest).
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index de73d2c203e4..54b98d13aa0a 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -15,15 +15,16 @@
*/
#include "ResourceTable.h"
-#include "Diagnostics.h"
-#include "ResourceValues.h"
-#include "test/Test.h"
-#include "util/Util.h"
#include <algorithm>
#include <ostream>
#include <string>
+#include "ResourceValues.h"
+#include "androidfw/IDiagnostics.h"
+#include "test/Test.h"
+#include "util/Util.h"
+
using ::android::ConfigDescription;
using ::android::StringPiece;
using ::testing::Eq;
@@ -186,7 +187,7 @@ static StringPiece LevelToString(Visibility::Level level) {
static ::testing::AssertionResult VisibilityOfResource(const ResourceTable& table,
const ResourceNameRef& name,
Visibility::Level level,
- const StringPiece& comment) {
+ StringPiece comment) {
std::optional<ResourceTable::SearchResult> result = table.FindResource(name);
if (!result) {
return ::testing::AssertionFailure() << "no resource '" << name << "' found in table";
@@ -263,13 +264,13 @@ TEST(ResourceTableTest, SetAllowNew) {
TEST(ResourceTableTest, SetOverlayable) {
ResourceTable table;
- auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme",
- Source("res/values/overlayable.xml", 40));
+ auto overlayable = std::make_shared<Overlayable>(
+ "Name", "overlay://theme", android::Source("res/values/overlayable.xml", 40));
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
overlayable_item.comment = "comment";
- overlayable_item.source = Source("res/values/overlayable.xml", 42);
+ overlayable_item.source = android::Source("res/values/overlayable.xml", 42);
const ResourceName name = test::ParseNameOrDie("android:string/foo");
ASSERT_TRUE(table.AddResource(NewResourceBuilder(name).SetOverlayable(overlayable_item).Build(),
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 3787f3b96f08..5a118a902963 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -40,6 +40,24 @@ using ::android::base::StringPrintf;
namespace aapt {
namespace ResourceUtils {
+static std::optional<ResourceNamedType> ToResourceNamedType(const char16_t* type16,
+ const char* type, size_t type_len) {
+ std::optional<ResourceNamedTypeRef> parsed_type;
+ std::string converted;
+ if (type16) {
+ converted = android::util::Utf16ToUtf8(StringPiece16(type16, type_len));
+ parsed_type = ParseResourceNamedType(converted);
+ } else if (type) {
+ parsed_type = ParseResourceNamedType(StringPiece(type, type_len));
+ } else {
+ return {};
+ }
+ if (!parsed_type) {
+ return {};
+ }
+ return parsed_type->ToResourceNamedType();
+}
+
std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name_in) {
// TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
ResourceName name_out;
@@ -47,29 +65,17 @@ std::optional<ResourceName> ToResourceName(const android::ResTable::resource_nam
return {};
}
- name_out.package =
- util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen));
-
- std::optional<ResourceNamedTypeRef> type;
- std::string converted;
- if (name_in.type) {
- converted = util::Utf16ToUtf8(StringPiece16(name_in.type, name_in.typeLen));
- type = ParseResourceNamedType(converted);
- } else if (name_in.type8) {
- type = ParseResourceNamedType(StringPiece(name_in.type8, name_in.typeLen));
- } else {
- return {};
- }
+ name_out.package = android::util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen));
+ std::optional<ResourceNamedType> type =
+ ToResourceNamedType(name_in.type, name_in.name8, name_in.typeLen);
if (!type) {
return {};
}
-
- name_out.type = type->ToResourceNamedType();
+ name_out.type = *type;
if (name_in.name) {
- name_out.entry =
- util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen));
+ name_out.entry = android::util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen));
} else if (name_in.name8) {
name_out.entry.assign(name_in.name8, name_in.nameLen);
} else {
@@ -86,26 +92,15 @@ std::optional<ResourceName> ToResourceName(const android::AssetManager2::Resourc
name_out.package = std::string(name_in.package, name_in.package_len);
- std::optional<ResourceNamedTypeRef> type;
- std::string converted;
- if (name_in.type16) {
- converted = util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len));
- type = ParseResourceNamedType(converted);
- } else if (name_in.type) {
- type = ParseResourceNamedType(StringPiece(name_in.type, name_in.type_len));
- } else {
- return {};
- }
-
+ std::optional<ResourceNamedType> type =
+ ToResourceNamedType(name_in.type16, name_in.type, name_in.type_len);
if (!type) {
return {};
}
-
- name_out.type = type->ToResourceNamedType();
+ name_out.type = *type;
if (name_in.entry16) {
- name_out.entry =
- util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len));
+ name_out.entry = android::util::Utf16ToUtf8(StringPiece16(name_in.entry16, name_in.entry_len));
} else if (name_in.entry) {
name_out.entry = std::string(name_in.entry, name_in.entry_len);
} else {
@@ -114,8 +109,7 @@ std::optional<ResourceName> ToResourceName(const android::AssetManager2::Resourc
return name_out;
}
-bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
- bool* out_private) {
+bool ParseResourceName(StringPiece str, ResourceNameRef* out_ref, bool* out_private) {
if (str.empty()) {
return false;
}
@@ -156,8 +150,8 @@ bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
return true;
}
-bool ParseReference(const StringPiece& str, ResourceNameRef* out_ref,
- bool* out_create, bool* out_private) {
+bool ParseReference(StringPiece str, ResourceNameRef* out_ref, bool* out_create,
+ bool* out_private) {
StringPiece trimmed_str(util::TrimWhitespace(str));
if (trimmed_str.empty()) {
return false;
@@ -203,11 +197,11 @@ bool ParseReference(const StringPiece& str, ResourceNameRef* out_ref,
return false;
}
-bool IsReference(const StringPiece& str) {
+bool IsReference(StringPiece str) {
return ParseReference(str, nullptr, nullptr, nullptr);
}
-bool ParseAttributeReference(const StringPiece& str, ResourceNameRef* out_ref) {
+bool ParseAttributeReference(StringPiece str, ResourceNameRef* out_ref) {
StringPiece trimmed_str(util::TrimWhitespace(str));
if (trimmed_str.empty()) {
return false;
@@ -240,7 +234,7 @@ bool ParseAttributeReference(const StringPiece& str, ResourceNameRef* out_ref) {
return false;
}
-bool IsAttributeReference(const StringPiece& str) {
+bool IsAttributeReference(StringPiece str) {
return ParseAttributeReference(str, nullptr);
}
@@ -252,7 +246,7 @@ bool IsAttributeReference(const StringPiece& str) {
* <[*]package>:[style/]<entry>
* [[*]package:style/]<entry>
*/
-std::optional<Reference> ParseStyleParentReference(const StringPiece& str, std::string* out_error) {
+std::optional<Reference> ParseStyleParentReference(StringPiece str, std::string* out_error) {
if (str.empty()) {
return {};
}
@@ -301,7 +295,7 @@ std::optional<Reference> ParseStyleParentReference(const StringPiece& str, std::
return result;
}
-std::optional<Reference> ParseXmlAttributeName(const StringPiece& str) {
+std::optional<Reference> ParseXmlAttributeName(StringPiece str) {
StringPiece trimmed_str = util::TrimWhitespace(str);
const char* start = trimmed_str.data();
const char* const end = start + trimmed_str.size();
@@ -330,8 +324,7 @@ std::optional<Reference> ParseXmlAttributeName(const StringPiece& str) {
return std::optional<Reference>(std::move(ref));
}
-std::unique_ptr<Reference> TryParseReference(const StringPiece& str,
- bool* out_create) {
+std::unique_ptr<Reference> TryParseReference(StringPiece str, bool* out_create) {
ResourceNameRef ref;
bool private_ref = false;
if (ParseReference(str, &ref, out_create, &private_ref)) {
@@ -349,7 +342,7 @@ std::unique_ptr<Reference> TryParseReference(const StringPiece& str,
return {};
}
-std::unique_ptr<Item> TryParseNullOrEmpty(const StringPiece& str) {
+std::unique_ptr<Item> TryParseNullOrEmpty(StringPiece str) {
const StringPiece trimmed_str(util::TrimWhitespace(str));
if (trimmed_str == "@null") {
return MakeNull();
@@ -370,8 +363,7 @@ std::unique_ptr<BinaryPrimitive> MakeEmpty() {
android::Res_value::DATA_NULL_EMPTY);
}
-std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
- const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr, StringPiece str) {
StringPiece trimmed_str(util::TrimWhitespace(str));
for (const Attribute::Symbol& symbol : enum_attr->symbols) {
// Enum symbols are stored as @package:id/symbol resources,
@@ -387,8 +379,7 @@ std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
return {};
}
-std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr,
- const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr, StringPiece str) {
android::Res_value flags = {};
flags.dataType = android::Res_value::TYPE_INT_HEX;
flags.data = 0u;
@@ -398,7 +389,7 @@ std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr,
return util::make_unique<BinaryPrimitive>(flags);
}
- for (const StringPiece& part : util::Tokenize(str, '|')) {
+ for (StringPiece part : util::Tokenize(str, '|')) {
StringPiece trimmed_part = util::TrimWhitespace(part);
bool flag_set = false;
@@ -434,7 +425,7 @@ static uint32_t ParseHex(char c, bool* out_error) {
}
}
-std::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseColor(StringPiece str) {
StringPiece color_str(util::TrimWhitespace(str));
const char* start = color_str.data();
const size_t len = color_str.size();
@@ -489,7 +480,7 @@ std::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str) {
: util::make_unique<BinaryPrimitive>(value);
}
-std::optional<bool> ParseBool(const StringPiece& str) {
+std::optional<bool> ParseBool(StringPiece str) {
StringPiece trimmed_str(util::TrimWhitespace(str));
if (trimmed_str == "true" || trimmed_str == "TRUE" || trimmed_str == "True") {
return std::optional<bool>(true);
@@ -500,8 +491,8 @@ std::optional<bool> ParseBool(const StringPiece& str) {
return {};
}
-std::optional<uint32_t> ParseInt(const StringPiece& str) {
- std::u16string str16 = util::Utf8ToUtf16(str);
+std::optional<uint32_t> ParseInt(StringPiece str) {
+ std::u16string str16 = android::util::Utf8ToUtf16(str);
android::Res_value value;
if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return value.data;
@@ -509,10 +500,10 @@ std::optional<uint32_t> ParseInt(const StringPiece& str) {
return {};
}
-std::optional<ResourceId> ParseResourceId(const StringPiece& str) {
+std::optional<ResourceId> ParseResourceId(StringPiece str) {
StringPiece trimmed_str(util::TrimWhitespace(str));
- std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
+ std::u16string str16 = android::util::Utf8ToUtf16(trimmed_str);
android::Res_value value;
if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
if (value.dataType == android::Res_value::TYPE_INT_HEX) {
@@ -525,10 +516,10 @@ std::optional<ResourceId> ParseResourceId(const StringPiece& str) {
return {};
}
-std::optional<int> ParseSdkVersion(const StringPiece& str) {
+std::optional<int> ParseSdkVersion(StringPiece str) {
StringPiece trimmed_str(util::TrimWhitespace(str));
- std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
+ std::u16string str16 = android::util::Utf8ToUtf16(trimmed_str);
android::Res_value value;
if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return static_cast<int>(value.data);
@@ -544,14 +535,14 @@ std::optional<int> ParseSdkVersion(const StringPiece& str) {
const StringPiece::const_iterator begin = std::begin(trimmed_str);
const StringPiece::const_iterator end = std::end(trimmed_str);
const StringPiece::const_iterator codename_end = std::find(begin, end, '.');
- entry = GetDevelopmentSdkCodeNameVersion(trimmed_str.substr(begin, codename_end));
+ entry = GetDevelopmentSdkCodeNameVersion(StringPiece(begin, codename_end - begin));
if (entry) {
return entry.value();
}
return {};
}
-std::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseBool(StringPiece str) {
if (std::optional<bool> maybe_result = ParseBool(str)) {
const uint32_t data = maybe_result.value() ? 0xffffffffu : 0u;
return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, data);
@@ -564,8 +555,8 @@ std::unique_ptr<BinaryPrimitive> MakeBool(bool val) {
val ? 0xffffffffu : 0u);
}
-std::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str) {
- std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
+std::unique_ptr<BinaryPrimitive> TryParseInt(StringPiece str) {
+ std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
if (!android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
return {};
@@ -577,8 +568,8 @@ std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t val) {
return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, val);
}
-std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
- std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
+std::unique_ptr<BinaryPrimitive> TryParseFloat(StringPiece str) {
+ std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
if (!android::ResTable::stringToFloat(str16.data(), str16.size(), &value)) {
return {};
@@ -628,7 +619,7 @@ uint32_t AndroidTypeToAttributeTypeMask(uint16_t type) {
}
std::unique_ptr<Item> TryParseItemForAttribute(
- const StringPiece& value, uint32_t type_mask,
+ StringPiece value, uint32_t type_mask,
const std::function<bool(const ResourceName&)>& on_create_reference) {
using android::ResTable_map;
@@ -692,7 +683,7 @@ std::unique_ptr<Item> TryParseItemForAttribute(
* allows.
*/
std::unique_ptr<Item> TryParseItemForAttribute(
- const StringPiece& str, const Attribute* attr,
+ StringPiece str, const Attribute* attr,
const std::function<bool(const ResourceName&)>& on_create_reference) {
using android::ResTable_map;
@@ -740,7 +731,7 @@ std::string BuildResourceFileName(const ResourceFile& res_file, const NameMangle
std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const ConfigDescription& config,
const android::ResStringPool& src_pool,
const android::Res_value& res_value,
- StringPool* dst_pool) {
+ android::StringPool* dst_pool) {
if (type == ResourceType::kId) {
if (res_value.dataType != android::Res_value::TYPE_REFERENCE &&
res_value.dataType != android::Res_value::TYPE_DYNAMIC_REFERENCE) {
@@ -751,30 +742,32 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config
// fall through to regular reference deserialization logic
}
- const uint32_t data = util::DeviceToHost32(res_value.data);
+ const uint32_t data = android::util::DeviceToHost32(res_value.data);
switch (res_value.dataType) {
case android::Res_value::TYPE_STRING: {
- const std::string str = util::GetString(src_pool, data);
+ const std::string str = android::util::GetString(src_pool, data);
auto spans_result = src_pool.styleAt(data);
// Check if the string has a valid style associated with it.
if (spans_result.has_value() &&
(*spans_result)->name.index != android::ResStringPool_span::END) {
const android::ResStringPool_span* spans = spans_result->unsafe_ptr();
- StyleString style_str = {str};
+ android::StyleString style_str = {str};
while (spans->name.index != android::ResStringPool_span::END) {
- style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index),
- spans->firstChar, spans->lastChar});
+ style_str.spans.push_back(
+ android::Span{android::util::GetString(src_pool, spans->name.index), spans->firstChar,
+ spans->lastChar});
spans++;
}
return util::make_unique<StyledString>(dst_pool->MakeRef(
- style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ style_str,
+ android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
} else {
if (type != ResourceType::kString && util::StartsWith(str, "res/")) {
// This must be a FileReference.
- std::unique_ptr<FileReference> file_ref =
- util::make_unique<FileReference>(dst_pool->MakeRef(
- str, StringPool::Context(StringPool::Context::kHighPriority, config)));
+ std::unique_ptr<FileReference> file_ref = util::make_unique<FileReference>(
+ dst_pool->MakeRef(str, android::StringPool::Context(
+ android::StringPool::Context::kHighPriority, config)));
if (type == ResourceType::kRaw) {
file_ref->type = ResourceFile::Type::kUnknown;
} else if (util::EndsWith(*file_ref->path, ".xml")) {
@@ -786,7 +779,8 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config
}
// There are no styles associated with this string, so treat it as a simple string.
- return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config)));
+ return util::make_unique<String>(
+ dst_pool->MakeRef(str, android::StringPool::Context(config)));
}
} break;
@@ -953,7 +947,7 @@ StringBuilder::SpanHandle StringBuilder::StartSpan(const std::string& name) {
// When we start a span, all state associated with whitespace truncation and quotation is ended.
ResetTextState();
- Span span;
+ android::Span span;
span.name = name;
span.first_char = span.last_char = utf16_len_;
xml_string_.spans.push_back(std::move(span));
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index fe450a834dfa..f30f4acfec7a 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -20,15 +20,14 @@
#include <functional>
#include <memory>
+#include "NameMangler.h"
+#include "Resource.h"
+#include "ResourceValues.h"
#include "androidfw/AssetManager2.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
-
-#include "NameMangler.h"
-#include "Resource.h"
-#include "ResourceValues.h"
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
namespace aapt {
namespace ResourceUtils {
@@ -39,7 +38,7 @@ namespace ResourceUtils {
* `out_resource` set to the parsed resource name and `out_private` set to true
* if a '*' prefix was present.
*/
-bool ParseResourceName(const android::StringPiece& str, ResourceNameRef* out_resource,
+bool ParseResourceName(android::StringPiece str, ResourceNameRef* out_resource,
bool* out_private = nullptr);
/*
@@ -50,27 +49,27 @@ bool ParseResourceName(const android::StringPiece& str, ResourceNameRef* out_res
* If '+' was present in the reference, `out_create` is set to true.
* If '*' was present in the reference, `out_private` is set to true.
*/
-bool ParseReference(const android::StringPiece& str, ResourceNameRef* out_reference,
+bool ParseReference(android::StringPiece str, ResourceNameRef* out_reference,
bool* out_create = nullptr, bool* out_private = nullptr);
/*
* Returns true if the string is in the form of a resource reference
* (@[+][package:]type/name).
*/
-bool IsReference(const android::StringPiece& str);
+bool IsReference(android::StringPiece str);
/*
* Returns true if the string was parsed as an attribute reference
* (?[package:][type/]name),
* with `out_reference` set to the parsed reference.
*/
-bool ParseAttributeReference(const android::StringPiece& str, ResourceNameRef* out_reference);
+bool ParseAttributeReference(android::StringPiece str, ResourceNameRef* out_reference);
/**
* Returns true if the string is in the form of an attribute
* reference(?[package:][type/]name).
*/
-bool IsAttributeReference(const android::StringPiece& str);
+bool IsAttributeReference(android::StringPiece str);
/**
* Convert an android::ResTable::resource_name to an aapt::ResourceName struct.
@@ -86,22 +85,22 @@ std::optional<ResourceName> ToResourceName(const android::AssetManager2::Resourc
* Returns a boolean value if the string is equal to TRUE, true, True, FALSE,
* false, or False.
*/
-std::optional<bool> ParseBool(const android::StringPiece& str);
+std::optional<bool> ParseBool(android::StringPiece str);
/**
* Returns a uint32_t if the string is an integer.
*/
-std::optional<uint32_t> ParseInt(const android::StringPiece& str);
+std::optional<uint32_t> ParseInt(android::StringPiece str);
/**
* Returns an ID if it the string represented a valid ID.
*/
-std::optional<ResourceId> ParseResourceId(const android::StringPiece& str);
+std::optional<ResourceId> ParseResourceId(android::StringPiece str);
/**
* Parses an SDK version, which can be an integer, or a letter from A-Z.
*/
-std::optional<int> ParseSdkVersion(const android::StringPiece& str);
+std::optional<int> ParseSdkVersion(android::StringPiece str);
/*
* Returns a Reference, or None Maybe instance if the string `str` was parsed as
@@ -114,7 +113,7 @@ std::optional<int> ParseSdkVersion(const android::StringPiece& str);
* ?[package:]style/<entry> or
* <package>:[style/]<entry>
*/
-std::optional<Reference> ParseStyleParentReference(const android::StringPiece& str,
+std::optional<Reference> ParseStyleParentReference(android::StringPiece str,
std::string* out_error);
/*
@@ -124,7 +123,7 @@ std::optional<Reference> ParseStyleParentReference(const android::StringPiece& s
*
* package:entry
*/
-std::optional<Reference> ParseXmlAttributeName(const android::StringPiece& str);
+std::optional<Reference> ParseXmlAttributeName(android::StringPiece str);
/*
* Returns a Reference object if the string was parsed as a resource or
@@ -133,14 +132,13 @@ std::optional<Reference> ParseXmlAttributeName(const android::StringPiece& str);
* if
* the '+' was present in the string.
*/
-std::unique_ptr<Reference> TryParseReference(const android::StringPiece& str,
- bool* out_create = nullptr);
+std::unique_ptr<Reference> TryParseReference(android::StringPiece str, bool* out_create = nullptr);
/*
* Returns a BinaryPrimitve object representing @null or @empty if the string
* was parsed as one.
*/
-std::unique_ptr<Item> TryParseNullOrEmpty(const android::StringPiece& str);
+std::unique_ptr<Item> TryParseNullOrEmpty(android::StringPiece str);
// Returns a Reference representing @null.
// Due to runtime compatibility issues, this is encoded as a reference with ID 0.
@@ -155,13 +153,13 @@ std::unique_ptr<BinaryPrimitive> MakeEmpty();
* Returns a BinaryPrimitve object representing a color if the string was parsed
* as one.
*/
-std::unique_ptr<BinaryPrimitive> TryParseColor(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseColor(android::StringPiece str);
/*
* Returns a BinaryPrimitve object representing a boolean if the string was
* parsed as one.
*/
-std::unique_ptr<BinaryPrimitive> TryParseBool(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseBool(android::StringPiece str);
// Returns a boolean BinaryPrimitive.
std::unique_ptr<BinaryPrimitive> MakeBool(bool val);
@@ -170,7 +168,7 @@ std::unique_ptr<BinaryPrimitive> MakeBool(bool val);
* Returns a BinaryPrimitve object representing an integer if the string was
* parsed as one.
*/
-std::unique_ptr<BinaryPrimitive> TryParseInt(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseInt(android::StringPiece str);
// Returns an integer BinaryPrimitive.
std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value);
@@ -179,21 +177,21 @@ std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value);
* Returns a BinaryPrimitve object representing a floating point number
* (float, dimension, etc) if the string was parsed as one.
*/
-std::unique_ptr<BinaryPrimitive> TryParseFloat(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseFloat(android::StringPiece str);
/*
* Returns a BinaryPrimitve object representing an enum symbol if the string was
* parsed as one.
*/
std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
- const android::StringPiece& str);
+ android::StringPiece str);
/*
* Returns a BinaryPrimitve object representing a flag symbol if the string was
* parsed as one.
*/
std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr,
- const android::StringPiece& str);
+ android::StringPiece str);
/*
* Try to convert a string to an Item for the given attribute. The attribute
* will
@@ -202,11 +200,11 @@ std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr,
* reference to an ID that must be created (@+id/foo).
*/
std::unique_ptr<Item> TryParseItemForAttribute(
- const android::StringPiece& value, const Attribute* attr,
+ android::StringPiece value, const Attribute* attr,
const std::function<bool(const ResourceName&)>& on_create_reference = {});
std::unique_ptr<Item> TryParseItemForAttribute(
- const android::StringPiece& value, uint32_t type_mask,
+ android::StringPiece value, uint32_t type_mask,
const std::function<bool(const ResourceName&)>& on_create_reference = {});
uint32_t AndroidTypeToAttributeTypeMask(uint16_t type);
@@ -230,14 +228,14 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type,
const android::ConfigDescription& config,
const android::ResStringPool& src_pool,
const android::Res_value& res_value,
- StringPool* dst_pool);
+ android::StringPool* dst_pool);
// A string flattened from an XML hierarchy, which maintains tags and untranslatable sections
// in parallel data structures.
struct FlattenedXmlString {
std::string text;
std::vector<UntranslatableSection> untranslatable_sections;
- std::vector<Span> spans;
+ std::vector<android::Span> spans;
};
// Flattens an XML hierarchy into a FlattenedXmlString, formatting the text, escaping characters,
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 1aaa34deee79..568871a4d66e 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -111,7 +111,7 @@ TEST(ResourceUtilsTest, ParsePrivateReference) {
TEST(ResourceUtilsTest, ParseBinaryDynamicReference) {
android::Res_value value = {};
- value.data = util::HostToDevice32(0x01);
+ value.data = android::util::HostToDevice32(0x01);
value.dataType = android::Res_value::TYPE_DYNAMIC_REFERENCE;
std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(ResourceType::kId,
android::ConfigDescription(),
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index b796eb07f076..a5754e0d168f 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -75,7 +75,8 @@ void BaseItem<Derived>::Accept(ConstValueVisitor* visitor) const {
visitor->Visit(static_cast<const Derived*>(this));
}
-RawString::RawString(const StringPool::Ref& ref) : value(ref) {}
+RawString::RawString(const android::StringPool::Ref& ref) : value(ref) {
+}
bool RawString::Equals(const Value* value) const {
const RawString* other = ValueCast<RawString>(value);
@@ -87,7 +88,7 @@ bool RawString::Equals(const Value* value) const {
bool RawString::Flatten(android::Res_value* out_value) const {
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
return true;
}
@@ -136,7 +137,7 @@ bool Reference::Flatten(android::Res_value* out_value) const {
out_value->dataType = android::Res_value::TYPE_ATTRIBUTE;
}
}
- out_value->data = util::HostToDevice32(resid.id);
+ out_value->data = android::util::HostToDevice32(resid.id);
return true;
}
@@ -205,7 +206,7 @@ void Reference::PrettyPrint(Printer* printer) const {
PrettyPrintReferenceImpl(*this, true /*print_package*/, printer);
}
-void Reference::PrettyPrint(const StringPiece& package, Printer* printer) const {
+void Reference::PrettyPrint(StringPiece package, Printer* printer) const {
const bool print_package = name ? package != name.value().package : true;
PrettyPrintReferenceImpl(*this, print_package, printer);
}
@@ -216,7 +217,7 @@ bool Id::Equals(const Value* value) const {
bool Id::Flatten(android::Res_value* out) const {
out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
- out->data = util::HostToDevice32(0);
+ out->data = android::util::HostToDevice32(0);
return true;
}
@@ -224,7 +225,7 @@ void Id::Print(std::ostream* out) const {
*out << "(id)";
}
-String::String(const StringPool::Ref& ref) : value(ref) {
+String::String(const android::StringPool::Ref& ref) : value(ref) {
}
bool String::Equals(const Value* value) const {
@@ -258,7 +259,7 @@ bool String::Flatten(android::Res_value* out_value) const {
}
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
return true;
}
@@ -272,7 +273,7 @@ void String::PrettyPrint(Printer* printer) const {
printer->Print("\"");
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+StyledString::StyledString(const android::StringPool::StyleRef& ref) : value(ref) {
}
bool StyledString::Equals(const Value* value) const {
@@ -305,18 +306,18 @@ bool StyledString::Flatten(android::Res_value* out_value) const {
}
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(value.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(value.index()));
return true;
}
void StyledString::Print(std::ostream* out) const {
*out << "(styled string) \"" << value->value << "\"";
- for (const StringPool::Span& span : value->spans) {
+ for (const android::StringPool::Span& span : value->spans) {
*out << " " << *span.name << ":" << span.first_char << "," << span.last_char;
}
}
-FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
+FileReference::FileReference(const android::StringPool::Ref& _path) : path(_path) {
}
bool FileReference::Equals(const Value* value) const {
@@ -333,7 +334,7 @@ bool FileReference::Flatten(android::Res_value* out_value) const {
}
out_value->dataType = android::Res_value::TYPE_STRING;
- out_value->data = util::HostToDevice32(static_cast<uint32_t>(path.index()));
+ out_value->data = android::util::HostToDevice32(static_cast<uint32_t>(path.index()));
return true;
}
@@ -373,7 +374,7 @@ bool BinaryPrimitive::Equals(const Value* value) const {
bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
out_value->dataType = value.dataType;
- out_value->data = util::HostToDevice32(value.data);
+ out_value->data = android::util::HostToDevice32(value.data);
return true;
}
@@ -678,7 +679,7 @@ void Attribute::Print(std::ostream* out) const {
}
static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& value,
- DiagMessage* out_msg) {
+ android::DiagMessage* out_msg) {
*out_msg << "expected";
if (attr.type_mask & android::ResTable_map::TYPE_BOOLEAN) {
*out_msg << " boolean";
@@ -723,7 +724,7 @@ static void BuildAttributeMismatchMessage(const Attribute& attr, const Item& val
*out_msg << " but got " << value;
}
-bool Attribute::Matches(const Item& item, DiagMessage* out_msg) const {
+bool Attribute::Matches(const Item& item, android::DiagMessage* out_msg) const {
constexpr const uint32_t TYPE_ENUM = android::ResTable_map::TYPE_ENUM;
constexpr const uint32_t TYPE_FLAGS = android::ResTable_map::TYPE_FLAGS;
constexpr const uint32_t TYPE_INTEGER = android::ResTable_map::TYPE_INTEGER;
@@ -732,7 +733,7 @@ bool Attribute::Matches(const Item& item, DiagMessage* out_msg) const {
android::Res_value val = {};
item.Flatten(&val);
- const uint32_t flattened_data = util::DeviceToHost32(val.data);
+ const uint32_t flattened_data = android::util::DeviceToHost32(val.data);
// Always allow references.
const uint32_t actual_type = ResourceUtils::AndroidTypeToAttributeTypeMask(val.dataType);
@@ -872,7 +873,7 @@ void Style::Print(std::ostream* out) const {
*out << " [" << util::Joiner(entries, ", ") << "]";
}
-Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) {
+Style::Entry CloneEntry(const Style::Entry& entry, android::StringPool* pool) {
Style::Entry cloned_entry{entry.key};
if (entry.value != nullptr) {
CloningValueTransformer cloner(pool);
@@ -881,7 +882,7 @@ Style::Entry CloneEntry(const Style::Entry& entry, StringPool* pool) {
return cloned_entry;
}
-void Style::MergeWith(Style* other, StringPool* pool) {
+void Style::MergeWith(Style* other, android::StringPool* pool) {
if (other->parent) {
parent = other->parent;
}
@@ -1077,7 +1078,7 @@ std::unique_ptr<T> CopyValueFields(std::unique_ptr<T> new_value, const T* value)
return new_value;
}
-CloningValueTransformer::CloningValueTransformer(StringPool* new_pool)
+CloningValueTransformer::CloningValueTransformer(android::StringPool* new_pool)
: ValueTransformer(new_pool) {
}
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 1694d6b6fe4a..6f9dccbd3bcc 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -22,13 +22,12 @@
#include <ostream>
#include <vector>
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
#include "Resource.h"
-#include "StringPool.h"
#include "ValueTransformer.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+#include "androidfw/StringPool.h"
#include "io/File.h"
#include "text/Printer.h"
@@ -67,15 +66,15 @@ class Value {
}
// Returns the source where this value was defined.
- const Source& GetSource() const {
+ const android::Source& GetSource() const {
return source_;
}
- void SetSource(const Source& source) {
+ void SetSource(const android::Source& source) {
source_ = source;
}
- void SetSource(Source&& source) {
+ void SetSource(android::Source&& source) {
source_ = std::move(source);
}
@@ -84,8 +83,8 @@ class Value {
return comment_;
}
- void SetComment(const android::StringPiece& str) {
- comment_ = str.to_string();
+ void SetComment(android::StringPiece str) {
+ comment_.assign(str);
}
void SetComment(std::string&& str) {
@@ -113,7 +112,7 @@ class Value {
friend std::ostream& operator<<(std::ostream& out, const Value& value);
protected:
- Source source_;
+ android::Source source_;
std::string comment_;
bool weak_ = false;
bool translatable_ = true;
@@ -177,7 +176,7 @@ struct Reference : public TransformableItem<Reference, BaseItem<Reference>> {
void PrettyPrint(text::Printer* printer) const override;
// Prints the reference without a package name if the package name matches the one given.
- void PrettyPrint(const android::StringPiece& package, text::Printer* printer) const;
+ void PrettyPrint(android::StringPiece package, text::Printer* printer) const;
};
bool operator<(const Reference&, const Reference&);
@@ -197,9 +196,9 @@ struct Id : public TransformableItem<Id, BaseItem<Id>> {
// A raw, unprocessed string. This may contain quotations, escape sequences, and whitespace.
// This shall *NOT* end up in the final resource table.
struct RawString : public TransformableItem<RawString, BaseItem<RawString>> {
- StringPool::Ref value;
+ android::StringPool::Ref value;
- explicit RawString(const StringPool::Ref& ref);
+ explicit RawString(const android::StringPool::Ref& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -225,14 +224,14 @@ inline bool operator!=(const UntranslatableSection& a, const UntranslatableSecti
}
struct String : public TransformableItem<String, BaseItem<String>> {
- StringPool::Ref value;
+ android::StringPool::Ref value;
// Sections of the string to NOT translate. Mainly used
// for pseudolocalization. This data is NOT persisted
// in any format.
std::vector<UntranslatableSection> untranslatable_sections;
- explicit String(const StringPool::Ref& ref);
+ explicit String(const android::StringPool::Ref& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -241,14 +240,14 @@ struct String : public TransformableItem<String, BaseItem<String>> {
};
struct StyledString : public TransformableItem<StyledString, BaseItem<StyledString>> {
- StringPool::StyleRef value;
+ android::StringPool::StyleRef value;
// Sections of the string to NOT translate. Mainly used
// for pseudolocalization. This data is NOT persisted
// in any format.
std::vector<UntranslatableSection> untranslatable_sections;
- explicit StyledString(const StringPool::StyleRef& ref);
+ explicit StyledString(const android::StringPool::StyleRef& ref);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -256,7 +255,7 @@ struct StyledString : public TransformableItem<StyledString, BaseItem<StyledStri
};
struct FileReference : public TransformableItem<FileReference, BaseItem<FileReference>> {
- StringPool::Ref path;
+ android::StringPool::Ref path;
// A handle to the file object from which this file can be read.
// This field is NOT persisted in any format. It is transient.
@@ -267,7 +266,7 @@ struct FileReference : public TransformableItem<FileReference, BaseItem<FileRefe
ResourceFile::Type type = ResourceFile::Type::kUnknown;
FileReference() = default;
- explicit FileReference(const StringPool::Ref& path);
+ explicit FileReference(const android::StringPool::Ref& path);
bool Equals(const Value* value) const override;
bool Flatten(android::Res_value* out_value) const override;
@@ -315,7 +314,7 @@ struct Attribute : public TransformableValue<Attribute, BaseValue<Attribute>> {
static std::string MaskString(uint32_t type_mask);
void Print(std::ostream* out) const override;
- bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const;
+ bool Matches(const Item& item, android::DiagMessage* out_msg = nullptr) const;
};
struct Style : public TransformableValue<Style, BaseValue<Style>> {
@@ -338,7 +337,7 @@ struct Style : public TransformableValue<Style, BaseValue<Style>> {
// Merges `style` into this Style. All identical attributes of `style` take precedence, including
// the parent, if there is one.
- void MergeWith(Style* style, StringPool* pool);
+ void MergeWith(Style* style, android::StringPool* pool);
};
struct Array : public TransformableValue<Array, BaseValue<Array>> {
@@ -367,7 +366,7 @@ struct Styleable : public TransformableValue<Styleable, BaseValue<Styleable>> {
struct Macro : public TransformableValue<Macro, BaseValue<Macro>> {
std::string raw_value;
- StyleString style_string;
+ android::StyleString style_string;
std::vector<UntranslatableSection> untranslatable_sections;
struct Namespace {
@@ -399,7 +398,7 @@ typename std::enable_if<std::is_base_of<Value, T>::value, std::ostream&>::type o
}
struct CloningValueTransformer : public ValueTransformer {
- explicit CloningValueTransformer(StringPool* new_pool);
+ explicit CloningValueTransformer(android::StringPool* new_pool);
std::unique_ptr<Reference> TransformDerived(const Reference* value) override;
std::unique_ptr<Id> TransformDerived(const Id* value) override;
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index c75a4b99e138..d788e3fd5fc7 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -37,7 +37,7 @@ constexpr const uint32_t TYPE_STRING = android::ResTable_map::TYPE_STRING;
} // namespace
TEST(ResourceValuesTest, PluralEquals) {
- StringPool pool;
+ android::StringPool pool;
Plural a;
a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
@@ -56,7 +56,7 @@ TEST(ResourceValuesTest, PluralEquals) {
}
TEST(ResourceValuesTest, PluralClone) {
- StringPool pool;
+ android::StringPool pool;
Plural a;
a.values[Plural::One] = util::make_unique<String>(pool.MakeRef("one"));
@@ -68,7 +68,7 @@ TEST(ResourceValuesTest, PluralClone) {
}
TEST(ResourceValuesTest, ArrayEquals) {
- StringPool pool;
+ android::StringPool pool;
Array a;
a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
@@ -92,7 +92,7 @@ TEST(ResourceValuesTest, ArrayEquals) {
}
TEST(ResourceValuesTest, ArrayClone) {
- StringPool pool;
+ android::StringPool pool;
Array a;
a.elements.push_back(util::make_unique<String>(pool.MakeRef("one")));
@@ -104,7 +104,7 @@ TEST(ResourceValuesTest, ArrayClone) {
}
TEST(ResourceValuesTest, StyleEquals) {
- StringPool pool;
+ android::StringPool pool;
std::unique_ptr<Style> a = test::StyleBuilder()
.SetParent("android:style/Parent")
@@ -168,10 +168,10 @@ TEST(ResourceValuesTest, StyleClone) {
}
TEST(ResourcesValuesTest, StringClones) {
- StringPool pool_a;
- StringPool pool_b;
+ android::StringPool pool_a;
+ android::StringPool pool_b;
- String str_a(pool_a.MakeRef("hello", StringPool::Context(test::ParseConfigOrDie("en"))));
+ String str_a(pool_a.MakeRef("hello", android::StringPool::Context(test::ParseConfigOrDie("en"))));
ASSERT_THAT(pool_a, SizeIs(1u));
EXPECT_THAT(pool_a.strings()[0]->context.config, Eq(test::ParseConfigOrDie("en")));
@@ -185,8 +185,8 @@ TEST(ResourcesValuesTest, StringClones) {
}
TEST(ResourceValuesTest, StyleMerges) {
- StringPool pool_a;
- StringPool pool_b;
+ android::StringPool pool_a;
+ android::StringPool pool_b;
std::unique_ptr<Style> a =
test::StyleBuilder()
@@ -204,7 +204,7 @@ TEST(ResourceValuesTest, StyleMerges) {
a->MergeWith(b.get(), &pool_a);
- StringPool pool;
+ android::StringPool pool;
std::unique_ptr<Style> expected =
test::StyleBuilder()
.SetParent("android:style/OverlayParent")
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
index 2c55d1d548db..01d3c84e05ba 100644
--- a/tools/aapt2/Resource_test.cpp
+++ b/tools/aapt2/Resource_test.cpp
@@ -135,13 +135,13 @@ TEST(ResourceTypeTest, ParseResourceNamedType) {
type = ParseResourceNamedType("layout");
EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout", ResourceType::kLayout))));
- type = ParseResourceNamedType("layout:2");
- EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:2", ResourceType::kLayout))));
+ type = ParseResourceNamedType("layout.2");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout.2", ResourceType::kLayout))));
- type = ParseResourceNamedType("layout:another");
- EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout:another", ResourceType::kLayout))));
+ type = ParseResourceNamedType("layout.another");
+ EXPECT_THAT(type, Optional(Eq(ResourceNamedType("layout.another", ResourceType::kLayout))));
- type = ParseResourceNamedType("layout:");
+ type = ParseResourceNamedType("layout.");
EXPECT_THAT(type, Eq(std::nullopt));
type = ParseResourceNamedType("layout2");
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 95b794964068..1d7fd1d17dcd 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -46,6 +46,13 @@ message ToolFingerprint {
string version = 2;
}
+// References to non local resources
+message DynamicRefTable {
+ PackageId package_id = 1;
+ string package_name = 2;
+}
+
+
// Top level message representing a resource table.
message ResourceTable {
// The string pool containing source paths referenced throughout the resource table. This does
@@ -60,6 +67,8 @@ message ResourceTable {
// The version fingerprints of the tools that built the resource table.
repeated ToolFingerprint tool_fingerprint = 4;
+
+ repeated DynamicRefTable dynamic_ref_table = 5;
}
// A package ID in the range [0x00, 0xff].
@@ -636,4 +645,4 @@ message StyleString {
message UntranslatableSection {
uint64 start_index = 1;
uint64 end_index = 2;
-} \ No newline at end of file
+}
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index e7b37704f3ea..a766bd437120 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -77,7 +77,7 @@ ApiVersion FindAttributeSdkLevel(const ResourceId& id) {
return iter->second;
}
-std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const StringPiece& code_name) {
+std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(StringPiece code_name) {
return (sDevelopmentSdkCodeNames.find(code_name) == sDevelopmentSdkCodeNames.end())
? std::optional<ApiVersion>()
: sDevelopmentSdkLevel;
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 0bd61c04f2b2..e47704ea2725 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -59,11 +59,12 @@ enum : ApiVersion {
SDK_S = 31,
SDK_S_V2 = 32,
SDK_TIRAMISU = 33,
+ SDK_UPSIDE_DOWN_CAKE = 34,
SDK_CUR_DEVELOPMENT = 10000,
};
ApiVersion FindAttributeSdkLevel(const ResourceId& id);
-std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const android::StringPiece& code_name);
+std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(android::StringPiece code_name);
} // namespace aapt
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
deleted file mode 100644
index 4f9369a5d517..000000000000
--- a/tools/aapt2/Source.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_SOURCE_H
-#define AAPT_SOURCE_H
-
-#include <optional>
-#include <ostream>
-#include <string>
-
-#include "android-base/stringprintf.h"
-#include "androidfw/StringPiece.h"
-
-namespace aapt {
-
-// Represents a file on disk. Used for logging and showing errors.
-struct Source {
- std::string path;
- std::optional<size_t> line;
- std::optional<std::string> archive;
-
- Source() = default;
-
- inline Source(const android::StringPiece& path) : path(path.to_string()) { // NOLINT(implicit)
- }
-
- inline Source(const android::StringPiece& path, const android::StringPiece& archive)
- : path(path.to_string()), archive(archive.to_string()) {}
-
- inline Source(const android::StringPiece& path, size_t line)
- : path(path.to_string()), line(line) {}
-
- inline Source WithLine(size_t line) const {
- return Source(path, line);
- }
-
- std::string to_string() const {
- std::string s = path;
- if (archive) {
- s = ::android::base::StringPrintf("%s@%s", archive.value().c_str(), s.c_str());
- }
- if (line) {
- s = ::android::base::StringPrintf("%s:%zd", s.c_str(), line.value());
- }
- return s;
- }
-};
-
-//
-// Implementations
-//
-
-inline ::std::ostream& operator<<(::std::ostream& out, const Source& source) {
- return out << source.to_string();
-}
-
-inline bool operator==(const Source& lhs, const Source& rhs) {
- return lhs.path == rhs.path && lhs.line == rhs.line;
-}
-
-inline bool operator<(const Source& lhs, const Source& rhs) {
- int cmp = lhs.path.compare(rhs.path);
- if (cmp < 0) return true;
- if (cmp > 0) return false;
- if (lhs.line) {
- if (rhs.line) {
- return lhs.line.value() < rhs.line.value();
- }
- return false;
- }
- return bool(rhs.line);
-}
-
-} // namespace aapt
-
-#endif // AAPT_SOURCE_H
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
deleted file mode 100644
index 8eabd3225d87..000000000000
--- a/tools/aapt2/StringPool.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "StringPool.h"
-
-#include <algorithm>
-#include <memory>
-#include <string>
-
-#include "android-base/logging.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
-#include "util/BigBuffer.h"
-#include "util/Util.h"
-
-using ::android::StringPiece;
-
-namespace aapt {
-
-StringPool::Ref::Ref() : entry_(nullptr) {}
-
-StringPool::Ref::Ref(const StringPool::Ref& rhs) : entry_(rhs.entry_) {
- if (entry_ != nullptr) {
- entry_->ref_++;
- }
-}
-
-StringPool::Ref::Ref(StringPool::Entry* entry) : entry_(entry) {
- if (entry_ != nullptr) {
- entry_->ref_++;
- }
-}
-
-StringPool::Ref::~Ref() {
- if (entry_ != nullptr) {
- entry_->ref_--;
- }
-}
-
-StringPool::Ref& StringPool::Ref::operator=(const StringPool::Ref& rhs) {
- if (rhs.entry_ != nullptr) {
- rhs.entry_->ref_++;
- }
-
- if (entry_ != nullptr) {
- entry_->ref_--;
- }
- entry_ = rhs.entry_;
- return *this;
-}
-
-bool StringPool::Ref::operator==(const Ref& rhs) const {
- return entry_->value == rhs.entry_->value;
-}
-
-bool StringPool::Ref::operator!=(const Ref& rhs) const {
- return entry_->value != rhs.entry_->value;
-}
-
-const std::string* StringPool::Ref::operator->() const {
- return &entry_->value;
-}
-
-const std::string& StringPool::Ref::operator*() const {
- return entry_->value;
-}
-
-size_t StringPool::Ref::index() const {
- // Account for the styles, which *always* come first.
- return entry_->pool_->styles_.size() + entry_->index_;
-}
-
-const StringPool::Context& StringPool::Ref::GetContext() const {
- return entry_->context;
-}
-
-StringPool::StyleRef::StyleRef() : entry_(nullptr) {}
-
-StringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs)
- : entry_(rhs.entry_) {
- if (entry_ != nullptr) {
- entry_->ref_++;
- }
-}
-
-StringPool::StyleRef::StyleRef(StringPool::StyleEntry* entry) : entry_(entry) {
- if (entry_ != nullptr) {
- entry_->ref_++;
- }
-}
-
-StringPool::StyleRef::~StyleRef() {
- if (entry_ != nullptr) {
- entry_->ref_--;
- }
-}
-
-StringPool::StyleRef& StringPool::StyleRef::operator=(const StringPool::StyleRef& rhs) {
- if (rhs.entry_ != nullptr) {
- rhs.entry_->ref_++;
- }
-
- if (entry_ != nullptr) {
- entry_->ref_--;
- }
- entry_ = rhs.entry_;
- return *this;
-}
-
-bool StringPool::StyleRef::operator==(const StyleRef& rhs) const {
- if (entry_->value != rhs.entry_->value) {
- return false;
- }
-
- if (entry_->spans.size() != rhs.entry_->spans.size()) {
- return false;
- }
-
- auto rhs_iter = rhs.entry_->spans.begin();
- for (const Span& span : entry_->spans) {
- const Span& rhs_span = *rhs_iter;
- if (span.first_char != rhs_span.first_char || span.last_char != rhs_span.last_char ||
- span.name != rhs_span.name) {
- return false;
- }
- }
- return true;
-}
-
-bool StringPool::StyleRef::operator!=(const StyleRef& rhs) const {
- return !operator==(rhs);
-}
-
-const StringPool::StyleEntry* StringPool::StyleRef::operator->() const {
- return entry_;
-}
-
-const StringPool::StyleEntry& StringPool::StyleRef::operator*() const {
- return *entry_;
-}
-
-size_t StringPool::StyleRef::index() const {
- return entry_->index_;
-}
-
-const StringPool::Context& StringPool::StyleRef::GetContext() const {
- return entry_->context;
-}
-
-StringPool::Ref StringPool::MakeRef(const StringPiece& str) {
- return MakeRefImpl(str, Context{}, true);
-}
-
-StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context) {
- return MakeRefImpl(str, context, true);
-}
-
-StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str, const Context& context,
- bool unique) {
- if (unique) {
- auto range = indexed_strings_.equal_range(str);
- for (auto iter = range.first; iter != range.second; ++iter) {
- if (context.priority == iter->second->context.priority) {
- return Ref(iter->second);
- }
- }
- }
-
- std::unique_ptr<Entry> entry(new Entry());
- entry->value = str.to_string();
- entry->context = context;
- entry->index_ = strings_.size();
- entry->ref_ = 0;
- entry->pool_ = this;
-
- Entry* borrow = entry.get();
- strings_.emplace_back(std::move(entry));
- indexed_strings_.insert(std::make_pair(StringPiece(borrow->value), borrow));
- return Ref(borrow);
-}
-
-StringPool::Ref StringPool::MakeRef(const Ref& ref) {
- if (ref.entry_->pool_ == this) {
- return ref;
- }
- return MakeRef(ref.entry_->value, ref.entry_->context);
-}
-
-StringPool::StyleRef StringPool::MakeRef(const StyleString& str) {
- return MakeRef(str, Context{});
-}
-
-StringPool::StyleRef StringPool::MakeRef(const StyleString& str, const Context& context) {
- std::unique_ptr<StyleEntry> entry(new StyleEntry());
- entry->value = str.str;
- entry->context = context;
- entry->index_ = styles_.size();
- entry->ref_ = 0;
- for (const aapt::Span& span : str.spans) {
- entry->spans.emplace_back(Span{MakeRef(span.name), span.first_char, span.last_char});
- }
-
- StyleEntry* borrow = entry.get();
- styles_.emplace_back(std::move(entry));
- return StyleRef(borrow);
-}
-
-StringPool::StyleRef StringPool::MakeRef(const StyleRef& ref) {
- std::unique_ptr<StyleEntry> entry(new StyleEntry());
- entry->value = ref.entry_->value;
- entry->context = ref.entry_->context;
- entry->index_ = styles_.size();
- entry->ref_ = 0;
- for (const Span& span : ref.entry_->spans) {
- entry->spans.emplace_back(Span{MakeRef(*span.name), span.first_char, span.last_char});
- }
-
- StyleEntry* borrow = entry.get();
- styles_.emplace_back(std::move(entry));
- return StyleRef(borrow);
-}
-
-void StringPool::ReAssignIndices() {
- // Assign the style indices.
- const size_t style_len = styles_.size();
- for (size_t index = 0; index < style_len; index++) {
- styles_[index]->index_ = index;
- }
-
- // Assign the string indices.
- const size_t string_len = strings_.size();
- for (size_t index = 0; index < string_len; index++) {
- strings_[index]->index_ = index;
- }
-}
-
-void StringPool::Merge(StringPool&& pool) {
- // First, change the owning pool for the incoming strings.
- for (std::unique_ptr<Entry>& entry : pool.strings_) {
- entry->pool_ = this;
- }
-
- // Now move the styles, strings, and indices over.
- std::move(pool.styles_.begin(), pool.styles_.end(), std::back_inserter(styles_));
- pool.styles_.clear();
- std::move(pool.strings_.begin(), pool.strings_.end(), std::back_inserter(strings_));
- pool.strings_.clear();
- indexed_strings_.insert(pool.indexed_strings_.begin(), pool.indexed_strings_.end());
- pool.indexed_strings_.clear();
-
- ReAssignIndices();
-}
-
-void StringPool::HintWillAdd(size_t string_count, size_t style_count) {
- strings_.reserve(strings_.size() + string_count);
- styles_.reserve(styles_.size() + style_count);
-}
-
-void StringPool::Prune() {
- const auto iter_end = indexed_strings_.end();
- auto index_iter = indexed_strings_.begin();
- while (index_iter != iter_end) {
- if (index_iter->second->ref_ <= 0) {
- index_iter = indexed_strings_.erase(index_iter);
- } else {
- ++index_iter;
- }
- }
-
- auto end_iter2 =
- std::remove_if(strings_.begin(), strings_.end(),
- [](const std::unique_ptr<Entry>& entry) -> bool { return entry->ref_ <= 0; });
- auto end_iter3 = std::remove_if(
- styles_.begin(), styles_.end(),
- [](const std::unique_ptr<StyleEntry>& entry) -> bool { return entry->ref_ <= 0; });
-
- // Remove the entries at the end or else we'll be accessing a deleted string from the StyleEntry.
- strings_.erase(end_iter2, strings_.end());
- styles_.erase(end_iter3, styles_.end());
-
- ReAssignIndices();
-}
-
-template <typename E>
-static void SortEntries(
- std::vector<std::unique_ptr<E>>& entries,
- const std::function<int(const StringPool::Context&, const StringPool::Context&)>& cmp) {
- using UEntry = std::unique_ptr<E>;
-
- if (cmp != nullptr) {
- std::sort(entries.begin(), entries.end(), [&cmp](const UEntry& a, const UEntry& b) -> bool {
- int r = cmp(a->context, b->context);
- if (r == 0) {
- r = a->value.compare(b->value);
- }
- return r < 0;
- });
- } else {
- std::sort(entries.begin(), entries.end(),
- [](const UEntry& a, const UEntry& b) -> bool { return a->value < b->value; });
- }
-}
-
-void StringPool::Sort(const std::function<int(const Context&, const Context&)>& cmp) {
- SortEntries(styles_, cmp);
- SortEntries(strings_, cmp);
- ReAssignIndices();
-}
-
-template <typename T>
-static T* EncodeLength(T* data, size_t length) {
- static_assert(std::is_integral<T>::value, "wat.");
-
- constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1);
- constexpr size_t kMaxSize = kMask - 1;
- if (length > kMaxSize) {
- *data++ = kMask | (kMaxSize & (length >> (sizeof(T) * 8)));
- }
- *data++ = length;
- return data;
-}
-
-/**
- * Returns the maximum possible string length that can be successfully encoded
- * using 2 units of the specified T.
- * EncodeLengthMax<char> -> maximum unit length of 0x7FFF
- * EncodeLengthMax<char16_t> -> maximum unit length of 0x7FFFFFFF
- **/
-template <typename T>
-static size_t EncodeLengthMax() {
- static_assert(std::is_integral<T>::value, "wat.");
-
- constexpr size_t kMask = 1 << ((sizeof(T) * 8 * 2) - 1);
- constexpr size_t max = kMask - 1;
- return max;
-}
-
-/**
- * Returns the number of units (1 or 2) needed to encode the string length
- * before writing the string.
- */
-template <typename T>
-static size_t EncodedLengthUnits(size_t length) {
- static_assert(std::is_integral<T>::value, "wat.");
-
- constexpr size_t kMask = 1 << ((sizeof(T) * 8) - 1);
- constexpr size_t kMaxSize = kMask - 1;
- return length > kMaxSize ? 2 : 1;
-}
-
-const std::string kStringTooLarge = "STRING_TOO_LARGE";
-
-static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out,
- IDiagnostics* diag) {
- if (utf8) {
- const std::string& encoded = util::Utf8ToModifiedUtf8(str);
- const ssize_t utf16_length = utf8_to_utf16_length(
- reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size());
- CHECK(utf16_length >= 0);
-
- // Make sure the lengths to be encoded do not exceed the maximum length that
- // can be encoded using chars
- if ((((size_t)encoded.size()) > EncodeLengthMax<char>())
- || (((size_t)utf16_length) > EncodeLengthMax<char>())) {
-
- diag->Error(DiagMessage() << "string too large to encode using UTF-8 "
- << "written instead as '" << kStringTooLarge << "'");
-
- EncodeString(kStringTooLarge, utf8, out, diag);
- return false;
- }
-
- const size_t total_size = EncodedLengthUnits<char>(utf16_length)
- + EncodedLengthUnits<char>(encoded.size()) + encoded.size() + 1;
-
- char* data = out->NextBlock<char>(total_size);
-
- // First encode the UTF16 string length.
- data = EncodeLength(data, utf16_length);
-
- // Now encode the size of the real UTF8 string.
- data = EncodeLength(data, encoded.size());
- strncpy(data, encoded.data(), encoded.size());
-
- } else {
- const std::u16string encoded = util::Utf8ToUtf16(str);
- const ssize_t utf16_length = encoded.size();
-
- // Make sure the length to be encoded does not exceed the maximum possible
- // length that can be encoded
- if (((size_t)utf16_length) > EncodeLengthMax<char16_t>()) {
- diag->Error(DiagMessage() << "string too large to encode using UTF-16 "
- << "written instead as '" << kStringTooLarge << "'");
-
- EncodeString(kStringTooLarge, utf8, out, diag);
- return false;
- }
-
- // Total number of 16-bit words to write.
- const size_t total_size = EncodedLengthUnits<char16_t>(utf16_length)
- + encoded.size() + 1;
-
- char16_t* data = out->NextBlock<char16_t>(total_size);
-
- // Encode the actual UTF16 string length.
- data = EncodeLength(data, utf16_length);
- const size_t byte_length = encoded.size() * sizeof(char16_t);
-
- // NOTE: For some reason, strncpy16(data, entry->value.data(),
- // entry->value.size()) truncates the string.
- memcpy(data, encoded.data(), byte_length);
-
- // The null-terminating character is already here due to the block of data
- // being set to 0s on allocation.
- }
-
- return true;
-}
-
-bool StringPool::Flatten(BigBuffer* out, const StringPool& pool, bool utf8,
- IDiagnostics* diag) {
- bool no_error = true;
- const size_t start_index = out->size();
- android::ResStringPool_header* header = out->NextBlock<android::ResStringPool_header>();
- header->header.type = util::HostToDevice16(android::RES_STRING_POOL_TYPE);
- header->header.headerSize = util::HostToDevice16(sizeof(*header));
- header->stringCount = util::HostToDevice32(pool.size());
- header->styleCount = util::HostToDevice32(pool.styles_.size());
- if (utf8) {
- header->flags |= android::ResStringPool_header::UTF8_FLAG;
- }
-
- uint32_t* indices = pool.size() != 0 ? out->NextBlock<uint32_t>(pool.size()) : nullptr;
- uint32_t* style_indices =
- pool.styles_.size() != 0 ? out->NextBlock<uint32_t>(pool.styles_.size()) : nullptr;
-
- const size_t before_strings_index = out->size();
- header->stringsStart = before_strings_index - start_index;
-
- // Styles always come first.
- for (const std::unique_ptr<StyleEntry>& entry : pool.styles_) {
- *indices++ = out->size() - before_strings_index;
- no_error = EncodeString(entry->value, utf8, out, diag) && no_error;
- }
-
- for (const std::unique_ptr<Entry>& entry : pool.strings_) {
- *indices++ = out->size() - before_strings_index;
- no_error = EncodeString(entry->value, utf8, out, diag) && no_error;
- }
-
- out->Align4();
-
- if (style_indices != nullptr) {
- const size_t before_styles_index = out->size();
- header->stylesStart = util::HostToDevice32(before_styles_index - start_index);
-
- for (const std::unique_ptr<StyleEntry>& entry : pool.styles_) {
- *style_indices++ = out->size() - before_styles_index;
-
- if (!entry->spans.empty()) {
- android::ResStringPool_span* span =
- out->NextBlock<android::ResStringPool_span>(entry->spans.size());
- for (const Span& s : entry->spans) {
- span->name.index = util::HostToDevice32(s.name.index());
- span->firstChar = util::HostToDevice32(s.first_char);
- span->lastChar = util::HostToDevice32(s.last_char);
- span++;
- }
- }
-
- uint32_t* spanEnd = out->NextBlock<uint32_t>();
- *spanEnd = android::ResStringPool_span::END;
- }
-
- // The error checking code in the platform looks for an entire
- // ResStringPool_span structure worth of 0xFFFFFFFF at the end
- // of the style block, so fill in the remaining 2 32bit words
- // with 0xFFFFFFFF.
- const size_t padding_length = sizeof(android::ResStringPool_span) -
- sizeof(android::ResStringPool_span::name);
- uint8_t* padding = out->NextBlock<uint8_t>(padding_length);
- memset(padding, 0xff, padding_length);
- out->Align4();
- }
- header->header.size = util::HostToDevice32(out->size() - start_index);
- return no_error;
-}
-
-bool StringPool::FlattenUtf8(BigBuffer* out, const StringPool& pool, IDiagnostics* diag) {
- return Flatten(out, pool, true, diag);
-}
-
-bool StringPool::FlattenUtf16(BigBuffer* out, const StringPool& pool, IDiagnostics* diag) {
- return Flatten(out, pool, false, diag);
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
deleted file mode 100644
index 3457e0b41859..000000000000
--- a/tools/aapt2/StringPool.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_STRING_POOL_H
-#define AAPT_STRING_POOL_H
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
-#include "util/BigBuffer.h"
-
-namespace aapt {
-
-struct Span {
- std::string name;
- uint32_t first_char;
- uint32_t last_char;
-
- bool operator==(const Span& right) const {
- return name == right.name && first_char == right.first_char && last_char == right.last_char;
- }
-};
-
-struct StyleString {
- std::string str;
- std::vector<Span> spans;
-};
-
-// A StringPool for storing the value of String and StyledString resources.
-// Styles and Strings are stored separately, since the runtime variant of this
-// class -- ResStringPool -- requires that styled strings *always* appear first, since their
-// style data is stored as an array indexed by the same indices as the main string pool array.
-// Otherwise, the style data array would have to be sparse and take up more space.
-class StringPool {
- public:
- using size_type = size_t;
-
- class Context {
- public:
- enum : uint32_t {
- kHighPriority = 1u,
- kNormalPriority = 0x7fffffffu,
- kLowPriority = 0xffffffffu,
- };
- uint32_t priority = kNormalPriority;
- android::ConfigDescription config;
-
- Context() = default;
- Context(uint32_t p, const android::ConfigDescription& c) : priority(p), config(c) {}
- explicit Context(uint32_t p) : priority(p) {}
- explicit Context(const android::ConfigDescription& c) : priority(kNormalPriority), config(c) {
- }
- };
-
- class Entry;
-
- class Ref {
- public:
- Ref();
- Ref(const Ref&);
- ~Ref();
-
- Ref& operator=(const Ref& rhs);
- bool operator==(const Ref& rhs) const;
- bool operator!=(const Ref& rhs) const;
- const std::string* operator->() const;
- const std::string& operator*() const;
-
- size_t index() const;
- const Context& GetContext() const;
-
- private:
- friend class StringPool;
-
- explicit Ref(Entry* entry);
-
- Entry* entry_;
- };
-
- class StyleEntry;
-
- class StyleRef {
- public:
- StyleRef();
- StyleRef(const StyleRef&);
- ~StyleRef();
-
- StyleRef& operator=(const StyleRef& rhs);
- bool operator==(const StyleRef& rhs) const;
- bool operator!=(const StyleRef& rhs) const;
- const StyleEntry* operator->() const;
- const StyleEntry& operator*() const;
-
- size_t index() const;
- const Context& GetContext() const;
-
- private:
- friend class StringPool;
-
- explicit StyleRef(StyleEntry* entry);
-
- StyleEntry* entry_;
- };
-
- class Entry {
- public:
- std::string value;
- Context context;
-
- private:
- friend class StringPool;
- friend class Ref;
-
- size_t index_;
- int ref_;
- const StringPool* pool_;
- };
-
- struct Span {
- Ref name;
- uint32_t first_char;
- uint32_t last_char;
- };
-
- class StyleEntry {
- public:
- std::string value;
- Context context;
- std::vector<Span> spans;
-
- private:
- friend class StringPool;
- friend class StyleRef;
-
- size_t index_;
- int ref_;
- };
-
- static bool FlattenUtf8(BigBuffer* out, const StringPool& pool, IDiagnostics* diag);
- static bool FlattenUtf16(BigBuffer* out, const StringPool& pool, IDiagnostics* diag);
-
- StringPool() = default;
- StringPool(StringPool&&) = default;
- StringPool& operator=(StringPool&&) = default;
-
- // Adds a string to the pool, unless it already exists. Returns a reference to the string in the
- // pool.
- Ref MakeRef(const android::StringPiece& str);
-
- // Adds a string to the pool, unless it already exists, with a context object that can be used
- // when sorting the string pool. Returns a reference to the string in the pool.
- Ref MakeRef(const android::StringPiece& str, const Context& context);
-
- // Adds a string from another string pool. Returns a reference to the string in the string pool.
- Ref MakeRef(const Ref& ref);
-
- // Adds a style to the string pool and returns a reference to it.
- StyleRef MakeRef(const StyleString& str);
-
- // Adds a style to the string pool with a context object that can be used when sorting the string
- // pool. Returns a reference to the style in the string pool.
- StyleRef MakeRef(const StyleString& str, const Context& context);
-
- // Adds a style from another string pool. Returns a reference to the style in the string pool.
- StyleRef MakeRef(const StyleRef& ref);
-
- // Moves pool into this one without coalescing strings. When this function returns, pool will be
- // empty.
- void Merge(StringPool&& pool);
-
- inline const std::vector<std::unique_ptr<Entry>>& strings() const {
- return strings_;
- }
-
- // Returns the number of strings in the table.
- inline size_t size() const {
- return styles_.size() + strings_.size();
- }
-
- // Reserves space for strings and styles as an optimization.
- void HintWillAdd(size_t string_count, size_t style_count);
-
- // Sorts the strings according to their Context using some comparison function.
- // Equal Contexts are further sorted by string value, lexicographically.
- // If no comparison function is provided, values are only sorted lexicographically.
- void Sort(const std::function<int(const Context&, const Context&)>& cmp = nullptr);
-
- // Removes any strings that have no references.
- void Prune();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(StringPool);
-
- static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag);
-
- Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
- void ReAssignIndices();
-
- std::vector<std::unique_ptr<Entry>> strings_;
- std::vector<std::unique_ptr<StyleEntry>> styles_;
- std::unordered_multimap<android::StringPiece, Entry*> indexed_strings_;
-};
-
-} // namespace aapt
-
-#endif // AAPT_STRING_POOL_H
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
deleted file mode 100644
index 6e5200bca44c..000000000000
--- a/tools/aapt2/StringPool_test.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "StringPool.h"
-
-#include <string>
-
-#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
-#include "test/Test.h"
-#include "util/Util.h"
-
-using ::android::StringPiece;
-using ::android::StringPiece16;
-using ::testing::Eq;
-using ::testing::Ne;
-using ::testing::NotNull;
-using ::testing::Pointee;
-
-namespace aapt {
-
-TEST(StringPoolTest, InsertOneString) {
- StringPool pool;
-
- StringPool::Ref ref = pool.MakeRef("wut");
- EXPECT_THAT(*ref, Eq("wut"));
-}
-
-TEST(StringPoolTest, InsertTwoUniqueStrings) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("wut");
- StringPool::Ref ref_b = pool.MakeRef("hey");
-
- EXPECT_THAT(*ref_a, Eq("wut"));
- EXPECT_THAT(*ref_b, Eq("hey"));
-}
-
-TEST(StringPoolTest, DoNotInsertNewDuplicateString) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("wut");
- StringPool::Ref ref_b = pool.MakeRef("wut");
-
- EXPECT_THAT(*ref_a, Eq("wut"));
- EXPECT_THAT(*ref_b, Eq("wut"));
- EXPECT_THAT(pool.size(), Eq(1u));
-}
-
-TEST(StringPoolTest, DoNotDedupeSameStringDifferentPriority) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("wut", StringPool::Context(0x81010001));
- StringPool::Ref ref_b = pool.MakeRef("wut", StringPool::Context(0x81010002));
-
- EXPECT_THAT(*ref_a, Eq("wut"));
- EXPECT_THAT(*ref_b, Eq("wut"));
- EXPECT_THAT(pool.size(), Eq(2u));
-}
-
-TEST(StringPoolTest, MaintainInsertionOrderIndex) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("z");
- StringPool::Ref ref_b = pool.MakeRef("a");
- StringPool::Ref ref_c = pool.MakeRef("m");
-
- EXPECT_THAT(ref_a.index(), Eq(0u));
- EXPECT_THAT(ref_b.index(), Eq(1u));
- EXPECT_THAT(ref_c.index(), Eq(2u));
-}
-
-TEST(StringPoolTest, PruneStringsWithNoReferences) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("foo");
-
- {
- StringPool::Ref ref_b = pool.MakeRef("wut");
- EXPECT_THAT(*ref_b, Eq("wut"));
- EXPECT_THAT(pool.size(), Eq(2u));
- pool.Prune();
- EXPECT_THAT(pool.size(), Eq(2u));
- }
- EXPECT_THAT(pool.size(), Eq(2u));
-
- {
- StringPool::Ref ref_c = pool.MakeRef("bar");
- EXPECT_THAT(pool.size(), Eq(3u));
-
- pool.Prune();
- EXPECT_THAT(pool.size(), Eq(2u));
- }
- EXPECT_THAT(pool.size(), Eq(2u));
-
- pool.Prune();
- EXPECT_THAT(pool.size(), Eq(1u));
-}
-
-TEST(StringPoolTest, SortAndMaintainIndexesInStringReferences) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("z");
- StringPool::Ref ref_b = pool.MakeRef("a");
- StringPool::Ref ref_c = pool.MakeRef("m");
-
- EXPECT_THAT(*ref_a, Eq("z"));
- EXPECT_THAT(ref_a.index(), Eq(0u));
-
- EXPECT_THAT(*ref_b, Eq("a"));
- EXPECT_THAT(ref_b.index(), Eq(1u));
-
- EXPECT_THAT(*ref_c, Eq("m"));
- EXPECT_THAT(ref_c.index(), Eq(2u));
-
- pool.Sort();
-
- EXPECT_THAT(*ref_a, Eq("z"));
- EXPECT_THAT(ref_a.index(), Eq(2u));
-
- EXPECT_THAT(*ref_b, Eq("a"));
- EXPECT_THAT(ref_b.index(), Eq(0u));
-
- EXPECT_THAT(*ref_c, Eq("m"));
- EXPECT_THAT(ref_c.index(), Eq(1u));
-}
-
-TEST(StringPoolTest, SortAndStillDedupe) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("z");
- StringPool::Ref ref_b = pool.MakeRef("a");
- StringPool::Ref ref_c = pool.MakeRef("m");
-
- pool.Sort();
-
- StringPool::Ref ref_d = pool.MakeRef("z");
- StringPool::Ref ref_e = pool.MakeRef("a");
- StringPool::Ref ref_f = pool.MakeRef("m");
-
- EXPECT_THAT(ref_d.index(), Eq(ref_a.index()));
- EXPECT_THAT(ref_e.index(), Eq(ref_b.index()));
- EXPECT_THAT(ref_f.index(), Eq(ref_c.index()));
-}
-
-TEST(StringPoolTest, AddStyles) {
- StringPool pool;
-
- StringPool::StyleRef ref = pool.MakeRef(StyleString{{"android"}, {Span{{"b"}, 2, 6}}});
- EXPECT_THAT(ref.index(), Eq(0u));
- EXPECT_THAT(ref->value, Eq("android"));
- ASSERT_THAT(ref->spans.size(), Eq(1u));
-
- const StringPool::Span& span = ref->spans.front();
- EXPECT_THAT(*span.name, Eq("b"));
- EXPECT_THAT(span.first_char, Eq(2u));
- EXPECT_THAT(span.last_char, Eq(6u));
-}
-
-TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
- StringPool pool;
-
- StringPool::Ref ref = pool.MakeRef("android");
-
- StyleString str{{"android"}};
- StringPool::StyleRef style_ref = pool.MakeRef(StyleString{{"android"}});
-
- EXPECT_THAT(ref.index(), Ne(style_ref.index()));
-}
-
-TEST(StringPoolTest, StylesAndStringsAreSeparateAfterSorting) {
- StringPool pool;
-
- StringPool::StyleRef ref_a = pool.MakeRef(StyleString{{"beta"}});
- StringPool::Ref ref_b = pool.MakeRef("alpha");
- StringPool::StyleRef ref_c = pool.MakeRef(StyleString{{"alpha"}});
-
- EXPECT_THAT(ref_b.index(), Ne(ref_c.index()));
-
- pool.Sort();
-
- EXPECT_THAT(ref_c.index(), Eq(0u));
- EXPECT_THAT(ref_a.index(), Eq(1u));
- EXPECT_THAT(ref_b.index(), Eq(2u));
-}
-
-TEST(StringPoolTest, FlattenEmptyStringPoolUtf8) {
- using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
-
- StringPool pool;
- BigBuffer buffer(1024);
- StringPool::FlattenUtf8(&buffer, pool, &diag);
-
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
- ResStringPool test;
- ASSERT_THAT(test.setTo(data.get(), buffer.size()), Eq(NO_ERROR));
-}
-
-TEST(StringPoolTest, FlattenOddCharactersUtf16) {
- using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
-
- StringPool pool;
- pool.MakeRef("\u093f");
- BigBuffer buffer(1024);
- StringPool::FlattenUtf16(&buffer, pool, &diag);
-
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
- ResStringPool test;
- ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- auto str = test.stringAt(0);
- ASSERT_TRUE(str.has_value());
- EXPECT_THAT(str->size(), Eq(1u));
- EXPECT_THAT(str->data(), Pointee(Eq(u'\u093f')));
- EXPECT_THAT(str->data()[1], Eq(0u));
-}
-
-constexpr const char* sLongString =
- "バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑"
- "え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限"
- "します。メール、SMSや、同期を使 "
- "用するその他のアプリは、起動しても更新されないことがあります。バッテリーセ"
- "ーバーは端末の充電中は自動的にOFFになります。";
-
-TEST(StringPoolTest, Flatten) {
- using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
-
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("hello");
- StringPool::Ref ref_b = pool.MakeRef("goodbye");
- StringPool::Ref ref_c = pool.MakeRef(sLongString);
- StringPool::Ref ref_d = pool.MakeRef("");
- StringPool::StyleRef ref_e =
- pool.MakeRef(StyleString{{"style"}, {Span{{"b"}, 0, 1}, Span{{"i"}, 2, 3}}});
-
- // Styles are always first.
- EXPECT_THAT(ref_e.index(), Eq(0u));
-
- EXPECT_THAT(ref_a.index(), Eq(1u));
- EXPECT_THAT(ref_b.index(), Eq(2u));
- EXPECT_THAT(ref_c.index(), Eq(3u));
- EXPECT_THAT(ref_d.index(), Eq(4u));
-
- BigBuffer buffers[2] = {BigBuffer(1024), BigBuffer(1024)};
- StringPool::FlattenUtf8(&buffers[0], pool, &diag);
- StringPool::FlattenUtf16(&buffers[1], pool, &diag);
-
- // Test both UTF-8 and UTF-16 buffers.
- for (const BigBuffer& buffer : buffers) {
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
-
- ResStringPool test;
- ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
-
- EXPECT_THAT(util::GetString(test, 1), Eq("hello"));
- EXPECT_THAT(util::GetString16(test, 1), Eq(u"hello"));
-
- EXPECT_THAT(util::GetString(test, 2), Eq("goodbye"));
- EXPECT_THAT(util::GetString16(test, 2), Eq(u"goodbye"));
-
- EXPECT_THAT(util::GetString(test, 3), Eq(sLongString));
- EXPECT_THAT(util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString)));
-
- EXPECT_TRUE(test.stringAt(4).has_value() || test.string8At(4).has_value());
-
- EXPECT_THAT(util::GetString(test, 0), Eq("style"));
- EXPECT_THAT(util::GetString16(test, 0), Eq(u"style"));
-
- auto span_result = test.styleAt(0);
- ASSERT_TRUE(span_result.has_value());
-
- const ResStringPool_span* span = span_result->unsafe_ptr();
- EXPECT_THAT(util::GetString(test, span->name.index), Eq("b"));
- EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"b"));
- EXPECT_THAT(span->firstChar, Eq(0u));
- EXPECT_THAT(span->lastChar, Eq(1u));
- span++;
-
- ASSERT_THAT(span->name.index, Ne(ResStringPool_span::END));
- EXPECT_THAT(util::GetString(test, span->name.index), Eq("i"));
- EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"i"));
- EXPECT_THAT(span->firstChar, Eq(2u));
- EXPECT_THAT(span->lastChar, Eq(3u));
- span++;
-
- EXPECT_THAT(span->name.index, Eq(ResStringPool_span::END));
- }
-}
-
-TEST(StringPoolTest, ModifiedUTF8) {
- using namespace android; // For NO_ERROR on Windows.
- StdErrDiagnostics diag;
- StringPool pool;
- StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400)
- StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437)
- StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7");
-
- BigBuffer buffer(1024);
- StringPool::FlattenUtf8(&buffer, pool, &diag);
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
-
- // Check that the codepoints are encoded using two three-byte surrogate pairs
- ResStringPool test;
- ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- auto str = test.string8At(0);
- ASSERT_TRUE(str.has_value());
- EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80"));
-
- str = test.string8At(1);
- ASSERT_TRUE(str.has_value());
- EXPECT_THAT(str->to_string(), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
-
- str = test.string8At(2);
- ASSERT_TRUE(str.has_value());
- EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
-
- // Check that retrieving the strings returns the original UTF-8 character bytes
- EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
- EXPECT_THAT(util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar"));
- EXPECT_THAT(util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7"));
-}
-
-TEST(StringPoolTest, MaxEncodingLength) {
- StdErrDiagnostics diag;
- using namespace android; // For NO_ERROR on Windows.
- ResStringPool test;
-
- StringPool pool;
- pool.MakeRef("aaaaaaaaaa");
- BigBuffer buffers[2] = {BigBuffer(1024), BigBuffer(1024)};
-
- // Make sure a UTF-8 string under the maximum length does not produce an error
- EXPECT_THAT(StringPool::FlattenUtf8(&buffers[0], pool, &diag), Eq(true));
- std::unique_ptr<uint8_t[]> data = util::Copy(buffers[0]);
- test.setTo(data.get(), buffers[0].size());
- EXPECT_THAT(util::GetString(test, 0), Eq("aaaaaaaaaa"));
-
- // Make sure a UTF-16 string under the maximum length does not produce an error
- EXPECT_THAT(StringPool::FlattenUtf16(&buffers[1], pool, &diag), Eq(true));
- data = util::Copy(buffers[1]);
- test.setTo(data.get(), buffers[1].size());
- EXPECT_THAT(util::GetString16(test, 0), Eq(u"aaaaaaaaaa"));
-
- StringPool pool2;
- std::string longStr(50000, 'a');
- pool2.MakeRef("this fits1");
- pool2.MakeRef(longStr);
- pool2.MakeRef("this fits2");
- BigBuffer buffers2[2] = {BigBuffer(1024), BigBuffer(1024)};
-
- // Make sure a string that exceeds the maximum length of UTF-8 produces an
- // error and writes a shorter error string instead
- EXPECT_THAT(StringPool::FlattenUtf8(&buffers2[0], pool2, &diag), Eq(false));
- data = util::Copy(buffers2[0]);
- test.setTo(data.get(), buffers2[0].size());
- EXPECT_THAT(util::GetString(test, 0), "this fits1");
- EXPECT_THAT(util::GetString(test, 1), "STRING_TOO_LARGE");
- EXPECT_THAT(util::GetString(test, 2), "this fits2");
-
- // Make sure a string that a string that exceeds the maximum length of UTF-8
- // but not UTF-16 does not error for UTF-16
- StringPool pool3;
- std::u16string longStr16(50000, 'a');
- pool3.MakeRef(longStr);
- EXPECT_THAT(StringPool::FlattenUtf16(&buffers2[1], pool3, &diag), Eq(true));
- data = util::Copy(buffers2[1]);
- test.setTo(data.get(), buffers2[1].size());
- EXPECT_THAT(util::GetString16(test, 0), Eq(longStr16));
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/ValueTransformer.h b/tools/aapt2/ValueTransformer.h
index 6fc4a191b04b..68242659dc73 100644
--- a/tools/aapt2/ValueTransformer.h
+++ b/tools/aapt2/ValueTransformer.h
@@ -19,7 +19,7 @@
#include <memory>
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
namespace aapt {
@@ -82,7 +82,7 @@ struct Macro;
struct ValueTransformer {
// `new_pool` is the new StringPool that newly created Values should use for string storing string
// values.
- explicit ValueTransformer(StringPool* new_pool);
+ explicit ValueTransformer(android::StringPool* new_pool);
virtual ~ValueTransformer() = default;
AAPT_TRANSFORM_ITEM(Id);
@@ -101,7 +101,7 @@ struct ValueTransformer {
AAPT_TRANSFORM_VALUE(Macro);
protected:
- StringPool* const pool_;
+ android::StringPool* const pool_;
};
#undef AAPT_TRANSFORM_VALUE
@@ -127,4 +127,4 @@ struct TransformableItem : public TransformableValue<Derived, Base> {
// Implementation
#include "ValueTransformer_inline.h"
-#endif // AAPT_VALUE_TRANSFORMER_H \ No newline at end of file
+#endif // AAPT_VALUE_TRANSFORMER_H
diff --git a/tools/aapt2/ValueTransformer_inline.h b/tools/aapt2/ValueTransformer_inline.h
index c6c07c0fd6f9..4f8eadca54e3 100644
--- a/tools/aapt2/ValueTransformer_inline.h
+++ b/tools/aapt2/ValueTransformer_inline.h
@@ -19,7 +19,7 @@
namespace aapt {
-inline ValueTransformer::ValueTransformer(StringPool* new_pool) : pool_(new_pool) {
+inline ValueTransformer::ValueTransformer(android::StringPool* new_pool) : pool_(new_pool) {
}
template <typename Derived, typename Base>
@@ -44,4 +44,4 @@ Item* TransformableItem<Derived, Base>::TransformItemImpl(ValueTransformer& tran
} // namespace aapt
-#endif // AAPT_VALUE_TRANSFORMER_IMPL_H \ No newline at end of file
+#endif // AAPT_VALUE_TRANSFORMER_IMPL_H
diff --git a/tools/aapt2/cmd/ApkInfo.cpp b/tools/aapt2/cmd/ApkInfo.cpp
new file mode 100644
index 000000000000..3c0831c7ec0d
--- /dev/null
+++ b/tools/aapt2/cmd/ApkInfo.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ApkInfo.h"
+
+#include <fcntl.h>
+
+#include <iostream>
+#include <memory>
+
+#include "LoadedApk.h"
+#include "android-base/file.h" // for O_BINARY
+#include "android-base/utf8.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/StringPiece.h"
+#include "dump/DumpManifest.h"
+#include "format/proto/ProtoSerialize.h"
+
+using ::android::StringPiece;
+
+namespace aapt {
+
+int ExportApkInfo(LoadedApk* apk, bool include_resource_table,
+ const std::unordered_set<std::string>& xml_resources, pb::ApkInfo* out_apk_info,
+ android::IDiagnostics* diag) {
+ auto result = DumpBadgingProto(apk, out_apk_info->mutable_badging(), diag);
+ if (result != 0) {
+ return result;
+ }
+
+ if (include_resource_table) {
+ SerializeTableToPb(*apk->GetResourceTable(), out_apk_info->mutable_resource_table(), diag);
+ }
+
+ for (auto& xml_resource : xml_resources) {
+ auto xml = apk->LoadXml(xml_resource, diag);
+ if (xml) {
+ auto out_xml = out_apk_info->add_xml_files();
+ out_xml->set_path(xml_resource);
+ SerializeXmlResourceToPb(*xml, out_xml->mutable_root(),
+ {/* remove_empty_text_nodes= */ true});
+ }
+ }
+
+ return 0;
+}
+
+int ApkInfoCommand::Action(const std::vector<std::string>& args) {
+ if (args.size() != 1) {
+ std::cerr << "must supply a single APK\n";
+ Usage(&std::cerr);
+ return 1;
+ }
+ StringPiece path = args[0];
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, diag_);
+ if (!apk) {
+ return 1;
+ }
+
+ pb::ApkInfo out_apk_info;
+ int result =
+ ExportApkInfo(apk.get(), include_resource_table_, xml_resources_, &out_apk_info, diag_);
+ if (result != 0) {
+ diag_->Error(android::DiagMessage() << "Failed to serialize ApkInfo into proto.");
+ return result;
+ }
+
+ int mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
+ int outfd = ::android::base::utf8::open(output_path_.c_str(), mode, 0666);
+ if (outfd == -1) {
+ diag_->Error(android::DiagMessage() << "Failed to open output file.");
+ return 1;
+ }
+
+ bool is_serialized = out_apk_info.SerializeToFileDescriptor(outfd);
+ close(outfd);
+
+ return is_serialized ? 0 : 1;
+}
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/cmd/ApkInfo.h b/tools/aapt2/cmd/ApkInfo.h
new file mode 100644
index 000000000000..bb92a8579bc0
--- /dev/null
+++ b/tools/aapt2/cmd/ApkInfo.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT2_APKINFO_H
+#define AAPT2_APKINFO_H
+
+#include "Command.h"
+#include "androidfw/IDiagnostics.h"
+
+namespace aapt {
+
+class ApkInfoCommand : public Command {
+ public:
+ explicit ApkInfoCommand(android::IDiagnostics* diag) : Command("apkinfo"), diag_(diag) {
+ SetDescription("Dump information about an APK in binary proto format.");
+ AddRequiredFlag("-o", "Output path", &output_path_, Command::kPath);
+ AddOptionalSwitch("--include-resource-table", "Include the resource table data into output.",
+ &include_resource_table_);
+ AddOptionalFlagList("--include-xml",
+ "Include an XML file content into output. Multiple XML files might be "
+ "requested during single invocation.",
+ &xml_resources_);
+ }
+
+ int Action(const std::vector<std::string>& args) override;
+
+ private:
+ android::IDiagnostics* diag_;
+ std::string output_path_;
+ bool include_resource_table_ = false;
+ std::unordered_set<std::string> xml_resources_;
+};
+
+} // namespace aapt
+
+#endif // AAPT2_APKINFO_H
diff --git a/tools/aapt2/cmd/ApkInfo_test.cpp b/tools/aapt2/cmd/ApkInfo_test.cpp
new file mode 100644
index 000000000000..97d4abebfe6a
--- /dev/null
+++ b/tools/aapt2/cmd/ApkInfo_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ApkInfo.h"
+
+#include "ApkInfo.pb.h"
+#include "LoadedApk.h"
+#include "android-base/unique_fd.h"
+#include "io/StringStream.h"
+#include "test/Test.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using ApkInfoTest = CommandTestFixture;
+
+void AssertProducedAndExpectedInfo(const std::string& produced_path,
+ const std::string& expected_path) {
+ android::base::unique_fd fd(open(produced_path.c_str(), O_RDONLY));
+ ASSERT_NE(fd.get(), -1);
+
+ pb::ApkInfo produced_apk_info;
+ produced_apk_info.ParseFromFileDescriptor(fd.get());
+
+ std::string expected;
+ ::android::base::ReadFileToString(expected_path, &expected);
+
+ EXPECT_EQ(produced_apk_info.DebugString(), expected);
+}
+
+static android::NoOpDiagnostics noop_diag;
+
+TEST_F(ApkInfoTest, ApkInfoWithBadging) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto out_info_path = GetTestPath("apk_info.pb");
+
+ ApkInfoCommand command(&noop_diag);
+ command.Execute({"-o", out_info_path, apk_path}, &std::cerr);
+
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_expected_proto.txt"});
+ AssertProducedAndExpectedInfo(out_info_path, expected_path);
+}
+
+TEST_F(ApkInfoTest, FullApkInfo) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto out_info_path = GetTestPath("apk_info.pb");
+
+ ApkInfoCommand command(&noop_diag);
+ command.Execute({"-o", out_info_path, "--include-resource-table", "--include-xml",
+ "AndroidManifest.xml", "--include-xml", "res/oy.xml", apk_path},
+ &std::cerr);
+
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_full_proto.txt"});
+ AssertProducedAndExpectedInfo(out_info_path, expected_path);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index b1452fad0e8f..514651e92c27 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -33,7 +33,7 @@ using android::StringPiece;
namespace aapt {
-std::string GetSafePath(const StringPiece& arg) {
+std::string GetSafePath(StringPiece arg) {
#ifdef _WIN32
// If the path exceeds the maximum path length for Windows, encode the path using the
// extended-length prefix
@@ -47,63 +47,62 @@ std::string GetSafePath(const StringPiece& arg) {
return path8;
#else
- return arg.to_string();
+ return std::string(arg);
#endif
}
-void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description,
- std::string* value, uint32_t flags) {
- auto func = [value, flags](const StringPiece& arg) -> bool {
- *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
+void Command::AddRequiredFlag(StringPiece name, StringPiece description, std::string* value,
+ uint32_t flags) {
+ auto func = [value, flags](StringPiece arg) -> bool {
+ *value = (flags & Command::kPath) ? GetSafePath(arg) : std::string(arg);
return true;
};
flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
}
-void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description,
+void Command::AddRequiredFlagList(StringPiece name, StringPiece description,
std::vector<std::string>* value, uint32_t flags) {
- auto func = [value, flags](const StringPiece& arg) -> bool {
- value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
+ auto func = [value, flags](StringPiece arg) -> bool {
+ value->push_back((flags & Command::kPath) ? GetSafePath(arg) : std::string(arg));
return true;
};
flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
}
-void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description,
+void Command::AddOptionalFlag(StringPiece name, StringPiece description,
std::optional<std::string>* value, uint32_t flags) {
- auto func = [value, flags](const StringPiece& arg) -> bool {
- *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
+ auto func = [value, flags](StringPiece arg) -> bool {
+ *value = (flags & Command::kPath) ? GetSafePath(arg) : std::string(arg);
return true;
};
flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
}
-void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+void Command::AddOptionalFlagList(StringPiece name, StringPiece description,
std::vector<std::string>* value, uint32_t flags) {
- auto func = [value, flags](const StringPiece& arg) -> bool {
- value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
+ auto func = [value, flags](StringPiece arg) -> bool {
+ value->push_back((flags & Command::kPath) ? GetSafePath(arg) : std::string(arg));
return true;
};
flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
}
-void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+void Command::AddOptionalFlagList(StringPiece name, StringPiece description,
std::unordered_set<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- value->insert(arg.to_string());
+ auto func = [value](StringPiece arg) -> bool {
+ value->emplace(arg);
return true;
};
flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
}
-void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description,
- bool* value) {
- auto func = [value](const StringPiece& arg) -> bool {
+void Command::AddOptionalSwitch(StringPiece name, StringPiece description, bool* value) {
+ auto func = [value](StringPiece arg) -> bool {
*value = true;
return true;
};
@@ -120,8 +119,8 @@ void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool
}
}
-void Command::SetDescription(const StringPiece& description) {
- description_ = description.to_string();
+void Command::SetDescription(StringPiece description) {
+ description_ = std::string(description);
}
void Command::Usage(std::ostream* out) {
@@ -183,7 +182,7 @@ int Command::Execute(const std::vector<StringPiece>& args, std::ostream* out_err
std::vector<std::string> file_args;
for (size_t i = 0; i < args.size(); i++) {
- const StringPiece& arg = args[i];
+ StringPiece arg = args[i];
if (*(arg.data()) != '-') {
// Continue parsing as the subcommand if the first argument matches one of the subcommands
if (i == 0) {
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index 8678cda59856..1416e980ed19 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -30,13 +30,10 @@ namespace aapt {
class Command {
public:
- explicit Command(const android::StringPiece& name)
- : name_(name.to_string()), full_subcommand_name_(name.to_string()){};
+ explicit Command(android::StringPiece name) : name_(name), full_subcommand_name_(name){};
- explicit Command(const android::StringPiece& name, const android::StringPiece& short_name)
- : name_(name.to_string()),
- short_name_(short_name.to_string()),
- full_subcommand_name_(name.to_string()){};
+ explicit Command(android::StringPiece name, android::StringPiece short_name)
+ : name_(name), short_name_(short_name), full_subcommand_name_(name){};
Command(Command&&) = default;
Command& operator=(Command&&) = default;
@@ -52,30 +49,26 @@ class Command {
kPath = 1 << 0,
};
- void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
+ void AddRequiredFlag(android::StringPiece name, android::StringPiece description,
std::string* value, uint32_t flags = 0);
- void AddRequiredFlagList(const android::StringPiece& name,
- const android::StringPiece& description, std::vector<std::string>* value,
- uint32_t flags = 0);
+ void AddRequiredFlagList(android::StringPiece name, android::StringPiece description,
+ std::vector<std::string>* value, uint32_t flags = 0);
- void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
+ void AddOptionalFlag(android::StringPiece name, android::StringPiece description,
std::optional<std::string>* value, uint32_t flags = 0);
- void AddOptionalFlagList(const android::StringPiece& name,
- const android::StringPiece& description, std::vector<std::string>* value,
- uint32_t flags = 0);
+ void AddOptionalFlagList(android::StringPiece name, android::StringPiece description,
+ std::vector<std::string>* value, uint32_t flags = 0);
- void AddOptionalFlagList(const android::StringPiece& name,
- const android::StringPiece& description,
+ void AddOptionalFlagList(android::StringPiece name, android::StringPiece description,
std::unordered_set<std::string>* value);
- void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
- bool* value);
+ void AddOptionalSwitch(android::StringPiece name, android::StringPiece description, bool* value);
void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
- void SetDescription(const android::StringPiece& name);
+ void SetDescription(android::StringPiece name);
// Prints the help menu of the command.
void Usage(std::ostream* out);
@@ -90,17 +83,21 @@ class Command {
private:
struct Flag {
- explicit Flag(const android::StringPiece& name, const android::StringPiece& description,
+ explicit Flag(android::StringPiece name, android::StringPiece description,
const bool is_required, const size_t num_args,
- std::function<bool(const android::StringPiece& value)>&& action)
- : name(name.to_string()), description(description.to_string()), is_required(is_required),
- num_args(num_args), action(std::move(action)) {}
+ std::function<bool(android::StringPiece value)>&& action)
+ : name(name),
+ description(description),
+ is_required(is_required),
+ num_args(num_args),
+ action(std::move(action)) {
+ }
const std::string name;
const std::string description;
const bool is_required;
const size_t num_args;
- const std::function<bool(const android::StringPiece& value)> action;
+ const std::function<bool(android::StringPiece value)> action;
bool found = false;
};
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index fe560180bd48..03f9715fb265 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -17,19 +17,17 @@
#include "Compile.h"
#include <dirent.h>
+
#include <string>
+#include "ResourceParser.h"
+#include "ResourceTable.h"
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/utf8.h"
#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
-#include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-#include "Diagnostics.h"
-#include "ResourceParser.h"
-#include "ResourceTable.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "compile/InlineXmlFormatParser.h"
@@ -39,6 +37,8 @@
#include "format/Archive.h"
#include "format/Container.h"
#include "format/proto/ProtoSerialize.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include "io/BigBufferStream.h"
#include "io/FileStream.h"
#include "io/FileSystem.h"
@@ -61,7 +61,7 @@ using ::google::protobuf::io::CopyingOutputStreamAdaptor;
namespace aapt {
struct ResourcePathData {
- Source source;
+ android::Source source;
std::string resource_dir;
std::string name;
std::string extension;
@@ -122,12 +122,15 @@ static std::optional<ResourcePathData> ExtractResourcePathData(const std::string
}
}
- const Source res_path = options.source_path
- ? StringPiece(options.source_path.value())
- : StringPiece(path);
+ const android::Source res_path =
+ options.source_path ? StringPiece(options.source_path.value()) : StringPiece(path);
- return ResourcePathData{res_path, dir_str.to_string(), name.to_string(),
- extension.to_string(), config_str.to_string(), config};
+ return ResourcePathData{res_path,
+ std::string(dir_str),
+ std::string(name),
+ std::string(extension),
+ std::string(config_str),
+ config};
}
static std::string BuildIntermediateContainerFilename(const ResourcePathData& data) {
@@ -154,8 +157,8 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
{
auto fin = file->OpenInputStream();
if (fin->HadError()) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source)
- << "failed to open file: " << fin->GetError());
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
+ << "failed to open file: " << fin->GetError());
return false;
}
@@ -191,7 +194,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
// Create the file/zip entry.
if (!writer->StartEntry(output_path, 0)) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to open");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to open");
return false;
}
@@ -204,13 +207,13 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
pb::ResourceTable pb_table;
SerializeTableToPb(table, &pb_table, context->GetDiagnostics());
if (!container_writer.AddResTableEntry(pb_table)) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to write");
return false;
}
}
if (!writer->FinishEntry()) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to finish entry");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to finish entry");
return false;
}
@@ -218,7 +221,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
io::FileOutputStream fout_text(options.generate_text_symbols_path.value());
if (fout_text.HadError()) {
- context->GetDiagnostics()->Error(DiagMessage()
+ context->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to'"
<< options.generate_text_symbols_path.value()
<< "': " << fout_text.GetError());
@@ -243,9 +246,9 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
r_txt_printer.Print("private ");
}
- if (type->type != ResourceType::kStyleable) {
+ if (type->named_type.type != ResourceType::kStyleable) {
r_txt_printer.Print("int ");
- r_txt_printer.Print(to_string(type->type));
+ r_txt_printer.Print(type->named_type.to_string());
r_txt_printer.Print(" ");
r_txt_printer.Println(entry->name);
} else {
@@ -280,13 +283,13 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
return true;
}
-static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const ResourceFile& file,
+static bool WriteHeaderAndDataToWriter(StringPiece output_path, const ResourceFile& file,
io::KnownSizeInputStream* in, IArchiveWriter* writer,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
TRACE_CALL();
// Start the entry so we can write the header.
if (!writer->StartEntry(output_path, 0)) {
- diag->Error(DiagMessage(output_path) << "failed to open file");
+ diag->Error(android::DiagMessage(output_path) << "failed to open file");
return false;
}
@@ -300,20 +303,20 @@ static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const Res
SerializeCompiledFileToPb(file, &pb_compiled_file);
if (!container_writer.AddResFileEntry(pb_compiled_file, in)) {
- diag->Error(DiagMessage(output_path) << "failed to write entry data");
+ diag->Error(android::DiagMessage(output_path) << "failed to write entry data");
return false;
}
}
if (!writer->FinishEntry()) {
- diag->Error(DiagMessage(output_path) << "failed to finish writing data");
+ diag->Error(android::DiagMessage(output_path) << "failed to finish writing data");
return false;
}
return true;
}
-static bool FlattenXmlToOutStream(const StringPiece& output_path, const xml::XmlResource& xmlres,
- ContainerWriter* container_writer, IDiagnostics* diag) {
+static bool FlattenXmlToOutStream(StringPiece output_path, const xml::XmlResource& xmlres,
+ ContainerWriter* container_writer, android::IDiagnostics* diag) {
pb::internal::CompiledFile pb_compiled_file;
SerializeCompiledFileToPb(xmlres.file, &pb_compiled_file);
@@ -324,7 +327,7 @@ static bool FlattenXmlToOutStream(const StringPiece& output_path, const xml::Xml
io::StringInputStream serialized_in(serialized_xml);
if (!container_writer->AddResFileEntry(pb_compiled_file, &serialized_in)) {
- diag->Error(DiagMessage(output_path) << "failed to write entry data");
+ diag->Error(android::DiagMessage(output_path) << "failed to write entry data");
return false;
}
return true;
@@ -334,12 +337,12 @@ static bool IsValidFile(IAaptContext* context, const std::string& input_path) {
const file::FileType file_type = file::GetFileType(input_path);
if (file_type != file::FileType::kRegular && file_type != file::FileType::kSymlink) {
if (file_type == file::FileType::kDirectory) {
- context->GetDiagnostics()->Error(DiagMessage(input_path)
+ context->GetDiagnostics()->Error(android::DiagMessage(input_path)
<< "resource file cannot be a directory");
} else if (file_type == file::FileType::kNonExistant) {
- context->GetDiagnostics()->Error(DiagMessage(input_path) << "file not found");
+ context->GetDiagnostics()->Error(android::DiagMessage(input_path) << "file not found");
} else {
- context->GetDiagnostics()->Error(DiagMessage(input_path)
+ context->GetDiagnostics()->Error(android::DiagMessage(input_path)
<< "not a valid resource file");
}
return false;
@@ -352,14 +355,14 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
const std::string& output_path) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling XML");
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source) << "compiling XML");
}
std::unique_ptr<xml::XmlResource> xmlres;
{
auto fin = file->OpenInputStream();
if (fin->HadError()) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source)
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
<< "failed to open file: " << fin->GetError());
return false;
}
@@ -389,7 +392,7 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
// Start the entry so we can write the header.
if (!writer->StartEntry(output_path, 0)) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to open file");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path) << "failed to open file");
return false;
}
@@ -416,7 +419,8 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
}
if (!writer->FinishEntry()) {
- context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to finish writing data");
+ context->GetDiagnostics()->Error(android::DiagMessage(output_path)
+ << "failed to finish writing data");
return false;
}
@@ -424,7 +428,7 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options,
io::FileOutputStream fout_text(options.generate_text_symbols_path.value());
if (fout_text.HadError()) {
- context->GetDiagnostics()->Error(DiagMessage()
+ context->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to'"
<< options.generate_text_symbols_path.value()
<< "': " << fout_text.GetError());
@@ -452,10 +456,10 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
const std::string& output_path) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling PNG");
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source) << "compiling PNG");
}
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
ResourceFile res_file;
res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name);
res_file.config = path_data.config;
@@ -465,11 +469,12 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
{
auto data = file->OpenAsData();
if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to open file ");
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
+ << "failed to open file ");
return false;
}
- BigBuffer crunched_png_buffer(4096);
+ android::BigBuffer crunched_png_buffer(4096);
io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer);
// Ensure that we only keep the chunks we care about if we end up
@@ -486,7 +491,7 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
std::string err;
nine_patch = NinePatch::Create(image->rows.get(), image->width, image->height, &err);
if (!nine_patch) {
- context->GetDiagnostics()->Error(DiagMessage() << err);
+ context->GetDiagnostics()->Error(android::DiagMessage() << err);
return false;
}
@@ -503,8 +508,8 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
}
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "9-patch: "
- << *nine_patch);
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source)
+ << "9-patch: " << *nine_patch);
}
}
@@ -522,13 +527,13 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
// The re-encoded PNG is larger than the original, and there is
// no mandatory transformation. Use the original.
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source)
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source)
<< "original PNG is smaller than crunched PNG"
<< ", using original");
}
png_chunk_filter.Rewind();
- BigBuffer filtered_png_buffer(4096);
+ android::BigBuffer filtered_png_buffer(4096);
io::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer);
io::Copy(&filtered_png_buffer_out, &png_chunk_filter);
buffer.AppendBuffer(std::move(filtered_png_buffer));
@@ -537,14 +542,14 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options,
if (context->IsVerbose()) {
// For debugging only, use the legacy PNG cruncher and compare the resulting file sizes.
// This will help catch exotic cases where the new code may generate larger PNGs.
- std::stringstream legacy_stream(content.to_string());
- BigBuffer legacy_buffer(4096);
+ std::stringstream legacy_stream{std::string(content)};
+ android::BigBuffer legacy_buffer(4096);
Png png(context->GetDiagnostics());
if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) {
return false;
}
- context->GetDiagnostics()->Note(DiagMessage(path_data.source)
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source)
<< "legacy=" << legacy_buffer.size()
<< " new=" << buffer.size());
}
@@ -560,7 +565,7 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
const std::string& output_path) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling file");
+ context->GetDiagnostics()->Note(android::DiagMessage(path_data.source) << "compiling file");
}
ResourceFile res_file;
@@ -571,7 +576,8 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
auto data = file->OpenAsData();
if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to open file ");
+ context->GetDiagnostics()->Error(android::DiagMessage(path_data.source)
+ << "failed to open file ");
return false;
}
@@ -581,7 +587,7 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
class CompileContext : public IAaptContext {
public:
- explicit CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
+ explicit CompileContext(android::IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
}
PackageType GetPackageType() override {
@@ -597,7 +603,7 @@ class CompileContext : public IAaptContext {
return verbose_;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return diagnostics_;
}
@@ -633,7 +639,7 @@ class CompileContext : public IAaptContext {
private:
DISALLOW_COPY_AND_ASSIGN(CompileContext);
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
bool verbose_ = false;
};
@@ -665,7 +671,7 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter*
path, inputs->GetDirSeparator(), &err_str, options)) {
path_data = maybe_path_data.value();
} else {
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << err_str);
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource()) << err_str);
error = true;
continue;
}
@@ -688,8 +694,8 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter*
}
}
} else {
- context->GetDiagnostics()->Error(DiagMessage()
- << "invalid file path '" << path_data.source << "'");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "invalid file path '" << path_data.source << "'");
error = true;
continue;
}
@@ -699,15 +705,16 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter*
if (compile_func != &CompileFile && !options.legacy_mode
&& std::count(path_data.name.begin(), path_data.name.end(), '.') != 0) {
error = true;
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource())
- << "file name cannot contain '.' other than for"
- << " specifying the extension");
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "file name cannot contain '.' other than for"
+ << " specifying the extension");
continue;
}
const std::string out_path = BuildIntermediateContainerFilename(path_data);
if (!compile_func(context, options, path_data, file, output_writer, out_path)) {
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "file failed to compile");
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "file failed to compile");
error = true;
}
}
@@ -728,9 +735,10 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
} else if (visibility_.value() == "default") {
options_.visibility = Visibility::Level::kUndefined;
} else {
- context.GetDiagnostics()->Error(
- DiagMessage() << "Unrecognized visibility level passes to --visibility: '"
- << visibility_.value() << "'. Accepted levels: public, private, default");
+ context.GetDiagnostics()->Error(android::DiagMessage()
+ << "Unrecognized visibility level passes to --visibility: '"
+ << visibility_.value()
+ << "'. Accepted levels: public, private, default");
return 1;
}
}
@@ -739,17 +747,17 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
// Collect the resources files to compile
if (options_.res_dir && options_.res_zip) {
- context.GetDiagnostics()->Error(DiagMessage()
- << "only one of --dir and --zip can be specified");
+ context.GetDiagnostics()->Error(android::DiagMessage()
+ << "only one of --dir and --zip can be specified");
return 1;
} else if ((options_.res_dir || options_.res_zip) &&
options_.source_path && args.size() > 1) {
- context.GetDiagnostics()->Error(DiagMessage(kPath)
- << "Cannot use an overriding source path with multiple files.");
- return 1;
+ context.GetDiagnostics()->Error(android::DiagMessage(kPath)
+ << "Cannot use an overriding source path with multiple files.");
+ return 1;
} else if (options_.res_dir) {
if (!args.empty()) {
- context.GetDiagnostics()->Error(DiagMessage() << "files given but --dir specified");
+ context.GetDiagnostics()->Error(android::DiagMessage() << "files given but --dir specified");
Usage(&std::cerr);
return 1;
}
@@ -758,12 +766,12 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
std::string err;
file_collection = io::FileCollection::Create(options_.res_dir.value(), &err);
if (!file_collection) {
- context.GetDiagnostics()->Error(DiagMessage(options_.res_dir.value()) << err);
+ context.GetDiagnostics()->Error(android::DiagMessage(options_.res_dir.value()) << err);
return 1;
}
} else if (options_.res_zip) {
if (!args.empty()) {
- context.GetDiagnostics()->Error(DiagMessage() << "files given but --zip specified");
+ context.GetDiagnostics()->Error(android::DiagMessage() << "files given but --zip specified");
Usage(&std::cerr);
return 1;
}
@@ -772,7 +780,7 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
std::string err;
file_collection = io::ZipFileCollection::Create(options_.res_zip.value(), &err);
if (!file_collection) {
- context.GetDiagnostics()->Error(DiagMessage(options_.res_zip.value()) << err);
+ context.GetDiagnostics()->Error(android::DiagMessage(options_.res_zip.value()) << err);
return 1;
}
} else {
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index bd2e3d72a551..14a730a1b1a0 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -17,15 +17,15 @@
#ifndef AAPT2_COMPILE_H
#define AAPT2_COMPILE_H
-#include <optional>
-
#include <androidfw/StringPiece.h>
-#include "format/Archive.h"
-#include "process/IResourceTableConsumer.h"
+#include <optional>
+
#include "Command.h"
-#include "Diagnostics.h"
#include "ResourceTable.h"
+#include "androidfw/IDiagnostics.h"
+#include "format/Archive.h"
+#include "process/IResourceTableConsumer.h"
namespace aapt {
@@ -47,8 +47,8 @@ struct CompileOptions {
/** Parses flags and compiles resources to be used in linking. */
class CompileCommand : public Command {
public:
- explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"),
- diagnostic_(diagnostic) {
+ explicit CompileCommand(android::IDiagnostics* diagnostic)
+ : Command("compile", "c"), diagnostic_(diagnostic) {
SetDescription("Compiles resources to be linked into an apk.");
AddRequiredFlag("-o", "Output path", &options_.output_path, Command::kPath);
AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir, Command::kPath);
@@ -81,7 +81,7 @@ class CompileCommand : public Command {
int Action(const std::vector<std::string>& args) override;
private:
- IDiagnostics* diagnostic_;
+ android::IDiagnostics* diagnostic_;
CompileOptions options_;
std::optional<std::string> visibility_;
std::optional<std::string> trace_folder_;
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index fbfbf68b30bb..3464a7662c60 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -219,7 +219,7 @@ static void AssertTranslations(CommandTestFixture *ctf, std::string file_name,
ASSERT_NE(table, nullptr);
table->string_pool.Sort();
- const std::vector<std::unique_ptr<StringPool::Entry>>& pool_strings =
+ const std::vector<std::unique_ptr<android::StringPool::Entry>>& pool_strings =
table->string_pool.strings();
// The actual / expected vectors have the same size
@@ -316,7 +316,7 @@ TEST_F(CompilerTest, RelativePathTest) {
std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(apk_path, &diag);
ResourceTable* resource_table = apk.get()->GetResourceTable();
- const std::vector<std::unique_ptr<StringPool::Entry>>& pool_strings =
+ const std::vector<std::unique_ptr<android::StringPool::Entry>>& pool_strings =
resource_table->string_pool.strings();
ASSERT_EQ(pool_strings.size(), 2);
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 3b097e09e09d..7381a85f4339 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -18,11 +18,13 @@
#include <vector>
-#include "android-base/macros.h"
-#include "androidfw/StringPiece.h"
-
+#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
@@ -43,8 +45,9 @@ namespace aapt {
class IApkSerializer {
public:
- IApkSerializer(IAaptContext* context, const Source& source) : context_(context),
- source_(source) {}
+ IApkSerializer(IAaptContext* context, const android::Source& source)
+ : context_(context), source_(source) {
+ }
virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) = 0;
@@ -55,21 +58,22 @@ class IApkSerializer {
protected:
IAaptContext* context_;
- Source source_;
+ android::Source source_;
};
class BinaryApkSerializer : public IApkSerializer {
public:
- BinaryApkSerializer(IAaptContext* context, const Source& source,
+ BinaryApkSerializer(IAaptContext* context, const android::Source& source,
const TableFlattenerOptions& table_flattener_options,
const XmlFlattenerOptions& xml_flattener_options)
: IApkSerializer(context, source),
table_flattener_options_(table_flattener_options),
- xml_flattener_options_(xml_flattener_options) {}
+ xml_flattener_options_(xml_flattener_options) {
+ }
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) override {
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
xml_flattener_options_.use_utf16 = utf16;
XmlFlattener flattener(&buffer, xml_flattener_options_);
if (!flattener.Consume(context_, xml)) {
@@ -81,7 +85,7 @@ class BinaryApkSerializer : public IApkSerializer {
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
TableFlattener table_flattener(table_flattener_options_, &buffer);
if (!table_flattener.Consume(context_, table)) {
return false;
@@ -96,7 +100,7 @@ class BinaryApkSerializer : public IApkSerializer {
if (file->type == ResourceFile::Type::kProtoXml) {
unique_ptr<io::InputStream> in = file->file->OpenInputStream();
if (in == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to open file " << *file->path);
return false;
}
@@ -104,7 +108,7 @@ class BinaryApkSerializer : public IApkSerializer {
pb::XmlNode pb_node;
io::ProtoInputStreamReader proto_reader(in.get());
if (!proto_reader.ReadMessage(&pb_node)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to parse proto XML " << *file->path);
return false;
}
@@ -112,15 +116,15 @@ class BinaryApkSerializer : public IApkSerializer {
std::string error;
unique_ptr<xml::XmlResource> xml = DeserializeXmlResourceFromPb(pb_node, &error);
if (xml == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "failed to deserialize proto XML "
- << *file->path << ": " << error);
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
+ << "failed to deserialize proto XML " << *file->path
+ << ": " << error);
return false;
}
if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to serialize to binary XML: " << *file->path);
return false;
}
@@ -128,7 +132,7 @@ class BinaryApkSerializer : public IApkSerializer {
file->type = ResourceFile::Type::kBinaryXml;
} else {
if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to copy file " << *file->path);
return false;
}
@@ -146,8 +150,9 @@ class BinaryApkSerializer : public IApkSerializer {
class ProtoApkSerializer : public IApkSerializer {
public:
- ProtoApkSerializer(IAaptContext* context, const Source& source)
- : IApkSerializer(context, source) {}
+ ProtoApkSerializer(IAaptContext* context, const android::Source& source)
+ : IApkSerializer(context, source) {
+ }
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) override {
@@ -167,7 +172,7 @@ class ProtoApkSerializer : public IApkSerializer {
if (file->type == ResourceFile::Type::kBinaryXml) {
std::unique_ptr<io::IData> data = file->file->OpenAsData();
if (!data) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to open file " << *file->path);
return false;
}
@@ -175,14 +180,14 @@ class ProtoApkSerializer : public IApkSerializer {
std::string error;
std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error);
if (xml == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "failed to parse binary XML: "
- << error);
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
+ << "failed to parse binary XML: " << error);
return false;
}
if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to serialize to proto XML: " << *file->path);
return false;
}
@@ -190,7 +195,7 @@ class ProtoApkSerializer : public IApkSerializer {
file->type = ResourceFile::Type::kProtoXml;
} else {
if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
+ context_->GetDiagnostics()->Error(android::DiagMessage(source_)
<< "failed to copy file " << *file->path);
return false;
}
@@ -216,7 +221,7 @@ class Context : public IAaptContext {
return &symbols_;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diag_;
}
@@ -240,7 +245,7 @@ class Context : public IAaptContext {
}
int GetMinSdkVersion() override {
- return 0u;
+ return min_sdk_;
}
const std::set<std::string>& GetSplitNameDependencies() override {
@@ -251,6 +256,7 @@ class Context : public IAaptContext {
bool verbose_ = false;
std::string package_;
+ int32_t min_sdk_ = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Context);
@@ -270,7 +276,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
} else if (output_format == ApkFormat::kProto) {
serializer.reset(new ProtoApkSerializer(context, apk->GetSource()));
} else {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "Cannot convert APK to unknown format");
return 1;
}
@@ -279,7 +285,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/,
output_writer, (manifest != nullptr && manifest->WasCompressed())
? ArchiveEntry::kCompress : 0u)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "failed to serialize AndroidManifest.xml");
return 1;
}
@@ -298,7 +304,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
FileReference* file = ValueCast<FileReference>(config_value->value.get());
if (file != nullptr) {
if (file->file == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "no file associated with " << *file);
return 1;
}
@@ -306,7 +312,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
// Only serialize if we haven't seen this file before
if (files_written.insert(*file->path).second) {
if (!serializer->SerializeFile(file, output_writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "failed to serialize file " << *file->path);
return 1;
}
@@ -319,7 +325,7 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
// Converted resource table
if (!serializer->SerializeTable(converted_table, output_writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
<< "failed to serialize the resource table");
return 1;
}
@@ -340,8 +346,8 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
}
if (!io::CopyFileToArchivePreserveCompression(context, file, path, output_writer)) {
- context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "failed to copy file " << path);
+ context->GetDiagnostics()->Error(android::DiagMessage(apk->GetSource())
+ << "failed to copy file " << path);
return 1;
}
}
@@ -349,6 +355,28 @@ int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer
return 0;
}
+bool ExtractResourceConfig(const std::string& path, IAaptContext* context,
+ TableFlattenerOptions& out_options) {
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
+ context->GetDiagnostics()->Error(android::DiagMessage(path) << "failed reading config file");
+ return false;
+ }
+ std::unordered_set<ResourceName> resources_exclude_list;
+ bool result = ParseResourceConfig(content, context, resources_exclude_list,
+ out_options.name_collapse_exemptions,
+ out_options.path_shorten_exemptions);
+ if (!result) {
+ return false;
+ }
+ if (!resources_exclude_list.empty()) {
+ context->GetDiagnostics()->Error(android::DiagMessage(path)
+ << "Unsupported '#remove' directive in resource config.");
+ return false;
+ }
+ return true;
+}
+
const char* ConvertCommand::kOutputFormatProto = "proto";
const char* ConvertCommand::kOutputFormatBinary = "binary";
@@ -360,10 +388,10 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
}
Context context;
- const StringPiece& path = args[0];
+ StringPiece path = args[0];
unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
if (apk == nullptr) {
- context.GetDiagnostics()->Error(DiagMessage(path) << "failed to load APK");
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << "failed to load APK");
return 1;
}
@@ -373,6 +401,7 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
}
context.package_ = app_info.value().package;
+ context.min_sdk_ = app_info.value().min_sdk_version.value_or(0);
unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(context.GetDiagnostics(),
output_path_);
if (writer == nullptr) {
@@ -385,10 +414,22 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
} else if (output_format_.value() == ConvertCommand::kOutputFormatProto) {
format = ApkFormat::kProto;
} else {
- context.GetDiagnostics()->Error(DiagMessage(path) << "Invalid value for flag --output-format: "
- << output_format_.value());
+ context.GetDiagnostics()->Error(android::DiagMessage(path)
+ << "Invalid value for flag --output-format: "
+ << output_format_.value());
return 1;
}
+ if (enable_sparse_encoding_) {
+ table_flattener_options_.sparse_entries = SparseEntriesMode::Enabled;
+ }
+ if (force_sparse_encoding_) {
+ table_flattener_options_.sparse_entries = SparseEntriesMode::Forced;
+ }
+ if (resources_config_path_) {
+ if (!ExtractResourceConfig(*resources_config_path_, &context, table_flattener_options_)) {
+ return 1;
+ }
+ }
return Convert(&context, apk.get(), writer.get(), format, table_flattener_options_,
xml_flattener_options_);
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
index 2cdb0c87310f..15fe11fd91cc 100644
--- a/tools/aapt2/cmd/Convert.h
+++ b/tools/aapt2/cmd/Convert.h
@@ -34,14 +34,41 @@ class ConvertCommand : public Command {
AddOptionalFlag("--output-format", android::base::StringPrintf("Format of the output. "
"Accepted values are '%s' and '%s'. When not set, defaults to '%s'.",
kOutputFormatProto, kOutputFormatBinary, kOutputFormatBinary), &output_format_);
- AddOptionalSwitch("--enable-sparse-encoding",
+ AddOptionalSwitch(
+ "--enable-sparse-encoding",
"Enables encoding sparse entries using a binary search tree.\n"
- "This decreases APK size at the cost of resource retrieval performance.",
- &table_flattener_options_.use_sparse_entries);
+ "This decreases APK size at the cost of resource retrieval performance.\n"
+ "Only applies sparse encoding to Android O+ resources or all resources if minSdk of "
+ "the APK is O+",
+ &enable_sparse_encoding_);
+ AddOptionalSwitch("--force-sparse-encoding",
+ "Enables encoding sparse entries using a binary search tree.\n"
+ "This decreases APK size at the cost of resource retrieval performance.\n"
+ "Applies sparse encoding to all resources regardless of minSdk.",
+ &force_sparse_encoding_);
AddOptionalSwitch("--keep-raw-values",
android::base::StringPrintf("Preserve raw attribute values in xml files when using the"
" '%s' output format", kOutputFormatBinary),
&xml_flattener_options_.keep_raw_values);
+ AddOptionalFlag("--resources-config-path",
+ "Path to the resources.cfg file containing the list of resources and \n"
+ "directives to each resource. \n"
+ "Format: type/resource_name#[directive][,directive]",
+ &resources_config_path_);
+ AddOptionalSwitch(
+ "--collapse-resource-names",
+ "Collapses resource names to a single value in the key string pool. Resources can \n"
+ "be exempted using the \"no_collapse\" directive in a file specified by "
+ "--resources-config-path.",
+ &table_flattener_options_.collapse_key_stringpool);
+ AddOptionalSwitch(
+ "--deduplicate-entry-values",
+ "Whether to deduplicate pairs of resource entry and value for simple resources.\n"
+ "This is recommended to be used together with '--collapse-resource-names' flag or for\n"
+ "APKs where resource names are manually collapsed. For such APKs this flag allows to\n"
+ "store the same resource value only once in resource table which decreases APK size.\n"
+ "Has no effect on APKs where resource names are kept.",
+ &table_flattener_options_.deduplicate_entry_values);
AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
}
@@ -56,6 +83,9 @@ class ConvertCommand : public Command {
std::string output_path_;
std::optional<std::string> output_format_;
bool verbose_ = false;
+ bool enable_sparse_encoding_ = false;
+ bool force_sparse_encoding_ = false;
+ std::optional<std::string> resources_config_path_;
};
int Convert(IAaptContext* context, LoadedApk* input, IArchiveWriter* output_writer,
diff --git a/tools/aapt2/cmd/Convert_test.cpp b/tools/aapt2/cmd/Convert_test.cpp
index f35237ec25e3..2c9388b7d711 100644
--- a/tools/aapt2/cmd/Convert_test.cpp
+++ b/tools/aapt2/cmd/Convert_test.cpp
@@ -17,13 +17,18 @@
#include "Convert.h"
#include "LoadedApk.h"
+#include "test/Common.h"
#include "test/Test.h"
#include "ziparchive/zip_archive.h"
+using testing::AnyOfArray;
using testing::Eq;
using testing::Ne;
+using testing::Not;
+using testing::SizeIs;
namespace aapt {
+using namespace aapt::test;
using ConvertTest = CommandTestFixture;
@@ -101,7 +106,8 @@ TEST_F(ConvertTest, KeepRawXmlStrings) {
// Check that the raw string index has been set to the correct string pool entry
int32_t raw_index = tree.getAttributeValueStringID(0);
ASSERT_THAT(raw_index, Ne(-1));
- EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+ EXPECT_THAT(android::util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)),
+ Eq("007"));
}
TEST_F(ConvertTest, DuplicateEntriesWrittenOnce) {
@@ -144,4 +150,76 @@ TEST_F(ConvertTest, DuplicateEntriesWrittenOnce) {
EXPECT_THAT(count, Eq(1));
}
+TEST_F(ConvertTest, ConvertWithResourceNameCollapsing) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
+ R"(<resources>
+ <string name="first">string</string>
+ <string name="second">string</string>
+ <string name="third">another string</string>
+
+ <bool name="bool1">true</bool>
+ <bool name="bool2">true</bool>
+ <bool name="bool3">true</bool>
+
+ <integer name="int1">10</integer>
+ <integer name="int2">10</integer>
+ </resources>)",
+ compiled_files_dir, &diag));
+ std::string resource_config_path = GetTestPath("resource-config");
+ WriteFile(resource_config_path, "integer/int1#no_collapse\ninteger/int2#no_collapse");
+
+ const std::string proto_apk = GetTestPath("proto.apk");
+ std::vector<std::string> link_args = {
+ "--proto-format", "--manifest", GetDefaultManifest(kDefaultPackageName), "-o", proto_apk,
+ };
+ ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+ const std::string binary_apk = GetTestPath("binary.apk");
+ std::vector<android::StringPiece> convert_args = {"-o",
+ binary_apk,
+ "--output-format",
+ "binary",
+ "--collapse-resource-names",
+ "--deduplicate-entry-values",
+ "--resources-config-path",
+ resource_config_path,
+ proto_apk};
+ ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
+
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(binary_apk, &diag);
+ for (const auto& package : apk->GetResourceTable()->packages) {
+ for (const auto& type : package->types) {
+ switch (type->named_type.type) {
+ case ResourceType::kBool:
+ EXPECT_THAT(type->entries, SizeIs(3));
+ for (const auto& entry : type->entries) {
+ auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
+ EXPECT_THAT(value.data, Eq(0xffffffffu));
+ }
+ break;
+ case ResourceType::kString:
+ EXPECT_THAT(type->entries, SizeIs(3));
+ for (const auto& entry : type->entries) {
+ auto value = ValueCast<String>(entry->FindValue({})->value.get())->value;
+ EXPECT_THAT(entry->name, Not(AnyOfArray({"first", "second", "third"})));
+ EXPECT_THAT(*value, AnyOfArray({"string", "another string"}));
+ }
+ break;
+ case ResourceType::kInteger:
+ EXPECT_THAT(type->entries, SizeIs(2));
+ for (const auto& entry : type->entries) {
+ auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
+ EXPECT_THAT(entry->name, AnyOfArray({"int1", "int2"}));
+ EXPECT_THAT(value.data, Eq(10));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index d9e8c921dbc5..5bfc73233bfe 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -16,10 +16,10 @@
#include "Diff.h"
-#include "android-base/macros.h"
-
+#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ValueVisitor.h"
+#include "android-base/macros.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -45,7 +45,7 @@ class DiffContext : public IAaptContext {
return 0x0;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -78,7 +78,7 @@ class DiffContext : public IAaptContext {
SymbolTable symbol_table_;
};
-static void EmitDiffLine(const Source& source, const StringPiece& message) {
+static void EmitDiffLine(const android::Source& source, StringPiece message) {
std::cerr << source << ": " << message << "\n";
}
@@ -105,7 +105,7 @@ static bool EmitResourceConfigValueDiff(
Value* value_b = config_value_b->value.get();
if (!value_a->Equals(value_b)) {
std::stringstream str_stream;
- str_stream << "value " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << "value " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " config=" << config_value_a->config << " does not match:\n";
value_a->Print(&str_stream);
str_stream << "\n vs \n";
@@ -128,7 +128,7 @@ static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
auto config_value_b = entry_b.FindValue(config_value_a->config);
if (!config_value_b) {
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << "missing " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " config=" << config_value_a->config;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
@@ -143,7 +143,7 @@ static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
auto config_value_a = entry_a.FindValue(config_value_b->config);
if (!config_value_a) {
std::stringstream str_stream;
- str_stream << "new config " << pkg_b.name << ":" << type_b.type << "/" << entry_b.name
+ str_stream << "new config " << pkg_b.name << ":" << type_b.named_type << "/" << entry_b.name
<< " config=" << config_value_b->config;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
@@ -164,13 +164,15 @@ static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
if (entry_b_iter == type_b.entries.end()) {
// Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a_iter->name;
+ str_stream << "missing " << pkg_a.name << ":" << type_a.named_type << "/"
+ << entry_a_iter->name;
EmitDiffLine(apk_a->GetSource(), str_stream.str());
diff = true;
} else if (entry_a_iter == type_a.entries.end()) {
// Type B contains a type that type A does not have.
std::stringstream str_stream;
- str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/" << entry_b_iter->name;
+ str_stream << "new entry " << pkg_b.name << ":" << type_b.named_type << "/"
+ << entry_b_iter->name;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
} else {
@@ -178,7 +180,7 @@ static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
const auto& entry_b = *entry_b_iter;
if (IsSymbolVisibilityDifferent(entry_a.visibility, entry_b.visibility)) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " has different visibility (";
if (entry_b.visibility.staged_api) {
str_stream << "STAGED ";
@@ -203,7 +205,7 @@ static bool EmitResourceTypeDiff(IAaptContext* context, LoadedApk* apk_a,
} else if (IsIdDiff(entry_a.visibility.level, entry_a.id, entry_b.visibility.level,
entry_b.id)) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
+ str_stream << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
<< " has different public ID (";
if (entry_b.id) {
str_stream << "0x" << std::hex << entry_b.id.value();
@@ -243,13 +245,13 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
if (type_b_iter == pkg_b.types.end()) {
// Type A contains a type that type B does not have.
std::stringstream str_stream;
- str_stream << "missing " << pkg_a.name << ":" << type_a_iter->type;
+ str_stream << "missing " << pkg_a.name << ":" << type_a_iter->named_type;
EmitDiffLine(apk_a->GetSource(), str_stream.str());
diff = true;
} else if (type_a_iter == pkg_a.types.end()) {
// Type B contains a type that type A does not have.
std::stringstream str_stream;
- str_stream << "new type " << pkg_b.name << ":" << type_b_iter->type;
+ str_stream << "new type " << pkg_b.name << ":" << type_b_iter->named_type;
EmitDiffLine(apk_b->GetSource(), str_stream.str());
diff = true;
} else {
@@ -257,7 +259,7 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
const auto& type_b = *type_b_iter;
if (type_a.visibility_level != type_b.visibility_level) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << " has different visibility (";
+ str_stream << pkg_a.name << ":" << type_a.named_type << " has different visibility (";
if (type_b.visibility_level == Visibility::Level::kPublic) {
str_stream << "PUBLIC";
} else {
@@ -274,7 +276,7 @@ static bool EmitResourcePackageDiff(IAaptContext* context, LoadedApk* apk_a,
diff = true;
} else if (IsIdDiff(type_a.visibility_level, type_a.id, type_b.visibility_level, type_b.id)) {
std::stringstream str_stream;
- str_stream << pkg_a.name << ":" << type_a.type << " has different public ID (";
+ str_stream << pkg_a.name << ":" << type_a.named_type << " has different public ID (";
if (type_b.id) {
str_stream << "0x" << std::hex << type_b.id.value();
} else {
@@ -383,7 +385,7 @@ int DiffCommand::Action(const std::vector<std::string>& args) {
return 1;
}
- IDiagnostics* diag = context.GetDiagnostics();
+ android::IDiagnostics* diag = context.GetDiagnostics();
std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(args[0], diag);
std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(args[1], diag);
if (!apk_a || !apk_b) {
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index bcce3e5a800f..71b08022f688 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -57,8 +57,8 @@ static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
return "UNKNOWN";
}
-static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
- size_t len, Printer* printer) {
+static void DumpCompiledFile(const ResourceFile& file, const android::Source& source,
+ off64_t offset, size_t len, Printer* printer) {
printer->Print("Resource: ");
printer->Println(file.name.to_string());
@@ -83,7 +83,7 @@ class DumpContext : public IAaptContext {
return PackageType::kApp;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -138,7 +138,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
print_options.show_values = !no_values_;
if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump container specified");
+ diag_->Error(android::DiagMessage() << "No dump container specified");
return 1;
}
@@ -146,7 +146,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
for (auto container : args) {
io::FileInputStream input(container);
if (input.HadError()) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to open file: " << input.GetError());
error = true;
continue;
@@ -155,7 +155,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
// Try as a compiled file.
ContainerReader reader(&input);
if (reader.HadError()) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to read container: " << reader.GetError());
error = true;
continue;
@@ -170,7 +170,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to parse proto table: " << entry->GetError());
error = true;
continue;
@@ -179,7 +179,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
ResourceTable table;
error.clear();
if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to parse table: " << error);
error = true;
continue;
@@ -194,7 +194,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
off64_t offset;
size_t length;
if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
- context.GetDiagnostics()->Error(DiagMessage(container)
+ context.GetDiagnostics()->Error(android::DiagMessage(container)
<< "failed to parse compiled proto file: "
<< entry->GetError());
error = true;
@@ -203,14 +203,14 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
ResourceFile file;
if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
- context.GetDiagnostics()->Warn(DiagMessage(container)
+ context.GetDiagnostics()->Warn(android::DiagMessage(container)
<< "failed to parse compiled file: " << error);
error = true;
continue;
}
printer_->Indent();
- DumpCompiledFile(file, Source(container), offset, length, printer_);
+ DumpCompiledFile(file, android::Source(container), offset, length, printer_);
printer_->Undent();
}
}
@@ -228,7 +228,7 @@ int DumpBadgerCommand::Action(const std::vector<std::string>& args) {
int DumpConfigsCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
@@ -268,13 +268,13 @@ int DumpPackageNameCommand::Dump(LoadedApk* apk) {
int DumpStringsCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
// Load the run-time xml string pool using the flattened data
- BigBuffer buffer(4096);
- StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics());
+ android::BigBuffer buffer(4096);
+ android::StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics());
auto data = buffer.to_string();
android::ResStringPool pool(data.data(), data.size(), false);
Debug::DumpResStringPool(&pool, GetPrinter());
@@ -291,14 +291,14 @@ int DumpStyleParentCommand::Dump(LoadedApk* apk) {
const auto table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
std::optional<ResourceTable::SearchResult> target = table->FindResource(target_style);
if (!target) {
- GetDiagnostics()->Error(
- DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist");
+ GetDiagnostics()->Error(android::DiagMessage()
+ << "Target style \"" << target_style.entry << "\" does not exist");
return 1;
}
@@ -315,7 +315,7 @@ int DumpTableCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
@@ -340,7 +340,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
}
// Flatten the xml document to get a binary representation of the proto xml file
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
@@ -356,7 +356,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
} else if (apk->GetApkFormat() == ApkFormat::kBinary) {
io::IFile* file = apk->GetFileCollection()->FindFile(xml_file);
if (!file) {
- GetDiagnostics()->Error(DiagMessage(xml_file)
+ GetDiagnostics()->Error(android::DiagMessage(xml_file)
<< "File '" << xml_file << "' not found in APK");
error = true;
continue;
@@ -364,7 +364,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to open " << xml_file);
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to open " << xml_file);
error = true;
continue;
}
@@ -372,7 +372,7 @@ int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
// Load the run-time xml tree from the file data
tree.setTo(data->data(), data->size(), /** copyData */ true);
} else {
- GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "Unknown APK format");
+ GetDiagnostics()->Error(android::DiagMessage(apk->GetSource()) << "Unknown APK format");
error = true;
continue;
}
@@ -396,7 +396,7 @@ int DumpXmlTreeCommand::Dump(LoadedApk* apk) {
int DumpOverlayableCommand::Dump(LoadedApk* apk) {
ResourceTable* table = apk->GetResourceTable();
if (!table) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to retrieve resource table");
return 1;
}
@@ -563,13 +563,13 @@ const char DumpBadgerCommand::kBadgerData[2925] = {
int DumpChunks::Dump(LoadedApk* apk) {
auto file = apk->GetFileCollection()->FindFile("resources.arsc");
if (!file) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to find resources.arsc in APK");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to find resources.arsc in APK");
return 1;
}
auto data = file->OpenAsData();
if (!data) {
- GetDiagnostics()->Error(DiagMessage() << "Failed to open resources.arsc ");
+ GetDiagnostics()->Error(android::DiagMessage() << "Failed to open resources.arsc ");
return 1;
}
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index ec320ecd2a32..76d33d7aa3b2 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -33,29 +33,30 @@ namespace aapt {
**/
class DumpApkCommand : public Command {
public:
- explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
+ explicit DumpApkCommand(const std::string&& name, text::Printer* printer,
+ android::IDiagnostics* diag)
: Command(name), printer_(printer), diag_(diag) {
- SetDescription("Dump information about an APK or APC.");
+ SetDescription("Dump information about an APK or APC.");
}
text::Printer* GetPrinter() {
return printer_;
}
- IDiagnostics* GetDiagnostics() {
+ android::IDiagnostics* GetDiagnostics() {
return diag_;
}
std::optional<std::string> GetPackageName(LoadedApk* apk) {
xml::Element* manifest_el = apk->GetManifest()->root.get();
if (!manifest_el) {
- GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest.");
+ GetDiagnostics()->Error(android::DiagMessage() << "No AndroidManifest.");
return {};
}
xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
if (!attr) {
- GetDiagnostics()->Error(DiagMessage() << "No package name.");
+ GetDiagnostics()->Error(android::DiagMessage() << "No package name.");
return {};
}
return attr->value;
@@ -66,7 +67,7 @@ class DumpApkCommand : public Command {
int Action(const std::vector<std::string>& args) final {
if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
+ diag_->Error(android::DiagMessage() << "No dump apk specified.");
return 1;
}
@@ -86,13 +87,13 @@ class DumpApkCommand : public Command {
private:
text::Printer* printer_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
};
/** Command that prints contents of files generated from the compilation stage. */
class DumpAPCCommand : public Command {
public:
- explicit DumpAPCCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpAPCCommand(text::Printer* printer, android::IDiagnostics* diag)
: Command("apc"), printer_(printer), diag_(diag) {
SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation.");
AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
@@ -104,7 +105,7 @@ class DumpAPCCommand : public Command {
private:
text::Printer* printer_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
bool no_values_ = false;
bool verbose_ = false;
};
@@ -124,13 +125,21 @@ class DumpBadgerCommand : public Command {
class DumpBadgingCommand : public DumpApkCommand {
public:
- explicit DumpBadgingCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpBadgingCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("badging", printer, diag) {
SetDescription("Print information extracted from the manifest of the APK.");
AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
&options_.include_meta_data);
}
+ void SetIncludeMetaData(bool value) {
+ options_.include_meta_data = value;
+ }
+
+ void SetOnlyPermissions(bool value) {
+ options_.only_permissions = value;
+ }
+
int Dump(LoadedApk* apk) override {
return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics());
}
@@ -141,7 +150,7 @@ class DumpBadgingCommand : public DumpApkCommand {
class DumpConfigsCommand : public DumpApkCommand {
public:
- explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpConfigsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("configurations", printer, diag) {
SetDescription("Print every configuration used by a resource in the APK.");
}
@@ -151,7 +160,7 @@ class DumpConfigsCommand : public DumpApkCommand {
class DumpPackageNameCommand : public DumpApkCommand {
public:
- explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpPackageNameCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("packagename", printer, diag) {
SetDescription("Print the package name of the APK.");
}
@@ -161,7 +170,7 @@ class DumpPackageNameCommand : public DumpApkCommand {
class DumpPermissionsCommand : public DumpApkCommand {
public:
- explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpPermissionsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("permissions", printer, diag) {
SetDescription("Print the permissions extracted from the manifest of the APK.");
}
@@ -175,7 +184,7 @@ class DumpPermissionsCommand : public DumpApkCommand {
class DumpStringsCommand : public DumpApkCommand {
public:
- explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpStringsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("strings", printer, diag) {
SetDescription("Print the contents of the resource table string pool in the APK.");
}
@@ -186,7 +195,7 @@ class DumpStringsCommand : public DumpApkCommand {
/** Prints the graph of parents of a style in an APK. */
class DumpStyleParentCommand : public DumpApkCommand {
public:
- explicit DumpStyleParentCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpStyleParentCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("styleparents", printer, diag) {
SetDescription("Print the parents of a style in an APK.");
AddRequiredFlag("--style", "The name of the style to print", &style_);
@@ -200,7 +209,7 @@ class DumpStyleParentCommand : public DumpApkCommand {
class DumpTableCommand : public DumpApkCommand {
public:
- explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpTableCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("resources", printer, diag) {
SetDescription("Print the contents of the resource table from the APK.");
AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
@@ -217,7 +226,7 @@ class DumpTableCommand : public DumpApkCommand {
class DumpXmlStringsCommand : public DumpApkCommand {
public:
- explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpXmlStringsCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("xmlstrings", printer, diag) {
SetDescription("Print the string pool of a compiled xml in an APK.");
AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
@@ -231,7 +240,8 @@ class DumpXmlStringsCommand : public DumpApkCommand {
class DumpChunks : public DumpApkCommand {
public:
- DumpChunks(text::Printer* printer, IDiagnostics* diag) : DumpApkCommand("chunks", printer, diag) {
+ DumpChunks(text::Printer* printer, android::IDiagnostics* diag)
+ : DumpApkCommand("chunks", printer, diag) {
SetDescription("Print the chunk information of the compiled resources.arsc in the APK.");
}
@@ -241,7 +251,7 @@ class DumpChunks : public DumpApkCommand {
/** Prints the tree of a compiled xml in an APK. */
class DumpXmlTreeCommand : public DumpApkCommand {
public:
- explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpXmlTreeCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("xmltree", printer, diag) {
SetDescription("Print the tree of a compiled xml in an APK.");
AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
@@ -255,7 +265,7 @@ class DumpXmlTreeCommand : public DumpApkCommand {
class DumpOverlayableCommand : public DumpApkCommand {
public:
- explicit DumpOverlayableCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpOverlayableCommand(text::Printer* printer, android::IDiagnostics* diag)
: DumpApkCommand("overlayable", printer, diag) {
SetDescription("Print the <overlayable> resources of an APK.");
}
@@ -266,7 +276,7 @@ class DumpOverlayableCommand : public DumpApkCommand {
/** The default dump command. Performs no action because a subcommand is required. */
class DumpCommand : public Command {
public:
- explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
+ explicit DumpCommand(text::Printer* printer, android::IDiagnostics* diag)
: Command("dump", "d"), diag_(diag) {
AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
@@ -285,16 +295,16 @@ class DumpCommand : public Command {
int Action(const std::vector<std::string>& args) override {
if (args.size() == 0) {
- diag_->Error(DiagMessage() << "no subcommand specified");
+ diag_->Error(android::DiagMessage() << "no subcommand specified");
} else {
- diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+ diag_->Error(android::DiagMessage() << "unknown subcommand '" << args[0] << "'");
}
Usage(&std::cerr);
return 1;
}
private:
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
};
} // namespace aapt
diff --git a/tools/aapt2/cmd/Dump_test.cpp b/tools/aapt2/cmd/Dump_test.cpp
new file mode 100644
index 000000000000..df35ebbc064d
--- /dev/null
+++ b/tools/aapt2/cmd/Dump_test.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dump.h"
+
+#include "LoadedApk.h"
+#include "io/StringStream.h"
+#include "test/Test.h"
+#include "text/Printer.h"
+
+using ::aapt::io::StringOutputStream;
+using ::aapt::text::Printer;
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using DumpTest = CommandTestFixture;
+
+static android::NoOpDiagnostics noop_diag;
+
+void DumpBadgingToString(LoadedApk* loaded_apk, std::string* output, bool include_meta_data = false,
+ bool only_permissions = false) {
+ StringOutputStream output_stream(output);
+ Printer printer(&output_stream);
+
+ DumpBadgingCommand command(&printer, &noop_diag);
+ command.SetIncludeMetaData(include_meta_data);
+ command.SetOnlyPermissions(only_permissions);
+ ASSERT_EQ(command.Dump(loaded_apk), 0);
+ output_stream.Flush();
+}
+
+TEST_F(DumpTest, DumpBadging) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "minimal.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output);
+
+ std::string expected;
+ auto expected_path = file::BuildPath({android::base::GetExecutableDirectory(),
+ "integration-tests", "DumpTest", "minimal_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+TEST_F(DumpTest, DumpBadgingMultipleUsesSdkTakesLatest) {
+ auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests",
+ "DumpTest", "multiple_uses_sdk.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "multiple_uses_sdk_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+TEST_F(DumpTest, DumpBadgingAllComponents) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output, /* include_meta_data= */ true);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+TEST_F(DumpTest, DumpBadgingPermissionsOnly) {
+ auto apk_path = file::BuildPath(
+ {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output, /* include_meta_data= */ false,
+ /* only_permissions= */ true);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "components_permissions_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+TEST_F(DumpTest, DumpBadgingApkBuiltWithAaptAndTagsInWrongPlace) {
+ auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests",
+ "DumpTest", "built_with_aapt.apk"});
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+ std::string output;
+ DumpBadgingToString(loaded_apk.get(), &output, /* include_meta_data= */ false,
+ /* only_permissions= */ false);
+
+ std::string expected;
+ auto expected_path =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+ "built_with_aapt_expected.txt"});
+ ::android::base::ReadFileToString(expected_path, &expected);
+ ASSERT_EQ(output, expected);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 790f2b34c58b..97404fc69af2 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -17,20 +17,13 @@
#include "Link.h"
#include <sys/stat.h>
-#include <cinttypes>
#include <algorithm>
+#include <cinttypes>
#include <queue>
#include <unordered_map>
#include <vector>
-#include "android-base/errors.h"
-#include "android-base/expected.h"
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-#include "androidfw/Locale.h"
-#include "androidfw/StringPiece.h"
-
#include "AppInfo.h"
#include "Debug.h"
#include "LoadedApk.h"
@@ -38,6 +31,13 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "android-base/errors.h"
+#include "android-base/expected.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Locale.h"
+#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "compile/XmlIdCollector.h"
@@ -98,7 +98,7 @@ constexpr uint8_t kAndroidPackageId = 0x01;
class LinkContext : public IAaptContext {
public:
- explicit LinkContext(IDiagnostics* diagnostics)
+ explicit LinkContext(android::IDiagnostics* diagnostics)
: diagnostics_(diagnostics), name_mangler_({}), symbols_(&name_mangler_) {
}
@@ -110,7 +110,7 @@ class LinkContext : public IAaptContext {
package_type_ = type;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return diagnostics_;
}
@@ -126,8 +126,8 @@ class LinkContext : public IAaptContext {
return compilation_package_;
}
- void SetCompilationPackage(const StringPiece& package_name) {
- compilation_package_ = package_name.to_string();
+ void SetCompilationPackage(StringPiece package_name) {
+ compilation_package_ = std::string(package_name);
}
uint8_t GetPackageId() override {
@@ -170,7 +170,7 @@ class LinkContext : public IAaptContext {
DISALLOW_COPY_AND_ASSIGN(LinkContext);
PackageType package_type_ = PackageType::kApp;
- IDiagnostics* diagnostics_;
+ android::IDiagnostics* diagnostics_;
NameMangler name_mangler_;
std::string compilation_package_;
uint8_t package_id_ = 0x0;
@@ -216,14 +216,16 @@ class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
// Check that this doesn't overlap another resource.
if (DefaultSymbolTableDelegate::FindById(rewritten_id, sources) != nullptr) {
// The ID overlaps, so log a message (since this is a weird failure) and fail.
- context_->GetDiagnostics()->Error(DiagMessage() << "Failed to rewrite " << name
- << " for pre-O feature split support");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "Failed to rewrite " << name
+ << " for pre-O feature split support");
return {};
}
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "rewriting " << name << " (" << *id
- << ") -> (" << rewritten_id << ")");
+ context_->GetDiagnostics()->Note(android::DiagMessage()
+ << "rewriting " << name << " (" << *id << ") -> ("
+ << rewritten_id << ")");
}
*id = rewritten_id;
@@ -238,19 +240,19 @@ class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
IAaptContext* context_;
};
-static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
- const StringPiece& path, bool keep_raw_values, bool utf16,
- OutputFormat format, IArchiveWriter* writer) {
+static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res, StringPiece path,
+ bool keep_raw_values, bool utf16, OutputFormat format,
+ IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage(path) << "writing to archive (keep_raw_values="
- << (keep_raw_values ? "true" : "false")
- << ")");
+ context->GetDiagnostics()->Note(android::DiagMessage(path)
+ << "writing to archive (keep_raw_values="
+ << (keep_raw_values ? "true" : "false") << ")");
}
switch (format) {
case OutputFormat::kApk: {
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
XmlFlattenerOptions options = {};
options.keep_raw_values = keep_raw_values;
options.use_utf16 = utf16;
@@ -260,8 +262,8 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
}
io::BigBufferInputStream input_stream(&buffer);
- return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
- ArchiveEntry::kCompress, writer);
+ return io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kCompress,
+ writer);
} break;
case OutputFormat::kProto: {
@@ -270,22 +272,22 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
SerializeXmlOptions options;
options.remove_empty_text_nodes = (path == kAndroidManifestPath);
SerializeXmlResourceToPb(xml_res, &pb_node);
- return io::CopyProtoToArchive(context, &pb_node, path.to_string(), ArchiveEntry::kCompress,
- writer);
+ return io::CopyProtoToArchive(context, &pb_node, path, ArchiveEntry::kCompress, writer);
} break;
}
return false;
}
// Inflates an XML file from the source path.
-static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path, IDiagnostics* diag) {
+static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path,
+ android::IDiagnostics* diag) {
TRACE_CALL();
FileInputStream fin(path);
if (fin.HadError()) {
- diag->Error(DiagMessage(path) << "failed to load XML file: " << fin.GetError());
+ diag->Error(android::DiagMessage(path) << "failed to load XML file: " << fin.GetError());
return {};
}
- return xml::Inflate(&fin, diag, Source(path));
+ return xml::Inflate(&fin, diag, android::Source(path));
}
struct ResourceFileFlattenerOptions {
@@ -326,13 +328,13 @@ struct R {
};
template <typename T>
-uint32_t GetCompressionFlags(const StringPiece& str, T options) {
+uint32_t GetCompressionFlags(StringPiece str, T options) {
if (options.do_not_compress_anything) {
return 0;
}
- if (options.regex_to_not_compress
- && std::regex_search(str.to_string(), options.regex_to_not_compress.value())) {
+ if (options.regex_to_not_compress &&
+ std::regex_search(str.begin(), str.end(), options.regex_to_not_compress.value())) {
return 0;
}
@@ -451,10 +453,10 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer
ResourceTable* table, FileOperation* file_op) {
TRACE_CALL();
xml::XmlResource* doc = file_op->xml_to_flatten.get();
- const Source& src = doc->file.source;
+ const android::Source& src = doc->file.source;
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "linking " << src.path << " (" << doc->file.name << ")");
}
@@ -545,7 +547,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
io::IFile* file = file_ref->file;
if (!file) {
- context_->GetDiagnostics()->Error(DiagMessage(file_ref->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file_ref->GetSource())
<< "file not found");
return false;
}
@@ -556,12 +558,12 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
file_op.config = config_value->config;
file_op.file_to_copy = file;
- if (type->type != ResourceType::kRaw &&
+ if (type->named_type.type != ResourceType::kRaw &&
(file_ref->type == ResourceFile::Type::kBinaryXml ||
file_ref->type == ResourceFile::Type::kProtoXml)) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to open file");
return false;
}
@@ -569,7 +571,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
if (file_ref->type == ResourceFile::Type::kProtoXml) {
pb::XmlNode pb_xml_node;
if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to parse proto XML");
return false;
}
@@ -577,7 +579,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
std::string error;
file_op.xml_to_flatten = DeserializeXmlResourceFromPb(pb_xml_node, &error);
if (file_op.xml_to_flatten == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to deserialize proto XML: " << error);
return false;
}
@@ -585,7 +587,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
std::string error_str;
file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(), &error_str);
if (file_op.xml_to_flatten == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
<< "failed to parse binary XML: " << error_str);
return false;
}
@@ -596,7 +598,8 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
file_op.xml_to_flatten->file.config = config_value->config;
file_op.xml_to_flatten->file.source = file_ref->GetSource();
- file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name);
+ file_op.xml_to_flatten->file.name =
+ ResourceName(pkg->name, type->named_type, entry->name);
}
// NOTE(adamlesinski): Explicitly construct a StringPiece here, or
@@ -620,10 +623,10 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
if (drawable_entry != kDrawableVersions.end()) {
if (drawable_entry->second > context_->GetMinSdkVersion()
&& drawable_entry->second > config.sdkVersion) {
- context_->GetDiagnostics()->Error(DiagMessage(file_op.xml_to_flatten->file.source)
- << "<" << drawable_entry->first << "> elements "
- << "require a sdk version of at least "
- << (int16_t) drawable_entry->second);
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(file_op.xml_to_flatten->file.source)
+ << "<" << drawable_entry->first << "> elements "
+ << "require a sdk version of at least " << (int16_t)drawable_entry->second);
error = true;
continue;
}
@@ -641,7 +644,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
if (doc->file.config != file_op.config) {
// Only add the new versioned configurations.
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage(doc->file.source)
+ context_->GetDiagnostics()->Note(android::DiagMessage(doc->file.source)
<< "auto-versioning resource from config '"
<< config << "' -> '" << doc->file.config << "'");
}
@@ -679,12 +682,12 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
return !error;
}
-static bool WriteStableIdMapToPath(IDiagnostics* diag,
+static bool WriteStableIdMapToPath(android::IDiagnostics* diag,
const std::unordered_map<ResourceName, ResourceId>& id_map,
const std::string& id_map_path) {
io::FileOutputStream fout(id_map_path);
if (fout.HadError()) {
- diag->Error(DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
+ diag->Error(android::DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
return false;
}
@@ -699,17 +702,17 @@ static bool WriteStableIdMapToPath(IDiagnostics* diag,
fout.Flush();
if (fout.HadError()) {
- diag->Error(DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
+ diag->Error(android::DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
return false;
}
return true;
}
-static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
+static bool LoadStableIdMap(android::IDiagnostics* diag, const std::string& path,
std::unordered_map<ResourceName, ResourceId>* out_id_map) {
std::string content;
if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
- diag->Error(DiagMessage(path) << "failed reading stable ID file");
+ diag->Error(android::DiagMessage(path) << "failed reading stable ID file");
return false;
}
@@ -724,7 +727,7 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
auto iter = std::find(line.begin(), line.end(), '=');
if (iter == line.end()) {
- diag->Error(DiagMessage(Source(path, line_no)) << "missing '='");
+ diag->Error(android::DiagMessage(android::Source(path, line_no)) << "missing '='");
return false;
}
@@ -732,8 +735,8 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
StringPiece res_name_str =
util::TrimWhitespace(line.substr(0, std::distance(line.begin(), iter)));
if (!ResourceUtils::ParseResourceName(res_name_str, &name)) {
- diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource name '" << res_name_str
- << "'");
+ diag->Error(android::DiagMessage(android::Source(path, line_no))
+ << "invalid resource name '" << res_name_str << "'");
return false;
}
@@ -743,8 +746,8 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str);
if (!maybe_id) {
- diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource ID '" << res_id_str
- << "'");
+ diag->Error(android::DiagMessage(android::Source(path, line_no))
+ << "invalid resource ID '" << res_id_str << "'");
return false;
}
@@ -834,20 +837,21 @@ class Linker {
auto asset_source = util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : options_.include_paths) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
+ context_->GetDiagnostics()->Note(android::DiagMessage() << "including " << path);
}
std::string error;
auto zip_collection = io::ZipFileCollection::Create(path, &error);
if (zip_collection == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to open APK: " << error);
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to open APK: " << error);
return false;
}
if (zip_collection->FindFile(kProtoResourceTablePath) != nullptr) {
// Load this as a static library include.
std::unique_ptr<LoadedApk> static_apk = LoadedApk::LoadProtoApkFromFileCollection(
- Source(path), std::move(zip_collection), context_->GetDiagnostics());
+ android::Source(path), std::move(zip_collection), context_->GetDiagnostics());
if (static_apk == nullptr) {
return false;
}
@@ -856,7 +860,8 @@ class Linker {
// Can't include static libraries when not building a static library (they have no IDs
// assigned).
context_->GetDiagnostics()->Error(
- DiagMessage(path) << "can't include static library when not building a static lib");
+ android::DiagMessage(path)
+ << "can't include static library when not building a static lib");
return false;
}
@@ -868,7 +873,8 @@ class Linker {
if (options_.no_static_lib_packages && !table->packages.empty()) {
auto lib_package_result = GetStaticLibraryPackage(table);
if (!lib_package_result.has_value()) {
- context_->GetDiagnostics()->Error(DiagMessage(path) << lib_package_result.error());
+ context_->GetDiagnostics()->Error(android::DiagMessage(path)
+ << lib_package_result.error());
return false;
}
lib_package_result.value()->name = context_->GetCompilationPackage();
@@ -879,7 +885,7 @@ class Linker {
static_library_includes_.push_back(std::move(static_apk));
} else {
if (!asset_source->AddAssetPath(path)) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to load include path " << path);
return false;
}
@@ -912,7 +918,8 @@ class Linker {
return true;
}
- std::optional<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
+ std::optional<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res,
+ android::IDiagnostics* diag) {
TRACE_CALL();
// Make sure the first element is <manifest> with package attribute.
xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get());
@@ -923,13 +930,13 @@ class Linker {
AppInfo app_info;
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
+ diag->Error(android::DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
return {};
}
xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
if (!package_attr) {
- diag->Error(DiagMessage(xml_res->file.source)
+ diag->Error(android::DiagMessage(xml_res->file.source)
<< "<manifest> must have a 'package' attribute");
return {};
}
@@ -939,7 +946,7 @@ class Linker {
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
<< "invalid android:versionCode '" << version_code_attr->value << "'");
return {};
}
@@ -950,9 +957,9 @@ class Linker {
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
- << "invalid android:versionCodeMajor '"
- << version_code_major_attr->value << "'");
+ diag->Error(android::DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ << "invalid android:versionCodeMajor '" << version_code_major_attr->value
+ << "'");
return {};
}
app_info.version_code_major = maybe_code.value();
@@ -962,7 +969,7 @@ class Linker {
manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
<< "invalid android:revisionCode '" << revision_code_attr->value << "'");
return {};
}
@@ -1009,21 +1016,21 @@ class Linker {
// We have a package that is not related to the one we're building!
for (const auto& type : package->types) {
for (const auto& entry : type->entries) {
- ResourceNameRef res_name(package->name, type->type, entry->name);
+ ResourceNameRef res_name(package->name, type->named_type, entry->name);
for (const auto& config_value : entry->values) {
// Special case the occurrence of an ID that is being generated
// for the 'android' package. This is due to legacy reasons.
if (ValueCast<Id>(config_value->value.get()) && package->name == "android") {
- context_->GetDiagnostics()->Warn(DiagMessage(config_value->value->GetSource())
- << "generated id '" << res_name
- << "' for external package '" << package->name
- << "'");
+ context_->GetDiagnostics()->Warn(
+ android::DiagMessage(config_value->value->GetSource())
+ << "generated id '" << res_name << "' for external package '" << package->name
+ << "'");
} else {
- context_->GetDiagnostics()->Error(DiagMessage(config_value->value->GetSource())
- << "defined resource '" << res_name
- << "' for external package '" << package->name
- << "'");
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(config_value->value->GetSource())
+ << "defined resource '" << res_name << "' for external package '"
+ << package->name << "'");
error = true;
}
}
@@ -1046,9 +1053,10 @@ class Linker {
for (const auto& type : package->types) {
for (const auto& entry : type->entries) {
if (entry->id) {
- ResourceNameRef res_name(package->name, type->type, entry->name);
- context_->GetDiagnostics()->Error(DiagMessage() << "resource " << res_name << " has ID "
- << entry->id.value() << " assigned");
+ ResourceNameRef res_name(package->name, type->named_type, entry->name);
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "resource " << res_name << " has ID "
+ << entry->id.value() << " assigned");
return false;
}
}
@@ -1057,7 +1065,117 @@ class Linker {
return true;
}
- std::unique_ptr<IArchiveWriter> MakeArchiveWriter(const StringPiece& out) {
+ bool VerifyLocaleFormat(xml::XmlResource* manifest, android::IDiagnostics* diag) {
+ // Skip it if the Manifest doesn't declare the localeConfig attribute within the <application>
+ // element.
+ const xml::Element* application = manifest->root->FindChild("", "application");
+ if (!application) {
+ return true;
+ }
+ const xml::Attribute* localeConfig =
+ application->FindAttribute(xml::kSchemaAndroid, "localeConfig");
+ if (!localeConfig) {
+ return true;
+ }
+
+ // Deserialize XML from the compiled file
+ if (localeConfig->compiled_value) {
+ const auto localeconfig_reference = ValueCast<Reference>(localeConfig->compiled_value.get());
+ const auto localeconfig_entry =
+ ResolveTableEntry(context_, &final_table_, localeconfig_reference);
+ if (!localeconfig_entry) {
+ // If locale config is resolved from external symbols - skip validation.
+ if (context_->GetExternalSymbols()->FindByReference(*localeconfig_reference)) {
+ return true;
+ }
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(localeConfig->compiled_value->GetSource())
+ << "no localeConfig entry");
+ return false;
+ }
+ for (const auto& value : localeconfig_entry->values) {
+ const FileReference* file_ref = ValueCast<FileReference>(value->value.get());
+ if (!file_ref) {
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(localeConfig->compiled_value->GetSource())
+ << "no file reference");
+ return false;
+ }
+ io::IFile* file = file_ref->file;
+ if (!file) {
+ context_->GetDiagnostics()->Error(android::DiagMessage(file_ref->GetSource())
+ << "file not found");
+ return false;
+ }
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (!data) {
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "failed to open file");
+ return false;
+ }
+ pb::XmlNode pb_xml_node;
+ if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "failed to parse proto XML");
+ return false;
+ }
+
+ std::string error;
+ std::unique_ptr<xml::XmlResource> localeConfig_xml =
+ DeserializeXmlResourceFromPb(pb_xml_node, &error);
+ if (!localeConfig_xml) {
+ context_->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "failed to deserialize proto XML: " << error);
+ return false;
+ }
+ xml::Element* localeConfig_el = xml::FindRootElement(localeConfig_xml->root.get());
+ if (!localeConfig_el) {
+ diag->Error(android::DiagMessage(file->GetSource()) << "no root tag defined");
+ return false;
+ }
+ if (localeConfig_el->name != "locale-config") {
+ diag->Error(android::DiagMessage(file->GetSource())
+ << "invalid element name: " << localeConfig_el->name
+ << ", expected: locale-config");
+ return false;
+ }
+ for (const xml::Element* child_el : localeConfig_el->GetChildElements()) {
+ if (child_el->name == "locale") {
+ if (const xml::Attribute* locale_name_attr =
+ child_el->FindAttribute(xml::kSchemaAndroid, "name")) {
+ const std::string& locale_name = locale_name_attr->value;
+ const std::string valid_name = ConvertToBCP47Tag(locale_name);
+ // Start to verify the locale format
+ ConfigDescription config;
+ if (!ConfigDescription::Parse(valid_name, &config)) {
+ diag->Error(android::DiagMessage(file->GetSource())
+ << "invalid configuration: " << locale_name);
+ return false;
+ }
+ } else {
+ diag->Error(android::DiagMessage(file->GetSource())
+ << "the attribute android:name is not found");
+ return false;
+ }
+ } else {
+ diag->Error(android::DiagMessage(file->GetSource())
+ << "invalid element name: " << child_el->name << ", expected: locale");
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ std::string ConvertToBCP47Tag(const std::string& locale) {
+ std::string bcp47tag = "b+";
+ bcp47tag += locale;
+ std::replace(bcp47tag.begin(), bcp47tag.end(), '-', '+');
+ return bcp47tag;
+ }
+
+ std::unique_ptr<IArchiveWriter> MakeArchiveWriter(StringPiece out) {
if (options_.output_to_directory) {
return CreateDirectoryArchiveWriter(context_->GetDiagnostics(), out);
} else {
@@ -1069,10 +1187,11 @@ class Linker {
TRACE_CALL();
switch (format) {
case OutputFormat::kApk: {
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
TableFlattener flattener(options_.table_flattener_options, &buffer);
if (!flattener.Consume(context_, table)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to flatten resource table");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to flatten resource table");
return false;
}
@@ -1092,8 +1211,8 @@ class Linker {
return false;
}
- bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
- const StringPiece& out_package, const JavaClassGeneratorOptions& java_options,
+ bool WriteJavaFile(ResourceTable* table, StringPiece package_name_to_generate,
+ StringPiece out_package, const JavaClassGeneratorOptions& java_options,
const std::optional<std::string>& out_text_symbols_path = {}) {
if (!options_.generate_java_class_path && !out_text_symbols_path) {
return true;
@@ -1105,7 +1224,7 @@ class Linker {
out_path = options_.generate_java_class_path.value();
file::AppendPath(&out_path, file::PackageToPath(out_package));
if (!file::mkdirs(out_path)) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to create directory '" << out_path << "'");
return false;
}
@@ -1114,8 +1233,9 @@ class Linker {
fout = util::make_unique<io::FileOutputStream>(out_path);
if (fout->HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout->GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed writing to '" << out_path
+ << "': " << fout->GetError());
return false;
}
}
@@ -1124,7 +1244,7 @@ class Linker {
if (out_text_symbols_path) {
fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
if (fout_text->HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed writing to '" << out_text_symbols_path.value()
<< "': " << fout_text->GetError());
return false;
@@ -1133,7 +1253,7 @@ class Linker {
JavaClassGenerator generator(context_, table, java_options);
if (!generator.Generate(package_name_to_generate, out_package, fout.get(), fout_text.get())) {
- context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage(out_path) << generator.GetError());
return false;
}
@@ -1257,8 +1377,8 @@ class Linker {
file::AppendPath(&out_path, file::PackageToPath(package_utf8));
if (!file::mkdirs(out_path)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create directory '" << out_path
- << "'");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to create directory '" << out_path << "'");
return false;
}
@@ -1266,8 +1386,8 @@ class Linker {
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path
+ << "': " << fout.GetError());
return false;
}
@@ -1276,8 +1396,8 @@ class Linker {
fout.Flush();
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed writing to '" << out_path
+ << "': " << fout.GetError());
return false;
}
return true;
@@ -1292,8 +1412,8 @@ class Linker {
const std::string& out_path = out.value();
io::FileOutputStream fout(out_path);
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path
+ << "': " << fout.GetError());
return false;
}
@@ -1302,8 +1422,8 @@ class Linker {
fout.Flush();
if (fout.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
- << "': " << fout.GetError());
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed writing to '" << out_path
+ << "': " << fout.GetError());
return false;
}
return true;
@@ -1312,12 +1432,13 @@ class Linker {
bool MergeStaticLibrary(const std::string& input, bool override) {
TRACE_CALL();
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "merging static library " << input);
+ context_->GetDiagnostics()->Note(android::DiagMessage()
+ << "merging static library " << input);
}
std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(input, context_->GetDiagnostics());
if (apk == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
+ context_->GetDiagnostics()->Error(android::DiagMessage(input) << "invalid static library");
return false;
}
@@ -1328,7 +1449,7 @@ class Linker {
auto lib_package_result = GetStaticLibraryPackage(table);
if (!lib_package_result.has_value()) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << lib_package_result.error());
+ context_->GetDiagnostics()->Error(android::DiagMessage(input) << lib_package_result.error());
return false;
}
@@ -1347,12 +1468,12 @@ class Linker {
// Clear the package name, so as to make the resources look like they are coming from the
// local package.
pkg->name = "";
- result = table_merger_->Merge(Source(input), table, override);
+ result = table_merger_->Merge(android::Source(input), table, override);
} else {
// This is the proper way to merge libraries, where the package name is
// preserved and resource names are mangled.
- result = table_merger_->MergeAndMangle(Source(input), pkg->name, table);
+ result = table_merger_->MergeAndMangle(android::Source(input), pkg->name, table);
}
if (!result) {
@@ -1364,7 +1485,7 @@ class Linker {
return true;
}
- bool MergeExportedSymbols(const Source& source,
+ bool MergeExportedSymbols(const android::Source& source,
const std::vector<SourcedResourceName>& exported_symbols) {
TRACE_CALL();
// Add the exports of this file to the table.
@@ -1394,7 +1515,7 @@ class Linker {
bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
TRACE_CALL();
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "merging '" << compiled_file.name
<< "' from compiled file " << compiled_file.source);
}
@@ -1413,14 +1534,14 @@ class Linker {
bool MergeArchive(const std::string& input, bool override) {
TRACE_CALL();
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "merging archive " << input);
+ context_->GetDiagnostics()->Note(android::DiagMessage() << "merging archive " << input);
}
std::string error_str;
std::unique_ptr<io::ZipFileCollection> collection =
io::ZipFileCollection::Create(input, &error_str);
if (!collection) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << error_str);
+ context_->GetDiagnostics()->Error(android::DiagMessage(input) << error_str);
return false;
}
@@ -1460,31 +1581,32 @@ class Linker {
// where we could have other files like classes.dex.
bool MergeFile(io::IFile* file, bool override) {
TRACE_CALL();
- const Source& src = file->GetSource();
+ const android::Source& src = file->GetSource();
if (util::EndsWith(src.path, ".xml") || util::EndsWith(src.path, ".png")) {
// Since AAPT compiles these file types and appends .flat to them, seeing
// their raw extensions is a sign that they weren't compiled.
const StringPiece file_type = util::EndsWith(src.path, ".xml") ? "XML" : "PNG";
- context_->GetDiagnostics()->Error(DiagMessage(src) << "uncompiled " << file_type
- << " file passed as argument. Must be "
- "compiled first into .flat file.");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "uncompiled " << file_type
+ << " file passed as argument. Must be "
+ "compiled first into .flat file.");
return false;
} else if (!util::EndsWith(src.path, ".apc") && !util::EndsWith(src.path, ".flat")) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring unrecognized file");
+ context_->GetDiagnostics()->Warn(android::DiagMessage(src) << "ignoring unrecognized file");
return true;
}
}
std::unique_ptr<io::InputStream> input_stream = file->OpenInputStream();
if (input_stream == nullptr) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to open file");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src) << "failed to open file");
return false;
}
if (input_stream->HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to open file: " << input_stream->GetError());
return false;
}
@@ -1493,7 +1615,7 @@ class Linker {
ContainerReader reader(input_stream.get());
if (reader.HadError()) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to read file: " << reader.GetError());
return false;
}
@@ -1503,21 +1625,22 @@ class Linker {
TRACE_NAME(std::string("Process ResTable:") + file->GetSource().path);
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to read resource table: "
- << entry->GetError());
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(src) << "failed to read resource table: " << entry->GetError());
return false;
}
ResourceTable table;
std::string error;
if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to deserialize resource table: " << error);
return false;
}
if (!table_merger_->Merge(src, &table, override)) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to merge resource table");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "failed to merge resource table");
return false;
}
} else if (entry->Type() == ContainerEntryType::kResFile) {
@@ -1526,15 +1649,15 @@ class Linker {
off64_t offset;
size_t len;
if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &len)) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "failed to get resource file: "
- << entry->GetError());
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage(src) << "failed to get resource file: " << entry->GetError());
return false;
}
ResourceFile resource_file;
std::string error;
if (!DeserializeCompiledFileFromPb(pb_compiled_file, &resource_file, &error)) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "failed to read compiled header: " << error);
return false;
}
@@ -1563,10 +1686,10 @@ class Linker {
auto iter = merged_assets.find(full_key);
if (iter == merged_assets.end()) {
- merged_assets.emplace(std::move(full_key),
- util::make_unique<io::RegularFile>(Source(std::move(full_path))));
+ merged_assets.emplace(std::move(full_key), util::make_unique<io::RegularFile>(
+ android::Source(std::move(full_path))));
} else if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Warn(DiagMessage(iter->second->GetSource())
+ context_->GetDiagnostics()->Warn(android::DiagMessage(iter->second->GetSource())
<< "asset file overrides '" << full_path << "'");
}
}
@@ -1651,10 +1774,10 @@ class Linker {
continue;
}
- context_->GetDiagnostics()->Note(DiagMessage() << "generating "
- << round_icon_reference->name.value()
- << " with config \"" << config_value->config
- << "\" for round icon compatibility");
+ context_->GetDiagnostics()->Note(android::DiagMessage()
+ << "generating " << round_icon_reference->name.value()
+ << " with config \"" << config_value->config
+ << "\" for round icon compatibility");
CloningValueTransformer cloner(&table->string_pool);
auto value = icon_reference->Transform(cloner);
@@ -1680,7 +1803,7 @@ class Linker {
if (util::IsAndroidSharedUserId(context_->GetCompilationPackage(), shared_user_id)) {
return true;
}
- DiagMessage error_msg(manifest_el->line_number);
+ android::DiagMessage error_msg(manifest_el->line_number);
error_msg << "attribute 'sharedUserId' in <manifest> tag is not a valid shared user id: '"
<< shared_user_id << "'";
if (options_.manifest_fixer_options.warn_validation) {
@@ -1756,7 +1879,7 @@ class Linker {
ResourceFileFlattener file_flattener(file_flattener_options, context_, keep_set);
if (!file_flattener.Flatten(table, writer)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed linking file resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed linking file resources");
return false;
}
@@ -1787,8 +1910,8 @@ class Linker {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(
- DiagMessage() << "rewriting resource package name for feature split to '"
- << new_package_name << "'");
+ android::DiagMessage() << "rewriting resource package name for feature split to '"
+ << new_package_name << "'");
}
package_to_rewrite->name = new_package_name;
}
@@ -1808,7 +1931,7 @@ class Linker {
}
if (!success) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to write resource table");
}
return success;
}
@@ -1869,7 +1992,7 @@ class Linker {
// Verify we're building a regular app.
if (context_->GetPackageType() != PackageType::kApp) {
context_->GetDiagnostics()->Error(
- DiagMessage() << "package 'android' can only be built as a regular app");
+ android::DiagMessage() << "package 'android' can only be built as a regular app");
return 1;
}
}
@@ -1882,7 +2005,7 @@ class Linker {
table_merger_ = util::make_unique<TableMerger>(context_, &final_table_, table_merger_options);
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< StringPrintf("linking package '%s' using package ID %02x",
context_->GetCompilationPackage().data(),
context_->GetPackageId()));
@@ -1903,14 +2026,14 @@ class Linker {
for (const std::string& input : input_files) {
if (!MergePath(input, false)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing input");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed parsing input");
return 1;
}
}
for (const std::string& input : options_.overlay_files) {
if (!MergePath(input, true)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed parsing overlays");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed parsing overlays");
return 1;
}
}
@@ -1923,14 +2046,15 @@ class Linker {
PrivateAttributeMover mover;
if (context_->GetPackageId() == kAndroidPackageId &&
!mover.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed moving private attributes");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed moving private attributes");
return 1;
}
// Assign IDs if we are building a regular app.
IdAssigner id_assigner(&options_.stable_id_map);
if (!id_assigner.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed assigning IDs");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed assigning IDs");
return 1;
}
@@ -1939,7 +2063,7 @@ class Linker {
for (auto& package : final_table_.packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- ResourceName name(package->name, type->type, entry->name);
+ ResourceName name(package->name, type->named_type, entry->name);
// The IDs are guaranteed to exist.
options_.stable_id_map[std::move(name)] = entry->id.value();
}
@@ -1974,7 +2098,7 @@ class Linker {
// are just identifiers.
if (context_->GetMinSdkVersion() < SDK_O && context_->GetPackageType() == PackageType::kApp) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "enabling pre-O feature split ID rewriting");
}
context_->GetExternalSymbols()->SetDelegate(
@@ -1985,7 +2109,7 @@ class Linker {
// We want to force any references to these to fail the build.
if (!options_.no_resource_removal) {
if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed removing resources with no defaults");
return 1;
}
@@ -1993,19 +2117,19 @@ class Linker {
ReferenceLinker linker;
if (!options_.merge_only && !linker.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed linking references");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed linking references");
return 1;
}
if (context_->GetPackageType() == PackageType::kStaticLib) {
if (!options_.products.empty()) {
- context_->GetDiagnostics()->Warn(DiagMessage()
+ context_->GetDiagnostics()->Warn(android::DiagMessage()
<< "can't select products when building static library");
}
} else {
ProductFilter product_filter(options_.products);
if (!product_filter.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed stripping products");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed stripping products");
return 1;
}
}
@@ -2013,14 +2137,14 @@ class Linker {
if (!options_.no_auto_version) {
AutoVersioner versioner;
if (!versioner.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed versioning styles");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed versioning styles");
return 1;
}
}
if (context_->GetPackageType() != PackageType::kStaticLib && context_->GetMinSdkVersion() > 0) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage()
+ context_->GetDiagnostics()->Note(android::DiagMessage()
<< "collapsing resource versions for minimum SDK "
<< context_->GetMinSdkVersion());
}
@@ -2039,9 +2163,8 @@ class Linker {
ConfigDescription config_description;
if (!ConfigDescription::Parse(config_string, &config_description)) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "failed to parse --excluded-configs "
- << config_string);
+ context_->GetDiagnostics()->Error(
+ android::DiagMessage() << "failed to parse --excluded-configs " << config_string);
return 1;
}
@@ -2050,7 +2173,8 @@ class Linker {
ResourceExcluder excluder(excluded_configs);
if (!excluder.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed excluding configurations");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed excluding configurations");
return 1;
}
}
@@ -2058,7 +2182,7 @@ class Linker {
if (!options_.no_resource_deduping) {
ResourceDeduper deduper;
if (!deduper.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed deduping resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed deduping resources");
return 1;
}
}
@@ -2070,7 +2194,7 @@ class Linker {
if (context_->GetPackageType() == PackageType::kStaticLib) {
if (options_.table_splitter_options.config_filter != nullptr ||
!options_.table_splitter_options.preferred_densities.empty()) {
- context_->GetDiagnostics()->Warn(DiagMessage()
+ context_->GetDiagnostics()->Warn(android::DiagMessage()
<< "can't strip resources when building static library");
}
} else {
@@ -2081,7 +2205,7 @@ class Linker {
AdjustSplitConstraintsForMinSdk(context_->GetMinSdkVersion(), options_.split_constraints);
if (origConstraintSize != options_.split_constraints.size()) {
- context_->GetDiagnostics()->Warn(DiagMessage()
+ context_->GetDiagnostics()->Warn(android::DiagMessage()
<< "requested to split resources prior to min sdk of "
<< context_->GetMinSdkVersion());
}
@@ -2096,7 +2220,7 @@ class Linker {
auto split_constraints_iter = options_.split_constraints.begin();
for (std::unique_ptr<ResourceTable>& split_table : table_splitter.splits()) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage(*path_iter)
+ context_->GetDiagnostics()->Note(android::DiagMessage(*path_iter)
<< "generating split with configurations '"
<< util::Joiner(split_constraints_iter->configs, ", ")
<< "'");
@@ -2104,7 +2228,7 @@ class Linker {
std::unique_ptr<IArchiveWriter> archive_writer = MakeArchiveWriter(*path_iter);
if (!archive_writer) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create archive");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to create archive");
return 1;
}
@@ -2114,7 +2238,7 @@ class Linker {
XmlReferenceLinker linker(&final_table_);
if (!linker.Consume(context_, split_manifest.get())) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to create Split AndroidManifest.xml");
return 1;
}
@@ -2132,7 +2256,7 @@ class Linker {
// Start writing the base APK.
std::unique_ptr<IArchiveWriter> archive_writer = MakeArchiveWriter(options_.output_path);
if (!archive_writer) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed to create archive");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to create archive");
return 1;
}
@@ -2176,10 +2300,14 @@ class Linker {
}
if (error) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed processing manifest");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed processing manifest");
return 1;
}
+ if (!VerifyLocaleFormat(manifest_xml.get(), context_->GetDiagnostics())) {
+ return 1;
+ };
+
if (!WriteApk(archive_writer.get(), &proguard_keep_set, manifest_xml.get(), &final_table_)) {
return 1;
}
@@ -2245,7 +2373,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
if (!file::AppendArgsFromFile(path, &arg_list, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(path) << error);
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
return 1;
}
} else {
@@ -2259,7 +2387,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
const std::string path = arg.substr(1, arg.size() - 1);
std::string error;
if (!file::AppendArgsFromFile(path, &options_.overlay_files, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(path) << error);
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
return 1;
}
} else {
@@ -2272,9 +2400,9 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
}
if (int{shared_lib_} + int{static_lib_} + int{proto_format_} > 1) {
- context.GetDiagnostics()->Error(
- DiagMessage()
- << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
+ context.GetDiagnostics()
+ ->Error(android::DiagMessage()
+ << "only one of --shared-lib, --static-lib, or --proto_format can be defined");
return 1;
}
@@ -2282,17 +2410,21 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
// If a shared library styleable in a public R.java uses a private attribute, attempting to
// reference the private attribute within the styleable array will cause a link error because
// the private attribute will not be emitted in the public R.java.
- context.GetDiagnostics()->Error(DiagMessage()
+ context.GetDiagnostics()->Error(android::DiagMessage()
<< "--shared-lib cannot currently be used in combination with"
<< " --private-symbols");
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");
+ context.GetDiagnostics()
+ ->Error(android::DiagMessage()
+ << "the --merge-only flag can be only used when building a static library");
return 1;
}
+ if (options_.use_sparse_encoding) {
+ options_.table_flattener_options.sparse_entries = SparseEntriesMode::Enabled;
+ }
// The default build type.
context.SetPackageType(PackageType::kApp);
@@ -2311,15 +2443,16 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
if (package_id_) {
if (context.GetPackageType() != PackageType::kApp) {
context.GetDiagnostics()->Error(
- DiagMessage() << "can't specify --package-id when not building a regular app");
+ android::DiagMessage() << "can't specify --package-id when not building a regular app");
return 1;
}
const std::optional<uint32_t> maybe_package_id_int =
ResourceUtils::ParseInt(package_id_.value());
if (!maybe_package_id_int) {
- context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id_.value()
- << "' is not a valid integer");
+ context.GetDiagnostics()->Error(android::DiagMessage()
+ << "package ID '" << package_id_.value()
+ << "' is not a valid integer");
return 1;
}
@@ -2328,7 +2461,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
|| package_id_int == kFrameworkPackageId
|| (!options_.allow_reserved_package_id && package_id_int < kAppPackageId)) {
context.GetDiagnostics()->Error(
- DiagMessage() << StringPrintf(
+ android::DiagMessage() << StringPrintf(
"invalid package ID 0x%02x. Must be in the range 0x7f-0xff.", package_id_int));
return 1;
}
@@ -2339,14 +2472,14 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
for (std::string& extra_package : extra_java_packages_) {
// A given package can actually be a colon separated list of packages.
for (StringPiece package : util::Split(extra_package, ':')) {
- options_.extra_java_packages.insert(package.to_string());
+ options_.extra_java_packages.emplace(package);
}
}
if (product_list_) {
for (StringPiece product : util::Tokenize(product_list_.value(), ',')) {
if (product != "" && product != "default") {
- options_.products.insert(product.to_string());
+ options_.products.emplace(product);
}
}
}
@@ -2392,7 +2525,7 @@ int LinkCommand::Action(const std::vector<std::string>& args) {
const std::string path = regex.substr(1, regex.size() -1);
std::string error;
if (!file::AppendSetArgsFromFile(path, &options_.extensions_to_not_compress, &error)) {
- context.GetDiagnostics()->Error(DiagMessage(path) << error);
+ context.GetDiagnostics()->Error(android::DiagMessage(path) << error);
return 1;
}
} else {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 2f5d8d19ebe5..1b1e93bd480a 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -20,12 +20,12 @@
#include <regex>
#include "Command.h"
-#include "Diagnostics.h"
#include "Resource.h"
-#include "split/TableSplitter.h"
+#include "androidfw/IDiagnostics.h"
#include "format/binary/TableFlattener.h"
#include "format/proto/ProtoSerialize.h"
#include "link/ManifestFixer.h"
+#include "split/TableSplitter.h"
#include "trace/TraceBuffer.h"
namespace aapt {
@@ -69,6 +69,7 @@ struct LinkOptions {
bool no_resource_removal = false;
bool no_xml_namespaces = false;
bool do_not_compress_anything = false;
+ bool use_sparse_encoding = false;
std::unordered_set<std::string> extensions_to_not_compress;
std::optional<std::regex> regex_to_not_compress;
@@ -111,8 +112,7 @@ struct LinkOptions {
class LinkCommand : public Command {
public:
- explicit LinkCommand(IDiagnostics* diag) : Command("link", "l"),
- diag_(diag) {
+ explicit LinkCommand(android::IDiagnostics* diag) : Command("link", "l"), diag_(diag) {
SetDescription("Links resources into an apk.");
AddRequiredFlag("-o", "Output path.", &options_.output_path, Command::kPath);
AddRequiredFlag("--manifest", "Path to the Android manifest to build.",
@@ -157,8 +157,11 @@ class LinkCommand : public Command {
"defaults. Use this only when building runtime resource overlay packages.",
&options_.no_resource_removal);
AddOptionalSwitch("--enable-sparse-encoding",
- "This decreases APK size at the cost of resource retrieval performance.",
- &options_.table_flattener_options.use_sparse_entries);
+ "This decreases APK size at the cost of resource retrieval performance.",
+ &options_.use_sparse_encoding);
+ AddOptionalSwitch("--enable-compact-entries",
+ "This decreases APK size by using compact resource entries for simple data types.",
+ &options_.table_flattener_options.use_compact_entries);
AddOptionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01.",
&legacy_x_flag_);
AddOptionalSwitch("-z", "Require localization of strings marked 'suggested'.",
@@ -211,6 +214,8 @@ class LinkCommand : public Command {
"Suppresses output of compile SDK-related attributes in AndroidManifest.xml,\n"
"including android:compileSdkVersion and platformBuildVersion.",
&options_.manifest_fixer_options.no_compile_sdk_metadata);
+ AddOptionalFlagList("--fingerprint-prefix", "Fingerprint prefix to add to install constraints.",
+ &options_.manifest_fixer_options.fingerprint_prefixes);
AddOptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
&shared_lib_);
AddOptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib_);
@@ -323,7 +328,7 @@ class LinkCommand : public Command {
int Action(const std::vector<std::string>& args) override;
private:
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
LinkOptions options_;
std::vector<std::string> overlay_arg_list_;
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 430c184ef87d..28fcc1a4800e 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -19,6 +19,7 @@
#include <android-base/file.h>
#include "AppInfo.h"
+#include "Diagnostics.h"
#include "LoadedApk.h"
#include "test/Test.h"
@@ -86,7 +87,8 @@ TEST_F(LinkTest, KeepRawXmlStrings) {
// Check that the raw string index has been set to the correct string pool entry
int32_t raw_index = tree.getAttributeValueStringID(0);
ASSERT_THAT(raw_index, Ne(-1));
- EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+ EXPECT_THAT(android::util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)),
+ Eq("007"));
}
TEST_F(LinkTest, NoCompressAssets) {
@@ -409,7 +411,7 @@ struct SourceXML {
static void BuildApk(const std::vector<SourceXML>& source_files, const std::string& apk_path,
LinkCommandBuilder&& link_args, CommandTestFixture* fixture,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
TemporaryDir res_dir;
TemporaryDir compiled_res_dir;
for (auto& source_file : source_files) {
@@ -422,7 +424,7 @@ static void BuildApk(const std::vector<SourceXML>& source_files, const std::stri
static void BuildSDK(const std::vector<SourceXML>& source_files, const std::string& apk_path,
const std::string& java_root_path, CommandTestFixture* fixture,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
auto android_manifest = ManifestBuilder(fixture).SetPackageName("android").Build();
auto android_link_args = LinkCommandBuilder(fixture)
@@ -434,7 +436,7 @@ static void BuildSDK(const std::vector<SourceXML>& source_files, const std::stri
}
static void BuildNonFinalizedSDK(const std::string& apk_path, const std::string& java_path,
- CommandTestFixture* fixture, IDiagnostics* diag) {
+ CommandTestFixture* fixture, android::IDiagnostics* diag) {
const std::string android_values =
R"(<resources>
<public type="attr" name="finalized_res" id="0x01010001"/>
@@ -470,7 +472,7 @@ static void BuildNonFinalizedSDK(const std::string& apk_path, const std::string&
}
static void BuildFinalizedSDK(const std::string& apk_path, const std::string& java_path,
- CommandTestFixture* fixture, IDiagnostics* diag) {
+ CommandTestFixture* fixture, android::IDiagnostics* diag) {
const std::string android_values =
R"(<resources>
<public type="attr" name="finalized_res" id="0x01010001"/>
@@ -510,7 +512,7 @@ static void BuildFinalizedSDK(const std::string& apk_path, const std::string& ja
static void BuildAppAgainstSDK(const std::string& apk_path, const std::string& java_path,
const std::string& sdk_path, CommandTestFixture* fixture,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
const std::string app_values =
R"(<resources xmlns:android="http://schemas.android.com/apk/res/android">
<attr name="bar" />
@@ -783,4 +785,212 @@ TEST_F(LinkTest, MacroSubstitution) {
EXPECT_THAT(xml_attrs[1].value, Eq("Hello World!"));
}
+TEST_F(LinkTest, LocaleConfigVerification) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+
+ // Normal case
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/locales_config.xml"), R"(
+ <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name="en-US"/>
+ <locale android:name="pt"/>
+ <locale android:name="es-419"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale-config>)",
+ compiled_files_dir, &diag));
+
+ const std::string localeconfig_manifest = GetTestPath("localeconfig_manifest.xml");
+ WriteFile(localeconfig_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/locales_config">
+ </application>
+ </manifest>)"));
+
+ const std::string out_apk = GetTestPath("out.apk");
+
+ auto link_args = LinkCommandBuilder(this)
+ .SetManifestFile(localeconfig_manifest)
+ .AddCompiledResDir(compiled_files_dir, &diag)
+ .Build(out_apk);
+ ASSERT_TRUE(Link(link_args, &diag));
+
+ // Empty locale list
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/empty_locales_config.xml"), R"(
+ <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ </locale-config>)",
+ compiled_files_dir, &diag));
+
+ const std::string empty_localeconfig_manifest = GetTestPath("empty_localeconfig_manifest.xml");
+ WriteFile(empty_localeconfig_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/empty_locales_config">
+ </application>
+ </manifest>)"));
+
+ auto link1_args = LinkCommandBuilder(this)
+ .SetManifestFile(empty_localeconfig_manifest)
+ .AddCompiledResDir(compiled_files_dir, &diag)
+ .Build(out_apk);
+ ASSERT_TRUE(Link(link1_args, &diag));
+}
+
+TEST_F(LinkTest, LocaleConfigVerificationExternalSymbol) {
+ StdErrDiagnostics diag;
+ const std::string base_files_dir = GetTestPath("base");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/locales_config.xml"), R"(
+ <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name="en-US"/>
+ <locale android:name="pt"/>
+ <locale android:name="es-419"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale-config>)",
+ base_files_dir, &diag));
+ const std::string base_apk = GetTestPath("base.apk");
+ std::vector<std::string> link_args = {
+ "--manifest",
+ GetDefaultManifest("com.aapt2.app"),
+ "-o",
+ base_apk,
+ };
+ ASSERT_TRUE(Link(link_args, base_files_dir, &diag));
+
+ const std::string localeconfig_manifest = GetTestPath("localeconfig_manifest.xml");
+ const std::string out_apk = GetTestPath("out.apk");
+ WriteFile(localeconfig_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/locales_config">
+ </application>
+ </manifest>)"));
+ link_args = LinkCommandBuilder(this)
+ .SetManifestFile(localeconfig_manifest)
+ .AddParameter("-I", base_apk)
+ .Build(out_apk);
+ ASSERT_TRUE(Link(link_args, &diag));
+}
+
+TEST_F(LinkTest, LocaleConfigWrongTag) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+
+ // Invalid element: locale1-config
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_locale_config.xml"), R"(
+ <locale1-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name="en-US"/>
+ <locale android:name="pt"/>
+ <locale android:name="es-419"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale1-config>)",
+ compiled_files_dir, &diag));
+
+ const std::string locale1config_manifest = GetTestPath("locale1config_manifest.xml");
+ WriteFile(locale1config_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/wrong_locale_config">
+ </application>
+ </manifest>)"));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ auto link_args = LinkCommandBuilder(this)
+ .SetManifestFile(locale1config_manifest)
+ .AddCompiledResDir(compiled_files_dir, &diag)
+ .Build(out_apk);
+ ASSERT_FALSE(Link(link_args, &diag));
+
+ // Invalid element: locale1
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_locale.xml"), R"(
+ <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale1 android:name="en-US"/>
+ <locale android:name="pt"/>
+ <locale android:name="es-419"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale-config>)",
+ compiled_files_dir, &diag));
+
+ const std::string locale1_manifest = GetTestPath("locale1_manifest.xml");
+ WriteFile(locale1_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/wrong_locale">
+ </application>
+ </manifest>)"));
+
+ auto link1_args = LinkCommandBuilder(this)
+ .SetManifestFile(locale1_manifest)
+ .AddCompiledResDir(compiled_files_dir, &diag)
+ .Build(out_apk);
+ ASSERT_FALSE(Link(link1_args, &diag));
+
+ // Invalid attribute: android:name1
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_attribute.xml"), R"(
+ <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name1="en-US"/>
+ <locale android:name="pt"/>
+ <locale android:name="es-419"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale-config>)",
+ compiled_files_dir, &diag));
+
+ const std::string wrong_attribute_manifest = GetTestPath("wrong_attribute_manifest.xml");
+ WriteFile(wrong_attribute_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/wrong_attribute">
+ </application>
+ </manifest>)"));
+
+ auto link2_args = LinkCommandBuilder(this)
+ .SetManifestFile(wrong_attribute_manifest)
+ .AddCompiledResDir(compiled_files_dir, &diag)
+ .Build(out_apk);
+ ASSERT_FALSE(Link(link2_args, &diag));
+}
+
+TEST_F(LinkTest, LocaleConfigWrongLocaleFormat) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+
+ // Invalid locale: en-U
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/wrong_locale.xml"), R"(
+ <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name="en-U"/>
+ <locale android:name="pt"/>
+ <locale android:name="es-419"/>
+ <locale android:name="zh-Hans-SG"/>
+ </locale-config>)",
+ compiled_files_dir, &diag));
+
+ const std::string wrong_locale_manifest = GetTestPath("wrong_locale_manifest.xml");
+ WriteFile(wrong_locale_manifest, android::base::StringPrintf(R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt2.app">
+
+ <application
+ android:localeConfig="@xml/wrong_locale">
+ </application>
+ </manifest>)"));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ auto link_args = LinkCommandBuilder(this)
+ .SetManifestFile(wrong_locale_manifest)
+ .AddCompiledResDir(compiled_files_dir, &diag)
+ .Build(out_apk);
+ ASSERT_FALSE(Link(link_args, &diag));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index caa3e60d6af1..dbe79701bf5c 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -16,21 +16,24 @@
#include "Optimize.h"
+#include <map>
#include <memory>
+#include <set>
+#include <string>
+#include <utility>
#include <vector>
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/StringPiece.h"
-
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
#include "cmd/Util.h"
#include "configuration/ConfigurationParser.h"
#include "filter/AbiFilter.h"
@@ -39,9 +42,9 @@
#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "optimize/MultiApkGenerator.h"
+#include "optimize/Obfuscator.h"
#include "optimize/ResourceDeduper.h"
#include "optimize/ResourceFilter.h"
-#include "optimize/ResourcePathShortener.h"
#include "optimize/VersionCollapser.h"
#include "split/TableSplitter.h"
#include "util/Files.h"
@@ -69,7 +72,7 @@ class OptimizeContext : public IAaptContext {
return PackageType::kApp;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -115,11 +118,11 @@ class OptimizeContext : public IAaptContext {
}
private:
- DISALLOW_COPY_AND_ASSIGN(OptimizeContext);
-
StdErrDiagnostics diagnostics_;
bool verbose_ = false;
int sdk_version_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(OptimizeContext);
};
class Optimizer {
@@ -130,12 +133,12 @@ class Optimizer {
int Run(std::unique_ptr<LoadedApk> apk) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK...");
+ context_->GetDiagnostics()->Note(android::DiagMessage() << "Optimizing APK...");
}
if (!options_.resources_exclude_list.empty()) {
ResourceFilter filter(options_.resources_exclude_list);
if (!filter.Consume(context_, apk->GetResourceTable())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed filtering resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed filtering resources");
return 1;
}
}
@@ -147,20 +150,30 @@ class Optimizer {
ResourceDeduper deduper;
if (!deduper.Consume(context_, apk->GetResourceTable())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed deduping resources");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << "failed deduping resources");
return 1;
}
- if (options_.shorten_resource_paths) {
- ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map);
- if (!shortener.Consume(context_, apk->GetResourceTable())) {
- context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths");
+ Obfuscator obfuscator(options_);
+ if (obfuscator.IsEnabled()) {
+ if (!obfuscator.Consume(context_, apk->GetResourceTable())) {
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed shortening resource paths");
+ return 1;
+ }
+
+ if (options_.obfuscation_map_path &&
+ !obfuscator.WriteObfuscationMap(options_.obfuscation_map_path.value())) {
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to write the obfuscation map to file");
return 1;
}
+
+ // TODO(b/246489170): keep the old option and format until transform to the new one
if (options_.shortened_paths_map_path
&& !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
options_.shortened_paths_map_path.value())) {
- context_->GetDiagnostics()->Error(DiagMessage()
+ context_->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to write shortened resource paths to file");
return 1;
}
@@ -183,9 +196,10 @@ class Optimizer {
auto split_constraints_iter = options_.split_constraints.begin();
for (std::unique_ptr<ResourceTable>& split_table : splitter.splits()) {
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(
- DiagMessage(*path_iter) << "generating split with configurations '"
- << util::Joiner(split_constraints_iter->configs, ", ") << "'");
+ context_->GetDiagnostics()->Note(android::DiagMessage(*path_iter)
+ << "generating split with configurations '"
+ << util::Joiner(split_constraints_iter->configs, ", ")
+ << "'");
}
// Generate an AndroidManifest.xml for each split.
@@ -228,7 +242,7 @@ class Optimizer {
private:
bool WriteSplitApk(ResourceTable* table, xml::XmlResource* manifest, IArchiveWriter* writer) {
- BigBuffer manifest_buffer(4096);
+ android::BigBuffer manifest_buffer(4096);
XmlFlattener xml_flattener(&manifest_buffer, {});
if (!xml_flattener.Consume(context_, manifest)) {
return false;
@@ -254,8 +268,8 @@ class Optimizer {
}
if (file_ref->file == nullptr) {
- ResourceNameRef name(pkg->name, type->type, entry->name);
- context_->GetDiagnostics()->Warn(DiagMessage(file_ref->GetSource())
+ ResourceNameRef name(pkg->name, type->named_type, entry->name);
+ context_->GetDiagnostics()->Warn(android::DiagMessage(file_ref->GetSource())
<< "file for resource " << name << " with config '"
<< config_value->config << "' not found");
continue;
@@ -276,7 +290,7 @@ class Optimizer {
}
}
- BigBuffer table_buffer(4096);
+ android::BigBuffer table_buffer(4096);
TableFlattener table_flattener(options_.table_flattener_options, &table_buffer);
if (!table_flattener.Consume(context_, table)) {
return false;
@@ -287,6 +301,7 @@ class Optimizer {
ArchiveEntry::kAlign, writer);
}
+ // TODO(b/246489170): keep the old option and format until transform to the new one
bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
const std::string &file_path) {
std::stringstream ss;
@@ -300,51 +315,15 @@ class Optimizer {
OptimizeContext* context_;
};
-bool ParseConfig(const std::string& content, IAaptContext* context, OptimizeOptions* options) {
- size_t line_no = 0;
- for (StringPiece line : util::Tokenize(content, '\n')) {
- line_no++;
- line = util::TrimWhitespace(line);
- if (line.empty()) {
- continue;
- }
-
- auto split_line = util::Split(line, '#');
- if (split_line.size() < 2) {
- context->GetDiagnostics()->Error(DiagMessage(line) << "No # found in line");
- return false;
- }
- StringPiece resource_string = split_line[0];
- StringPiece directives = split_line[1];
- ResourceNameRef resource_name;
- if (!ResourceUtils::ParseResourceName(resource_string, &resource_name)) {
- context->GetDiagnostics()->Error(DiagMessage(line) << "Malformed resource name");
- return false;
- }
- if (!resource_name.package.empty()) {
- context->GetDiagnostics()->Error(DiagMessage(line)
- << "Package set for resource. Only use type/name");
- return false;
- }
- for (StringPiece directive : util::Tokenize(directives, ',')) {
- if (directive == "remove") {
- options->resources_exclude_list.insert(resource_name.ToResourceName());
- } else if (directive == "no_collapse" || directive == "no_obfuscate") {
- options->table_flattener_options.name_collapse_exemptions.insert(
- resource_name.ToResourceName());
- }
- }
- }
- return true;
-}
-
bool ExtractConfig(const std::string& path, IAaptContext* context, OptimizeOptions* options) {
std::string content;
if (!android::base::ReadFileToString(path, &content, true /*follow_symlinks*/)) {
- context->GetDiagnostics()->Error(DiagMessage(path) << "failed reading config file");
+ context->GetDiagnostics()->Error(android::DiagMessage(path) << "failed reading config file");
return false;
}
- return ParseConfig(content, context, options);
+ return ParseResourceConfig(content, context, options->resources_exclude_list,
+ options->table_flattener_options.name_collapse_exemptions,
+ options->table_flattener_options.path_shorten_exemptions);
}
bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
@@ -356,7 +335,7 @@ bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
auto app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics());
if (!app_info) {
- context->GetDiagnostics()->Error(DiagMessage()
+ context->GetDiagnostics()->Error(android::DiagMessage()
<< "failed to extract data from AndroidManifest.xml");
return false;
}
@@ -376,7 +355,7 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
const std::string& apk_path = args[0];
OptimizeContext context;
context.SetVerbose(verbose_);
- IDiagnostics* diag = context.GetDiagnostics();
+ android::IDiagnostics* diag = context.GetDiagnostics();
if (config_path_) {
std::string& path = config_path_.value();
@@ -384,12 +363,12 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
if (for_path) {
options_.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path);
if (!options_.apk_artifacts) {
- diag->Error(DiagMessage() << "Failed to parse the output artifact list");
+ diag->Error(android::DiagMessage() << "Failed to parse the output artifact list");
return 1;
}
} else {
- diag->Error(DiagMessage() << "Could not parse config file " << path);
+ diag->Error(android::DiagMessage() << "Could not parse config file " << path);
return 1;
}
@@ -402,8 +381,8 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
if (!kept_artifacts_.empty()) {
for (const std::string& artifact_str : kept_artifacts_) {
- for (const StringPiece& artifact : util::Tokenize(artifact_str, ',')) {
- options_.kept_artifacts.insert(artifact.to_string());
+ for (StringPiece artifact : util::Tokenize(artifact_str, ',')) {
+ options_.kept_artifacts.emplace(artifact);
}
}
}
@@ -411,11 +390,13 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
// Since we know that we are going to process the APK (not just print targets), make sure we
// have somewhere to write them to.
if (!options_.output_dir) {
- diag->Error(DiagMessage() << "Output directory is required when using a configuration file");
+ diag->Error(android::DiagMessage()
+ << "Output directory is required when using a configuration file");
return 1;
}
} else if (print_only_) {
- diag->Error(DiagMessage() << "Asked to print artifacts without providing a configurations");
+ diag->Error(android::DiagMessage()
+ << "Asked to print artifacts without providing a configurations");
return 1;
}
@@ -424,9 +405,16 @@ int OptimizeCommand::Action(const std::vector<std::string>& args) {
return 1;
}
+ if (options_.enable_sparse_encoding) {
+ options_.table_flattener_options.sparse_entries = SparseEntriesMode::Enabled;
+ }
+ if (options_.force_sparse_encoding) {
+ options_.table_flattener_options.sparse_entries = SparseEntriesMode::Forced;
+ }
+
if (target_densities_) {
// Parse the target screen densities.
- for (const StringPiece& config_str : util::Tokenize(target_densities_.value(), ',')) {
+ for (StringPiece config_str : util::Tokenize(target_densities_.value(), ',')) {
std::optional<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag);
if (!target_density) {
return 1;
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index ff63e8dd76d4..ee53af107b17 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -26,8 +26,6 @@
namespace aapt {
struct OptimizeOptions {
- friend class OptimizeCommand;
-
// Path to the output APK.
std::optional<std::string> output_path;
// Path to the output APK directory for splits.
@@ -60,7 +58,17 @@ struct OptimizeOptions {
bool shorten_resource_paths = false;
// Path to the output map of original resource paths to shortened paths.
+ // TODO(b/246489170): keep the old option and format until transform to the new one
std::optional<std::string> shortened_paths_map_path;
+
+ // Whether sparse encoding should be used for O+ resources.
+ bool enable_sparse_encoding = false;
+
+ // Whether sparse encoding should be used for all resources.
+ bool force_sparse_encoding = false;
+
+ // Path to the output map of original resource paths/names to obfuscated paths/names.
+ std::optional<std::string> obfuscation_map_path;
};
class OptimizeCommand : public Command {
@@ -96,21 +104,42 @@ class OptimizeCommand : public Command {
"Comma separated list of artifacts to keep. If none are specified,\n"
"all artifacts will be kept.",
&kept_artifacts_);
- AddOptionalSwitch("--enable-sparse-encoding",
+ AddOptionalSwitch(
+ "--enable-sparse-encoding",
"Enables encoding sparse entries using a binary search tree.\n"
- "This decreases APK size at the cost of resource retrieval performance.",
- &options_.table_flattener_options.use_sparse_entries);
+ "This decreases APK size at the cost of resource retrieval performance.\n"
+ "Only applies sparse encoding to Android O+ resources or all resources if minSdk of "
+ "the APK is O+",
+ &options_.enable_sparse_encoding);
+ AddOptionalSwitch("--force-sparse-encoding",
+ "Enables encoding sparse entries using a binary search tree.\n"
+ "This decreases APK size at the cost of resource retrieval performance.\n"
+ "Applies sparse encoding to all resources regardless of minSdk.",
+ &options_.force_sparse_encoding);
AddOptionalSwitch("--collapse-resource-names",
"Collapses resource names to a single value in the key string pool. Resources can \n"
"be exempted using the \"no_collapse\" directive in a file specified by "
"--resources-config-path.",
&options_.table_flattener_options.collapse_key_stringpool);
AddOptionalSwitch("--shorten-resource-paths",
- "Shortens the paths of resources inside the APK.",
+ "Shortens the paths of resources inside the APK. Resources can be exempted using the \n"
+ "\"no_path_shorten\" directive in a file specified by --resources-config-path.",
&options_.shorten_resource_paths);
+ // TODO(b/246489170): keep the old option and format until transform to the new one
AddOptionalFlag("--resource-path-shortening-map",
- "Path to output the map of old resource paths to shortened paths.",
- &options_.shortened_paths_map_path);
+ "[Deprecated]Path to output the map of old resource paths to shortened paths.",
+ &options_.shortened_paths_map_path);
+ AddOptionalFlag("--save-obfuscation-map",
+ "Path to output the map of original paths/names to obfuscated paths/names.",
+ &options_.obfuscation_map_path);
+ AddOptionalSwitch(
+ "--deduplicate-entry-values",
+ "Whether to deduplicate pairs of resource entry and value for simple resources.\n"
+ "This is recommended to be used together with '--collapse-resource-names' flag or for\n"
+ "APKs where resource names are manually collapsed. For such APKs this flag allows to\n"
+ "store the same resource value only once in resource table which decreases APK size.\n"
+ "Has no effect on APKs where resource names are kept.",
+ &options_.table_flattener_options.deduplicate_entry_values);
AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
}
diff --git a/tools/aapt2/cmd/Optimize_test.cpp b/tools/aapt2/cmd/Optimize_test.cpp
deleted file mode 100644
index ac681e85b3d6..000000000000
--- a/tools/aapt2/cmd/Optimize_test.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Optimize.h"
-
-#include "AppInfo.h"
-#include "Diagnostics.h"
-#include "LoadedApk.h"
-#include "Resource.h"
-#include "test/Test.h"
-
-using testing::Contains;
-using testing::Eq;
-
-namespace aapt {
-
-bool ParseConfig(const std::string&, IAaptContext*, OptimizeOptions*);
-
-using OptimizeTest = CommandTestFixture;
-
-TEST_F(OptimizeTest, ParseConfigWithNoCollapseExemptions) {
- const std::string& content = R"(
-string/foo#no_collapse
-dimen/bar#no_collapse
-)";
- aapt::test::Context context;
- OptimizeOptions options;
- ParseConfig(content, &context, &options);
-
- const std::set<ResourceName>& name_collapse_exemptions =
- options.table_flattener_options.name_collapse_exemptions;
-
- ASSERT_THAT(name_collapse_exemptions.size(), Eq(2));
- EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kString, "foo")));
- EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kDimen, "bar")));
-}
-
-TEST_F(OptimizeTest, ParseConfigWithNoObfuscateExemptions) {
- const std::string& content = R"(
-string/foo#no_obfuscate
-dimen/bar#no_obfuscate
-)";
- aapt::test::Context context;
- OptimizeOptions options;
- ParseConfig(content, &context, &options);
-
- const std::set<ResourceName>& name_collapse_exemptions =
- options.table_flattener_options.name_collapse_exemptions;
-
- ASSERT_THAT(name_collapse_exemptions.size(), Eq(2));
- EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kString, "foo")));
- EXPECT_THAT(name_collapse_exemptions, Contains(ResourceName({}, ResourceType::kDimen, "bar")));
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 73a8d683c2bd..a92f24b82547 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -34,10 +34,11 @@ using ::android::base::StringPrintf;
namespace aapt {
-std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDiagnostics* diag) {
+std::optional<uint16_t> ParseTargetDensityParameter(StringPiece arg, android::IDiagnostics* diag) {
ConfigDescription preferred_density_config;
if (!ConfigDescription::Parse(arg, &preferred_density_config)) {
- diag->Error(DiagMessage() << "invalid density '" << arg << "' for --preferred-density option");
+ diag->Error(android::DiagMessage()
+ << "invalid density '" << arg << "' for --preferred-density option");
return {};
}
@@ -46,14 +47,14 @@ std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDia
if (preferred_density_config.diff(ConfigDescription::DefaultConfig()) !=
ConfigDescription::CONFIG_DENSITY) {
- diag->Error(DiagMessage() << "invalid preferred density '" << arg << "'. "
- << "Preferred density must only be a density value");
+ diag->Error(android::DiagMessage() << "invalid preferred density '" << arg << "'. "
+ << "Preferred density must only be a density value");
return {};
}
return preferred_density_config.density;
}
-bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string* out_path,
+bool ParseSplitParameter(StringPiece arg, android::IDiagnostics* diag, std::string* out_path,
SplitConstraints* out_split) {
CHECK(diag != nullptr);
CHECK(out_path != nullptr);
@@ -67,19 +68,19 @@ bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string
std::vector<std::string> parts = util::Split(arg, sSeparator);
if (parts.size() != 2) {
- diag->Error(DiagMessage() << "invalid split parameter '" << arg << "'");
- diag->Note(DiagMessage() << "should be --split path/to/output.apk" << sSeparator
- << "<config>[,<config>...].");
+ diag->Error(android::DiagMessage() << "invalid split parameter '" << arg << "'");
+ diag->Note(android::DiagMessage() << "should be --split path/to/output.apk" << sSeparator
+ << "<config>[,<config>...].");
return false;
}
*out_path = parts[0];
out_split->name = parts[1];
- for (const StringPiece& config_str : util::Tokenize(parts[1], ',')) {
+ for (StringPiece config_str : util::Tokenize(parts[1], ',')) {
ConfigDescription config;
if (!ConfigDescription::Parse(config_str, &config)) {
- diag->Error(DiagMessage() << "invalid config '" << config_str << "' in split parameter '"
- << arg << "'");
+ diag->Error(android::DiagMessage()
+ << "invalid config '" << config_str << "' in split parameter '" << arg << "'");
return false;
}
out_split->configs.insert(config);
@@ -88,21 +89,22 @@ bool ParseSplitParameter(const StringPiece& arg, IDiagnostics* diag, std::string
}
std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std::string>& args,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::unique_ptr<AxisConfigFilter> filter = util::make_unique<AxisConfigFilter>();
for (const std::string& config_arg : args) {
- for (const StringPiece& config_str : util::Tokenize(config_arg, ',')) {
+ for (StringPiece config_str : util::Tokenize(config_arg, ',')) {
ConfigDescription config;
LocaleValue lv;
if (lv.InitFromFilterString(config_str)) {
lv.WriteTo(&config);
} else if (!ConfigDescription::Parse(config_str, &config)) {
- diag->Error(DiagMessage() << "invalid config '" << config_str << "' for -c option");
+ diag->Error(android::DiagMessage()
+ << "invalid config '" << config_str << "' for -c option");
return {};
}
if (config.density != 0) {
- diag->Warn(DiagMessage() << "ignoring density '" << config << "' for -c option");
+ diag->Warn(android::DiagMessage() << "ignoring density '" << config << "' for -c option");
} else {
filter->AddConfig(config);
}
@@ -331,7 +333,7 @@ static std::optional<int> ExtractSdkVersion(const xml::Attribute& attr, std::str
}
std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
// Make sure the first element is <manifest> with package attribute.
const xml::Element* manifest_el = xml_res.root.get();
if (manifest_el == nullptr) {
@@ -341,20 +343,21 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
AppInfo app_info;
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(xml_res.file.source) << "root tag must be <manifest>");
+ diag->Error(android::DiagMessage(xml_res.file.source) << "root tag must be <manifest>");
return {};
}
const xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
if (!package_attr) {
- diag->Error(DiagMessage(xml_res.file.source) << "<manifest> must have a 'package' attribute");
+ diag->Error(android::DiagMessage(xml_res.file.source)
+ << "<manifest> must have a 'package' attribute");
return {};
}
std::string error_msg;
std::optional<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg);
if (!maybe_package) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid package name: " << error_msg);
return {};
}
@@ -364,7 +367,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:versionCode: " << error_msg);
return {};
}
@@ -375,8 +378,8 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
- << "invalid android:versionCodeMajor: " << error_msg);
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ << "invalid android:versionCodeMajor: " << error_msg);
return {};
}
app_info.version_code_major = maybe_code.value();
@@ -386,7 +389,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
std::optional<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:revisionCode: " << error_msg);
return {};
}
@@ -397,7 +400,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
std::optional<std::string> maybe_split_name =
ExtractCompiledString(*split_name_attr, &error_msg);
if (!maybe_split_name) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid split name: " << error_msg);
return {};
}
@@ -409,7 +412,7 @@ std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource&
uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
std::optional<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg);
if (!maybe_sdk) {
- diag->Error(DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
+ diag->Error(android::DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
<< "invalid android:minSdkVersion: " << error_msg);
return {};
}
@@ -443,4 +446,44 @@ std::regex GetRegularExpression(const std::string &input) {
return case_insensitive;
}
+bool ParseResourceConfig(const std::string& content, IAaptContext* context,
+ std::unordered_set<ResourceName>& out_resource_exclude_list,
+ std::set<ResourceName>& out_name_collapse_exemptions,
+ std::set<ResourceName>& out_path_shorten_exemptions) {
+ for (StringPiece line : util::Tokenize(content, '\n')) {
+ line = util::TrimWhitespace(line);
+ if (line.empty()) {
+ continue;
+ }
+
+ auto split_line = util::Split(line, '#');
+ if (split_line.size() < 2) {
+ context->GetDiagnostics()->Error(android::DiagMessage(line) << "No # found in line");
+ return false;
+ }
+ StringPiece resource_string = split_line[0];
+ StringPiece directives = split_line[1];
+ ResourceNameRef resource_name;
+ if (!ResourceUtils::ParseResourceName(resource_string, &resource_name)) {
+ context->GetDiagnostics()->Error(android::DiagMessage(line) << "Malformed resource name");
+ return false;
+ }
+ if (!resource_name.package.empty()) {
+ context->GetDiagnostics()->Error(android::DiagMessage(line)
+ << "Package set for resource. Only use type/name");
+ return false;
+ }
+ for (StringPiece directive : util::Tokenize(directives, ',')) {
+ if (directive == "remove") {
+ out_resource_exclude_list.insert(resource_name.ToResourceName());
+ } else if (directive == "no_collapse" || directive == "no_obfuscate") {
+ out_name_collapse_exemptions.insert(resource_name.ToResourceName());
+ } else if (directive == "no_path_shorten") {
+ out_path_shorten_exemptions.insert(resource_name.ToResourceName());
+ }
+ }
+ }
+ return true;
+}
+
} // namespace aapt
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index 1b98eb468700..712c07b71695 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -18,13 +18,15 @@
#define AAPT_SPLIT_UTIL_H
#include <regex>
-
-#include "androidfw/StringPiece.h"
+#include <set>
+#include <unordered_set>
#include "AppInfo.h"
-#include "Diagnostics.h"
#include "SdkConstants.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/StringPiece.h"
#include "filter/ConfigFilter.h"
+#include "process/IResourceTableConsumer.h"
#include "split/TableSplitter.h"
#include "xml/XmlDom.h"
@@ -32,19 +34,19 @@ namespace aapt {
// Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc).
// Returns Nothing and logs a human friendly error message if the string was not legal.
-std::optional<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg,
- IDiagnostics* diag);
+std::optional<uint16_t> ParseTargetDensityParameter(android::StringPiece arg,
+ android::IDiagnostics* diag);
// Parses a string of the form 'path/to/output.apk:<config>[,<config>...]' and fills in
// `out_path` with the path and `out_split` with the set of ConfigDescriptions.
// Returns false and logs a human friendly error message if the string was not legal.
-bool ParseSplitParameter(const android::StringPiece& arg, IDiagnostics* diag, std::string* out_path,
- SplitConstraints* out_split);
+bool ParseSplitParameter(android::StringPiece arg, android::IDiagnostics* diag,
+ std::string* out_path, SplitConstraints* out_split);
// Parses a set of config filter strings of the form 'en,fr-rFR' and returns an IConfigFilter.
// Returns nullptr and logs a human friendly error message if the string was not legal.
std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std::string>& args,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Adjust the SplitConstraints so that their SDK version is stripped if it
// is less than or equal to the min_sdk. Otherwise the resources that have had
@@ -60,7 +62,7 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
// Extracts relevant info from the AndroidManifest.xml.
std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Returns a copy of 'name' which conforms to the regex '[a-zA-Z]+[a-zA-Z0-9_]*' by
// replacing nonconforming characters with underscores.
@@ -77,6 +79,11 @@ void SetLongVersionCode(xml::Element* manifest, uint64_t version_code);
// Returns a case insensitive regular expression based on the input.
std::regex GetRegularExpression(const std::string &input);
+bool ParseResourceConfig(const std::string& content, IAaptContext* context,
+ std::unordered_set<ResourceName>& out_resource_exclude_list,
+ std::set<ResourceName>& out_name_collapse_exemptions,
+ std::set<ResourceName>& out_path_shorten_exemptions);
+
} // namespace aapt
#endif /* AAPT_SPLIT_UTIL_H */
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index ac1f981d753c..139bfbcd0f41 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -25,6 +25,7 @@
#include "util/Files.h"
using ::android::ConfigDescription;
+using testing::UnorderedElementsAre;
namespace aapt {
@@ -102,7 +103,7 @@ TEST (UtilTest, LongVersionCodeUndefined) {
TEST (UtilTest, ParseSplitParameters) {
- IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
+ android::IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
std::string path;
SplitConstraints constraints;
ConfigDescription expected_configuration;
@@ -356,7 +357,7 @@ TEST (UtilTest, ParseSplitParameters) {
TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
- IDiagnostics* diagnostics = context.get()->GetDiagnostics();
+ android::IDiagnostics* diagnostics = context.get()->GetDiagnostics();
std::vector<SplitConstraints> test_constraints;
std::string path;
@@ -411,4 +412,72 @@ TEST (UtilTest, RegularExpressionNonEnglish) {
EXPECT_FALSE(std::regex_search("file.koncowka", expression));
}
+TEST(UtilTest, ParseConfigWithDirectives) {
+ const std::string& content = R"(
+bool/remove_me#remove
+bool/keep_name#no_collapse
+layout/keep_path#no_path_shorten
+string/foo#no_obfuscate
+dimen/bar#no_obfuscate
+layout/keep_name_and_path#no_collapse,no_path_shorten
+)";
+ aapt::test::Context context;
+ std::unordered_set<ResourceName> resource_exclusion;
+ std::set<ResourceName> name_collapse_exemptions;
+ std::set<ResourceName> path_shorten_exemptions;
+
+ EXPECT_TRUE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
+ path_shorten_exemptions));
+
+ EXPECT_THAT(name_collapse_exemptions,
+ UnorderedElementsAre(ResourceName({}, ResourceType::kString, "foo"),
+ ResourceName({}, ResourceType::kDimen, "bar"),
+ ResourceName({}, ResourceType::kBool, "keep_name"),
+ ResourceName({}, ResourceType::kLayout, "keep_name_and_path")));
+ EXPECT_THAT(path_shorten_exemptions,
+ UnorderedElementsAre(ResourceName({}, ResourceType::kLayout, "keep_path"),
+ ResourceName({}, ResourceType::kLayout, "keep_name_and_path")));
+ EXPECT_THAT(resource_exclusion,
+ UnorderedElementsAre(ResourceName({}, ResourceType::kBool, "remove_me")));
+}
+
+TEST(UtilTest, ParseConfigResourceWithPackage) {
+ const std::string& content = R"(
+package:bool/remove_me#remove
+)";
+ aapt::test::Context context;
+ std::unordered_set<ResourceName> resource_exclusion;
+ std::set<ResourceName> name_collapse_exemptions;
+ std::set<ResourceName> path_shorten_exemptions;
+
+ EXPECT_FALSE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
+ path_shorten_exemptions));
+}
+
+TEST(UtilTest, ParseConfigInvalidName) {
+ const std::string& content = R"(
+package:bool/1231#remove
+)";
+ aapt::test::Context context;
+ std::unordered_set<ResourceName> resource_exclusion;
+ std::set<ResourceName> name_collapse_exemptions;
+ std::set<ResourceName> path_shorten_exemptions;
+
+ EXPECT_FALSE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
+ path_shorten_exemptions));
+}
+
+TEST(UtilTest, ParseConfigNoHash) {
+ const std::string& content = R"(
+package:bool/my_bool
+)";
+ aapt::test::Context context;
+ std::unordered_set<ResourceName> resource_exclusion;
+ std::set<ResourceName> name_collapse_exemptions;
+ std::set<ResourceName> path_shorten_exemptions;
+
+ EXPECT_FALSE(ParseResourceConfig(content, &context, resource_exclusion, name_collapse_exemptions,
+ path_shorten_exemptions));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index fa816be43be3..b3f98a9d3e30 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -107,10 +107,10 @@ struct IdAssignerContext {
// Returns whether the id was reserved successfully.
// Reserving identifiers must be completed before `NextId` is called for the first time.
bool ReserveId(const ResourceName& name, ResourceId id, const Visibility& visibility,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
// Retrieves the next available resource id that has not been reserved.
- std::optional<ResourceId> NextId(const ResourceName& name, IDiagnostics* diag);
+ std::optional<ResourceId> NextId(const ResourceName& name, android::IDiagnostics* diag);
private:
std::string package_name_;
@@ -128,7 +128,7 @@ bool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- const ResourceName name(package->name, type->type, entry->name);
+ const ResourceName name(package->name, type->named_type, entry->name);
if (entry->id && !assigned_ids.ReserveId(name, entry->id.value(), entry->visibility,
context->GetDiagnostics())) {
return false;
@@ -175,7 +175,7 @@ bool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
- const ResourceName name(package->name, type->type, entry->name);
+ const ResourceName name(package->name, type->named_type, entry->name);
if (entry->id) {
continue;
}
@@ -267,11 +267,11 @@ Result<ResourceId> TypeGroup::NextId() {
}
bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
- const Visibility& visibility, IDiagnostics* diag) {
+ const Visibility& visibility, android::IDiagnostics* diag) {
if (package_id_ != id.package_id()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because package already has ID " << std::hex
- << (int)id.package_id());
+ diag->Error(android::DiagMessage()
+ << "can't assign ID " << id << " to resource " << name
+ << " because package already has ID " << std::hex << (int)id.package_id());
return false;
}
@@ -282,8 +282,8 @@ bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
// another type.
auto assign_result = type_id_finder_.ReserveId(key, id.type_id());
if (!assign_result.has_value()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because type " << assign_result.error());
+ diag->Error(android::DiagMessage() << "can't assign ID " << id << " to resource " << name
+ << " because type " << assign_result.error());
return false;
}
type = types_.emplace(key, TypeGroup(package_id_, id.type_id())).first;
@@ -293,24 +293,25 @@ bool IdAssignerContext::ReserveId(const ResourceName& name, ResourceId id,
// Ensure that non-staged resources can only exist in one type ID.
auto non_staged_type = non_staged_type_ids_.emplace(name.type.type, id.type_id());
if (!non_staged_type.second && non_staged_type.first->second != id.type_id()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name
- << " because type already has ID " << std::hex
- << (int)id.type_id());
+ diag->Error(android::DiagMessage()
+ << "can't assign ID " << id << " to resource " << name
+ << " because type already has ID " << std::hex << (int)id.type_id());
return false;
}
}
auto assign_result = type->second.ReserveId(name, id);
if (!assign_result.has_value()) {
- diag->Error(DiagMessage() << "can't assign ID " << id << " to resource " << name << " because "
- << assign_result.error());
+ diag->Error(android::DiagMessage() << "can't assign ID " << id << " to resource " << name
+ << " because " << assign_result.error());
return false;
}
return true;
}
-std::optional<ResourceId> IdAssignerContext::NextId(const ResourceName& name, IDiagnostics* diag) {
+std::optional<ResourceId> IdAssignerContext::NextId(const ResourceName& name,
+ android::IDiagnostics* diag) {
// The package name is not known during the compile stage.
// Resources without a package name are considered a part of the app being linked.
CHECK(name.package.empty() || name.package == package_name_);
@@ -331,8 +332,8 @@ std::optional<ResourceId> IdAssignerContext::NextId(const ResourceName& name, ID
auto assign_result = type->second.NextId();
if (!assign_result.has_value()) {
- diag->Error(DiagMessage() << "can't assign resource ID to resource " << name << " because "
- << assign_result.error());
+ diag->Error(android::DiagMessage() << "can't assign resource ID to resource " << name
+ << " because " << assign_result.error());
return {};
}
return assign_result.value();
diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp
index d3575716ae4f..8911dad39470 100644
--- a/tools/aapt2/compile/IdAssigner_test.cpp
+++ b/tools/aapt2/compile/IdAssigner_test.cpp
@@ -191,12 +191,12 @@ TEST_F(IdAssignerTests, ExaustEntryIdsLastIdIsPublic) {
for (auto& entry : type->entries) {
if (!entry->id) {
return ::testing::AssertionFailure()
- << "resource " << ResourceNameRef(package->name, type->type, entry->name)
+ << "resource " << ResourceNameRef(package->name, type->named_type, entry->name)
<< " has no ID";
}
if (!seen_ids.insert(entry->id.value()).second) {
return ::testing::AssertionFailure()
- << "resource " << ResourceNameRef(package->name, type->type, entry->name)
+ << "resource " << ResourceNameRef(package->name, type->named_type, entry->name)
<< " has a non-unique ID" << std::hex << entry->id.value() << std::dec;
}
}
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index de1c3bb3dd7e..444f82109de4 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -47,19 +47,19 @@ class Visitor : public xml::PackageAwareVisitor {
return;
}
- const Source src = xml_resource_->file.source.WithLine(el->line_number);
+ const android::Source src = xml_resource_->file.source.WithLine(el->line_number);
xml::Attribute* attr = el->FindAttribute({}, "name");
if (!attr) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "missing 'name' attribute");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src) << "missing 'name' attribute");
error_ = true;
return;
}
std::optional<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value);
if (!ref) {
- context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid XML attribute '" << attr->value
- << "'");
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "invalid XML attribute '" << attr->value << "'");
error_ = true;
return;
}
@@ -67,7 +67,7 @@ class Visitor : public xml::PackageAwareVisitor {
const ResourceName& name = ref.value().name.value();
std::optional<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
if (!maybe_pkg) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "invalid namespace prefix '" << name.package << "'");
error_ = true;
return;
@@ -136,15 +136,15 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc
// Extracted elements must be the only child of <aapt:attr>.
// Make sure there is one root node in the children (ignore empty text).
for (std::unique_ptr<xml::Node>& child : decl.el->children) {
- const Source child_source = doc->file.source.WithLine(child->line_number);
+ const android::Source child_source = doc->file.source.WithLine(child->line_number);
if (xml::Text* t = xml::NodeCast<xml::Text>(child.get())) {
if (!util::TrimWhitespace(t->text).empty()) {
- context->GetDiagnostics()->Error(DiagMessage(child_source)
+ context->GetDiagnostics()->Error(android::DiagMessage(child_source)
<< "can't extract text into its own resource");
return false;
}
} else if (new_doc->root) {
- context->GetDiagnostics()->Error(DiagMessage(child_source)
+ context->GetDiagnostics()->Error(android::DiagMessage(child_source)
<< "inline XML resources must have a single root");
return false;
} else {
@@ -160,7 +160,7 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc
// Get the parent element of <aapt:attr>
xml::Element* parent_el = decl.el->parent;
if (!parent_el) {
- context->GetDiagnostics()->Error(DiagMessage(new_doc->file.source)
+ context->GetDiagnostics()->Error(android::DiagMessage(new_doc->file.source)
<< "no suitable parent for inheriting attribute");
return false;
}
diff --git a/tools/aapt2/compile/NinePatch.cpp b/tools/aapt2/compile/NinePatch.cpp
index c931da48c889..4538ecc56e4c 100644
--- a/tools/aapt2/compile/NinePatch.cpp
+++ b/tools/aapt2/compile/NinePatch.cpp
@@ -218,11 +218,9 @@ inline static uint32_t get_alpha(uint32_t color) {
static bool PopulateBounds(const std::vector<Range>& padding,
const std::vector<Range>& layout_bounds,
- const std::vector<Range>& stretch_regions,
- const int32_t length, int32_t* padding_start,
- int32_t* padding_end, int32_t* layout_start,
- int32_t* layout_end, const StringPiece& edge_name,
- std::string* out_err) {
+ const std::vector<Range>& stretch_regions, const int32_t length,
+ int32_t* padding_start, int32_t* padding_end, int32_t* layout_start,
+ int32_t* layout_end, StringPiece edge_name, std::string* out_err) {
if (padding.size() > 1) {
std::stringstream err_stream;
err_stream << "too many padding sections on " << edge_name << " border";
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index d396d81d699a..76db815129dd 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -24,11 +24,10 @@
#include <string>
#include <vector>
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
-
-#include "Source.h"
+#include "androidfw/Source.h"
#include "trace/TraceBuffer.h"
-#include "util/BigBuffer.h"
#include "util/Util.h"
namespace aapt {
@@ -91,7 +90,7 @@ static void readDataFromStream(png_structp readPtr, png_bytep data,
static void writeDataToStream(png_structp writePtr, png_bytep data,
png_size_t length) {
- BigBuffer* outBuffer = reinterpret_cast<BigBuffer*>(png_get_io_ptr(writePtr));
+ android::BigBuffer* outBuffer = reinterpret_cast<android::BigBuffer*>(png_get_io_ptr(writePtr));
png_bytep buf = outBuffer->NextBlock<png_byte>(length);
memcpy(buf, data, length);
}
@@ -99,15 +98,15 @@ static void writeDataToStream(png_structp writePtr, png_bytep data,
static void flushDataToStream(png_structp /*writePtr*/) {}
static void logWarning(png_structp readPtr, png_const_charp warningMessage) {
- IDiagnostics* diag =
- reinterpret_cast<IDiagnostics*>(png_get_error_ptr(readPtr));
- diag->Warn(DiagMessage() << warningMessage);
+ android::IDiagnostics* diag =
+ reinterpret_cast<android::IDiagnostics*>(png_get_error_ptr(readPtr));
+ diag->Warn(android::DiagMessage() << warningMessage);
}
-static bool readPng(IDiagnostics* diag, png_structp readPtr, png_infop infoPtr,
+static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop infoPtr,
PngInfo* outInfo) {
if (setjmp(png_jmpbuf(readPtr))) {
- diag->Error(DiagMessage() << "failed reading png");
+ diag->Error(android::DiagMessage() << "failed reading png");
return false;
}
@@ -245,10 +244,9 @@ PNG_COLOR_TYPE_RGB_ALPHA) {
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ABS(a) ((a) < 0 ? -(a) : (a))
-static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo,
- int grayscaleTolerance, png_colorp rgbPalette,
- png_bytep alphaPalette, int* paletteEntries,
- bool* hasTransparency, int* colorType,
+static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo,
+ int grayscaleTolerance, png_colorp rgbPalette, png_bytep alphaPalette,
+ int* paletteEntries, bool* hasTransparency, int* colorType,
png_bytepp outRows) {
int w = imageInfo.width;
int h = imageInfo.height;
@@ -383,8 +381,8 @@ static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo,
*colorType = PNG_COLOR_TYPE_PALETTE;
} else {
if (maxGrayDeviation <= grayscaleTolerance) {
- diag->Note(DiagMessage() << "forcing image to gray (max deviation = "
- << maxGrayDeviation << ")");
+ diag->Note(android::DiagMessage()
+ << "forcing image to gray (max deviation = " << maxGrayDeviation << ")");
*colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA;
} else {
*colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
@@ -431,10 +429,10 @@ static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo,
}
}
-static bool writePng(IDiagnostics* diag, png_structp writePtr,
- png_infop infoPtr, PngInfo* info, int grayScaleTolerance) {
+static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_infop infoPtr,
+ PngInfo* info, int grayScaleTolerance) {
if (setjmp(png_jmpbuf(writePtr))) {
- diag->Error(DiagMessage() << "failed to write png");
+ diag->Error(android::DiagMessage() << "failed to write png");
return false;
}
@@ -463,8 +461,8 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
png_set_compression_level(writePtr, Z_BEST_COMPRESSION);
if (kDebug) {
- diag->Note(DiagMessage() << "writing image: w = " << info->width
- << ", h = " << info->height);
+ diag->Note(android::DiagMessage()
+ << "writing image: w = " << info->width << ", h = " << info->height);
}
png_color rgbPalette[256];
@@ -486,24 +484,21 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
if (kDebug) {
switch (colorType) {
case PNG_COLOR_TYPE_PALETTE:
- diag->Note(DiagMessage() << "has " << paletteEntries << " colors"
- << (hasTransparency ? " (with alpha)" : "")
- << ", using PNG_COLOR_TYPE_PALLETTE");
+ diag->Note(android::DiagMessage() << "has " << paletteEntries << " colors"
+ << (hasTransparency ? " (with alpha)" : "")
+ << ", using PNG_COLOR_TYPE_PALLETTE");
break;
case PNG_COLOR_TYPE_GRAY:
- diag->Note(DiagMessage()
- << "is opaque gray, using PNG_COLOR_TYPE_GRAY");
+ diag->Note(android::DiagMessage() << "is opaque gray, using PNG_COLOR_TYPE_GRAY");
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
- diag->Note(DiagMessage()
- << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA");
+ diag->Note(android::DiagMessage() << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA");
break;
case PNG_COLOR_TYPE_RGB:
- diag->Note(DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB");
+ diag->Note(android::DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB");
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
- diag->Note(DiagMessage()
- << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA");
+ diag->Note(android::DiagMessage() << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA");
break;
}
}
@@ -537,7 +532,7 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
// base 9 patch data
if (kDebug) {
- diag->Note(DiagMessage() << "adding 9-patch info..");
+ diag->Note(android::DiagMessage() << "adding 9-patch info..");
}
memcpy((char*)unknowns[pIndex].name, "npTc", 5);
unknowns[pIndex].data = (png_byte*)info->serialize9Patch();
@@ -614,11 +609,10 @@ static bool writePng(IDiagnostics* diag, png_structp writePtr,
&interlaceType, &compressionType, nullptr);
if (kDebug) {
- diag->Note(DiagMessage() << "image written: w = " << width
- << ", h = " << height << ", d = " << bitDepth
- << ", colors = " << colorType
- << ", inter = " << interlaceType
- << ", comp = " << compressionType);
+ diag->Note(android::DiagMessage()
+ << "image written: w = " << width << ", h = " << height << ", d = " << bitDepth
+ << ", colors = " << colorType << ", inter = " << interlaceType
+ << ", comp = " << compressionType);
}
return true;
}
@@ -1232,20 +1226,20 @@ getout:
return true;
}
-bool Png::process(const Source& source, std::istream* input,
- BigBuffer* outBuffer, const PngOptions& options) {
+bool Png::process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer,
+ const PngOptions& options) {
TRACE_CALL();
png_byte signature[kPngSignatureSize];
// Read the PNG signature first.
if (!input->read(reinterpret_cast<char*>(signature), kPngSignatureSize)) {
- mDiag->Error(DiagMessage() << strerror(errno));
+ mDiag->Error(android::DiagMessage() << strerror(errno));
return false;
}
// If the PNG signature doesn't match, bail early.
if (png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
- mDiag->Error(DiagMessage() << "not a valid png file");
+ mDiag->Error(android::DiagMessage() << "not a valid png file");
return false;
}
@@ -1258,13 +1252,13 @@ bool Png::process(const Source& source, std::istream* input,
readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
if (!readPtr) {
- mDiag->Error(DiagMessage() << "failed to allocate read ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate read ptr");
goto bail;
}
infoPtr = png_create_info_struct(readPtr);
if (!infoPtr) {
- mDiag->Error(DiagMessage() << "failed to allocate info ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate info ptr");
goto bail;
}
@@ -1281,7 +1275,7 @@ bool Png::process(const Source& source, std::istream* input,
if (util::EndsWith(source.path, ".9.png")) {
std::string errorMsg;
if (!do9Patch(&pngInfo, &errorMsg)) {
- mDiag->Error(DiagMessage() << errorMsg);
+ mDiag->Error(android::DiagMessage() << errorMsg);
goto bail;
}
}
@@ -1289,13 +1283,13 @@ bool Png::process(const Source& source, std::istream* input,
writePtr =
png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
if (!writePtr) {
- mDiag->Error(DiagMessage() << "failed to allocate write ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate write ptr");
goto bail;
}
writeInfoPtr = png_create_info_struct(writePtr);
if (!writeInfoPtr) {
- mDiag->Error(DiagMessage() << "failed to allocate write info ptr");
+ mDiag->Error(android::DiagMessage() << "failed to allocate write info ptr");
goto bail;
}
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index 7ca1f0ec7800..a8b7dd18f12f 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -21,13 +21,12 @@
#include <string>
#include "android-base/macros.h"
-
-#include "Diagnostics.h"
-#include "Source.h"
+#include "androidfw/BigBuffer.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
#include "compile/Image.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
namespace aapt {
@@ -43,15 +42,16 @@ struct PngOptions {
*/
class Png {
public:
- explicit Png(IDiagnostics* diag) : mDiag(diag) {}
+ explicit Png(android::IDiagnostics* diag) : mDiag(diag) {
+ }
- bool process(const Source& source, std::istream* input, BigBuffer* outBuffer,
+ bool process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer,
const PngOptions& options);
private:
DISALLOW_COPY_AND_ASSIGN(Png);
- IDiagnostics* mDiag;
+ android::IDiagnostics* mDiag;
};
/**
@@ -59,7 +59,7 @@ class Png {
*/
class PngChunkFilter : public io::InputStream {
public:
- explicit PngChunkFilter(const android::StringPiece& data);
+ explicit PngChunkFilter(android::StringPiece data);
virtual ~PngChunkFilter() = default;
bool Next(const void** buffer, size_t* len) override;
@@ -90,7 +90,8 @@ class PngChunkFilter : public io::InputStream {
/**
* Reads a PNG from the InputStream into memory as an RGBA Image.
*/
-std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in);
+std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source,
+ io::InputStream* in);
/**
* Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index 4db2392b4eab..2e55d0c82b7b 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -70,7 +70,7 @@ static bool IsPngChunkAllowed(uint32_t type) {
}
}
-PngChunkFilter::PngChunkFilter(const StringPiece& data) : data_(data) {
+PngChunkFilter::PngChunkFilter(StringPiece data) : data_(data) {
if (util::StartsWith(data_, kPngSignature)) {
window_start_ = 0;
window_end_ = kPngSignatureSize;
diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp
index 1f4ea44d9f86..4ef87ba3671b 100644
--- a/tools/aapt2/compile/PngCrunch.cpp
+++ b/tools/aapt2/compile/PngCrunch.cpp
@@ -67,14 +67,14 @@ class PngWriteStructDeleter {
// Custom warning logging method that uses IDiagnostics.
static void LogWarning(png_structp png_ptr, png_const_charp warning_msg) {
- IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
- diag->Warn(DiagMessage() << warning_msg);
+ android::IDiagnostics* diag = (android::IDiagnostics*)png_get_error_ptr(png_ptr);
+ diag->Warn(android::DiagMessage() << warning_msg);
}
// Custom error logging method that uses IDiagnostics.
static void LogError(png_structp png_ptr, png_const_charp error_msg) {
- IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
- diag->Error(DiagMessage() << error_msg);
+ android::IDiagnostics* diag = (android::IDiagnostics*)png_get_error_ptr(png_ptr);
+ diag->Error(android::DiagMessage() << error_msg);
// Causes libpng to longjmp to the spot where setjmp was set. This is how libpng does
// error handling. If this custom error handler method were to return, libpng would, by
@@ -143,10 +143,11 @@ static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t
}
}
-std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in) {
+std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source,
+ io::InputStream* in) {
TRACE_CALL();
// Create a diagnostics that has the source information encoded.
- SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
+ android::SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
// Read the first 8 bytes of the file looking for the PNG signature.
// Bail early if it does not match.
@@ -154,15 +155,16 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::
size_t buffer_size;
if (!in->Next((const void**)&signature, &buffer_size)) {
if (in->HadError()) {
- source_diag.Error(DiagMessage() << "failed to read PNG signature: " << in->GetError());
+ source_diag.Error(android::DiagMessage()
+ << "failed to read PNG signature: " << in->GetError());
} else {
- source_diag.Error(DiagMessage() << "not enough data for PNG signature");
+ source_diag.Error(android::DiagMessage() << "not enough data for PNG signature");
}
return {};
}
if (buffer_size < kPngSignatureSize || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
- source_diag.Error(DiagMessage() << "file signature does not match PNG signature");
+ source_diag.Error(android::DiagMessage() << "file signature does not match PNG signature");
return {};
}
@@ -174,14 +176,14 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::
// version of libpng.
png_structp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (read_ptr == nullptr) {
- source_diag.Error(DiagMessage() << "failed to create libpng read png_struct");
+ source_diag.Error(android::DiagMessage() << "failed to create libpng read png_struct");
return {};
}
// Create and initialize the memory for image header and data.
png_infop info_ptr = png_create_info_struct(read_ptr);
if (info_ptr == nullptr) {
- source_diag.Error(DiagMessage() << "failed to create libpng read png_info");
+ source_diag.Error(android::DiagMessage() << "failed to create libpng read png_info");
png_destroy_read_struct(&read_ptr, nullptr, nullptr);
return {};
}
@@ -254,7 +256,7 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::
// something
// that can always be represented by 9-patch.
if (width > std::numeric_limits<int32_t>::max() || height > std::numeric_limits<int32_t>::max()) {
- source_diag.Error(DiagMessage()
+ source_diag.Error(android::DiagMessage()
<< "PNG image dimensions are too large: " << width << "x" << height);
return {};
}
@@ -490,14 +492,16 @@ bool WritePng(IAaptContext* context, const Image* image,
// version of libpng.
png_structp write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (write_ptr == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to create libpng write png_struct");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to create libpng write png_struct");
return false;
}
// Allocate memory to store image header data.
png_infop write_info_ptr = png_create_info_struct(write_ptr);
if (write_info_ptr == nullptr) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to create libpng write png_info");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to create libpng write png_info");
png_destroy_write_struct(&write_ptr, nullptr);
return false;
}
@@ -575,7 +579,7 @@ bool WritePng(IAaptContext* context, const Image* image,
}
if (context->IsVerbose()) {
- DiagMessage msg;
+ android::DiagMessage msg;
msg << " paletteSize=" << color_palette.size()
<< " alphaPaletteSize=" << alpha_palette.size()
<< " maxGrayDeviation=" << max_gray_deviation
@@ -590,7 +594,7 @@ bool WritePng(IAaptContext* context, const Image* image,
nine_patch != nullptr, color_palette.size(), alpha_palette.size());
if (context->IsVerbose()) {
- DiagMessage msg;
+ android::DiagMessage msg;
msg << "encoding PNG ";
if (nine_patch) {
msg << "(with 9-patch) as ";
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 2461438c49b6..09a8560f984a 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -21,6 +21,7 @@
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "androidfw/Util.h"
#include "compile/Pseudolocalizer.h"
#include "util/Util.h"
@@ -53,7 +54,7 @@ inline static bool operator<(const UnifiedSpan& left, const UnifiedSpan& right)
return false;
}
-inline static UnifiedSpan SpanToUnifiedSpan(const StringPool::Span& span) {
+inline static UnifiedSpan SpanToUnifiedSpan(const android::StringPool::Span& span) {
return UnifiedSpan{*span.name, span.first_char, span.last_char};
}
@@ -111,7 +112,7 @@ static std::vector<UnifiedSpan> MergeSpans(const StyledString& string) {
std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
Pseudolocalizer::Method method,
- StringPool* pool) {
+ android::StringPool* pool) {
Pseudolocalizer localizer(method);
// Collect the spans and untranslatable sections into one set of spans, sorted by first_char.
@@ -121,7 +122,7 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
// All Span indices are UTF-16 based, according to the resources.arsc format expected by the
// runtime. So we will do all our processing in UTF-16, then convert back.
- const std::u16string text16 = util::Utf8ToUtf16(string->value->value);
+ const std::u16string text16 = android::util::Utf8ToUtf16(string->value->value);
// Convenient wrapper around the text that allows us to work with StringPieces.
const StringPiece16 text(text16);
@@ -154,7 +155,7 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
cursor += substr.size();
// Pseudolocalize the substring.
- std::string new_substr = util::Utf16ToUtf8(substr);
+ std::string new_substr = android::util::Utf16ToUtf8(substr);
if (translatable) {
new_substr = localizer.Text(new_substr);
}
@@ -181,7 +182,7 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
cursor += substr.size();
// Pseudolocalize the substring.
- std::string new_substr = util::Utf16ToUtf8(substr);
+ std::string new_substr = android::util::Utf16ToUtf8(substr);
if (translatable) {
new_substr = localizer.Text(new_substr);
}
@@ -199,16 +200,18 @@ std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
}
// Finish the pseudolocalization at the end of the string.
- new_string += localizer.Text(util::Utf16ToUtf8(text.substr(cursor, text.size() - cursor)));
+ new_string +=
+ localizer.Text(android::util::Utf16ToUtf8(text.substr(cursor, text.size() - cursor)));
new_string += localizer.End();
- StyleString localized;
+ android::StyleString localized;
localized.str = std::move(new_string);
// Convert the UnifiedSpans into regular Spans, skipping the UntranslatableSections.
for (UnifiedSpan& span : merged_spans) {
if (span.tag) {
- localized.spans.push_back(Span{std::move(span.tag.value()), span.first_char, span.last_char});
+ localized.spans.push_back(
+ android::Span{std::move(span.tag.value()), span.first_char, span.last_char});
}
}
return util::make_unique<StyledString>(pool->MakeRef(localized));
@@ -222,8 +225,9 @@ class Visitor : public ValueVisitor {
std::unique_ptr<Value> value;
std::unique_ptr<Item> item;
- Visitor(StringPool* pool, Pseudolocalizer::Method method)
- : pool_(pool), method_(method), localizer_(method) {}
+ Visitor(android::StringPool* pool, Pseudolocalizer::Method method)
+ : pool_(pool), method_(method), localizer_(method) {
+ }
void Visit(Plural* plural) override {
CloningValueTransformer cloner(pool_);
@@ -284,7 +288,7 @@ class Visitor : public ValueVisitor {
private:
DISALLOW_COPY_AND_ASSIGN(Visitor);
- StringPool* pool_;
+ android::StringPool* pool_;
Pseudolocalizer::Method method_;
Pseudolocalizer localizer_;
};
@@ -313,8 +317,8 @@ ConfigDescription ModifyConfigForPseudoLocale(const ConfigDescription& base,
}
void PseudolocalizeIfNeeded(const Pseudolocalizer::Method method,
- ResourceConfigValue* original_value,
- StringPool* pool, ResourceEntry* entry) {
+ ResourceConfigValue* original_value, android::StringPool* pool,
+ ResourceEntry* entry) {
Visitor visitor(pool, method);
original_value->value->Accept(&visitor);
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.h b/tools/aapt2/compile/PseudolocaleGenerator.h
index ace378603f65..44e6e3e86f92 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.h
+++ b/tools/aapt2/compile/PseudolocaleGenerator.h
@@ -17,14 +17,15 @@
#ifndef AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
#define AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
#include "compile/Pseudolocalizer.h"
#include "process/IResourceTableConsumer.h"
namespace aapt {
-std::unique_ptr<StyledString> PseudolocalizeStyledString(
- StyledString* string, Pseudolocalizer::Method method, StringPool* pool);
+std::unique_ptr<StyledString> PseudolocalizeStyledString(StyledString* string,
+ Pseudolocalizer::Method method,
+ android::StringPool* pool);
struct PseudolocaleGenerator : public IResourceTableConsumer {
bool Consume(IAaptContext* context, ResourceTable* table) override;
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
index 432d7bfdad49..2f90cbf722c2 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -24,10 +24,11 @@ using ::android::ConfigDescription;
namespace aapt {
TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "Hello world!";
- original_style.spans = {Span{"i", 1, 10}, Span{"b", 2, 3}, Span{"b", 6, 7}};
+ original_style.spans = {android::Span{"i", 1, 10}, android::Span{"b", 2, 3},
+ android::Span{"b", 6, 7}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -48,7 +49,7 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
EXPECT_EQ(std::u16string(u"Hello ").size(), new_string->value->spans[2].first_char);
EXPECT_EQ(std::u16string(u"Hello w").size(), new_string->value->spans[2].last_char);
- original_style.spans.insert(original_style.spans.begin(), Span{"em", 0, 11u});
+ original_style.spans.insert(original_style.spans.begin(), android::Span{"em", 0, 11u});
new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -71,10 +72,10 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentNestedTags) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "bold";
- original_style.spans = {Span{"b", 0, 3}, Span{"i", 0, 3}};
+ original_style.spans = {android::Span{"b", 0, 3}, android::Span{"i", 0, 3}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -93,10 +94,10 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentNestedTags) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentTagsUnsorted) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "bold";
- original_style.spans = {Span{"i", 2, 3}, Span{"b", 0, 1}};
+ original_style.spans = {android::Span{"i", 2, 3}, android::Span{"b", 0, 1}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -115,11 +116,11 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeAdjacentTagsUnsorted) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizeNestedAndAdjacentTags) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "This sentence is not what you think it is at all.";
- original_style.spans = {Span{"b", 16u, 19u}, Span{"em", 29u, 47u}, Span{"i", 38u, 40u},
- Span{"b", 44u, 47u}};
+ original_style.spans = {android::Span{"b", 16u, 19u}, android::Span{"em", 29u, 47u},
+ android::Span{"i", 38u, 40u}, android::Span{"b", 44u, 47u}};
std::unique_ptr<StyledString> new_string = PseudolocalizeStyledString(
util::make_unique<StyledString>(pool.MakeRef(original_style)).get(),
@@ -154,10 +155,10 @@ TEST(PseudolocaleGeneratorTest, PseudolocalizeNestedAndAdjacentTags) {
}
TEST(PseudolocaleGeneratorTest, PseudolocalizePartsOfString) {
- StringPool pool;
- StyleString original_style;
+ android::StringPool pool;
+ android::StyleString original_style;
original_style.str = "This should NOT be pseudolocalized.";
- original_style.spans = {Span{"em", 4u, 14u}, Span{"i", 18u, 33u}};
+ original_style.spans = {android::Span{"em", 4u, 14u}, android::Span{"i", 18u, 33u}};
std::unique_ptr<StyledString> original_string =
util::make_unique<StyledString>(pool.MakeRef(original_style));
original_string->untranslatable_sections = {UntranslatableSection{11u, 15u}};
@@ -263,9 +264,10 @@ TEST(PseudolocaleGeneratorTest, RespectUntranslateableSections) {
std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
{
- StyleString original_style;
+ android::StyleString original_style;
original_style.str = "Hello world!";
- original_style.spans = {Span{"i", 1, 10}, Span{"b", 2, 3}, Span{"b", 6, 7}};
+ original_style.spans = {android::Span{"i", 1, 10}, android::Span{"b", 2, 3},
+ android::Span{"b", 6, 7}};
auto styled_string =
util::make_unique<StyledString>(table->string_pool.MakeRef(original_style));
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
index 3a515fad3202..463ce787dae7 100644
--- a/tools/aapt2/compile/Pseudolocalizer.cpp
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -20,36 +20,42 @@
using android::StringPiece;
+using namespace std::literals;
+
namespace aapt {
// String basis to generate expansion
-static const std::string kExpansionString =
+static constexpr auto kExpansionString =
"one two three "
"four five six seven eight nine ten eleven twelve thirteen "
- "fourteen fiveteen sixteen seventeen nineteen twenty";
+ "fourteen fiveteen sixteen seventeen nineteen twenty"sv;
// Special unicode characters to override directionality of the words
-static const std::string kRlm = "\u200f";
-static const std::string kRlo = "\u202e";
-static const std::string kPdf = "\u202c";
+static constexpr auto kRlm = "\u200f"sv;
+static constexpr auto kRlo = "\u202e"sv;
+static constexpr auto kPdf = "\u202c"sv;
// Placeholder marks
-static const std::string kPlaceholderOpen = "\u00bb";
-static const std::string kPlaceholderClose = "\u00ab";
+static constexpr auto kPlaceholderOpen = "\u00bb"sv;
+static constexpr auto kPlaceholderClose = "\u00ab"sv;
static const char kArgStart = '{';
static const char kArgEnd = '}';
class PseudoMethodNone : public PseudoMethodImpl {
public:
- std::string Text(const StringPiece& text) override { return text.to_string(); }
- std::string Placeholder(const StringPiece& text) override { return text.to_string(); }
+ std::string Text(StringPiece text) override {
+ return std::string(text);
+ }
+ std::string Placeholder(StringPiece text) override {
+ return std::string(text);
+ }
};
class PseudoMethodBidi : public PseudoMethodImpl {
public:
- std::string Text(const StringPiece& text) override;
- std::string Placeholder(const StringPiece& text) override;
+ std::string Text(StringPiece text) override;
+ std::string Placeholder(StringPiece text) override;
};
class PseudoMethodAccent : public PseudoMethodImpl {
@@ -57,8 +63,8 @@ class PseudoMethodAccent : public PseudoMethodImpl {
PseudoMethodAccent() : depth_(0), word_count_(0), length_(0) {}
std::string Start() override;
std::string End() override;
- std::string Text(const StringPiece& text) override;
- std::string Placeholder(const StringPiece& text) override;
+ std::string Text(StringPiece text) override;
+ std::string Placeholder(StringPiece text) override;
private:
size_t depth_;
@@ -84,7 +90,7 @@ void Pseudolocalizer::SetMethod(Method method) {
}
}
-std::string Pseudolocalizer::Text(const StringPiece& text) {
+std::string Pseudolocalizer::Text(StringPiece text) {
std::string out;
size_t depth = last_depth_;
size_t lastpos, pos;
@@ -116,7 +122,7 @@ std::string Pseudolocalizer::Text(const StringPiece& text) {
}
size_t size = nextpos - lastpos;
if (size) {
- std::string chunk = text.substr(lastpos, size).to_string();
+ std::string chunk(text.substr(lastpos, size));
if (pseudo) {
chunk = impl_->Text(chunk);
} else if (str[lastpos] == kArgStart && str[nextpos - 1] == kArgEnd) {
@@ -301,21 +307,23 @@ static bool IsPossibleNormalPlaceholderEnd(const char c) {
}
static std::string PseudoGenerateExpansion(const unsigned int length) {
- std::string result = kExpansionString;
- const char* s = result.data();
+ std::string result(kExpansionString);
if (result.size() < length) {
result += " ";
result += PseudoGenerateExpansion(length - result.size());
} else {
int ext = 0;
// Should contain only whole words, so looking for a space
- for (unsigned int i = length + 1; i < result.size(); ++i) {
- ++ext;
- if (s[i] == ' ') {
- break;
+ {
+ const char* const s = result.data();
+ for (unsigned int i = length + 1; i < result.size(); ++i) {
+ ++ext;
+ if (s[i] == ' ') {
+ break;
+ }
}
}
- result = result.substr(0, length + ext);
+ result.resize(length + ext);
}
return result;
}
@@ -349,7 +357,7 @@ std::string PseudoMethodAccent::End() {
*
* Note: This leaves placeholder syntax untouched.
*/
-std::string PseudoMethodAccent::Text(const StringPiece& source) {
+std::string PseudoMethodAccent::Text(StringPiece source) {
const char* s = source.data();
std::string result;
const size_t I = source.size();
@@ -435,12 +443,12 @@ std::string PseudoMethodAccent::Text(const StringPiece& source) {
return result;
}
-std::string PseudoMethodAccent::Placeholder(const StringPiece& source) {
+std::string PseudoMethodAccent::Placeholder(StringPiece source) {
// Surround a placeholder with brackets
- return kPlaceholderOpen + source.to_string() + kPlaceholderClose;
+ return (std::string(kPlaceholderOpen) += source) += kPlaceholderClose;
}
-std::string PseudoMethodBidi::Text(const StringPiece& source) {
+std::string PseudoMethodBidi::Text(StringPiece source) {
const char* s = source.data();
std::string result;
bool lastspace = true;
@@ -456,10 +464,10 @@ std::string PseudoMethodBidi::Text(const StringPiece& source) {
space = (!escape && isspace(c)) || (escape && (c == 'n' || c == 't'));
if (lastspace && !space) {
// Word start
- result += kRlm + kRlo;
+ (result += kRlm) += kRlo;
} else if (!lastspace && space) {
// Word end
- result += kPdf + kRlm;
+ (result += kPdf) += kRlm;
}
lastspace = space;
if (escape) {
@@ -470,14 +478,14 @@ std::string PseudoMethodBidi::Text(const StringPiece& source) {
}
if (!lastspace) {
// End of last word
- result += kPdf + kRlm;
+ (result += kPdf) += kRlm;
}
return result;
}
-std::string PseudoMethodBidi::Placeholder(const StringPiece& source) {
+std::string PseudoMethodBidi::Placeholder(StringPiece source) {
// Surround a placeholder with directionality change sequence
- return kRlm + kRlo + source.to_string() + kPdf + kRlm;
+ return (((std::string(kRlm) += kRlo) += source) += kPdf) += kRlm;
}
} // namespace aapt
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
index 6cf003b24157..2b94bcc87fc9 100644
--- a/tools/aapt2/compile/Pseudolocalizer.h
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -19,11 +19,10 @@
#include <memory>
+#include "ResourceValues.h"
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
-
-#include "ResourceValues.h"
-#include "StringPool.h"
+#include "androidfw/StringPool.h"
namespace aapt {
@@ -32,8 +31,8 @@ class PseudoMethodImpl {
virtual ~PseudoMethodImpl() {}
virtual std::string Start() { return {}; }
virtual std::string End() { return {}; }
- virtual std::string Text(const android::StringPiece& text) = 0;
- virtual std::string Placeholder(const android::StringPiece& text) = 0;
+ virtual std::string Text(android::StringPiece text) = 0;
+ virtual std::string Placeholder(android::StringPiece text) = 0;
};
class Pseudolocalizer {
@@ -48,7 +47,7 @@ class Pseudolocalizer {
void SetMethod(Method method);
std::string Start() { return impl_->Start(); }
std::string End() { return impl_->End(); }
- std::string Text(const android::StringPiece& text);
+ std::string Text(android::StringPiece text);
private:
std::unique_ptr<PseudoMethodImpl> impl_;
diff --git a/tools/aapt2/compile/XmlIdCollector.cpp b/tools/aapt2/compile/XmlIdCollector.cpp
index bb72159f9e77..68cb36a078dd 100644
--- a/tools/aapt2/compile/XmlIdCollector.cpp
+++ b/tools/aapt2/compile/XmlIdCollector.cpp
@@ -38,8 +38,9 @@ struct IdCollector : public xml::Visitor {
using xml::Visitor::Visit;
explicit IdCollector(std::vector<SourcedResourceName>* out_symbols,
- SourcePathDiagnostics* source_diag) : out_symbols_(out_symbols),
- source_diag_(source_diag) {}
+ android::SourcePathDiagnostics* source_diag)
+ : out_symbols_(out_symbols), source_diag_(source_diag) {
+ }
void Visit(xml::Element* element) override {
for (xml::Attribute& attr : element->attributes) {
@@ -48,8 +49,8 @@ struct IdCollector : public xml::Visitor {
if (ResourceUtils::ParseReference(attr.value, &name, &create, nullptr)) {
if (create && name.type.type == ResourceType::kId) {
if (!text::IsValidResourceEntryName(name.entry)) {
- source_diag_->Error(DiagMessage(element->line_number)
- << "id '" << name << "' has an invalid entry name");
+ source_diag_->Error(android::DiagMessage(element->line_number)
+ << "id '" << name << "' has an invalid entry name");
} else {
auto iter = std::lower_bound(out_symbols_->begin(),
out_symbols_->end(), name, cmp_name);
@@ -67,7 +68,7 @@ struct IdCollector : public xml::Visitor {
private:
std::vector<SourcedResourceName>* out_symbols_;
- SourcePathDiagnostics* source_diag_;
+ android::SourcePathDiagnostics* source_diag_;
};
} // namespace
@@ -75,7 +76,7 @@ struct IdCollector : public xml::Visitor {
bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) {
TRACE_CALL();
xmlRes->file.exported_symbols.clear();
- SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
+ android::SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
IdCollector collector(&xmlRes->file.exported_symbols, &source_diag);
xmlRes->root->Accept(&collector);
return !source_diag.HadError();
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index e7a45851e239..1b0325325778 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -23,12 +23,11 @@
#include <string>
#include <utility>
+#include "ResourceUtils.h"
#include "android-base/file.h"
#include "android-base/logging.h"
#include "androidfw/ConfigDescription.h"
-
-#include "Diagnostics.h"
-#include "ResourceUtils.h"
+#include "androidfw/IDiagnostics.h"
#include "configuration/ConfigurationParser.internal.h"
#include "io/File.h"
#include "io/FileSystem.h"
@@ -88,15 +87,10 @@ const std::array<StringPiece, 8> kAbiToStringMap = {
constexpr const char* kAaptXmlNs = "http://schemas.android.com/tools/aapt";
-/** A default noop diagnostics context. */
-class NoopDiagnostics : public IDiagnostics {
- public:
- void Log(Level level, DiagMessageActual& actualMsg) override {}
-};
-NoopDiagnostics noop_;
+android::NoOpDiagnostics noop_;
/** Returns the value of the label attribute for a given element. */
-std::string GetLabel(const Element* element, IDiagnostics* diag) {
+std::string GetLabel(const Element* element, android::IDiagnostics* diag) {
std::string label;
for (const auto& attr : element->attributes) {
if (attr.name == "label") {
@@ -106,18 +100,18 @@ std::string GetLabel(const Element* element, IDiagnostics* diag) {
}
if (label.empty()) {
- diag->Error(DiagMessage() << "No label found for element " << element->name);
+ diag->Error(android::DiagMessage() << "No label found for element " << element->name);
}
return label;
}
/** Returns the value of the version-code-order attribute for a given element. */
-std::optional<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
+std::optional<int32_t> GetVersionCodeOrder(const Element* element, android::IDiagnostics* diag) {
const xml::Attribute* version = element->FindAttribute("", "version-code-order");
if (version == nullptr) {
std::string label = GetLabel(element, diag);
- diag->Error(DiagMessage() << "No version-code-order found for element '" << element->name
- << "' with label '" << label << "'");
+ diag->Error(android::DiagMessage() << "No version-code-order found for element '"
+ << element->name << "' with label '" << label << "'");
return {};
}
return std::stoi(version->value);
@@ -158,15 +152,15 @@ bool CopyXmlReferences(const std::optional<std::string>& name, const Group<T>& g
* success, or false if the either the placeholder is not found in the name, or the value is not
* present and the placeholder was.
*/
-bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<StringPiece>& value,
- std::string* name, IDiagnostics* diag) {
+bool ReplacePlaceholder(StringPiece placeholder, const std::optional<StringPiece>& value,
+ std::string* name, android::IDiagnostics* diag) {
size_t offset = name->find(placeholder.data());
bool found = (offset != std::string::npos);
// Make sure the placeholder was present if the desired value is present.
if (!found) {
if (value) {
- diag->Error(DiagMessage() << "Missing placeholder for artifact: " << placeholder);
+ diag->Error(android::DiagMessage() << "Missing placeholder for artifact: " << placeholder);
return false;
}
return true;
@@ -176,7 +170,8 @@ bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<Stri
// Make sure the placeholder was not present if the desired value was not present.
if (!value) {
- diag->Error(DiagMessage() << "Placeholder present but no value for artifact: " << placeholder);
+ diag->Error(android::DiagMessage()
+ << "Placeholder present but no value for artifact: " << placeholder);
return false;
}
@@ -184,7 +179,7 @@ bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<Stri
// Make sure there was only one instance of the placeholder.
if (name->find(placeholder.data()) != std::string::npos) {
- diag->Error(DiagMessage() << "Placeholder present multiple times: " << placeholder);
+ diag->Error(android::DiagMessage() << "Placeholder present multiple times: " << placeholder);
return false;
}
return true;
@@ -195,12 +190,12 @@ bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<Stri
* element was successfully processed, otherwise returns false.
*/
using ActionHandler = std::function<bool(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag)>;
+ xml::Element* element, android::IDiagnostics* diag)>;
/** Binds an ActionHandler to the current configuration being populated. */
xml::XmlNodeAction::ActionFuncWithDiag Bind(configuration::PostProcessingConfiguration* config,
const ActionHandler& handler) {
- return [config, handler](xml::Element* root_element, SourcePathDiagnostics* diag) {
+ return [config, handler](xml::Element* root_element, android::SourcePathDiagnostics* diag) {
return handler(config, root_element, diag);
};
}
@@ -209,10 +204,10 @@ xml::XmlNodeAction::ActionFuncWithDiag Bind(configuration::PostProcessingConfigu
std::optional<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact,
const std::string& apk_name,
const PostProcessingConfiguration& config,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
if (!artifact.name && !config.artifact_format) {
- diag->Error(
- DiagMessage() << "Artifact does not have a name and no global name template defined");
+ diag->Error(android::DiagMessage()
+ << "Artifact does not have a name and no global name template defined");
return {};
}
@@ -221,54 +216,54 @@ std::optional<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifac
: artifact.ToArtifactName(config.artifact_format.value(), apk_name, diag);
if (!artifact_name) {
- diag->Error(DiagMessage() << "Could not determine split APK artifact name");
+ diag->Error(android::DiagMessage() << "Could not determine split APK artifact name");
return {};
}
OutputArtifact output_artifact;
output_artifact.name = artifact_name.value();
- SourcePathDiagnostics src_diag{{output_artifact.name}, diag};
+ android::SourcePathDiagnostics src_diag{{output_artifact.name}, diag};
bool has_errors = false;
if (!CopyXmlReferences(artifact.abi_group, config.abi_groups, &output_artifact.abis)) {
- src_diag.Error(DiagMessage() << "Could not lookup required ABIs: "
- << artifact.abi_group.value());
+ src_diag.Error(android::DiagMessage()
+ << "Could not lookup required ABIs: " << artifact.abi_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.locale_group, config.locale_groups, &output_artifact.locales)) {
- src_diag.Error(DiagMessage() << "Could not lookup required locales: "
- << artifact.locale_group.value());
+ src_diag.Error(android::DiagMessage()
+ << "Could not lookup required locales: " << artifact.locale_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.screen_density_group, config.screen_density_groups,
&output_artifact.screen_densities)) {
- src_diag.Error(DiagMessage() << "Could not lookup required screen densities: "
- << artifact.screen_density_group.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required screen densities: "
+ << artifact.screen_density_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.device_feature_group, config.device_feature_groups,
&output_artifact.features)) {
- src_diag.Error(DiagMessage() << "Could not lookup required device features: "
- << artifact.device_feature_group.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required device features: "
+ << artifact.device_feature_group.value());
has_errors = true;
}
if (!CopyXmlReferences(artifact.gl_texture_group, config.gl_texture_groups,
&output_artifact.textures)) {
- src_diag.Error(DiagMessage() << "Could not lookup required OpenGL texture formats: "
- << artifact.gl_texture_group.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required OpenGL texture formats: "
+ << artifact.gl_texture_group.value());
has_errors = true;
}
if (artifact.android_sdk) {
auto entry = config.android_sdks.find(artifact.android_sdk.value());
if (entry == config.android_sdks.end()) {
- src_diag.Error(DiagMessage() << "Could not lookup required Android SDK version: "
- << artifact.android_sdk.value());
+ src_diag.Error(android::DiagMessage() << "Could not lookup required Android SDK version: "
+ << artifact.android_sdk.value());
has_errors = true;
} else {
output_artifact.android_sdk = {entry->second};
@@ -288,9 +283,9 @@ namespace configuration {
/** Returns the binary reprasentation of the XML configuration. */
std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
const std::string& config_path,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
StringInputStream in(contents);
- std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, Source(config_path));
+ std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, android::Source(config_path));
if (!doc) {
return {};
}
@@ -298,14 +293,14 @@ std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::strin
// Strip any namespaces from the XML as the XmlActionExecutor ignores anything with a namespace.
Element* root = doc->root.get();
if (root == nullptr) {
- diag->Error(DiagMessage() << "Could not find the root element in the XML document");
+ diag->Error(android::DiagMessage() << "Could not find the root element in the XML document");
return {};
}
std::string& xml_ns = root->namespace_uri;
if (!xml_ns.empty()) {
if (xml_ns != kAaptXmlNs) {
- diag->Error(DiagMessage() << "Unknown namespace found on root element: " << xml_ns);
+ diag->Error(android::DiagMessage() << "Unknown namespace found on root element: " << xml_ns);
return {};
}
@@ -336,24 +331,24 @@ std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::strin
Bind(&config, DeviceFeatureGroupTagHandler));
if (!executor.Execute(XmlActionExecutorPolicy::kNone, diag, doc.get())) {
- diag->Error(DiagMessage() << "Could not process XML document");
+ diag->Error(android::DiagMessage() << "Could not process XML document");
return {};
}
return {config};
}
-const StringPiece& AbiToString(Abi abi) {
+StringPiece AbiToString(Abi abi) {
return kAbiToStringMap.at(static_cast<size_t>(abi));
}
/**
* Returns the common artifact base name from a template string.
*/
-std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk_name,
- IDiagnostics* diag) {
+std::optional<std::string> ToBaseName(std::string result, StringPiece apk_name,
+ android::IDiagnostics* diag) {
const StringPiece ext = file::GetExtension(apk_name);
- size_t end_index = apk_name.to_string().rfind(ext.to_string());
+ size_t end_index = apk_name.rfind(ext);
const std::string base_name =
(end_index != std::string::npos) ? std::string{apk_name.begin(), end_index} : "";
@@ -376,17 +371,17 @@ std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk
// If no extension is specified, and the name template does not end in the current extension,
// add the existing extension.
if (!util::EndsWith(result, ext)) {
- result.append(ext.to_string());
+ result.append(ext);
}
}
return result;
}
-std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format,
- const StringPiece& apk_name,
- IDiagnostics* diag) const {
- std::optional<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
+std::optional<std::string> ConfiguredArtifact::ToArtifactName(StringPiece format,
+ StringPiece apk_name,
+ android::IDiagnostics* diag) const {
+ std::optional<std::string> base = ToBaseName(std::string(format), apk_name, diag);
if (!base) {
return {};
}
@@ -419,8 +414,8 @@ std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece&
return result;
}
-std::optional<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name,
- IDiagnostics* diag) const {
+std::optional<std::string> ConfiguredArtifact::Name(StringPiece apk_name,
+ android::IDiagnostics* diag) const {
if (!name) {
return {};
}
@@ -444,7 +439,7 @@ ConfigurationParser::ConfigurationParser(std::string contents, const std::string
}
std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse(
- const android::StringPiece& apk_path) {
+ android::StringPiece apk_path) {
std::optional<PostProcessingConfiguration> maybe_config =
ExtractConfiguration(contents_, config_path_, diag_);
if (!maybe_config) {
@@ -452,7 +447,7 @@ std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse(
}
// Convert from a parsed configuration to a list of artifacts for processing.
- const std::string& apk_name = file::GetFilename(apk_path).to_string();
+ const std::string apk_name(file::GetFilename(apk_path));
std::vector<OutputArtifact> output_artifacts;
PostProcessingConfiguration& config = maybe_config.value();
@@ -473,7 +468,7 @@ std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse(
}
if (!config.ValidateVersionCodeOrdering(diag_)) {
- diag_->Error(DiagMessage() << "could not validate post processing configuration");
+ diag_->Error(android::DiagMessage() << "could not validate post processing configuration");
valid = false;
}
@@ -493,7 +488,7 @@ namespace configuration {
namespace handler {
bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
ConfiguredArtifact artifact{};
for (const auto& attr : root_element->attributes) {
if (attr.name == "name") {
@@ -511,8 +506,8 @@ bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_eleme
} else if (attr.name == "device-feature-group") {
artifact.device_feature_group = {attr.value};
} else {
- diag->Note(DiagMessage() << "Unknown artifact attribute: " << attr.name << " = "
- << attr.value);
+ diag->Note(android::DiagMessage()
+ << "Unknown artifact attribute: " << attr.name << " = " << attr.value);
}
}
config->artifacts.push_back(artifact);
@@ -520,11 +515,11 @@ bool ArtifactTagHandler(PostProcessingConfiguration* config, Element* root_eleme
};
bool ArtifactFormatTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* /* diag */) {
+ android::IDiagnostics* /* diag */) {
for (auto& node : root_element->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
- config->artifact_format = TrimWhitespace(t->text).to_string();
+ config->artifact_format.emplace(TrimWhitespace(t->text));
break;
}
}
@@ -532,7 +527,7 @@ bool ArtifactFormatTagHandler(PostProcessingConfiguration* config, Element* root
};
bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -560,17 +555,17 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
for (auto* child : root_element->GetChildElements()) {
if (child->name != "abi") {
- diag->Error(DiagMessage() << "Unexpected element in ABI group: " << child->name);
+ diag->Error(android::DiagMessage() << "Unexpected element in ABI group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
- auto abi = kStringToAbiMap.find(TrimWhitespace(t->text).to_string());
+ auto abi = kStringToAbiMap.find(TrimWhitespace(t->text));
if (abi != kStringToAbiMap.end()) {
group.push_back(abi->second);
} else {
- diag->Error(DiagMessage() << "Could not parse ABI value: " << t->text);
+ diag->Error(android::DiagMessage() << "Could not parse ABI value: " << t->text);
valid = false;
}
break;
@@ -583,7 +578,7 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
};
bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -609,9 +604,8 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
// Copy the density with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
- << "Could not parse config descriptor for empty screen-density-group: "
- << label);
+ diag->Error(android::DiagMessage()
+ << "Could not parse config descriptor for empty screen-density-group: " << label);
valid = false;
}
@@ -620,15 +614,15 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
for (auto* child : root_element->GetChildElements()) {
if (child->name != "screen-density") {
- diag->Error(DiagMessage() << "Unexpected root_element in screen density group: "
- << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected root_element in screen density group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
ConfigDescription config_descriptor;
- const android::StringPiece& text = TrimWhitespace(t->text);
+ android::StringPiece text = TrimWhitespace(t->text);
bool parsed = ConfigDescription::Parse(text, &config_descriptor);
if (parsed &&
(config_descriptor.CopyWithoutSdkVersion().diff(ConfigDescription::DefaultConfig()) ==
@@ -636,7 +630,7 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
// Copy the density with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
+ diag->Error(android::DiagMessage()
<< "Could not parse config descriptor for screen-density: " << text);
valid = false;
}
@@ -650,7 +644,7 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
};
bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -676,9 +670,8 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
// Copy the locale with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
- << "Could not parse config descriptor for empty screen-density-group: "
- << label);
+ diag->Error(android::DiagMessage()
+ << "Could not parse config descriptor for empty screen-density-group: " << label);
valid = false;
}
@@ -687,15 +680,15 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
for (auto* child : root_element->GetChildElements()) {
if (child->name != "locale") {
- diag->Error(DiagMessage() << "Unexpected root_element in screen density group: "
- << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected root_element in screen density group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
ConfigDescription config_descriptor;
- const android::StringPiece& text = TrimWhitespace(t->text);
+ android::StringPiece text = TrimWhitespace(t->text);
bool parsed = ConfigDescription::Parse(text, &config_descriptor);
if (parsed &&
(config_descriptor.CopyWithoutSdkVersion().diff(ConfigDescription::DefaultConfig()) ==
@@ -703,7 +696,7 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
// Copy the locale with the minimum SDK version stripped out.
group.push_back(config_descriptor.CopyWithoutSdkVersion());
} else {
- diag->Error(DiagMessage()
+ diag->Error(android::DiagMessage()
<< "Could not parse config descriptor for screen-density: " << text);
valid = false;
}
@@ -717,7 +710,7 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
};
bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
AndroidSdk entry = AndroidSdk::ForMinSdk(-1);
bool valid = true;
for (const auto& attr : root_element->attributes) {
@@ -746,13 +739,14 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele
}
if (!valid_attr) {
- diag->Error(DiagMessage() << "Invalid attribute: " << attr.name << " = " << attr.value);
+ diag->Error(android::DiagMessage()
+ << "Invalid attribute: " << attr.name << " = " << attr.value);
valid = false;
}
}
if (entry.min_sdk_version == -1) {
- diag->Error(DiagMessage() << "android-sdk is missing minSdkVersion attribute");
+ diag->Error(android::DiagMessage() << "android-sdk is missing minSdkVersion attribute");
valid = false;
}
@@ -760,7 +754,7 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele
for (auto node : root_element->GetChildElements()) {
if (node->name == "manifest") {
if (entry.manifest) {
- diag->Warn(DiagMessage() << "Found multiple manifest tags. Ignoring duplicates.");
+ diag->Warn(android::DiagMessage() << "Found multiple manifest tags. Ignoring duplicates.");
continue;
}
entry.manifest = {AndroidManifest()};
@@ -772,7 +766,7 @@ bool AndroidSdkTagHandler(PostProcessingConfiguration* config, Element* root_ele
};
bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -791,7 +785,8 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
GlTexture result;
for (auto* child : root_element->GetChildElements()) {
if (child->name != "gl-texture") {
- diag->Error(DiagMessage() << "Unexpected element in GL texture group: " << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected element in GL texture group: " << child->name);
valid = false;
} else {
for (const auto& attr : child->attributes) {
@@ -803,14 +798,15 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
for (auto* element : child->GetChildElements()) {
if (element->name != "texture-path") {
- diag->Error(DiagMessage() << "Unexpected element in gl-texture element: " << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected element in gl-texture element: " << child->name);
valid = false;
continue;
}
for (auto& node : element->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
- result.texture_paths.push_back(TrimWhitespace(t->text).to_string());
+ result.texture_paths.emplace_back(TrimWhitespace(t->text));
}
}
}
@@ -822,7 +818,7 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
};
bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element* root_element,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
std::string label = GetLabel(root_element, diag);
if (label.empty()) {
return false;
@@ -840,14 +836,14 @@ bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element*
for (auto* child : root_element->GetChildElements()) {
if (child->name != "supports-feature") {
- diag->Error(DiagMessage() << "Unexpected root_element in device feature group: "
- << child->name);
+ diag->Error(android::DiagMessage()
+ << "Unexpected root_element in device feature group: " << child->name);
valid = false;
} else {
for (auto& node : child->children) {
xml::Text* t;
if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
- group.push_back(TrimWhitespace(t->text).to_string());
+ group.emplace_back(TrimWhitespace(t->text));
break;
}
}
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 195b4baac319..d66f4ab000a3 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -24,8 +24,7 @@
#include <vector>
#include "androidfw/ConfigDescription.h"
-
-#include "Diagnostics.h"
+#include "androidfw/IDiagnostics.h"
namespace aapt {
@@ -44,7 +43,7 @@ enum class Abi {
};
/** Helper method to convert an ABI to a string representing the path within the APK. */
-const android::StringPiece& AbiToString(Abi abi);
+android::StringPiece AbiToString(Abi abi);
/**
* Represents an individual locale. When a locale is included, it must be
@@ -126,9 +125,6 @@ struct OutputArtifact {
} // namespace configuration
-// Forward declaration of classes used in the API.
-struct IDiagnostics;
-
/**
* XML configuration file parser for the split and optimize commands.
*/
@@ -145,7 +141,7 @@ class ConfigurationParser {
}
/** Sets the diagnostics context to use when parsing. */
- ConfigurationParser& WithDiagnostics(IDiagnostics* diagnostics) {
+ ConfigurationParser& WithDiagnostics(android::IDiagnostics* diagnostics) {
diag_ = diagnostics;
return *this;
}
@@ -154,8 +150,7 @@ class ConfigurationParser {
* Parses the configuration file and returns the results. If the configuration could not be parsed
* the result is empty and any errors will be displayed with the provided diagnostics context.
*/
- std::optional<std::vector<configuration::OutputArtifact>> Parse(
- const android::StringPiece& apk_path);
+ std::optional<std::vector<configuration::OutputArtifact>> Parse(android::StringPiece apk_path);
protected:
/**
@@ -166,7 +161,7 @@ class ConfigurationParser {
ConfigurationParser(std::string contents, const std::string& config_path);
/** Returns the current diagnostics context to any subclasses. */
- IDiagnostics* diagnostics() {
+ android::IDiagnostics* diagnostics() {
return diag_;
}
@@ -176,7 +171,7 @@ class ConfigurationParser {
/** Path to the input configuration. */
const std::string config_path_;
/** The diagnostics context to send messages to. */
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
};
} // namespace aapt
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index 42ef51591d4f..198f730f1e12 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -47,15 +47,16 @@ using Entry = std::unordered_map<std::string, T>;
template <class T>
using Group = Entry<OrderedEntry<T>>;
-template<typename T>
-bool IsGroupValid(const Group<T>& group, const std::string& name, IDiagnostics* diag) {
+template <typename T>
+bool IsGroupValid(const Group<T>& group, const std::string& name, android::IDiagnostics* diag) {
std::set<int32_t> orders;
for (const auto& p : group) {
orders.insert(p.second.order);
}
bool valid = orders.size() == group.size();
if (!valid) {
- diag->Error(DiagMessage() << name << " have overlapping version-code-order attributes");
+ diag->Error(android::DiagMessage()
+ << name << " have overlapping version-code-order attributes");
}
return valid;
}
@@ -137,12 +138,12 @@ struct ConfiguredArtifact {
std::optional<std::string> gl_texture_group;
/** Convert an artifact name template into a name string based on configuration contents. */
- std::optional<std::string> ToArtifactName(const android::StringPiece& format,
- const android::StringPiece& apk_name,
- IDiagnostics* diag) const;
+ std::optional<std::string> ToArtifactName(android::StringPiece format,
+ android::StringPiece apk_name,
+ android::IDiagnostics* diag) const;
/** Convert an artifact name template into a name string based on configuration contents. */
- std::optional<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
+ std::optional<std::string> Name(android::StringPiece apk_name, android::IDiagnostics* diag) const;
};
/** AAPT2 XML configuration file binary representation. */
@@ -157,7 +158,7 @@ struct PostProcessingConfiguration {
Group<GlTexture> gl_texture_groups;
Entry<AndroidSdk> android_sdks;
- bool ValidateVersionCodeOrdering(IDiagnostics* diag) {
+ bool ValidateVersionCodeOrdering(android::IDiagnostics* diag) {
bool valid = IsGroupValid(abi_groups, "abi-groups", diag);
valid &= IsGroupValid(screen_density_groups, "screen-density-groups", diag);
valid &= IsGroupValid(locale_groups, "locale-groups", diag);
@@ -215,41 +216,41 @@ struct PostProcessingConfiguration {
/** Parses the provided XML document returning the post processing configuration. */
std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
const std::string& config_path,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
namespace handler {
/** Handler for <artifact> tags. */
bool ArtifactTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
/** Handler for <artifact-format> tags. */
bool ArtifactFormatTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <abi-group> tags. */
bool AbiGroupTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
/** Handler for <screen-density-group> tags. */
bool ScreenDensityGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <locale-group> tags. */
bool LocaleGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <android-sdk> tags. */
bool AndroidSdkTagHandler(configuration::PostProcessingConfiguration* config, xml::Element* element,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
/** Handler for <gl-texture-group> tags. */
bool GlTextureGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
/** Handler for <device-feature-group> tags. */
bool DeviceFeatureGroupTagHandler(configuration::PostProcessingConfiguration* config,
- xml::Element* element, IDiagnostics* diag);
+ xml::Element* element, android::IDiagnostics* diag);
} // namespace handler
} // namespace configuration
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 9828b97982ed..a43bf1b60f42 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -16,18 +16,24 @@
#include "DumpManifest.h"
+#include <androidfw/ApkParsing.h>
+
#include <algorithm>
+#include <array>
+#include <memory>
+#include <set>
+#include <string_view>
+#include <vector>
#include "LoadedApk.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "androidfw/ConfigDescription.h"
#include "io/File.h"
#include "io/FileStream.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
-#include "androidfw/ConfigDescription.h"
-
using ::android::base::StringPrintf;
using ::android::ConfigDescription;
@@ -112,7 +118,101 @@ static xml::Attribute* FindAttribute(xml::Element *el, const std::string &packag
return el->FindAttribute(package, name);
}
+class Architectures {
+ public:
+ std::set<std::string> architectures;
+ std::set<std::string> alt_architectures;
+
+ void Print(text::Printer* printer) {
+ if (!architectures.empty()) {
+ printer->Print("native-code:");
+ for (auto& arch : architectures) {
+ printer->Print(StringPrintf(" '%s'", arch.data()));
+ }
+ printer->Print("\n");
+ }
+ if (!alt_architectures.empty()) {
+ printer->Print("alt-native-code:");
+ for (auto& arch : alt_architectures) {
+ printer->Print(StringPrintf(" '%s'", arch.data()));
+ }
+ printer->Print("\n");
+ }
+ }
+
+ void ToProto(pb::Badging* out_badging) {
+ auto out_architectures = out_badging->mutable_architectures();
+ for (auto& arch : architectures) {
+ out_architectures->add_architectures(arch);
+ }
+ for (auto& arch : alt_architectures) {
+ out_architectures->add_alt_architectures(arch);
+ }
+ }
+};
+
+const static std::array<std::string_view, 14> printable_components{"app-widget",
+ "device-admin",
+ "ime",
+ "wallpaper",
+ "accessibility",
+ "print-service",
+ "payment",
+ "search",
+ "document-provider",
+ "launcher",
+ "notification-listener",
+ "dream",
+ "camera",
+ "camera-secure"};
+
+class Components {
+ public:
+ std::set<std::string, std::less<>> discovered_components;
+ bool other_activities = false;
+ bool other_receivers = false;
+ bool other_services = false;
+
+ void Print(text::Printer* printer) {
+ for (auto& component : printable_components) {
+ if (discovered_components.find(component) != discovered_components.end()) {
+ printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
+ }
+ }
+ // Print presence of main activity
+ if (discovered_components.find("main") != discovered_components.end()) {
+ printer->Print("main\n");
+ }
+
+ if (other_activities) {
+ printer->Print("other-activities\n");
+ }
+ if (other_receivers) {
+ printer->Print("other-receivers\n");
+ }
+ if (other_services) {
+ printer->Print("other-services\n");
+ }
+ }
+
+ void ToProto(pb::Badging* out_badging) {
+ auto out_components = out_badging->mutable_components();
+ for (auto& component : printable_components) {
+ auto discovered = discovered_components.find(component);
+ if (discovered != discovered_components.end()) {
+ out_components->add_provided_components(*discovered);
+ }
+ }
+ out_components->set_main(discovered_components.find("main") != discovered_components.end());
+ out_components->set_other_activities(other_activities);
+ out_components->set_other_receivers(other_receivers);
+ out_components->set_other_services(other_services);
+ }
+};
+
class CommonFeatureGroup;
+class FeatureGroup;
+class SupportsScreen;
class ManifestExtractor {
public:
@@ -125,10 +225,16 @@ class ManifestExtractor {
Element() = default;
virtual ~Element() = default;
- static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
+ static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el,
+ const std::string& parent_tag);
/** Writes out the extracted contents of the element. */
- virtual void Print(text::Printer* printer) { }
+ virtual void Print(text::Printer* printer) {
+ }
+
+ /** Saves extracted information into Badging proto. */
+ virtual void ToProto(pb::Badging* out_badging) {
+ }
/** Adds an element to the list of children of the element. */
void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
@@ -146,10 +252,15 @@ class ManifestExtractor {
}
/** Retrieves the extracted xml element tag. */
- const std::string tag() const {
+ const std::string& tag() const {
return tag_;
}
+ /** Whether this element has special Extract/Print/ToProto logic. */
+ bool is_featured() const {
+ return featured_;
+ }
+
protected:
ManifestExtractor* extractor() const {
return extractor_;
@@ -291,6 +402,8 @@ class ManifestExtractor {
return &(*intValue->value);
} else if (RawString* rawValue = ValueCast<RawString>(value)) {
return &(*rawValue->value);
+ } else if (StyledString* styledStrValue = ValueCast<StyledString>(value)) {
+ return &(styledStrValue->value->value);
} else if (FileReference* strValue = ValueCast<FileReference>(value)) {
return &(*strValue->path);
}
@@ -321,6 +434,7 @@ class ManifestExtractor {
ManifestExtractor* extractor_;
std::vector<std::unique_ptr<Element>> children_;
std::string tag_;
+ bool featured_ = false;
};
friend Element;
@@ -338,12 +452,19 @@ class ManifestExtractor {
return config;
}
- bool Dump(text::Printer* printer, IDiagnostics* diag);
+ bool Extract(android::IDiagnostics* diag);
+ bool Dump(text::Printer* printer);
+ bool DumpProto(pb::Badging* out_badging);
/** Recursively visit the xml element tree and return a processed badging element tree. */
- std::unique_ptr<Element> Visit(xml::Element* element);
+ std::unique_ptr<Element> Visit(xml::Element* element, const std::string& parent_tag);
+
+ /** Resets target SDK to 0. */
+ void ResetTargetSdk() {
+ target_sdk_ = 0;
+ }
- /** Raises the target sdk value if the min target is greater than the current target. */
+ /** Raises the target sdk value if the min target is greater than the current target. */
void RaiseTargetSdk(int32_t min_target) {
if (min_target > target_sdk_) {
target_sdk_ = min_target;
@@ -354,7 +475,7 @@ class ManifestExtractor {
* Retrieves the default feature group that features are added into when <uses-feature>
* are not in a <feature-group> element.
**/
- CommonFeatureGroup* GetCommonFeatureGroup() {
+ CommonFeatureGroup* common_feature_group() {
return commonFeatureGroup_.get();
}
@@ -375,7 +496,7 @@ class ManifestExtractor {
}
/** Retrieves the current stack of parent during data extraction. */
- const std::vector<Element*> parent_stack() const {
+ const std::vector<Element*>& parent_stack() const {
return parent_stack_;
}
@@ -387,11 +508,19 @@ class ManifestExtractor {
DumpManifestOptions& options_;
private:
+ std::unique_ptr<xml::XmlResource> doc_;
std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
std::map<std::string, ConfigDescription> locales_;
std::map<uint16_t, ConfigDescription> densities_;
std::vector<Element*> parent_stack_;
int32_t target_sdk_ = 0;
+
+ std::unique_ptr<ManifestExtractor::Element> root_element_;
+ std::vector<std::unique_ptr<ManifestExtractor::Element>> implied_permissions_;
+ std::vector<FeatureGroup*> feature_groups_;
+ Components components_;
+ Architectures architectures_;
+ const SupportsScreen* supports_screen_;
};
template<typename T> T* ElementCast(ManifestExtractor::Element* element);
@@ -415,8 +544,9 @@ static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
if (f(root)) {
return root;
}
- for (auto& child : root->children()) {
- if (auto b2 = FindElement(child.get(), f)) {
+ const auto& children = root->children();
+ for (auto it = children.rbegin(); it != children.rend(); ++it) {
+ if (auto b2 = FindElement(it->get(), f)) {
return b2;
}
}
@@ -427,6 +557,7 @@ static ManifestExtractor::Element* FindElement(ManifestExtractor::Element* root,
class Manifest : public ManifestExtractor::Element {
public:
Manifest() = default;
+ bool only_package_name;
std::string package;
int32_t versionCode;
std::string versionName;
@@ -462,7 +593,54 @@ class Manifest : public ManifestExtractor::Element {
installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
}
+ void ToProto(pb::Badging* out_badging) override {
+ auto out_package = out_badging->mutable_package();
+ out_package->set_package(package);
+ out_package->set_version_code(versionCode);
+ out_package->set_version_name(versionName);
+ if (compilesdkVersion) {
+ out_package->set_compile_sdk_version(*compilesdkVersion);
+ }
+ if (compilesdkVersionCodename) {
+ out_package->set_compile_sdk_version_codename(*compilesdkVersionCodename);
+ }
+ if (platformVersionName) {
+ out_package->set_platform_version_name(*platformVersionName);
+ } else if (platformVersionNameInt) {
+ out_package->set_platform_version_name(std::to_string(*platformVersionNameInt));
+ }
+ if (platformVersionCode) {
+ out_package->set_platform_version_code(*platformVersionCode);
+ } else if (platformVersionCodeInt) {
+ out_package->set_platform_version_code(std::to_string(*platformVersionCodeInt));
+ }
+
+ if (installLocation) {
+ switch (*installLocation) {
+ case 0:
+ out_package->set_install_location(pb::PackageInfo_InstallLocation_AUTO);
+ break;
+ case 1:
+ out_package->set_install_location(pb::PackageInfo_InstallLocation_INTERNAL_ONLY);
+ break;
+ case 2:
+ out_package->set_install_location(pb::PackageInfo_InstallLocation_PREFER_EXTERNAL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
void Print(text::Printer* printer) override {
+ if (only_package_name) {
+ printer->Println(StringPrintf("package: %s", package.data()));
+ } else {
+ PrintFull(printer);
+ }
+ }
+
+ void PrintFull(text::Printer* printer) {
printer->Print(StringPrintf("package: name='%s' ", package.data()));
printer->Print(StringPrintf("versionCode='%s' ",
(versionCode > 0) ? std::to_string(versionCode).data() : ""));
@@ -598,6 +776,27 @@ class Application : public ManifestExtractor::Element {
printer->Print("application-debuggable\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto application = out_badging->mutable_application();
+ application->set_label(android::ResTable::normalizeForOutput(label.data()));
+ application->set_icon(icon);
+ application->set_banner(banner);
+ application->set_test_only(test_only != 0);
+ application->set_game(is_game != 0);
+ application->set_debuggable(debuggable != 0);
+
+ auto out_locale_labels = application->mutable_locale_labels();
+ for (auto& p : locale_labels) {
+ if (!p.first.empty()) {
+ (*out_locale_labels)[p.first] = p.second;
+ }
+ }
+ auto out_density_icons = application->mutable_density_icons();
+ for (auto& p : density_icons) {
+ (*out_density_icons)[p.first] = p.second;
+ }
+ }
};
/** Represents <uses-sdk> elements. **/
@@ -617,6 +816,10 @@ class UsesSdkBadging : public ManifestExtractor::Element {
target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
+ // Resets target SDK first. This is required if APK contains multiple <uses-sdk> elements,
+ // we only need to take the latest values.
+ extractor()->ResetTargetSdk();
+
// Detect the target sdk of the element
if ((min_sdk_name && *min_sdk_name == "Donut")
|| (target_sdk_name && *target_sdk_name == "Donut")) {
@@ -647,6 +850,23 @@ class UsesSdkBadging : public ManifestExtractor::Element {
printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto out_sdks = out_badging->mutable_uses_sdk();
+ if (min_sdk) {
+ out_sdks->set_min_sdk_version(*min_sdk);
+ } else if (min_sdk_name) {
+ out_sdks->set_min_sdk_version_name(*min_sdk_name);
+ }
+ if (max_sdk) {
+ out_sdks->set_max_sdk_version(*max_sdk);
+ }
+ if (target_sdk) {
+ out_sdks->set_target_sdk_version(*target_sdk);
+ } else if (target_sdk_name) {
+ out_sdks->set_target_sdk_version_name(*target_sdk_name);
+ }
+ }
};
/** Represents <uses-configuration> elements. **/
@@ -691,6 +911,15 @@ class UsesConfiguarion : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto out_configuration = out_badging->add_uses_configurations();
+ out_configuration->set_req_touch_screen(req_touch_screen);
+ out_configuration->set_req_keyboard_type(req_keyboard_type);
+ out_configuration->set_req_hard_keyboard(req_hard_keyboard);
+ out_configuration->set_req_navigation(req_navigation);
+ out_configuration->set_req_five_way_nav(req_five_way_nav);
+ }
};
/** Represents <supports-screen> elements. **/
@@ -733,54 +962,24 @@ class SupportsScreen : public ManifestExtractor::Element {
}
}
- void PrintScreens(text::Printer* printer, int32_t target_sdk) {
- int32_t small_screen_temp = small_screen;
- int32_t normal_screen_temp = normal_screen;
- int32_t large_screen_temp = large_screen;
- int32_t xlarge_screen_temp = xlarge_screen;
- int32_t any_density_temp = any_density;
-
- // Determine default values for any unspecified screen sizes,
- // based on the target SDK of the package. As of 4 (donut)
- // the screen size support was introduced, so all default to
- // enabled.
- if (small_screen_temp > 0) {
- small_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
- }
- if (normal_screen_temp > 0) {
- normal_screen_temp = -1;
- }
- if (large_screen_temp > 0) {
- large_screen_temp = target_sdk >= SDK_DONUT ? -1 : 0;
- }
- if (xlarge_screen_temp > 0) {
- // Introduced in Gingerbread.
- xlarge_screen_temp = target_sdk >= SDK_GINGERBREAD ? -1 : 0;
- }
- if (any_density_temp > 0) {
- any_density_temp = (target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
- compatible_width_limit_dp > 0)
- ? -1
- : 0;
- }
-
+ void PrintScreens(text::Printer* printer, int32_t target_sdk) const {
// Print the formatted screen info
printer->Print("supports-screens:");
- if (small_screen_temp != 0) {
+ if (IsSmallScreenSupported(target_sdk)) {
printer->Print(" 'small'");
}
- if (normal_screen_temp != 0) {
+ if (normal_screen != 0) {
printer->Print(" 'normal'");
}
- if (large_screen_temp != 0) {
+ if (IsLargeScreenSupported(target_sdk)) {
printer->Print(" 'large'");
}
- if (xlarge_screen_temp != 0) {
+ if (IsXLargeScreenSupported(target_sdk)) {
printer->Print(" 'xlarge'");
}
printer->Print("\n");
printer->Print(StringPrintf("supports-any-density: '%s'\n",
- (any_density_temp ) ? "true" : "false"));
+ (IsAnyDensitySupported(target_sdk)) ? "true" : "false"));
if (requires_smallest_width_dp > 0) {
printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
}
@@ -791,6 +990,60 @@ class SupportsScreen : public ManifestExtractor::Element {
printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
}
}
+
+ void ToProtoScreens(pb::Badging* out_badging, int32_t target_sdk) const {
+ auto supports_screen = out_badging->mutable_supports_screen();
+ if (IsSmallScreenSupported(target_sdk)) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_SMALL);
+ }
+ if (normal_screen != 0) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_NORMAL);
+ }
+ if (IsLargeScreenSupported(target_sdk)) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_LARGE);
+ }
+ if (IsXLargeScreenSupported(target_sdk)) {
+ supports_screen->add_screens(pb::SupportsScreen_ScreenType_XLARGE);
+ }
+ supports_screen->set_supports_any_densities(IsAnyDensitySupported(target_sdk));
+ supports_screen->set_requires_smallest_width_dp(requires_smallest_width_dp);
+ supports_screen->set_compatible_width_limit_dp(compatible_width_limit_dp);
+ supports_screen->set_largest_width_limit_dp(largest_width_limit_dp);
+ }
+
+ private:
+ // Determine default values for any unspecified screen sizes,
+ // based on the target SDK of the package. As of 4 (donut)
+ // the screen size support was introduced, so all default to
+ // enabled.
+ bool IsSmallScreenSupported(int32_t target_sdk) const {
+ if (small_screen > 0) {
+ return target_sdk >= SDK_DONUT;
+ }
+ return small_screen != 0;
+ }
+
+ bool IsLargeScreenSupported(int32_t target_sdk) const {
+ if (large_screen > 0) {
+ return target_sdk >= SDK_DONUT;
+ }
+ return large_screen != 0;
+ }
+
+ bool IsXLargeScreenSupported(int32_t target_sdk) const {
+ if (xlarge_screen > 0) {
+ return target_sdk >= SDK_GINGERBREAD;
+ }
+ return xlarge_screen != 0;
+ }
+
+ bool IsAnyDensitySupported(int32_t target_sdk) const {
+ if (any_density > 0) {
+ return target_sdk >= SDK_DONUT || requires_smallest_width_dp > 0 ||
+ compatible_width_limit_dp > 0;
+ }
+ return any_density != 0;
+ }
};
/** Represents <feature-group> elements. **/
@@ -821,9 +1074,21 @@ class FeatureGroup : public ManifestExtractor::Element {
}
}
+ virtual void GroupToProto(pb::Badging* out_badging) {
+ auto feature_group = out_badging->add_feature_groups();
+ feature_group->set_label(label);
+ feature_group->set_open_gles_version(open_gles_version);
+ for (auto& feature : features_) {
+ auto out_feature = feature_group->add_features();
+ out_feature->set_name(feature.first);
+ out_feature->set_required(feature.second.required);
+ out_feature->set_version(feature.second.version);
+ }
+ }
+
/** Adds a feature to the feature group. */
void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
- features_.insert(std::make_pair(name, Feature{ required, version }));
+ features_.insert_or_assign(name, Feature{required, version});
if (required) {
if (name == "android.hardware.camera.autofocus" ||
name == "android.hardware.camera.flash") {
@@ -910,6 +1175,23 @@ class CommonFeatureGroup : public FeatureGroup {
}
}
+ virtual void GroupToProto(pb::Badging* out_badging) override {
+ FeatureGroup::GroupToProto(out_badging);
+ auto feature_group =
+ out_badging->mutable_feature_groups(out_badging->feature_groups_size() - 1);
+ for (auto& feature : implied_features_) {
+ if (features_.find(feature.first) == features_.end()) {
+ auto out_feature = feature_group->add_features();
+ out_feature->set_name(feature.first);
+ auto implied_data = out_feature->mutable_implied_data();
+ implied_data->set_from_sdk_23_permission(feature.second.implied_from_sdk_k23);
+ for (auto& reason : feature.second.reasons) {
+ implied_data->add_reasons(reason);
+ }
+ }
+ }
+ }
+
/** Returns true if the feature group has the given feature. */
bool HasFeature(const std::string& name) override {
return FeatureGroup::HasFeature(name)
@@ -1050,7 +1332,7 @@ class UsesFeature : public ManifestExtractor::Element {
// common feature group
FeatureGroup* feature_group = ElementCast<FeatureGroup>(extractor()->parent_stack()[0]);
if (!feature_group) {
- feature_group = extractor()->GetCommonFeatureGroup();
+ feature_group = extractor()->common_feature_group();
} else {
// All features in side of <feature-group> elements are required.
required = true;
@@ -1068,12 +1350,14 @@ class UsesFeature : public ManifestExtractor::Element {
class UsesPermission : public ManifestExtractor::Element {
public:
UsesPermission() = default;
+ bool implied;
std::string name;
std::vector<std::string> requiredFeatures;
std::vector<std::string> requiredNotFeatures;
int32_t required = true;
int32_t maxSdkVersion = -1;
int32_t usesPermissionFlags = 0;
+ std::string impliedReason;
void Extract(xml::Element* element) override {
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
@@ -1094,7 +1378,7 @@ class UsesPermission : public ManifestExtractor::Element {
FindAttribute(element, USES_PERMISSION_FLAGS_ATTR), 0);
if (!name.empty()) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
common->addImpliedFeaturesForPermission(extractor()->target_sdk(), name, false);
}
}
@@ -1126,17 +1410,37 @@ class UsesPermission : public ManifestExtractor::Element {
printer->Print("\n");
}
}
+ if (implied) {
+ printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+ if (maxSdkVersion >= 0) {
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ }
+ if ((usesPermissionFlags & kNeverForLocation) != 0) {
+ printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
+ }
+ printer->Print(StringPrintf(" reason='%s'\n", impliedReason.data()));
+ }
}
- void PrintImplied(text::Printer* printer, const std::string& reason) {
- printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
- if (maxSdkVersion >= 0) {
- printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
- }
- if ((usesPermissionFlags & kNeverForLocation) != 0) {
- printer->Print(StringPrintf(" usesPermissionFlags='neverForLocation'"));
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto permission = out_badging->add_uses_permissions();
+ permission->set_name(name);
+ if (maxSdkVersion > 0) {
+ permission->set_max_sdk_version(maxSdkVersion);
+ }
+ if ((usesPermissionFlags & kNeverForLocation) != 0) {
+ permission->mutable_permission_flags()->set_never_for_location(true);
+ }
+ for (auto& requiredFeature : requiredFeatures) {
+ permission->add_required_features(requiredFeature);
+ }
+ for (auto& requiredNotFeature : requiredNotFeatures) {
+ permission->add_required_not_features(requiredNotFeature);
+ }
+ permission->set_required(required != 0);
+ permission->set_implied(implied);
}
- printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
}
};
@@ -1184,7 +1488,7 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element {
maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
if (name) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
common->addImpliedFeaturesForPermission(extractor()->target_sdk(), *name, true);
}
}
@@ -1198,6 +1502,17 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element {
printer->Print("\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ auto permission = out_badging->add_uses_permissions();
+ permission->set_sdk23_and_above(true);
+ permission->set_name(*name);
+ if (maxSdkVersion) {
+ permission->set_max_sdk_version(*maxSdkVersion);
+ }
+ }
+ }
};
/** Represents <permission> elements. These elements are only printing when dumping permissions. **/
@@ -1215,6 +1530,12 @@ class Permission : public ManifestExtractor::Element {
printer->Print(StringPrintf("permission: %s\n", name.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ out_badging->add_permissions()->set_name(name);
+ }
+ }
};
/** Represents <activity> elements. **/
@@ -1256,7 +1577,7 @@ class Activity : public ManifestExtractor::Element {
auto orientation = GetAttributeInteger(FindAttribute(element, SCREEN_ORIENTATION_ATTR));
if (orientation) {
- CommonFeatureGroup* common = extractor()->GetCommonFeatureGroup();
+ CommonFeatureGroup* common = extractor()->common_feature_group();
int orien = *orientation;
if (orien == 0 || orien == 6 || orien == 8) {
// Requests landscape, sensorLandscape, or reverseLandscape.
@@ -1295,6 +1616,22 @@ class Activity : public ManifestExtractor::Element {
icon.data(), banner.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (has_main_action && has_launcher_category) {
+ auto activity = out_badging->mutable_launchable_activity();
+ activity->set_name(name);
+ activity->set_label(android::ResTable::normalizeForOutput(label.data()));
+ activity->set_icon(icon);
+ }
+ if (has_leanback_launcher_category) {
+ auto activity = out_badging->mutable_leanback_launchable_activity();
+ activity->set_name(name);
+ activity->set_label(android::ResTable::normalizeForOutput(label.data()));
+ activity->set_icon(icon);
+ activity->set_banner(banner);
+ }
+ }
};
/** Represents <intent-filter> elements. */
@@ -1382,11 +1719,8 @@ class UsesLibrary : public ManifestExtractor::Element {
int required;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
}
void Print(text::Printer* printer) override {
@@ -1395,6 +1729,14 @@ class UsesLibrary : public ManifestExtractor::Element {
(required == 0) ? "-not-required" : "", name.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto uses_library = out_badging->add_uses_libraries();
+ uses_library->set_name(name);
+ uses_library->set_required(required != 0);
+ }
+ }
};
/** Represents <static-library> elements. **/
@@ -1406,12 +1748,9 @@ class StaticLibrary : public ManifestExtractor::Element {
int versionMajor;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
}
void Print(text::Printer* printer) override {
@@ -1419,6 +1758,13 @@ class StaticLibrary : public ManifestExtractor::Element {
"static-library: name='%s' version='%d' versionMajor='%d'\n",
name.data(), version, versionMajor));
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto static_library = out_badging->mutable_static_library();
+ static_library->set_name(name);
+ static_library->set_version(version);
+ static_library->set_version_major(versionMajor);
+ }
};
/** Represents <uses-static-library> elements. **/
@@ -1431,13 +1777,10 @@ class UsesStaticLibrary : public ManifestExtractor::Element {
std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- AddCertDigest(element);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
}
void AddCertDigest(xml::Element* element) {
@@ -1459,6 +1802,16 @@ class UsesStaticLibrary : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto uses_static_library = out_badging->add_uses_static_libraries();
+ uses_static_library->set_name(name);
+ uses_static_library->set_version(version);
+ uses_static_library->set_version_major(versionMajor);
+ for (auto& cert : certDigests) {
+ uses_static_library->add_certificates(cert);
+ }
+ }
};
/** Represents <sdk-library> elements. **/
@@ -1469,17 +1822,20 @@ class SdkLibrary : public ManifestExtractor::Element {
int versionMajor;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
}
void Print(text::Printer* printer) override {
printer->Print(
StringPrintf("sdk-library: name='%s' versionMajor='%d'\n", name.data(), versionMajor));
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto sdk_library = out_badging->mutable_sdk_library();
+ sdk_library->set_name(name);
+ sdk_library->set_version_major(versionMajor);
+ }
};
/** Represents <uses-sdk-library> elements. **/
@@ -1491,12 +1847,9 @@ class UsesSdkLibrary : public ManifestExtractor::Element {
std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- AddCertDigest(element);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
}
void AddCertDigest(xml::Element* element) {
@@ -1517,6 +1870,15 @@ class UsesSdkLibrary : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto uses_sdk_library = out_badging->add_uses_sdk_libraries();
+ uses_sdk_library->set_name(name);
+ uses_sdk_library->set_version_major(versionMajor);
+ for (auto& cert : certDigests) {
+ uses_sdk_library->add_certificates(cert);
+ }
+ }
};
/** Represents <uses-native-library> elements. **/
@@ -1527,11 +1889,8 @@ class UsesNativeLibrary : public ManifestExtractor::Element {
int required;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
- }
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
}
void Print(text::Printer* printer) override {
@@ -1540,6 +1899,14 @@ class UsesNativeLibrary : public ManifestExtractor::Element {
(required == 0) ? "-not-required" : "", name.data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto uses_native_library = out_badging->add_uses_native_libraries();
+ uses_native_library->set_name(name);
+ uses_native_library->set_required(required != 0);
+ }
+ }
};
/**
@@ -1565,21 +1932,39 @@ class MetaData : public ManifestExtractor::Element {
void Print(text::Printer* printer) override {
if (extractor()->options_.include_meta_data && !name.empty()) {
- printer->Print(StringPrintf("meta-data: name='%s' ", name.data()));
+ printer->Print(StringPrintf("meta-data: name='%s'", name.data()));
if (!value.empty()) {
- printer->Print(StringPrintf("value='%s' ", value.data()));
+ printer->Print(StringPrintf(" value='%s'", value.data()));
} else if (value_int) {
- printer->Print(StringPrintf("value='%d' ", *value_int));
+ printer->Print(StringPrintf(" value='%d'", *value_int));
} else {
if (!resource.empty()) {
- printer->Print(StringPrintf("resource='%s' ", resource.data()));
+ printer->Print(StringPrintf(" resource='%s'", resource.data()));
} else if (resource_int) {
- printer->Print(StringPrintf("resource='%d' ", *resource_int));
+ printer->Print(StringPrintf(" resource='%d'", *resource_int));
}
}
printer->Print("\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto metadata = out_badging->add_metadata();
+ metadata->set_name(name);
+ if (!value.empty()) {
+ metadata->set_value_string(value);
+ } else if (value_int) {
+ metadata->set_value_int(*value_int);
+ } else {
+ if (!resource.empty()) {
+ metadata->set_resource_string(resource);
+ } else if (resource_int) {
+ metadata->set_resource_int(*resource_int);
+ }
+ }
+ }
+ }
};
/**
@@ -1599,10 +1984,11 @@ class Action : public ManifestExtractor::Element {
if (ElementCast<Activity>(parent_stack[1])) {
// Detects the presence of a particular type of activity.
Activity* activity = ElementCast<Activity>(parent_stack[1]);
- auto map = std::map<std::string, std::string>({
- { "android.intent.action.MAIN" , "main" },
- { "android.intent.action.VIDEO_CAMERA" , "camera" },
- { "android.intent.action.STILL_IMAGE_CAMERA_SECURE" , "camera-secure" },
+ static const auto map = std::map<std::string, std::string>({
+ {"android.intent.action.MAIN", "main"},
+ {"android.media.action.VIDEO_CAMERA", "camera"},
+ {"android.media.action.STILL_IMAGE_CAMERA", "camera"},
+ {"android.media.action.STILL_IMAGE_CAMERA_SECURE", "camera-secure"},
});
auto entry = map.find(action);
@@ -1709,6 +2095,13 @@ class SupportsInput : public ManifestExtractor::Element {
printer->Print("\n");
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto supports_input = out_badging->mutable_supports_input();
+ for (auto& input : inputs) {
+ supports_input->add_inputs(input);
+ }
+ }
};
/** Represents <input-type> elements. **/
@@ -1727,6 +2120,33 @@ class InputType : public ManifestExtractor::Element {
}
};
+/** Represents <install-constraints> elements. **/
+class InstallConstraints : public ManifestExtractor::Element {
+ public:
+ InstallConstraints() = default;
+ std::vector<std::string> fingerprint_prefixes;
+
+ void Extract(xml::Element* element) override {
+ for (xml::Element* child : element->GetChildElements()) {
+ if (child->name == "fingerprint-prefix") {
+ xml::Attribute* attr = child->FindAttribute(kAndroidNamespace, "value");
+ if (attr) {
+ fingerprint_prefixes.push_back(attr->value);
+ }
+ }
+ }
+ }
+
+ void Print(text::Printer* printer) override {
+ if (!fingerprint_prefixes.empty()) {
+ printer->Print(StringPrintf("install-constraints:\n"));
+ for (const auto& prefix : fingerprint_prefixes) {
+ printer->Print(StringPrintf(" fingerprint-prefix='%s'\n", prefix.c_str()));
+ }
+ }
+ }
+};
+
/** Represents <original-package> elements. **/
class OriginalPackage : public ManifestExtractor::Element {
public:
@@ -1742,6 +2162,12 @@ class OriginalPackage : public ManifestExtractor::Element {
printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ out_badging->mutable_package()->set_original_package(*name);
+ }
+ }
};
@@ -1780,6 +2206,21 @@ class Overlay : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto overlay = out_badging->mutable_overlay();
+ if (target_package) {
+ overlay->set_target_package(*target_package);
+ }
+ overlay->set_priority(priority);
+ overlay->set_static_(is_static);
+ if (required_property_name) {
+ overlay->set_required_property_name(*required_property_name);
+ }
+ if (required_property_value) {
+ overlay->set_required_property_value(*required_property_value);
+ }
+ }
};
/** * Represents <package-verifier> elements. **/
@@ -1800,6 +2241,14 @@ class PackageVerifier : public ManifestExtractor::Element {
name->data(), public_key->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ auto package_verifier = out_badging->mutable_package_verifier();
+ if (name && public_key) {
+ package_verifier->set_name(*name);
+ package_verifier->set_public_key(*public_key);
+ }
+ }
};
/** Represents <uses-package> elements. **/
@@ -1813,14 +2262,11 @@ class UsesPackage : public ManifestExtractor::Element {
std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- auto parent_stack = extractor()->parent_stack();
- if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
- packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
- name = GetAttributeString(FindAttribute(element, NAME_ATTR));
- version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
- versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
- AddCertDigest(element);
- }
+ packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
}
void AddCertDigest(xml::Element* element) {
@@ -1848,6 +2294,21 @@ class UsesPackage : public ManifestExtractor::Element {
}
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ auto uses_package = out_badging->add_uses_packages();
+ uses_package->set_name(*name);
+ if (packageType) {
+ uses_package->set_package_type(*packageType);
+ uses_package->set_version(version);
+ uses_package->set_version_major(versionMajor);
+ for (auto& cert : certDigests) {
+ uses_package->add_certificates(cert);
+ }
+ }
+ }
+ }
};
/** Represents <additional-certificate> elements. **/
@@ -1880,6 +2341,14 @@ class Screen : public ManifestExtractor::Element {
size = GetAttributeInteger(FindAttribute(element, SCREEN_SIZE_ATTR));
density = GetAttributeInteger(FindAttribute(element, SCREEN_DENSITY_ATTR));
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (size && density) {
+ auto screen = out_badging->mutable_compatible_screens()->add_screens();
+ screen->set_density(*density);
+ screen->set_size(*size);
+ }
+ }
};
/**
@@ -1925,6 +2394,12 @@ class SupportsGlTexture : public ManifestExtractor::Element {
printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
}
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (name) {
+ out_badging->mutable_supports_gl_texture()->add_name(*name);
+ }
+ }
};
/** Represents <property> elements. **/
@@ -1960,6 +2435,24 @@ class Property : public ManifestExtractor::Element {
}
printer->Print("\n");
}
+
+ void ToProto(pb::Badging* out_badging) override {
+ if (!name.empty()) {
+ auto property = out_badging->add_properties();
+ property->set_name(name);
+ if (!value.empty()) {
+ property->set_value_string(value);
+ } else if (value_int) {
+ property->set_value_int(*value_int);
+ } else {
+ if (!resource.empty()) {
+ property->set_resource_string(resource);
+ } else if (resource_int) {
+ property->set_resource_int(*resource_int);
+ }
+ }
+ }
+ }
};
/** Recursively prints the extracted badging element. */
@@ -1970,44 +2463,46 @@ static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
}
}
-bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
+/** Recursively serializes extracted badging elements to proto. */
+static void ToProto(ManifestExtractor::Element* el, pb::Badging* out_badging) {
+ el->ToProto(out_badging);
+ for (auto& child : el->children()) {
+ ToProto(child.get(), out_badging);
+ }
+}
+
+bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
// Load the manifest
- std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
- if (doc == nullptr) {
- diag->Error(DiagMessage() << "failed to find AndroidManifest.xml");
+ doc_ = apk_->LoadXml("AndroidManifest.xml", diag);
+ if (doc_ == nullptr) {
+ diag->Error(android::DiagMessage() << "failed to find AndroidManifest.xml");
return false;
}
- xml::Element* element = doc->root.get();
+ xml::Element* element = doc_->root.get();
if (element->name != "manifest") {
- diag->Error(DiagMessage() << "manifest does not start with <manifest> tag");
+ diag->Error(android::DiagMessage() << "manifest does not start with <manifest> tag");
return false;
}
// Print only the <uses-permission>, <uses-permission-sdk23>, and <permission> elements if
// printing only permission elements is requested
if (options_.only_permissions) {
- std::unique_ptr<ManifestExtractor::Element> manifest_element =
- ManifestExtractor::Element::Inflate(this, element);
+ root_element_ = ManifestExtractor::Element::Inflate(this, element, "");
+
+ if (auto manifest = ElementCast<Manifest>(root_element_.get())) {
+ manifest->only_package_name = true;
- if (auto manifest = ElementCast<Manifest>(manifest_element.get())) {
for (xml::Element* child : element->GetChildElements()) {
if (child->name == "uses-permission" || child->name == "uses-permission-sdk-23"
|| child->name == "permission") {
// Inflate the element and its descendants
- auto permission_element = Visit(child);
+ auto permission_element = Visit(child, "manifest");
manifest->AddChild(permission_element);
}
}
-
- printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
- ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
- el->Print(printer);
- });
-
return true;
}
-
return false;
}
@@ -2041,27 +2536,24 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
}
// Extract badging information
- auto root = Visit(element);
+ root_element_ = Visit(element, "");
// Filter out all "uses-sdk" tags besides the very last tag. The android runtime only uses the
// attribute values from the last defined tag.
std::vector<UsesSdkBadging*> filtered_uses_sdk_tags;
- for (const auto& child : root->children()) {
+ for (const auto& child : root_element_->children()) {
if (auto uses_sdk = ElementCast<UsesSdkBadging>(child.get())) {
filtered_uses_sdk_tags.emplace_back(uses_sdk);
}
}
if (filtered_uses_sdk_tags.size() >= 2U) {
filtered_uses_sdk_tags.pop_back();
- root->Filter([&](const ManifestExtractor::Element* e) {
+ root_element_->Filter([&](const ManifestExtractor::Element* e) {
return std::find(filtered_uses_sdk_tags.begin(), filtered_uses_sdk_tags.end(), e) !=
filtered_uses_sdk_tags.end();
});
}
- // Print the elements in order seen
- Print(root.get(), printer);
-
/** Recursively checks the extracted elements for the specified permission. **/
auto FindPermission = [&](ManifestExtractor::Element* root,
const std::string& name) -> ManifestExtractor::Element* {
@@ -2073,30 +2565,30 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
});
};
- auto PrintPermission = [&printer](const std::string& name, const std::string& reason,
- int32_t max_sdk_version) -> void {
+ auto AddImpliedPermission = [&](const std::string& name, const std::string& reason,
+ int32_t max_sdk_version) -> void {
auto permission = util::make_unique<UsesPermission>();
permission->name = name;
permission->maxSdkVersion = max_sdk_version;
- permission->Print(printer);
- permission->PrintImplied(printer, reason);
+ permission->implied = true;
+ permission->impliedReason = reason;
+ implied_permissions_.push_back(std::move(permission));
};
// Implied permissions
// Pre-1.6 implicitly granted permission compatibility logic
- CommonFeatureGroup* common_feature_group = GetCommonFeatureGroup();
bool insert_write_external = false;
auto write_external_permission = ElementCast<UsesPermission>(
- FindPermission(root.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
+ FindPermission(root_element_.get(), "android.permission.WRITE_EXTERNAL_STORAGE"));
if (target_sdk() < SDK_DONUT) {
if (!write_external_permission) {
- PrintPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
+ AddImpliedPermission("android.permission.WRITE_EXTERNAL_STORAGE", "targetSdkVersion < 4", -1);
insert_write_external = true;
}
- if (!FindPermission(root.get(), "android.permission.READ_PHONE_STATE")) {
- PrintPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.READ_PHONE_STATE")) {
+ AddImpliedPermission("android.permission.READ_PHONE_STATE", "targetSdkVersion < 4", -1);
}
}
@@ -2104,62 +2596,60 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
// force them to always take READ_EXTERNAL_STORAGE as well. We always
// do this (regardless of target API version) because we can't have
// an app with write permission but not read permission.
- auto read_external = FindPermission(root.get(), "android.permission.READ_EXTERNAL_STORAGE");
+ auto read_external =
+ FindPermission(root_element_.get(), "android.permission.READ_EXTERNAL_STORAGE");
if (!read_external && (insert_write_external || write_external_permission)) {
- PrintPermission("android.permission.READ_EXTERNAL_STORAGE",
- "requested WRITE_EXTERNAL_STORAGE",
- (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
+ AddImpliedPermission(
+ "android.permission.READ_EXTERNAL_STORAGE", "requested WRITE_EXTERNAL_STORAGE",
+ (write_external_permission) ? write_external_permission->maxSdkVersion : -1);
}
// Pre-JellyBean call log permission compatibility.
if (target_sdk() < SDK_JELLY_BEAN) {
- if (!FindPermission(root.get(), "android.permission.READ_CALL_LOG")
- && FindPermission(root.get(), "android.permission.READ_CONTACTS")) {
- PrintPermission("android.permission.READ_CALL_LOG",
- "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.READ_CALL_LOG") &&
+ FindPermission(root_element_.get(), "android.permission.READ_CONTACTS")) {
+ AddImpliedPermission("android.permission.READ_CALL_LOG",
+ "targetSdkVersion < 16 and requested READ_CONTACTS", -1);
}
- if (!FindPermission(root.get(), "android.permission.WRITE_CALL_LOG")
- && FindPermission(root.get(), "android.permission.WRITE_CONTACTS")) {
- PrintPermission("android.permission.WRITE_CALL_LOG",
- "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
+ if (!FindPermission(root_element_.get(), "android.permission.WRITE_CALL_LOG") &&
+ FindPermission(root_element_.get(), "android.permission.WRITE_CONTACTS")) {
+ AddImpliedPermission("android.permission.WRITE_CALL_LOG",
+ "targetSdkVersion < 16 and requested WRITE_CONTACTS", -1);
}
}
// If the app hasn't declared the touchscreen as a feature requirement (either
// directly or implied, required or not), then the faketouch feature is implied.
- if (!common_feature_group->HasFeature("android.hardware.touchscreen")) {
- common_feature_group->addImpliedFeature("android.hardware.faketouch",
- "default feature for all apps", false);
+ if (!common_feature_group()->HasFeature("android.hardware.touchscreen")) {
+ common_feature_group()->addImpliedFeature("android.hardware.faketouch",
+ "default feature for all apps", false);
}
// Only print the common feature group if no feature group is defined
std::vector<FeatureGroup*> feature_groups;
- ForEachChild(root.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [&feature_groups](ManifestExtractor::Element* el) -> void {
if (auto feature_group = ElementCast<FeatureGroup>(el)) {
feature_groups.push_back(feature_group);
}
});
if (feature_groups.empty()) {
- common_feature_group->PrintGroup(printer);
+ feature_groups_.push_back(common_feature_group());
} else {
// Merge the common feature group into the feature group
for (auto& feature_group : feature_groups) {
- feature_group->open_gles_version = std::max(feature_group->open_gles_version,
- common_feature_group->open_gles_version);
- feature_group->Merge(common_feature_group);
- feature_group->PrintGroup(printer);
+ feature_group->Merge(common_feature_group());
+ feature_groups_.push_back(feature_group);
}
};
// Collect the component types of the application
- std::set<std::string> components;
- ForEachChild(root.get(), [&components](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [&](ManifestExtractor::Element* el) -> void {
if (ElementCast<Action>(el)) {
auto action = ElementCast<Action>(el);
if (!action->component.empty()) {
- components.insert(action->component);
+ components_.discovered_components.insert(action->component);
return;
}
}
@@ -2167,15 +2657,14 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
if (ElementCast<Category>(el)) {
auto category = ElementCast<Category>(el);
if (!category->component.empty()) {
- components.insert(category->component);
+ components_.discovered_components.insert(category->component);
return;
}
}
});
// Check for the payment component
- auto apk = apk_;
- ForEachChild(root.get(), [&apk, &components, &diag](ManifestExtractor::Element* el) -> void {
+ ForEachChild(root_element_.get(), [this, &diag](ManifestExtractor::Element* el) -> void {
if (auto service = ElementCast<Service>(el)) {
auto host_apdu_action = ElementCast<Action>(FindElement(service,
[&](ManifestExtractor::Element* el) -> bool {
@@ -2193,159 +2682,112 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
return false;
}));
- ForEachChild(service, [&apk, &components, &diag, &host_apdu_action,
- &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
- if (auto meta_data = ElementCast<MetaData>(el)) {
- if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" && host_apdu_action)
- || (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service"
- && offhost_apdu_action)) {
-
- // Attempt to load the resource file
- if (!meta_data->resource.empty()) {
- return;
- }
- auto resource = apk->LoadXml(meta_data->resource, diag);
- if (!resource) {
- return;
- }
-
- // Look for the payment category on an <aid-group> element
- auto& root = resource.get()->root;
- if ((host_apdu_action && root->name == "host-apdu-service")
- || (offhost_apdu_action && root->name == "offhost-apdu-service")) {
-
- for (auto& child : root->GetChildElements()) {
- if (child->name == "aid-group") {
- auto category = FindAttribute(child, CATEGORY_ATTR);
- if (category && category->value == "payment") {
- components.insert("payment");
- return;
- }
- }
- }
- }
- }
- }
- });
+ ForEachChild(service,
+ [this, &diag, &host_apdu_action,
+ &offhost_apdu_action](ManifestExtractor::Element* el) -> void {
+ if (auto meta_data = ElementCast<MetaData>(el)) {
+ if ((meta_data->name == "android.nfc.cardemulation.host_apdu_service" &&
+ host_apdu_action) ||
+ (meta_data->name == "android.nfc.cardemulation.off_host_apdu_service" &&
+ offhost_apdu_action)) {
+ // Attempt to load the resource file
+ if (meta_data->resource.empty()) {
+ return;
+ }
+ auto resource = this->apk_->LoadXml(meta_data->resource, diag);
+ if (!resource) {
+ return;
+ }
+
+ // Look for the payment category on an <aid-group> element
+ auto& root = resource.get()->root;
+ if ((host_apdu_action && root->name == "host-apdu-service") ||
+ (offhost_apdu_action && root->name == "offhost-apdu-service")) {
+ for (auto& child : root->GetChildElements()) {
+ if (child->name == "aid-group") {
+ auto category = FindAttribute(child, CATEGORY_ATTR);
+ if (category && category->value == "payment") {
+ this->components_.discovered_components.insert("payment");
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ });
}
});
- // Print the components types if they are present
- auto PrintComponent = [&components, &printer](const std::string& component) -> void {
- if (components.find(component) != components.end()) {
- printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
- }
- };
-
- PrintComponent("app-widget");
- PrintComponent("device-admin");
- PrintComponent("ime");
- PrintComponent("wallpaper");
- PrintComponent("accessibility");
- PrintComponent("print-service");
- PrintComponent("payment");
- PrintComponent("search");
- PrintComponent("document-provider");
- PrintComponent("launcher");
- PrintComponent("notification-listener");
- PrintComponent("dream");
- PrintComponent("camera");
- PrintComponent("camera-secure");
-
- // Print presence of main activity
- if (components.find("main") != components.end()) {
- printer->Print("main\n");
- }
-
- // Print presence of activities, recivers, and services with no special components
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ // Print presence of activities, receivers, and services with no special components
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
if (auto activity = ElementCast<Activity>(el)) {
if (!activity->has_component_) {
- printer->Print("other-activities\n");
+ components_.other_activities = true;
return true;
}
}
return false;
});
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
if (auto receiver = ElementCast<Receiver>(el)) {
if (!receiver->has_component) {
- printer->Print("other-receivers\n");
+ components_.other_receivers = true;
return true;
}
}
return false;
});
- FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
if (auto service = ElementCast<Service>(el)) {
if (!service->has_component) {
- printer->Print("other-services\n");
+ components_.other_services = true;
return true;
}
}
return false;
});
- // Print the supported screens
- SupportsScreen* screen = ElementCast<SupportsScreen>(FindElement(root.get(),
- [&](ManifestExtractor::Element* el) -> bool {
- return ElementCast<SupportsScreen>(el) != nullptr;
- }));
-
- if (screen) {
- screen->PrintScreens(printer, target_sdk_);
- } else {
- // Print the default supported screens
- SupportsScreen default_screens;
- default_screens.PrintScreens(printer, target_sdk_);
- }
+ // Gather the supported screens
+ const static SupportsScreen default_screens{};
+ SupportsScreen* screen = ElementCast<SupportsScreen>(
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ return ElementCast<SupportsScreen>(el) != nullptr;
+ }));
+ supports_screen_ = screen ? screen : &default_screens;
- // Print all the unique locales of the apk
- printer->Print("locales:");
- for (auto& config : locales_) {
- if (config.first.empty()) {
- printer->Print(" '--_--'");
- } else {
- printer->Print(StringPrintf(" '%s'", config.first.data()));
+ bool has_renderscript_bitcode = false;
+ auto it = apk_->GetFileCollection()->Iterator();
+ while (it->HasNext()) {
+ if (it->Next()->GetSource().path.ends_with(".bc")) {
+ has_renderscript_bitcode = true;
+ break;
}
}
- printer->Print("\n");
-
- // Print all the densities locales of the apk
- printer->Print("densities:");
- for (auto& config : densities_) {
- printer->Print(StringPrintf(" '%d'", config.first));
- }
- printer->Print("\n");
- // Print the supported architectures of the app
- std::set<std::string> architectures;
- auto it = apk_->GetFileCollection()->Iterator();
+ // Gather the supported architectures_ of the app
+ std::set<std::string> architectures_from_apk;
+ it = apk_->GetFileCollection()->Iterator();
while (it->HasNext()) {
- auto file_path = it->Next()->GetSource().path;
-
-
- size_t pos = file_path.find("lib/");
- if (pos != std::string::npos) {
- file_path = file_path.substr(pos + 4);
- pos = file_path.find('/');
- if (pos != std::string::npos) {
- file_path = file_path.substr(0, pos);
- }
+ auto file_path = it->Next()->GetSource().path.c_str();
- architectures.insert(file_path);
+ const char* last_slash =
+ android::util::ValidLibraryPathLastSlash(file_path, has_renderscript_bitcode, false);
+ if (last_slash) {
+ architectures_from_apk.insert(std::string(file_path + APK_LIB_LEN, last_slash));
}
}
// Determine if the application has multiArch supports
- auto has_multi_arch = FindElement(root.get(), [&](ManifestExtractor::Element* el) -> bool {
- if (auto application = ElementCast<Application>(el)) {
- return application->has_multi_arch;
- }
- return false;
- });
+ auto has_multi_arch =
+ FindElement(root_element_.get(), [&](ManifestExtractor::Element* el) -> bool {
+ if (auto application = ElementCast<Application>(el)) {
+ return application->has_multi_arch;
+ }
+ return false;
+ });
bool output_alt_native_code = false;
// A multiArch package is one that contains 64-bit and
@@ -2366,84 +2808,151 @@ bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
const std::string kIntel64 = "x86_64";
const std::string kArm64 = "arm64-v8a";
- auto arch = architectures.find(kIntel64);
- if (arch == architectures.end()) {
- arch = architectures.find(kArm64);
+ auto arch = architectures_from_apk.find(kIntel64);
+ if (arch == architectures_from_apk.end()) {
+ arch = architectures_from_apk.find(kArm64);
}
- if (arch != architectures.end()) {
- printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
- architectures.erase(arch);
+ if (arch != architectures_from_apk.end()) {
+ architectures_.architectures.insert(*arch);
+ architectures_from_apk.erase(arch);
output_alt_native_code = true;
}
}
-
- if (architectures.size() > 0) {
+ for (auto& arch : architectures_from_apk) {
if (output_alt_native_code) {
- printer->Print("alt-");
+ architectures_.alt_architectures.insert(arch);
+ } else {
+ architectures_.architectures.insert(arch);
}
- printer->Print("native-code:");
- for (auto& arch : architectures) {
- printer->Print(StringPrintf(" '%s'", arch.data()));
+ }
+ return true;
+}
+
+bool ManifestExtractor::Dump(text::Printer* printer) {
+ Print(root_element_.get(), printer);
+ if (options_.only_permissions) {
+ return true;
+ }
+
+ for (auto& implied_permission : implied_permissions_) {
+ implied_permission->Print(printer);
+ }
+ for (auto& feature_group : feature_groups_) {
+ feature_group->PrintGroup(printer);
+ }
+ components_.Print(printer);
+ supports_screen_->PrintScreens(printer, target_sdk_);
+
+ // Print all the unique locales of the apk
+ printer->Print("locales:");
+ for (auto& config : locales_) {
+ if (config.first.empty()) {
+ printer->Print(" '--_--'");
+ } else {
+ printer->Print(StringPrintf(" '%s'", config.first.data()));
}
- printer->Print("\n");
}
+ printer->Print("\n");
+
+ // Print all the densities locales of the apk
+ printer->Print("densities:");
+ for (auto& config : densities_) {
+ printer->Print(StringPrintf(" '%d'", config.first));
+ }
+ printer->Print("\n");
+ architectures_.Print(printer);
return true;
}
+bool ManifestExtractor::DumpProto(pb::Badging* out_badging) {
+ ToProto(root_element_.get(), out_badging);
+ for (auto& implied_permission : implied_permissions_) {
+ implied_permission->ToProto(out_badging);
+ }
+ for (auto& feature_group : feature_groups_) {
+ feature_group->GroupToProto(out_badging);
+ }
+ components_.ToProto(out_badging);
+ supports_screen_->ToProtoScreens(out_badging, target_sdk_);
+
+ for (auto& config : locales_) {
+ if (config.first.empty()) {
+ out_badging->add_locales("--_--");
+ } else {
+ out_badging->add_locales(config.first);
+ }
+ }
+ for (auto& config : densities_) {
+ out_badging->add_densities(config.first);
+ }
+
+ architectures_.ToProto(out_badging);
+ return true;
+}
+
+template <typename T>
+constexpr const char* GetExpectedTagForType() {
+ // This array does not appear at runtime, as GetExpectedTagForType function is used by compiler
+ // to inject proper 'expected_tag' into ElementCast.
+ std::array<std::pair<const char*, bool>, 38> tags = {
+ std::make_pair("action", std::is_same<Action, T>::value),
+ std::make_pair("activity", std::is_same<Activity, T>::value),
+ std::make_pair("additional-certificate", std::is_same<AdditionalCertificate, T>::value),
+ std::make_pair("application", std::is_same<Application, T>::value),
+ std::make_pair("category", std::is_same<Category, T>::value),
+ std::make_pair("compatible-screens", std::is_same<CompatibleScreens, T>::value),
+ std::make_pair("feature-group", std::is_same<FeatureGroup, T>::value),
+ std::make_pair("input-type", std::is_same<InputType, T>::value),
+ std::make_pair("install-constraints", std::is_same<InstallConstraints, T>::value),
+ std::make_pair("intent-filter", std::is_same<IntentFilter, T>::value),
+ std::make_pair("meta-data", std::is_same<MetaData, T>::value),
+ std::make_pair("manifest", std::is_same<Manifest, T>::value),
+ std::make_pair("original-package", std::is_same<OriginalPackage, T>::value),
+ std::make_pair("overlay", std::is_same<Overlay, T>::value),
+ std::make_pair("package-verifier", std::is_same<PackageVerifier, T>::value),
+ std::make_pair("permission", std::is_same<Permission, T>::value),
+ std::make_pair("property", std::is_same<Property, T>::value),
+ std::make_pair("provider", std::is_same<Provider, T>::value),
+ std::make_pair("receiver", std::is_same<Receiver, T>::value),
+ std::make_pair("required-feature", std::is_same<RequiredFeature, T>::value),
+ std::make_pair("required-not-feature", std::is_same<RequiredNotFeature, T>::value),
+ std::make_pair("screen", std::is_same<Screen, T>::value),
+ std::make_pair("service", std::is_same<Service, T>::value),
+ std::make_pair("sdk-library", std::is_same<SdkLibrary, T>::value),
+ std::make_pair("static-library", std::is_same<StaticLibrary, T>::value),
+ std::make_pair("supports-gl-texture", std::is_same<SupportsGlTexture, T>::value),
+ std::make_pair("supports-input", std::is_same<SupportsInput, T>::value),
+ std::make_pair("supports-screens", std::is_same<SupportsScreen, T>::value),
+ std::make_pair("uses-configuration", std::is_same<UsesConfiguarion, T>::value),
+ std::make_pair("uses-feature", std::is_same<UsesFeature, T>::value),
+ std::make_pair("uses-library", std::is_same<UsesLibrary, T>::value),
+ std::make_pair("uses-native-library", std::is_same<UsesNativeLibrary, T>::value),
+ std::make_pair("uses-package", std::is_same<UsesPackage, T>::value),
+ std::make_pair("uses-permission", std::is_same<UsesPermission, T>::value),
+ std::make_pair("uses-permission-sdk-23", std::is_same<UsesPermissionSdk23, T>::value),
+ std::make_pair("uses-sdk", std::is_same<UsesSdkBadging, T>::value),
+ std::make_pair("uses-sdk-library", std::is_same<UsesSdkLibrary, T>::value),
+ std::make_pair("uses-static-library", std::is_same<UsesStaticLibrary, T>::value),
+ };
+ for (const auto& pair : tags) {
+ if (pair.second) {
+ return pair.first;
+ }
+ }
+ return nullptr;
+}
+
/**
* Returns the element casted to the type if the element is of that type. Otherwise, returns a null
* pointer.
**/
template<typename T>
T* ElementCast(ManifestExtractor::Element* element) {
- if (element == nullptr) {
- return nullptr;
- }
-
- const std::unordered_map<std::string, bool> kTagCheck = {
- {"action", std::is_base_of<Action, T>::value},
- {"activity", std::is_base_of<Activity, T>::value},
- {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
- {"application", std::is_base_of<Application, T>::value},
- {"category", std::is_base_of<Category, T>::value},
- {"compatible-screens", std::is_base_of<CompatibleScreens, T>::value},
- {"feature-group", std::is_base_of<FeatureGroup, T>::value},
- {"input-type", std::is_base_of<InputType, T>::value},
- {"intent-filter", std::is_base_of<IntentFilter, T>::value},
- {"meta-data", std::is_base_of<MetaData, T>::value},
- {"manifest", std::is_base_of<Manifest, T>::value},
- {"original-package", std::is_base_of<OriginalPackage, T>::value},
- {"overlay", std::is_base_of<Overlay, T>::value},
- {"package-verifier", std::is_base_of<PackageVerifier, T>::value},
- {"permission", std::is_base_of<Permission, T>::value},
- {"property", std::is_base_of<Property, T>::value},
- {"provider", std::is_base_of<Provider, T>::value},
- {"receiver", std::is_base_of<Receiver, T>::value},
- {"required-feature", std::is_base_of<RequiredFeature, T>::value},
- {"required-not-feature", std::is_base_of<RequiredNotFeature, T>::value},
- {"screen", std::is_base_of<Screen, T>::value},
- {"service", std::is_base_of<Service, T>::value},
- {"sdk-library", std::is_base_of<SdkLibrary, T>::value},
- {"static-library", std::is_base_of<StaticLibrary, T>::value},
- {"supports-gl-texture", std::is_base_of<SupportsGlTexture, T>::value},
- {"supports-input", std::is_base_of<SupportsInput, T>::value},
- {"supports-screens", std::is_base_of<SupportsScreen, T>::value},
- {"uses-configuration", std::is_base_of<UsesConfiguarion, T>::value},
- {"uses-feature", std::is_base_of<UsesFeature, T>::value},
- {"uses-library", std::is_base_of<UsesLibrary, T>::value},
- {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
- {"uses-package", std::is_base_of<UsesPackage, T>::value},
- {"uses-permission", std::is_base_of<UsesPermission, T>::value},
- {"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
- {"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
- {"uses-sdk-library", std::is_base_of<UsesSdkLibrary, T>::value},
- {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
- };
-
- auto check = kTagCheck.find(element->tag());
- if (check != kTagCheck.end() && check->second) {
+ constexpr const char* expected_tag = GetExpectedTagForType<T>();
+ if (element != nullptr && expected_tag != nullptr && element->is_featured() &&
+ element->tag() == expected_tag) {
return static_cast<T*>(element);
}
return nullptr;
@@ -2455,9 +2964,9 @@ std::unique_ptr<T> CreateType() {
}
std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
- ManifestExtractor* extractor, xml::Element* el) {
- const std::unordered_map<std::string,
- std::function<std::unique_ptr<ManifestExtractor::Element>()>>
+ ManifestExtractor* extractor, xml::Element* el, const std::string& parent_tag) {
+ static const std::unordered_map<std::string_view,
+ std::function<std::unique_ptr<ManifestExtractor::Element>()>>
kTagCheck = {
{"action", &CreateType<Action>},
{"activity", &CreateType<Activity>},
@@ -2467,6 +2976,7 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
{"compatible-screens", &CreateType<CompatibleScreens>},
{"feature-group", &CreateType<FeatureGroup>},
{"input-type", &CreateType<InputType>},
+ {"install-constraints", &CreateType<InstallConstraints>},
{"intent-filter", &CreateType<IntentFilter>},
{"manifest", &CreateType<Manifest>},
{"meta-data", &CreateType<MetaData>},
@@ -2497,12 +3007,71 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
{"uses-sdk-library", &CreateType<UsesSdkLibrary>},
{"uses-static-library", &CreateType<UsesStaticLibrary>},
};
-
+ static constexpr std::array<std::pair<std::string_view, std::string_view>, 53>
+ kValidChildParentTags = {
+ std::make_pair("action", "intent-filter"),
+ std::make_pair("activity", "application"),
+ std::make_pair("additional-certificate", "uses-package"),
+ std::make_pair("additional-certificate", "uses-static-library"),
+ std::make_pair("application", "manifest"),
+ std::make_pair("category", "intent-filter"),
+ std::make_pair("compatible-screens", "manifest"),
+ std::make_pair("feature-group", "manifest"),
+ std::make_pair("input-type", "supports-input"),
+ std::make_pair("intent-filter", "activity"),
+ std::make_pair("intent-filter", "activity-alias"),
+ std::make_pair("intent-filter", "service"),
+ std::make_pair("intent-filter", "receiver"),
+ std::make_pair("intent-filter", "provider"),
+ std::make_pair("manifest", ""),
+ std::make_pair("meta-data", "activity"),
+ std::make_pair("meta-data", "activity-alias"),
+ std::make_pair("meta-data", "application"),
+ std::make_pair("meta-data", "service"),
+ std::make_pair("meta-data", "receiver"),
+ std::make_pair("meta-data", "provider"),
+ std::make_pair("original-package", "manifest"),
+ std::make_pair("overlay", "manifest"),
+ std::make_pair("package-verifier", "manifest"),
+ std::make_pair("permission", "manifest"),
+ std::make_pair("property", "activity"),
+ std::make_pair("property", "activity-alias"),
+ std::make_pair("property", "application"),
+ std::make_pair("property", "service"),
+ std::make_pair("property", "receiver"),
+ std::make_pair("property", "provider"),
+ std::make_pair("provider", "application"),
+ std::make_pair("receiver", "application"),
+ std::make_pair("required-feature", "uses-permission"),
+ std::make_pair("required-not-feature", "uses-permission"),
+ std::make_pair("screen", "compatible-screens"),
+ std::make_pair("service", "application"),
+ std::make_pair("sdk-library", "application"),
+ std::make_pair("static-library", "application"),
+ std::make_pair("supports-gl-texture", "manifest"),
+ std::make_pair("supports-input", "manifest"),
+ std::make_pair("supports-screens", "manifest"),
+ std::make_pair("uses-configuration", "manifest"),
+ std::make_pair("uses-feature", "feature-group"),
+ std::make_pair("uses-feature", "manifest"),
+ std::make_pair("uses-library", "application"),
+ std::make_pair("uses-native-library", "application"),
+ std::make_pair("uses-package", "application"),
+ std::make_pair("uses-permission", "manifest"),
+ std::make_pair("uses-permission-sdk-23", "manifest"),
+ std::make_pair("uses-sdk", "manifest"),
+ std::make_pair("uses-sdk-library", "application"),
+ std::make_pair("uses-static-library", "application"),
+ };
+ bool is_valid_tag = std::find(kValidChildParentTags.begin(), kValidChildParentTags.end(),
+ std::make_pair<std::string_view, std::string_view>(
+ el->name, parent_tag)) != kValidChildParentTags.end();
// Attempt to map the xml tag to a element inflater
std::unique_ptr<ManifestExtractor::Element> element;
auto check = kTagCheck.find(el->name);
- if (check != kTagCheck.end()) {
+ if (check != kTagCheck.end() && is_valid_tag) {
element = check->second();
+ element->featured_ = true;
} else {
element = util::make_unique<ManifestExtractor::Element>();
}
@@ -2513,13 +3082,14 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
return element;
}
-std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Element* el) {
- auto element = ManifestExtractor::Element::Inflate(this, el);
+std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(
+ xml::Element* el, const std::string& parent_tag) {
+ auto element = ManifestExtractor::Element::Inflate(this, el, parent_tag);
parent_stack_.insert(parent_stack_.begin(), element.get());
// Process the element and recursively visit the children
for (xml::Element* child : el->GetChildElements()) {
- auto v = Visit(child);
+ auto v = Visit(child, el->name);
element->AddChild(v);
}
@@ -2527,11 +3097,23 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Elemen
return element;
}
-
int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
ManifestExtractor extractor(apk, options);
- return extractor.Dump(printer, diag) ? 0 : 1;
+ if (!extractor.Extract(diag)) {
+ return 1;
+ }
+ return extractor.Dump(printer) ? 0 : 1;
+}
+
+int DumpBadgingProto(LoadedApk* apk, pb::Badging* out_badging, android::IDiagnostics* diag) {
+ DumpManifestOptions options{/* include_meta_data= */ true,
+ /* only_permissions= */ false};
+ ManifestExtractor extractor(apk, options);
+ if (!extractor.Extract(diag)) {
+ return 1;
+ }
+ return extractor.DumpProto(out_badging) ? 0 : 1;
}
} // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h
index daf22ed57a84..138b9e377b8a 100644
--- a/tools/aapt2/dump/DumpManifest.h
+++ b/tools/aapt2/dump/DumpManifest.h
@@ -17,8 +17,9 @@
#ifndef AAPT2_DUMP_MANIFEST_H
#define AAPT2_DUMP_MANIFEST_H
-#include "Diagnostics.h"
+#include "ApkInfo.pb.h"
#include "LoadedApk.h"
+#include "androidfw/IDiagnostics.h"
#include "text/Printer.h"
namespace aapt {
@@ -32,8 +33,11 @@ struct DumpManifestOptions {
/** Print information extracted from the manifest of the APK. */
int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
- IDiagnostics* diag);
+ android::IDiagnostics* diag);
+
+/** Extracts badging data from the manifest of the APK and stores it in Badging proto. */
+int DumpBadgingProto(LoadedApk* apk, pb::Badging* out_badging, android::IDiagnostics* diag);
} // namespace aapt
-#endif // AAPT2_DUMP_MANIFEST_H \ No newline at end of file
+#endif // AAPT2_DUMP_MANIFEST_H
diff --git a/tools/aapt2/filter/AbiFilter.cpp b/tools/aapt2/filter/AbiFilter.cpp
index 9ace82ad4af7..908b1714bd14 100644
--- a/tools/aapt2/filter/AbiFilter.cpp
+++ b/tools/aapt2/filter/AbiFilter.cpp
@@ -23,15 +23,15 @@
namespace aapt {
std::unique_ptr<AbiFilter> AbiFilter::FromAbiList(const std::vector<configuration::Abi>& abi_list) {
- std::unordered_set<std::string> abi_set;
+ std::unordered_set<std::string_view> abi_set;
for (auto& abi : abi_list) {
- abi_set.insert(configuration::AbiToString(abi).to_string());
+ abi_set.insert(configuration::AbiToString(abi));
}
// Make unique by hand as the constructor is private.
- return std::unique_ptr<AbiFilter>(new AbiFilter(abi_set));
+ return std::unique_ptr<AbiFilter>(new AbiFilter(std::move(abi_set)));
}
-bool AbiFilter::Keep(const std::string& path) {
+bool AbiFilter::Keep(std::string_view path) {
// We only care about libraries.
if (!util::StartsWith(path, kLibPrefix)) {
return true;
@@ -44,7 +44,7 @@ bool AbiFilter::Keep(const std::string& path) {
}
// Strip the lib/ prefix.
- const std::string& path_abi = path.substr(kLibPrefixLen, abi_end - kLibPrefixLen);
+ const auto path_abi = path.substr(kLibPrefixLen, abi_end - kLibPrefixLen);
return (abis_.find(path_abi) != abis_.end());
}
diff --git a/tools/aapt2/filter/AbiFilter.h b/tools/aapt2/filter/AbiFilter.h
index 2832711efb2c..7380f3f479ae 100644
--- a/tools/aapt2/filter/AbiFilter.h
+++ b/tools/aapt2/filter/AbiFilter.h
@@ -18,7 +18,7 @@
#define AAPT2_ABISPLITTER_H
#include <memory>
-#include <string>
+#include <string_view>
#include <unordered_set>
#include <vector>
@@ -39,16 +39,16 @@ class AbiFilter : public IPathFilter {
static std::unique_ptr<AbiFilter> FromAbiList(const std::vector<configuration::Abi>& abi_list);
/** Returns true if the path is for a native library in the list of desired ABIs. */
- bool Keep(const std::string& path) override;
+ bool Keep(std::string_view path) override;
private:
- explicit AbiFilter(std::unordered_set<std::string> abis) : abis_(std::move(abis)) {
+ explicit AbiFilter(std::unordered_set<std::string_view> abis) : abis_(std::move(abis)) {
}
/** The path prefix to where all native libs end up inside an APK file. */
static constexpr const char* kLibPrefix = "lib/";
static constexpr size_t kLibPrefixLen = 4;
- const std::unordered_set<std::string> abis_;
+ const std::unordered_set<std::string_view> abis_;
};
} // namespace aapt
diff --git a/tools/aapt2/filter/Filter.h b/tools/aapt2/filter/Filter.h
index f932f9ccc82e..baf4791f76c8 100644
--- a/tools/aapt2/filter/Filter.h
+++ b/tools/aapt2/filter/Filter.h
@@ -18,6 +18,7 @@
#define AAPT2_FILTER_H
#include <string>
+#include <string_view>
#include <vector>
#include "util/Util.h"
@@ -30,7 +31,7 @@ class IPathFilter {
virtual ~IPathFilter() = default;
/** Returns true if the path should be kept. */
- virtual bool Keep(const std::string& path) = 0;
+ virtual bool Keep(std::string_view path) = 0;
};
/**
@@ -42,7 +43,7 @@ class PrefixFilter : public IPathFilter {
}
/** Returns true if the provided path matches the prefix. */
- bool Keep(const std::string& path) override {
+ bool Keep(std::string_view path) override {
return util::StartsWith(path, prefix_);
}
@@ -59,7 +60,7 @@ class FilterChain : public IPathFilter {
}
/** Returns true if all filters keep the path. */
- bool Keep(const std::string& path) override {
+ bool Keep(std::string_view path) override {
for (auto& filter : filters_) {
if (!filter->Keep(path)) {
return false;
diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp
index c20b053c37b1..e9a93d8b12ad 100644
--- a/tools/aapt2/format/Archive.cpp
+++ b/tools/aapt2/format/Archive.cpp
@@ -25,9 +25,9 @@
#include "android-base/macros.h"
#include "android-base/utf8.h"
#include "androidfw/StringPiece.h"
-#include "ziparchive/zip_writer.h"
-
#include "util/Files.h"
+#include "util/Util.h"
+#include "ziparchive/zip_writer.h"
using ::android::StringPiece;
using ::android::base::SystemErrorCodeToString;
@@ -40,8 +40,8 @@ class DirectoryWriter : public IArchiveWriter {
public:
DirectoryWriter() = default;
- bool Open(const StringPiece& out_dir) {
- dir_ = out_dir.to_string();
+ bool Open(StringPiece out_dir) {
+ dir_ = std::string(out_dir);
file::FileType type = file::GetFileType(dir_);
if (type == file::FileType::kNonExistant) {
error_ = "directory does not exist";
@@ -53,14 +53,14 @@ class DirectoryWriter : public IArchiveWriter {
return true;
}
- bool StartEntry(const StringPiece& path, uint32_t flags) override {
+ bool StartEntry(StringPiece path, uint32_t flags) override {
if (file_) {
return false;
}
std::string full_path = dir_;
file::AppendPath(&full_path, path);
- file::mkdirs(file::GetStem(full_path).to_string());
+ file::mkdirs(std::string(file::GetStem(full_path)));
file_ = {::android::base::utf8::fopen(full_path.c_str(), "wb"), fclose};
if (!file_) {
@@ -91,7 +91,7 @@ class DirectoryWriter : public IArchiveWriter {
return true;
}
- bool WriteFile(const StringPiece& path, uint32_t flags, io::InputStream* in) override {
+ bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override {
if (!StartEntry(path, flags)) {
return false;
}
@@ -132,8 +132,8 @@ class ZipFileWriter : public IArchiveWriter {
public:
ZipFileWriter() = default;
- bool Open(const StringPiece& path) {
- file_ = {::android::base::utf8::fopen(path.to_string().c_str(), "w+b"), fclose};
+ bool Open(StringPiece path) {
+ file_ = {::android::base::utf8::fopen(path.data(), "w+b"), fclose};
if (!file_) {
error_ = SystemErrorCodeToString(errno);
return false;
@@ -142,7 +142,7 @@ class ZipFileWriter : public IArchiveWriter {
return true;
}
- bool StartEntry(const StringPiece& path, uint32_t flags) override {
+ bool StartEntry(StringPiece path, uint32_t flags) override {
if (!writer_) {
return false;
}
@@ -182,7 +182,7 @@ class ZipFileWriter : public IArchiveWriter {
return true;
}
- bool WriteFile(const StringPiece& path, uint32_t flags, io::InputStream* in) override {
+ bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override {
while (true) {
if (!StartEntry(path, flags)) {
return false;
@@ -256,21 +256,21 @@ class ZipFileWriter : public IArchiveWriter {
} // namespace
-std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(IDiagnostics* diag,
- const StringPiece& path) {
+std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(android::IDiagnostics* diag,
+ StringPiece path) {
std::unique_ptr<DirectoryWriter> writer = util::make_unique<DirectoryWriter>();
if (!writer->Open(path)) {
- diag->Error(DiagMessage(path) << writer->GetError());
+ diag->Error(android::DiagMessage(path) << writer->GetError());
return {};
}
return std::move(writer);
}
-std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(IDiagnostics* diag,
- const StringPiece& path) {
+std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(android::IDiagnostics* diag,
+ StringPiece path) {
std::unique_ptr<ZipFileWriter> writer = util::make_unique<ZipFileWriter>();
if (!writer->Open(path)) {
- diag->Error(DiagMessage(path) << writer->GetError());
+ diag->Error(android::DiagMessage(path) << writer->GetError());
return {};
}
return std::move(writer);
diff --git a/tools/aapt2/format/Archive.h b/tools/aapt2/format/Archive.h
index 4e8a39df9165..6cde753a255d 100644
--- a/tools/aapt2/format/Archive.h
+++ b/tools/aapt2/format/Archive.h
@@ -22,12 +22,11 @@
#include <string>
#include <vector>
+#include "androidfw/BigBuffer.h"
+#include "androidfw/IDiagnostics.h"
#include "androidfw/StringPiece.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-#include "Diagnostics.h"
#include "io/Io.h"
-#include "util/BigBuffer.h"
#include "util/Files.h"
namespace aapt {
@@ -47,12 +46,12 @@ class IArchiveWriter : public ::google::protobuf::io::CopyingOutputStream {
public:
virtual ~IArchiveWriter() = default;
- virtual bool WriteFile(const android::StringPiece& path, uint32_t flags, io::InputStream* in) = 0;
+ virtual bool WriteFile(android::StringPiece path, uint32_t flags, io::InputStream* in) = 0;
// Starts a new entry and allows caller to write bytes to it sequentially.
// Only use StartEntry if code you do not control needs to write to a CopyingOutputStream.
// Prefer WriteFile instead of manually calling StartEntry/FinishEntry.
- virtual bool StartEntry(const android::StringPiece& path, uint32_t flags) = 0;
+ virtual bool StartEntry(android::StringPiece path, uint32_t flags) = 0;
// Called to finish writing an entry previously started by StartEntry.
// Prefer WriteFile instead of manually calling StartEntry/FinishEntry.
@@ -70,11 +69,11 @@ class IArchiveWriter : public ::google::protobuf::io::CopyingOutputStream {
virtual std::string GetError() const = 0;
};
-std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(IDiagnostics* diag,
- const android::StringPiece& path);
+std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(android::IDiagnostics* diag,
+ android::StringPiece path);
-std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(IDiagnostics* diag,
- const android::StringPiece& path);
+std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(android::IDiagnostics* diag,
+ android::StringPiece path);
} // namespace aapt
diff --git a/tools/aapt2/format/Archive_test.cpp b/tools/aapt2/format/Archive_test.cpp
index ceed3740f37a..3c44da710d94 100644
--- a/tools/aapt2/format/Archive_test.cpp
+++ b/tools/aapt2/format/Archive_test.cpp
@@ -50,7 +50,7 @@ std::unique_ptr<IArchiveWriter> MakeDirectoryWriter(const std::string& output_pa
}
std::unique_ptr<IArchiveWriter> MakeZipFileWriter(const std::string& output_path) {
- file::mkdirs(file::GetStem(output_path).to_string());
+ file::mkdirs(std::string(file::GetStem(output_path)));
std::remove(output_path.c_str());
StdErrDiagnostics diag;
diff --git a/tools/aapt2/format/Container.h b/tools/aapt2/format/Container.h
index aa5c82cd322c..121c592537bf 100644
--- a/tools/aapt2/format/Container.h
+++ b/tools/aapt2/format/Container.h
@@ -19,14 +19,13 @@
#include <inttypes.h>
-#include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream.h"
-
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
+#include "androidfw/BigBuffer.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream.h"
#include "io/Io.h"
#include "io/Util.h"
-#include "util/BigBuffer.h"
namespace aapt {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 5ed84879d561..2e20e8175213 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -18,19 +18,19 @@
#include <algorithm>
#include <map>
+#include <optional>
#include <string>
+#include "ResourceTable.h"
+#include "ResourceUtils.h"
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
+#include "androidfw/Source.h"
#include "androidfw/TypeWrappers.h"
-
-#include "ResourceTable.h"
-#include "ResourceUtils.h"
-#include "ResourceValues.h"
-#include "Source.h"
-#include "ValueVisitor.h"
#include "format/binary/ResChunkPullParser.h"
#include "util/Util.h"
@@ -50,7 +50,7 @@ static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
std::u16string dst;
dst.resize(utf16_len);
for (size_t i = 0; i < utf16_len; i++) {
- dst[i] = util::DeviceToHost16(src[i]);
+ dst[i] = android::util::DeviceToHost16(src[i]);
}
return dst;
}
@@ -87,8 +87,8 @@ class ReferenceIdToNameVisitor : public DescendingValueVisitor {
} // namespace
BinaryResourceParser::BinaryResourceParser(IDiagnostics* diag, ResourceTable* table,
- const Source& source, const void* data, size_t len,
- io::IFileCollection* files)
+ const android::Source& source, const void* data,
+ size_t len, io::IFileCollection* files)
: diag_(diag), table_(table), source_(source), data_(data), data_len_(len), files_(files) {
}
@@ -96,13 +96,13 @@ bool BinaryResourceParser::Parse() {
ResChunkPullParser parser(data_, data_len_);
if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
- diag_->Error(DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
return false;
}
if (parser.chunk()->type != android::RES_TABLE_TYPE) {
- diag_->Error(DiagMessage(source_) << StringPrintf("unknown chunk of type 0x%02x",
- static_cast<int>(parser.chunk()->type)));
+ diag_->Error(android::DiagMessage(source_) << StringPrintf(
+ "unknown chunk of type 0x%02x", static_cast<int>(parser.chunk()->type)));
return false;
}
@@ -112,18 +112,18 @@ bool BinaryResourceParser::Parse() {
if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
} else {
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< StringPrintf("unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
static_cast<int>(parser.chunk()->type)));
}
}
if (!staged_entries_to_remove_.empty()) {
- diag_->Error(DiagMessage(source_) << "didn't find " << staged_entries_to_remove_.size()
- << " original staged resources");
+ diag_->Error(android::DiagMessage(source_) << "didn't find " << staged_entries_to_remove_.size()
+ << " original staged resources");
return false;
}
@@ -134,20 +134,20 @@ bool BinaryResourceParser::Parse() {
bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
if (!table_header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_header chunk");
return false;
}
ResChunkPullParser parser(GetChunkData(&table_header->header),
GetChunkDataLen(&table_header->header));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- switch (util::DeviceToHost16(parser.chunk()->type)) {
+ switch (android::util::DeviceToHost16(parser.chunk()->type)) {
case android::RES_STRING_POOL_TYPE:
if (value_pool_.getError() == NO_INIT) {
- status_t err =
- value_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ status_t err = value_pool_.setTo(parser.chunk(),
+ android::util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- diag_->Error(DiagMessage(source_)
+ diag_->Error(android::DiagMessage(source_)
<< "corrupt string pool in ResTable: " << value_pool_.getError());
return false;
}
@@ -155,7 +155,7 @@ bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
// Reserve some space for the strings we are going to add.
table_->string_pool.HintWillAdd(value_pool_.size(), value_pool_.styleCount());
} else {
- diag_->Warn(DiagMessage(source_) << "unexpected string pool in ResTable");
+ diag_->Warn(android::DiagMessage(source_) << "unexpected string pool in ResTable");
}
break;
@@ -166,15 +166,15 @@ bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
break;
default:
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ << static_cast<int>(android::util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt resource table: " << parser.error());
return false;
}
return true;
@@ -185,13 +185,13 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
if (!package_header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_package chunk");
return false;
}
- uint32_t package_id = util::DeviceToHost32(package_header->id);
+ uint32_t package_id = android::util::DeviceToHost32(package_header->id);
if (package_id > std::numeric_limits<uint8_t>::max()) {
- diag_->Error(DiagMessage(source_) << "package ID is too big (" << package_id << ")");
+ diag_->Error(android::DiagMessage(source_) << "package ID is too big (" << package_id << ")");
return false;
}
@@ -199,9 +199,10 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
arraysize(package_header->name));
- ResourceTablePackage* package = table_->FindOrCreatePackage(util::Utf16ToUtf8(package_name));
+ ResourceTablePackage* package =
+ table_->FindOrCreatePackage(android::util::Utf16ToUtf8(package_name));
if (!package) {
- diag_->Error(DiagMessage(source_)
+ diag_->Error(android::DiagMessage(source_)
<< "incompatible package '" << package_name << "' with ID " << package_id);
return false;
}
@@ -214,26 +215,28 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
ResChunkPullParser parser(GetChunkData(&package_header->header),
GetChunkDataLen(&package_header->header));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- switch (util::DeviceToHost16(parser.chunk()->type)) {
+ switch (android::util::DeviceToHost16(parser.chunk()->type)) {
case android::RES_STRING_POOL_TYPE:
if (type_pool_.getError() == NO_INIT) {
status_t err =
- type_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ type_pool_.setTo(parser.chunk(), android::util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "corrupt type string pool in "
- << "ResTable_package: " << type_pool_.getError());
+ diag_->Error(android::DiagMessage(source_)
+ << "corrupt type string pool in "
+ << "ResTable_package: " << type_pool_.getError());
return false;
}
} else if (key_pool_.getError() == NO_INIT) {
status_t err =
- key_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ key_pool_.setTo(parser.chunk(), android::util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "corrupt key string pool in "
- << "ResTable_package: " << key_pool_.getError());
+ diag_->Error(android::DiagMessage(source_)
+ << "corrupt key string pool in "
+ << "ResTable_package: " << key_pool_.getError());
return false;
}
} else {
- diag_->Warn(DiagMessage(source_) << "unexpected string pool");
+ diag_->Warn(android::DiagMessage(source_) << "unexpected string pool");
}
break;
@@ -268,15 +271,15 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
break;
default:
- diag_->Warn(DiagMessage(source_)
+ diag_->Warn(android::DiagMessage(source_)
<< "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ << static_cast<int>(android::util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
return false;
}
@@ -290,18 +293,19 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
const ResChunk_header* chunk, uint8_t package_id) {
if (type_pool_.getError() != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(android::DiagMessage(source_) << "missing type string pool");
return false;
}
const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
if (!type_spec) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
return false;
}
if (type_spec->id == 0) {
- diag_->Error(DiagMessage(source_) << "ResTable_typeSpec has invalid id: " << type_spec->id);
+ diag_->Error(android::DiagMessage(source_)
+ << "ResTable_typeSpec has invalid id: " << type_spec->id);
return false;
}
@@ -312,25 +316,26 @@ bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
// There can only be 2^16 entries in a type, because that is the ID
// space for entries (EEEE) in the resource ID 0xPPTTEEEE.
if (entry_count > std::numeric_limits<uint16_t>::max()) {
- diag_->Error(DiagMessage(source_)
+ diag_->Error(android::DiagMessage(source_)
<< "ResTable_typeSpec has too many entries (" << entry_count << ")");
return false;
}
- const size_t data_size = util::DeviceToHost32(type_spec->header.size) -
- util::DeviceToHost16(type_spec->header.headerSize);
+ const size_t data_size = android::util::DeviceToHost32(type_spec->header.size) -
+ android::util::DeviceToHost16(type_spec->header.headerSize);
if (entry_count * sizeof(uint32_t) > data_size) {
- diag_->Error(DiagMessage(source_) << "ResTable_typeSpec too small to hold entries.");
+ diag_->Error(android::DiagMessage(source_) << "ResTable_typeSpec too small to hold entries.");
return false;
}
// Record the type_spec_flags for later. We don't know resource names yet, and we need those
// to mark resources as overlayable.
const uint32_t* type_spec_flags = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<uintptr_t>(type_spec) + util::DeviceToHost16(type_spec->header.headerSize));
+ reinterpret_cast<uintptr_t>(type_spec) +
+ android::util::DeviceToHost16(type_spec->header.headerSize));
for (size_t i = 0; i < entry_count; i++) {
ResourceId id(package_id, type_spec->id, static_cast<size_t>(i));
- entry_type_spec_flags_[id] = util::DeviceToHost32(type_spec_flags[i]);
+ entry_type_spec_flags_[id] = android::util::DeviceToHost32(type_spec_flags[i]);
}
return true;
}
@@ -338,12 +343,12 @@ bool BinaryResourceParser::ParseTypeSpec(const ResourceTablePackage* package,
bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
const ResChunk_header* chunk, uint8_t package_id) {
if (type_pool_.getError() != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(android::DiagMessage(source_) << "missing type string pool");
return false;
}
if (key_pool_.getError() != NO_ERROR) {
- diag_->Error(DiagMessage(source_) << "missing key string pool");
+ diag_->Error(android::DiagMessage(source_) << "missing key string pool");
return false;
}
@@ -351,23 +356,24 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
// a lot and has its own code to handle variable size.
const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
if (!type) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_type chunk");
return false;
}
if (type->id == 0) {
- diag_->Error(DiagMessage(source_) << "ResTable_type has invalid id: " << (int)type->id);
+ diag_->Error(android::DiagMessage(source_)
+ << "ResTable_type has invalid id: " << (int)type->id);
return false;
}
ConfigDescription config;
config.copyFromDtoH(type->config);
- const std::string type_str = util::GetString(type_pool_, type->id - 1);
- const ResourceType* parsed_type = ParseResourceType(type_str);
+ const std::string type_str = android::util::GetString(type_pool_, type->id - 1);
+ std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(type_str);
if (!parsed_type) {
- diag_->Warn(DiagMessage(source_)
- << "invalid type name '" << type_str << "' for type with ID " << type->id);
+ diag_->Warn(android::DiagMessage(source_)
+ << "invalid type name '" << type_str << "' for type with ID " << int(type->id));
return true;
}
@@ -379,24 +385,21 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
}
const ResourceName name(package->name, *parsed_type,
- util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
+ android::util::GetString(key_pool_, entry->key()));
const ResourceId res_id(package_id, type->id, static_cast<uint16_t>(it.index()));
std::unique_ptr<Value> resource_value;
- if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
- const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
-
+ if (auto mapEntry = entry->map_entry()) {
// TODO(adamlesinski): Check that the entry count is valid.
resource_value = ParseMapEntry(name, config, mapEntry);
} else {
- const Res_value* value =
- (const Res_value*)((const uint8_t*)entry + util::DeviceToHost32(entry->size));
- resource_value = ParseValue(name, config, *value);
+ resource_value = ParseValue(name, config, entry->value());
}
if (!resource_value) {
- diag_->Error(DiagMessage(source_) << "failed to parse value for resource " << name << " ("
- << res_id << ") with configuration '" << config << "'");
+ diag_->Error(android::DiagMessage(source_)
+ << "failed to parse value for resource " << name << " (" << res_id
+ << ") with configuration '" << config << "'");
return false;
}
@@ -411,7 +414,7 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
.SetId(res_id, OnIdConflict::CREATE_ENTRY)
.SetAllowMangled(true);
- if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
+ if (entry->flags() & ResTable_entry::FLAG_PUBLIC) {
Visibility visibility{Visibility::Level::kPublic};
auto spec_flags = entry_type_spec_flags_.find(res_id);
@@ -450,7 +453,7 @@ bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
const size_t count = entries.size();
for (size_t i = 0; i < count; i++) {
table_->included_packages_[entries.valueAt(i)] =
- util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).c_str()));
+ android::util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).c_str()));
}
return true;
}
@@ -458,36 +461,39 @@ bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
const ResTable_overlayable_header* header = ConvertTo<ResTable_overlayable_header>(chunk);
if (!header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_category_header chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_category_header chunk");
return false;
}
auto overlayable = std::make_shared<Overlayable>();
- overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
- arraysize(header->name)));
- overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
- arraysize(header->name)));
+ overlayable->name = android::util::Utf16ToUtf8(
+ strcpy16_dtoh((const char16_t*)header->name, arraysize(header->name)));
+ overlayable->actor = android::util::Utf16ToUtf8(
+ strcpy16_dtoh((const char16_t*)header->actor, arraysize(header->name)));
ResChunkPullParser parser(GetChunkData(chunk),
GetChunkDataLen(chunk));
while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- if (util::DeviceToHost16(parser.chunk()->type) == android::RES_TABLE_OVERLAYABLE_POLICY_TYPE) {
+ if (android::util::DeviceToHost16(parser.chunk()->type) ==
+ android::RES_TABLE_OVERLAYABLE_POLICY_TYPE) {
const ResTable_overlayable_policy_header* policy_header =
ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
- ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
- const ResTable_ref* const ref_end = ref_begin
- + util::DeviceToHost32(policy_header->entry_count);
+ ((uint8_t*)policy_header) +
+ android::util::DeviceToHost32(policy_header->header.headerSize));
+ const ResTable_ref* const ref_end =
+ ref_begin + android::util::DeviceToHost32(policy_header->entry_count);
for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
- ResourceId res_id(util::DeviceToHost32(ref_iter->ident));
+ ResourceId res_id(android::util::DeviceToHost32(ref_iter->ident));
const auto iter = id_index_.find(res_id);
// If the overlayable chunk comes before the type chunks, the resource ids and resource name
// pairing will not exist at this point.
if (iter == id_index_.cend()) {
- diag_->Error(DiagMessage(source_) << "failed to find resource name for overlayable"
- << " resource " << res_id);
+ diag_->Error(android::DiagMessage(source_)
+ << "failed to find resource name for overlayable"
+ << " resource " << res_id);
return false;
}
@@ -511,23 +517,23 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseStagedAliases(const ResChunk_header* chunk) {
auto header = ConvertTo<ResTable_staged_alias_header>(chunk);
if (!header) {
- diag_->Error(DiagMessage(source_) << "corrupt ResTable_staged_alias_header chunk");
+ diag_->Error(android::DiagMessage(source_) << "corrupt ResTable_staged_alias_header chunk");
return false;
}
const auto ref_begin = reinterpret_cast<const ResTable_staged_alias_entry*>(
- ((uint8_t*)header) + util::DeviceToHost32(header->header.headerSize));
- const auto ref_end = ref_begin + util::DeviceToHost32(header->count);
+ ((uint8_t*)header) + android::util::DeviceToHost32(header->header.headerSize));
+ const auto ref_end = ref_begin + android::util::DeviceToHost32(header->count);
for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
- const auto staged_id = ResourceId(util::DeviceToHost32(ref_iter->stagedResId));
- const auto finalized_id = ResourceId(util::DeviceToHost32(ref_iter->finalizedResId));
+ const auto staged_id = ResourceId(android::util::DeviceToHost32(ref_iter->stagedResId));
+ const auto finalized_id = ResourceId(android::util::DeviceToHost32(ref_iter->finalizedResId));
// If the staged alias chunk comes before the type chunks, the resource ids and resource name
// pairing will not exist at this point.
const auto iter = id_index_.find(finalized_id);
if (iter == id_index_.cend()) {
- diag_->Error(DiagMessage(source_) << "failed to find resource name for finalized"
- << " resource ID " << finalized_id);
+ diag_->Error(android::DiagMessage(source_) << "failed to find resource name for finalized"
+ << " resource ID " << finalized_id);
return false;
}
@@ -563,9 +569,9 @@ std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& na
if (file_ref != nullptr) {
file_ref->file = files_->FindFile(*file_ref->path);
if (file_ref->file == nullptr) {
- diag_->Warn(DiagMessage() << "resource " << name << " for config '" << config
- << "' is a file reference to '" << *file_ref->path
- << "' but no such path exists");
+ diag_->Warn(android::DiagMessage() << "resource " << name << " for config '" << config
+ << "' is a file reference to '" << *file_ref->path
+ << "' but no such path exists");
}
}
}
@@ -594,8 +600,8 @@ std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef
// We can ignore the value here.
return util::make_unique<Id>();
default:
- diag_->Error(DiagMessage() << "illegal map type '" << name.type << "' ("
- << (int)name.type.type << ")");
+ diag_->Error(android::DiagMessage()
+ << "illegal map type '" << name.type << "' (" << (int)name.type.type << ")");
break;
}
return {};
@@ -605,18 +611,18 @@ std::unique_ptr<Style> BinaryResourceParser::ParseStyle(const ResourceNameRef& n
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Style> style = util::make_unique<Style>();
- if (util::DeviceToHost32(map->parent.ident) != 0) {
+ if (android::util::DeviceToHost32(map->parent.ident) != 0) {
// The parent is a regular reference to a resource.
- style->parent = Reference(util::DeviceToHost32(map->parent.ident));
+ style->parent = Reference(android::util::DeviceToHost32(map->parent.ident));
}
for (const ResTable_map& map_entry : map) {
- if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
+ if (Res_INTERNALID(android::util::DeviceToHost32(map_entry.name.ident))) {
continue;
}
Style::Entry style_entry;
- style_entry.key = Reference(util::DeviceToHost32(map_entry.name.ident));
+ style_entry.key = Reference(android::util::DeviceToHost32(map_entry.name.ident));
style_entry.value = ParseValue(name, config, map_entry.value);
if (!style_entry.value) {
return {};
@@ -630,20 +636,20 @@ std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef
const ConfigDescription& config,
const ResTable_map_entry* map) {
std::unique_ptr<Attribute> attr = util::make_unique<Attribute>();
- attr->SetWeak((util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0);
+ attr->SetWeak((android::util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0);
// First we must discover what type of attribute this is. Find the type mask.
auto type_mask_iter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
- return util::DeviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE;
+ return android::util::DeviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE;
});
if (type_mask_iter != end(map)) {
- attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
+ attr->type_mask = android::util::DeviceToHost32(type_mask_iter->value.data);
}
for (const ResTable_map& map_entry : map) {
- if (Res_INTERNALID(util::DeviceToHost32(map_entry.name.ident))) {
- switch (util::DeviceToHost32(map_entry.name.ident)) {
+ if (Res_INTERNALID(android::util::DeviceToHost32(map_entry.name.ident))) {
+ switch (android::util::DeviceToHost32(map_entry.name.ident)) {
case ResTable_map::ATTR_MIN:
attr->min_int = static_cast<int32_t>(map_entry.value.data);
break;
@@ -656,9 +662,9 @@ std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef
if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Attribute::Symbol symbol;
- symbol.value = util::DeviceToHost32(map_entry.value.data);
+ symbol.value = android::util::DeviceToHost32(map_entry.value.data);
symbol.type = map_entry.value.dataType;
- symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
+ symbol.symbol = Reference(android::util::DeviceToHost32(map_entry.name.ident));
attr->symbols.push_back(std::move(symbol));
}
}
@@ -687,7 +693,7 @@ std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(const ResourceNameRef&
return {};
}
- switch (util::DeviceToHost32(map_entry.name.ident)) {
+ switch (android::util::DeviceToHost32(map_entry.name.ident)) {
case ResTable_map::ATTR_ZERO:
plural->values[Plural::Zero] = std::move(item);
break;
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index 1c83166c5cce..8f6949e7e630 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -19,13 +19,13 @@
#include <string>
+#include "ResourceTable.h"
+#include "ResourceValues.h"
#include "android-base/macros.h"
#include "androidfw/ConfigDescription.h"
#include "androidfw/ResourceTypes.h"
-
-#include "ResourceTable.h"
-#include "ResourceValues.h"
-#include "Source.h"
+#include "androidfw/Source.h"
+#include "androidfw/Util.h"
#include "process/IResourceTableConsumer.h"
#include "util/Util.h"
@@ -40,8 +40,9 @@ class BinaryResourceParser {
public:
// Creates a parser, which will read `len` bytes from `data`, and add any resources parsed to
// `table`. `source` is for logging purposes.
- BinaryResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
- const void* data, size_t data_len, io::IFileCollection* files = nullptr);
+ BinaryResourceParser(android::IDiagnostics* diag, ResourceTable* table,
+ const android::Source& source, const void* data, size_t data_len,
+ io::IFileCollection* files = nullptr);
// Parses the binary resource table and returns true if successful.
bool Parse();
@@ -91,10 +92,10 @@ class BinaryResourceParser {
*/
bool CollectMetaData(const android::ResTable_map& map_entry, Value* value);
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
ResourceTable* table_;
- const Source source_;
+ const android::Source source_;
const void* data_;
const size_t data_len_;
@@ -132,11 +133,11 @@ namespace android {
// Iterator functionality for ResTable_map_entry.
inline const ResTable_map* begin(const ResTable_map_entry* map) {
- return (const ResTable_map*)((const uint8_t*)map + ::aapt::util::DeviceToHost32(map->size));
+ return (const ResTable_map*)((const uint8_t*)map + android::util::DeviceToHost32(map->size));
}
inline const ResTable_map* end(const ResTable_map_entry* map) {
- return begin(map) + aapt::util::DeviceToHost32(map->count);
+ return begin(map) + android::util::DeviceToHost32(map->count);
}
} // namespace android
diff --git a/tools/aapt2/format/binary/ChunkWriter.h b/tools/aapt2/format/binary/ChunkWriter.h
index 1892a295dcf5..e1a403476ff8 100644
--- a/tools/aapt2/format/binary/ChunkWriter.h
+++ b/tools/aapt2/format/binary/ChunkWriter.h
@@ -18,16 +18,15 @@
#define AAPT_FORMAT_BINARY_CHUNKWRITER_H
#include "android-base/macros.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
-
-#include "util/BigBuffer.h"
#include "util/Util.h"
namespace aapt {
class ChunkWriter {
public:
- explicit inline ChunkWriter(BigBuffer* buffer) : buffer_(buffer) {
+ explicit inline ChunkWriter(android::BigBuffer* buffer) : buffer_(buffer) {
}
ChunkWriter(ChunkWriter&&) = default;
ChunkWriter& operator=(ChunkWriter&&) = default;
@@ -37,8 +36,8 @@ class ChunkWriter {
start_size_ = buffer_->size();
T* chunk = buffer_->NextBlock<T>();
header_ = &chunk->header;
- header_->type = util::HostToDevice16(type);
- header_->headerSize = util::HostToDevice16(sizeof(T));
+ header_->type = android::util::HostToDevice16(type);
+ header_->headerSize = android::util::HostToDevice16(sizeof(T));
return chunk;
}
@@ -47,7 +46,7 @@ class ChunkWriter {
return buffer_->NextBlock<T>(count);
}
- inline BigBuffer* buffer() {
+ inline android::BigBuffer* buffer() {
return buffer_;
}
@@ -61,14 +60,14 @@ class ChunkWriter {
inline android::ResChunk_header* Finish() {
buffer_->Align4();
- header_->size = util::HostToDevice32(buffer_->size() - start_size_);
+ header_->size = android::util::HostToDevice32(buffer_->size() - start_size_);
return header_;
}
private:
DISALLOW_COPY_AND_ASSIGN(ChunkWriter);
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
size_t start_size_ = 0;
android::ResChunk_header* header_ = nullptr;
};
@@ -77,8 +76,8 @@ template <>
inline android::ResChunk_header* ChunkWriter::StartChunk(uint16_t type) {
start_size_ = buffer_->size();
header_ = buffer_->NextBlock<android::ResChunk_header>();
- header_->type = util::HostToDevice16(type);
- header_->headerSize = util::HostToDevice16(sizeof(android::ResChunk_header));
+ header_->type = android::util::HostToDevice16(type);
+ header_->headerSize = android::util::HostToDevice16(sizeof(android::ResChunk_header));
return header_;
}
diff --git a/tools/aapt2/format/binary/ResChunkPullParser.cpp b/tools/aapt2/format/binary/ResChunkPullParser.cpp
index fd6919d1de60..2f3df5cae829 100644
--- a/tools/aapt2/format/binary/ResChunkPullParser.cpp
+++ b/tools/aapt2/format/binary/ResChunkPullParser.cpp
@@ -17,12 +17,13 @@
#include "format/binary/ResChunkPullParser.h"
#include <inttypes.h>
+
#include <cstddef>
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
-
+#include "androidfw/Util.h"
#include "util/Util.h"
namespace aapt {
@@ -32,8 +33,9 @@ using android::base::StringPrintf;
static std::string ChunkHeaderDump(const ResChunk_header* header) {
return StringPrintf("(type=%02" PRIx16 " header_size=%" PRIu16 " size=%" PRIu32 ")",
- util::DeviceToHost16(header->type), util::DeviceToHost16(header->headerSize),
- util::DeviceToHost32(header->size));
+ android::util::DeviceToHost16(header->type),
+ android::util::DeviceToHost16(header->headerSize),
+ android::util::DeviceToHost32(header->size));
}
ResChunkPullParser::Event ResChunkPullParser::Next() {
@@ -45,7 +47,7 @@ ResChunkPullParser::Event ResChunkPullParser::Next() {
current_chunk_ = data_;
} else {
current_chunk_ = (const ResChunk_header*)(((const char*)current_chunk_) +
- util::DeviceToHost32(current_chunk_->size));
+ android::util::DeviceToHost32(current_chunk_->size));
}
const std::ptrdiff_t diff = (const char*)current_chunk_ - (const char*)data_;
@@ -61,16 +63,16 @@ ResChunkPullParser::Event ResChunkPullParser::Next() {
return (event_ = Event::kBadDocument);
}
- if (util::DeviceToHost16(current_chunk_->headerSize) < sizeof(ResChunk_header)) {
+ if (android::util::DeviceToHost16(current_chunk_->headerSize) < sizeof(ResChunk_header)) {
error_ = "chunk has too small header";
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
- } else if (util::DeviceToHost32(current_chunk_->size) <
- util::DeviceToHost16(current_chunk_->headerSize)) {
+ } else if (android::util::DeviceToHost32(current_chunk_->size) <
+ android::util::DeviceToHost16(current_chunk_->headerSize)) {
error_ = "chunk's total size is smaller than header " + ChunkHeaderDump(current_chunk_);
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
- } else if (offset + util::DeviceToHost32(current_chunk_->size) > len_) {
+ } else if (offset + android::util::DeviceToHost32(current_chunk_->size) > len_) {
error_ = "chunk's data extends past the end of the document " + ChunkHeaderDump(current_chunk_);
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
diff --git a/tools/aapt2/format/binary/ResChunkPullParser.h b/tools/aapt2/format/binary/ResChunkPullParser.h
index 5ff13598a31d..0f46db1876fb 100644
--- a/tools/aapt2/format/binary/ResChunkPullParser.h
+++ b/tools/aapt2/format/binary/ResChunkPullParser.h
@@ -21,7 +21,7 @@
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
-
+#include "androidfw/Util.h"
#include "util/Util.h"
namespace aapt {
@@ -69,18 +69,19 @@ class ResChunkPullParser {
template <typename T, size_t MinSize = sizeof(T)>
inline static const T* ConvertTo(const android::ResChunk_header* chunk) {
- if (util::DeviceToHost16(chunk->headerSize) < MinSize) {
+ if (android::util::DeviceToHost16(chunk->headerSize) < MinSize) {
return nullptr;
}
return reinterpret_cast<const T*>(chunk);
}
inline static const uint8_t* GetChunkData(const android::ResChunk_header* chunk) {
- return reinterpret_cast<const uint8_t*>(chunk) + util::DeviceToHost16(chunk->headerSize);
+ return reinterpret_cast<const uint8_t*>(chunk) + android::util::DeviceToHost16(chunk->headerSize);
}
inline static uint32_t GetChunkDataLen(const android::ResChunk_header* chunk) {
- return util::DeviceToHost32(chunk->size) - util::DeviceToHost16(chunk->headerSize);
+ return android::util::DeviceToHost32(chunk->size) -
+ android::util::DeviceToHost16(chunk->headerSize);
}
//
diff --git a/tools/aapt2/format/binary/ResEntryWriter.cpp b/tools/aapt2/format/binary/ResEntryWriter.cpp
new file mode 100644
index 000000000000..9dc205f4c1ba
--- /dev/null
+++ b/tools/aapt2/format/binary/ResEntryWriter.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "format/binary/ResEntryWriter.h"
+
+#include "ValueVisitor.h"
+#include "androidfw/BigBuffer.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/Util.h"
+#include "format/binary/ResourceTypeExtensions.h"
+
+namespace aapt {
+
+struct less_style_entries {
+ bool operator()(const Style::Entry* a, const Style::Entry* b) const {
+ if (a->key.id) {
+ if (b->key.id) {
+ return cmp_ids_dynamic_after_framework(a->key.id.value(), b->key.id.value());
+ }
+ return true;
+ }
+ if (!b->key.id) {
+ return a->key.name.value() < b->key.name.value();
+ }
+ return false;
+ }
+};
+
+class MapFlattenVisitor : public ConstValueVisitor {
+ public:
+ using ConstValueVisitor::Visit;
+
+ MapFlattenVisitor(ResTable_entry_ext* out_entry, BigBuffer* buffer)
+ : out_entry_(out_entry), buffer_(buffer) {
+ }
+
+ void Visit(const Attribute* attr) override {
+ {
+ Reference key = Reference(ResourceId(ResTable_map::ATTR_TYPE));
+ BinaryPrimitive val(Res_value::TYPE_INT_DEC, attr->type_mask);
+ FlattenEntry(&key, &val);
+ }
+
+ if (attr->min_int != std::numeric_limits<int32_t>::min()) {
+ Reference key = Reference(ResourceId(ResTable_map::ATTR_MIN));
+ BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->min_int));
+ FlattenEntry(&key, &val);
+ }
+
+ if (attr->max_int != std::numeric_limits<int32_t>::max()) {
+ Reference key = Reference(ResourceId(ResTable_map::ATTR_MAX));
+ BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->max_int));
+ FlattenEntry(&key, &val);
+ }
+
+ for (const Attribute::Symbol& s : attr->symbols) {
+ BinaryPrimitive val(s.type, s.value);
+ FlattenEntry(&s.symbol, &val);
+ }
+ }
+
+ void Visit(const Style* style) override {
+ if (style->parent) {
+ const Reference& parent_ref = style->parent.value();
+ CHECK(bool(parent_ref.id)) << "parent has no ID";
+ out_entry_->parent.ident = android::util::HostToDevice32(parent_ref.id.value().id);
+ }
+
+ // Sort the style.
+ std::vector<const Style::Entry*> sorted_entries;
+ for (const auto& entry : style->entries) {
+ sorted_entries.emplace_back(&entry);
+ }
+
+ std::sort(sorted_entries.begin(), sorted_entries.end(), less_style_entries());
+
+ for (const Style::Entry* entry : sorted_entries) {
+ FlattenEntry(&entry->key, entry->value.get());
+ }
+ }
+
+ void Visit(const Styleable* styleable) override {
+ for (auto& attr_ref : styleable->entries) {
+ BinaryPrimitive val(Res_value{});
+ FlattenEntry(&attr_ref, &val);
+ }
+ }
+
+ void Visit(const Array* array) override {
+ const size_t count = array->elements.size();
+ for (size_t i = 0; i < count; i++) {
+ Reference key(android::ResTable_map::ATTR_MIN + i);
+ FlattenEntry(&key, array->elements[i].get());
+ }
+ }
+
+ void Visit(const Plural* plural) override {
+ const size_t count = plural->values.size();
+ for (size_t i = 0; i < count; i++) {
+ if (!plural->values[i]) {
+ continue;
+ }
+
+ ResourceId q;
+ switch (i) {
+ case Plural::Zero:
+ q.id = android::ResTable_map::ATTR_ZERO;
+ break;
+
+ case Plural::One:
+ q.id = android::ResTable_map::ATTR_ONE;
+ break;
+
+ case Plural::Two:
+ q.id = android::ResTable_map::ATTR_TWO;
+ break;
+
+ case Plural::Few:
+ q.id = android::ResTable_map::ATTR_FEW;
+ break;
+
+ case Plural::Many:
+ q.id = android::ResTable_map::ATTR_MANY;
+ break;
+
+ case Plural::Other:
+ q.id = android::ResTable_map::ATTR_OTHER;
+ break;
+
+ default:
+ LOG(FATAL) << "unhandled plural type";
+ break;
+ }
+
+ Reference key(q);
+ FlattenEntry(&key, plural->values[i].get());
+ }
+ }
+
+ /**
+ * Call this after visiting a Value. This will finish any work that
+ * needs to be done to prepare the entry.
+ */
+ void Finish() {
+ out_entry_->count = android::util::HostToDevice32(entry_count_);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MapFlattenVisitor);
+
+ void FlattenKey(const Reference* key, ResTable_map* out_entry) {
+ CHECK(bool(key->id)) << "key has no ID";
+ out_entry->name.ident = android::util::HostToDevice32(key->id.value().id);
+ }
+
+ void FlattenValue(const Item* value, ResTable_map* out_entry) {
+ CHECK(value->Flatten(&out_entry->value)) << "flatten failed";
+ }
+
+ void FlattenEntry(const Reference* key, Item* value) {
+ ResTable_map* out_entry = buffer_->NextBlock<ResTable_map>();
+ FlattenKey(key, out_entry);
+ FlattenValue(value, out_entry);
+ out_entry->value.size = android::util::HostToDevice16(sizeof(out_entry->value));
+ entry_count_++;
+ }
+
+ ResTable_entry_ext* out_entry_;
+ BigBuffer* buffer_;
+ size_t entry_count_ = 0;
+};
+
+template <typename T>
+void WriteEntry(const FlatEntry* entry, T* out_result, bool compact = false) {
+ static_assert(std::is_same_v<ResTable_entry, T> || std::is_same_v<ResTable_entry_ext, T>,
+ "T must be ResTable_entry or ResTable_entry_ext");
+
+ ResTable_entry* out_entry = (ResTable_entry*)out_result;
+ uint16_t flags = 0;
+
+ if (entry->entry->visibility.level == Visibility::Level::kPublic) {
+ flags |= ResTable_entry::FLAG_PUBLIC;
+ }
+
+ if (entry->value->IsWeak()) {
+ flags |= ResTable_entry::FLAG_WEAK;
+ }
+
+ if constexpr (std::is_same_v<ResTable_entry_ext, T>) {
+ flags |= ResTable_entry::FLAG_COMPLEX;
+ }
+
+ if (!compact) {
+ out_entry->full.flags = android::util::HostToDevice16(flags);
+ out_entry->full.key.index = android::util::HostToDevice32(entry->entry_key);
+ out_entry->full.size = android::util::HostToDevice16(sizeof(T));
+ } else {
+ Res_value value;
+ CHECK(entry->entry_key < 0xffffu) << "cannot encode key in 16-bit";
+ CHECK(compact && (std::is_same_v<ResTable_entry, T>)) << "cannot encode complex entry";
+ CHECK(ValueCast<Item>(entry->value)->Flatten(&value)) << "flatten failed";
+
+ flags |= ResTable_entry::FLAG_COMPACT | (value.dataType << 8);
+ out_entry->compact.flags = android::util::HostToDevice16(flags);
+ out_entry->compact.key = android::util::HostToDevice16(entry->entry_key);
+ out_entry->compact.data = value.data;
+ }
+}
+
+int32_t WriteMapToBuffer(const FlatEntry* map_entry, BigBuffer* buffer) {
+ int32_t offset = buffer->size();
+ ResTable_entry_ext* out_entry = buffer->NextBlock<ResTable_entry_ext>();
+ WriteEntry<ResTable_entry_ext>(map_entry, out_entry);
+
+ MapFlattenVisitor visitor(out_entry, buffer);
+ map_entry->value->Accept(&visitor);
+ visitor.Finish();
+ return offset;
+}
+
+template <bool compact_entry, typename T>
+std::pair<int32_t, T*> WriteItemToBuffer(const FlatEntry* item_entry, BigBuffer* buffer) {
+ int32_t offset = buffer->size();
+ T* out_entry = buffer->NextBlock<T>();
+
+ if constexpr (compact_entry) {
+ WriteEntry(item_entry, out_entry, true);
+ } else {
+ WriteEntry(item_entry, &out_entry->entry);
+ CHECK(ValueCast<Item>(item_entry->value)->Flatten(&out_entry->value)) << "flatten failed";
+ out_entry->value.size = android::util::HostToDevice16(sizeof(out_entry->value));
+ }
+ return {offset, out_entry};
+}
+
+// explicitly specialize both versions
+template std::pair<int32_t, ResEntryValue<false>*> WriteItemToBuffer<false>(
+ const FlatEntry* item_entry, BigBuffer* buffer);
+
+template std::pair<int32_t, ResEntryValue<true>*> WriteItemToBuffer<true>(
+ const FlatEntry* item_entry, BigBuffer* buffer);
+
+} // namespace aapt
diff --git a/tools/aapt2/format/binary/ResEntryWriter.h b/tools/aapt2/format/binary/ResEntryWriter.h
new file mode 100644
index 000000000000..c11598ec12f7
--- /dev/null
+++ b/tools/aapt2/format/binary/ResEntryWriter.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_FORMAT_BINARY_RESENTRY_SERIALIZER_H
+#define AAPT_FORMAT_BINARY_RESENTRY_SERIALIZER_H
+
+#include <unordered_map>
+
+#include "ResourceTable.h"
+#include "ValueVisitor.h"
+#include "android-base/macros.h"
+#include "androidfw/BigBuffer.h"
+#include "androidfw/ResourceTypes.h"
+
+namespace aapt {
+
+using android::BigBuffer;
+using android::Res_value;
+using android::ResTable_entry;
+using android::ResTable_map;
+
+struct FlatEntry {
+ const ResourceTableEntryView* entry;
+ const Value* value;
+
+ // The entry string pool index to the entry's name.
+ uint32_t entry_key;
+};
+
+// Pair of ResTable_entry and Res_value. These pairs are stored sequentially in values buffer.
+// We introduce this structure for ResEntryWriter to a have single allocation using
+// BigBuffer::NextBlock which allows to return it back with BigBuffer::Backup.
+struct ResEntryValuePair {
+ ResTable_entry entry;
+ Res_value value;
+};
+
+static_assert(sizeof(ResEntryValuePair) == sizeof(ResTable_entry) + sizeof(Res_value),
+ "ResEntryValuePair must not have padding between entry and value.");
+
+template <bool compact>
+using ResEntryValue = std::conditional_t<compact, ResTable_entry, ResEntryValuePair>;
+
+// References ResEntryValue object stored in BigBuffer used as a key in std::unordered_map.
+// Allows access to memory address where ResEntryValue is stored.
+template <bool compact>
+union ResEntryValueRef {
+ using T = ResEntryValue<compact>;
+ const std::reference_wrapper<const T> ref;
+ const u_char* ptr;
+
+ explicit ResEntryValueRef(const T& rev) : ref(rev) {
+ }
+};
+
+// Hasher which computes hash of ResEntryValue using its bytes representation in memory.
+struct ResEntryValueContentHasher {
+ template <typename R>
+ std::size_t operator()(const R& ref) const {
+ return android::JenkinsHashMixBytes(0, ref.ptr, sizeof(typename R::T));
+ }
+};
+
+// Equaler which compares ResEntryValuePairs using theirs bytes representation in memory.
+struct ResEntryValueContentEqualTo {
+ template <typename R>
+ bool operator()(const R& a, const R& b) const {
+ return std::memcmp(a.ptr, b.ptr, sizeof(typename R::T)) == 0;
+ }
+};
+
+// Base class that allows to write FlatEntries into entries_buffer.
+class ResEntryWriter {
+ public:
+ virtual ~ResEntryWriter() = default;
+
+ // Writes resource table entry and its value into 'entries_buffer_' and returns offset
+ // in the buffer where entry was written.
+ int32_t Write(const FlatEntry* entry) {
+ if (ValueCast<Item>(entry->value) != nullptr) {
+ return WriteItem(entry);
+ } else {
+ return WriteMap(entry);
+ }
+ }
+
+ protected:
+ ResEntryWriter(BigBuffer* entries_buffer) : entries_buffer_(entries_buffer) {
+ }
+ BigBuffer* entries_buffer_;
+
+ virtual int32_t WriteItem(const FlatEntry* entry) = 0;
+
+ virtual int32_t WriteMap(const FlatEntry* entry) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResEntryWriter);
+};
+
+int32_t WriteMapToBuffer(const FlatEntry* map_entry, BigBuffer* buffer);
+
+template <bool compact_entry, typename T=ResEntryValue<compact_entry>>
+std::pair<int32_t, T*> WriteItemToBuffer(const FlatEntry* item_entry, BigBuffer* buffer);
+
+// ResEntryWriter which writes FlatEntries sequentially into entries_buffer.
+// Next entry is always written right after previous one in the buffer.
+template <bool compact_entry = false>
+class SequentialResEntryWriter : public ResEntryWriter {
+ public:
+ explicit SequentialResEntryWriter(BigBuffer* entries_buffer)
+ : ResEntryWriter(entries_buffer) {
+ }
+ ~SequentialResEntryWriter() override = default;
+
+ int32_t WriteItem(const FlatEntry* entry) override {
+ auto result = WriteItemToBuffer<compact_entry>(entry, entries_buffer_);
+ return result.first;
+ }
+
+ int32_t WriteMap(const FlatEntry* entry) override {
+ return WriteMapToBuffer(entry, entries_buffer_);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SequentialResEntryWriter);
+};
+
+// ResEntryWriter that writes only unique entry and value pairs into entries_buffer.
+// Next entry is written into buffer only if there is no entry with the same bytes representation
+// in memory written before. Otherwise returns offset of already written entry.
+template <bool compact_entry = false>
+class DeduplicateItemsResEntryWriter : public ResEntryWriter {
+ public:
+ explicit DeduplicateItemsResEntryWriter(BigBuffer* entries_buffer)
+ : ResEntryWriter(entries_buffer) {
+ }
+ ~DeduplicateItemsResEntryWriter() override = default;
+
+ int32_t WriteItem(const FlatEntry* entry) override {
+ const auto& [offset, out_entry] = WriteItemToBuffer<compact_entry>(entry, entries_buffer_);
+
+ auto [it, inserted] = entry_offsets.insert({Ref{*out_entry}, offset});
+ if (inserted) {
+ // If inserted just return a new offset as this is a first time we store
+ // this entry
+ return offset;
+ }
+
+ // If not inserted this means that this is a duplicate, backup allocated block to the buffer
+ // and return offset of previously stored entry
+ entries_buffer_->BackUp(sizeof(*out_entry));
+ return it->second;
+ }
+
+ int32_t WriteMap(const FlatEntry* entry) override {
+ return WriteMapToBuffer(entry, entries_buffer_);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DeduplicateItemsResEntryWriter);
+
+ using Ref = ResEntryValueRef<compact_entry>;
+ using Map = std::unordered_map<Ref, int32_t,
+ ResEntryValueContentHasher,
+ ResEntryValueContentEqualTo>;
+ Map entry_offsets;
+};
+
+} // namespace aapt
+
+#endif
diff --git a/tools/aapt2/format/binary/ResEntryWriter_test.cpp b/tools/aapt2/format/binary/ResEntryWriter_test.cpp
new file mode 100644
index 000000000000..4cb17c33e64a
--- /dev/null
+++ b/tools/aapt2/format/binary/ResEntryWriter_test.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "format/binary/ResEntryWriter.h"
+
+#include "androidfw/BigBuffer.h"
+#include "format/binary/ResourceTypeExtensions.h"
+#include "test/Test.h"
+#include "util/Util.h"
+
+using ::android::BigBuffer;
+using ::android::Res_value;
+using ::android::ResTable_map;
+using ::testing::Eq;
+using ::testing::Ge;
+using ::testing::IsNull;
+using ::testing::Ne;
+using ::testing::NotNull;
+
+namespace aapt {
+
+using SequentialResEntryWriterTest = CommandTestFixture;
+using DeduplicateItemsResEntryWriterTest = CommandTestFixture;
+
+std::vector<int32_t> WriteAllEntries(const ResourceTableView& table, ResEntryWriter& writer) {
+ std::vector<int32_t> result = {};
+ for (const auto& type : table.packages[0].types) {
+ for (const auto& entry : type.entries) {
+ for (const auto& value : entry.values) {
+ auto flat_entry = FlatEntry{&entry, value->value.get(), 0};
+ result.push_back(writer.Write(&flat_entry));
+ }
+ }
+ }
+ return result;
+}
+
+TEST_F(SequentialResEntryWriterTest, WriteEntriesOneByOne) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/id1", ResourceId(0x7f010000))
+ .AddSimple("com.app.test:id/id2", ResourceId(0x7f010001))
+ .AddSimple("com.app.test:id/id3", ResourceId(0x7f010002))
+ .Build();
+
+ {
+ BigBuffer out(512);
+ SequentialResEntryWriter<false> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, sizeof(ResEntryValuePair),
+ 2 * sizeof(ResEntryValuePair)};
+ EXPECT_EQ(out.size(), 3 * sizeof(ResEntryValuePair));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+
+ {
+ /* expect a compact entry to only take sizeof(ResTable_entry) */
+ BigBuffer out(512);
+ SequentialResEntryWriter<true> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry),
+ 2 * sizeof(ResTable_entry)};
+ EXPECT_EQ(out.size(), 3 * sizeof(ResTable_entry));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+};
+
+TEST_F(SequentialResEntryWriterTest, WriteMapEntriesOneByOne) {
+ std::unique_ptr<Array> array1 = util::make_unique<Array>();
+ array1->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
+ array1->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
+ std::unique_ptr<Array> array2 = util::make_unique<Array>();
+ array2->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
+ array2->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
+
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .AddValue("com.app.test:array/arr1", std::move(array1))
+ .AddValue("com.app.test:array/arr2", std::move(array2))
+ .Build();
+
+ {
+ BigBuffer out(512);
+ SequentialResEntryWriter<false> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
+ EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+
+ {
+ /* compact_entry should have no impact to map items */
+ BigBuffer out(512);
+ SequentialResEntryWriter<true> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
+ EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+};
+
+TEST_F(DeduplicateItemsResEntryWriterTest, DeduplicateItemEntries) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/id1", ResourceId(0x7f010000))
+ .AddSimple("com.app.test:id/id2", ResourceId(0x7f010001))
+ .AddSimple("com.app.test:id/id3", ResourceId(0x7f010002))
+ .Build();
+
+ {
+ BigBuffer out(512);
+ DeduplicateItemsResEntryWriter<false> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, 0, 0};
+ EXPECT_EQ(out.size(), sizeof(ResEntryValuePair));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+
+ {
+ /* expect a compact entry to only take sizeof(ResTable_entry) */
+ BigBuffer out(512);
+ DeduplicateItemsResEntryWriter<true> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, 0, 0};
+ EXPECT_EQ(out.size(), sizeof(ResTable_entry));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+};
+
+TEST_F(DeduplicateItemsResEntryWriterTest, WriteMapEntriesOneByOne) {
+ std::unique_ptr<Array> array1 = util::make_unique<Array>();
+ array1->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
+ array1->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
+ std::unique_ptr<Array> array2 = util::make_unique<Array>();
+ array2->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
+ array2->elements.push_back(
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
+
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .AddValue("com.app.test:array/arr1", std::move(array1))
+ .AddValue("com.app.test:array/arr2", std::move(array2))
+ .Build();
+
+ {
+ BigBuffer out(512);
+ DeduplicateItemsResEntryWriter<false> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
+ EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+
+ {
+ /* compact_entry should have no impact to map items */
+ BigBuffer out(512);
+ DeduplicateItemsResEntryWriter<true> writer(&out);
+ auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
+
+ std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
+ EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
+ EXPECT_EQ(offsets, expected_offsets);
+ }
+ };
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index a9192e889c17..8c594ba553a0 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -16,24 +16,24 @@
#include "format/binary/TableFlattener.h"
-#include <algorithm>
-#include <numeric>
+#include <limits>
#include <sstream>
#include <type_traits>
+#include <variant>
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "SdkConstants.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceUtils.h"
-
-#include "ResourceTable.h"
-#include "ResourceValues.h"
-#include "SdkConstants.h"
-#include "ValueVisitor.h"
#include "format/binary/ChunkWriter.h"
+#include "format/binary/ResEntryWriter.h"
#include "format/binary/ResourceTypeExtensions.h"
+#include "optimize/Obfuscator.h"
#include "trace/TraceBuffer.h"
-#include "util/BigBuffer.h"
using namespace android;
@@ -54,225 +54,68 @@ static void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) {
size_t i;
const char16_t* src_data = src.data();
for (i = 0; i < len - 1 && i < src.size(); i++) {
- dst[i] = util::HostToDevice16((uint16_t)src_data[i]);
+ dst[i] = android::util::HostToDevice16((uint16_t)src_data[i]);
}
dst[i] = 0;
}
-static bool cmp_style_entries(const Style::Entry* a, const Style::Entry* b) {
- if (a->key.id) {
- if (b->key.id) {
- return cmp_ids_dynamic_after_framework(a->key.id.value(), b->key.id.value());
- }
- return true;
- } else if (!b->key.id) {
- return a->key.name.value() < b->key.name.value();
- }
- return false;
-}
-
-struct FlatEntry {
- const ResourceTableEntryView* entry;
- const Value* value;
-
- // The entry string pool index to the entry's name.
- uint32_t entry_key;
-};
-
-class MapFlattenVisitor : public ConstValueVisitor {
- public:
- using ConstValueVisitor::Visit;
-
- MapFlattenVisitor(ResTable_entry_ext* out_entry, BigBuffer* buffer)
- : out_entry_(out_entry), buffer_(buffer) {
- }
-
- void Visit(const Attribute* attr) override {
- {
- Reference key = Reference(ResourceId(ResTable_map::ATTR_TYPE));
- BinaryPrimitive val(Res_value::TYPE_INT_DEC, attr->type_mask);
- FlattenEntry(&key, &val);
- }
-
- if (attr->min_int != std::numeric_limits<int32_t>::min()) {
- Reference key = Reference(ResourceId(ResTable_map::ATTR_MIN));
- BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->min_int));
- FlattenEntry(&key, &val);
- }
-
- if (attr->max_int != std::numeric_limits<int32_t>::max()) {
- Reference key = Reference(ResourceId(ResTable_map::ATTR_MAX));
- BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->max_int));
- FlattenEntry(&key, &val);
- }
-
- for (const Attribute::Symbol& s : attr->symbols) {
- BinaryPrimitive val(s.type, s.value);
- FlattenEntry(&s.symbol, &val);
- }
- }
-
- void Visit(const Style* style) override {
- if (style->parent) {
- const Reference& parent_ref = style->parent.value();
- CHECK(bool(parent_ref.id)) << "parent has no ID";
- out_entry_->parent.ident = util::HostToDevice32(parent_ref.id.value().id);
- }
-
- // Sort the style.
- std::vector<const Style::Entry*> sorted_entries;
- for (const auto& entry : style->entries) {
- sorted_entries.emplace_back(&entry);
- }
-
- std::sort(sorted_entries.begin(), sorted_entries.end(), cmp_style_entries);
-
- for (const Style::Entry* entry : sorted_entries) {
- FlattenEntry(&entry->key, entry->value.get());
- }
- }
-
- void Visit(const Styleable* styleable) override {
- for (auto& attr_ref : styleable->entries) {
- BinaryPrimitive val(Res_value{});
- FlattenEntry(&attr_ref, &val);
- }
- }
-
- void Visit(const Array* array) override {
- const size_t count = array->elements.size();
- for (size_t i = 0; i < count; i++) {
- Reference key(android::ResTable_map::ATTR_MIN + i);
- FlattenEntry(&key, array->elements[i].get());
- }
- }
-
- void Visit(const Plural* plural) override {
- const size_t count = plural->values.size();
- for (size_t i = 0; i < count; i++) {
- if (!plural->values[i]) {
- continue;
- }
-
- ResourceId q;
- switch (i) {
- case Plural::Zero:
- q.id = android::ResTable_map::ATTR_ZERO;
- break;
-
- case Plural::One:
- q.id = android::ResTable_map::ATTR_ONE;
- break;
-
- case Plural::Two:
- q.id = android::ResTable_map::ATTR_TWO;
- break;
-
- case Plural::Few:
- q.id = android::ResTable_map::ATTR_FEW;
- break;
-
- case Plural::Many:
- q.id = android::ResTable_map::ATTR_MANY;
- break;
-
- case Plural::Other:
- q.id = android::ResTable_map::ATTR_OTHER;
- break;
-
- default:
- LOG(FATAL) << "unhandled plural type";
- break;
- }
-
- Reference key(q);
- FlattenEntry(&key, plural->values[i].get());
- }
- }
-
- /**
- * Call this after visiting a Value. This will finish any work that
- * needs to be done to prepare the entry.
- */
- void Finish() {
- out_entry_->count = util::HostToDevice32(entry_count_);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MapFlattenVisitor);
-
- void FlattenKey(const Reference* key, ResTable_map* out_entry) {
- CHECK(bool(key->id)) << "key has no ID";
- out_entry->name.ident = util::HostToDevice32(key->id.value().id);
- }
-
- void FlattenValue(const Item* value, ResTable_map* out_entry) {
- CHECK(value->Flatten(&out_entry->value)) << "flatten failed";
- }
-
- void FlattenEntry(const Reference* key, Item* value) {
- ResTable_map* out_entry = buffer_->NextBlock<ResTable_map>();
- FlattenKey(key, out_entry);
- FlattenValue(value, out_entry);
- out_entry->value.size = util::HostToDevice16(sizeof(out_entry->value));
- entry_count_++;
- }
-
- ResTable_entry_ext* out_entry_;
- BigBuffer* buffer_;
- size_t entry_count_ = 0;
-};
-
struct OverlayableChunk {
std::string actor;
- Source source;
+ android::Source source;
std::map<PolicyFlags, std::set<ResourceId>> policy_ids;
};
class PackageFlattener {
public:
PackageFlattener(IAaptContext* context, const ResourceTablePackageView& package,
- const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries,
+ const std::map<size_t, std::string>* shared_libs,
+ SparseEntriesMode sparse_entries,
+ bool compact_entries,
bool collapse_key_stringpool,
- const std::set<ResourceName>& name_collapse_exemptions)
+ const std::set<ResourceName>& name_collapse_exemptions,
+ bool deduplicate_entry_values)
: context_(context),
diag_(context->GetDiagnostics()),
package_(package),
shared_libs_(shared_libs),
- use_sparse_entries_(use_sparse_entries),
+ sparse_entries_(sparse_entries),
+ compact_entries_(compact_entries),
collapse_key_stringpool_(collapse_key_stringpool),
- name_collapse_exemptions_(name_collapse_exemptions) {
+ name_collapse_exemptions_(name_collapse_exemptions),
+ deduplicate_entry_values_(deduplicate_entry_values) {
}
bool FlattenPackage(BigBuffer* buffer) {
TRACE_CALL();
ChunkWriter pkg_writer(buffer);
ResTable_package* pkg_header = pkg_writer.StartChunk<ResTable_package>(RES_TABLE_PACKAGE_TYPE);
- pkg_header->id = util::HostToDevice32(package_.id.value());
+ pkg_header->id = android::util::HostToDevice32(package_.id.value());
// AAPT truncated the package name, so do the same.
// Shared libraries require full package names, so don't truncate theirs.
if (context_->GetPackageType() != PackageType::kApp &&
package_.name.size() >= arraysize(pkg_header->name)) {
- diag_->Error(DiagMessage() << "package name '" << package_.name
- << "' is too long. "
- "Shared libraries cannot have truncated package names");
+ diag_->Error(android::DiagMessage()
+ << "package name '" << package_.name
+ << "' is too long. "
+ "Shared libraries cannot have truncated package names");
return false;
}
// Copy the package name in device endianness.
- strcpy16_htod(pkg_header->name, arraysize(pkg_header->name), util::Utf8ToUtf16(package_.name));
+ strcpy16_htod(pkg_header->name, arraysize(pkg_header->name),
+ android::util::Utf8ToUtf16(package_.name));
// Serialize the types. We do this now so that our type and key strings
// are populated. We write those first.
- BigBuffer type_buffer(1024);
+ android::BigBuffer type_buffer(1024);
FlattenTypes(&type_buffer);
- pkg_header->typeStrings = util::HostToDevice32(pkg_writer.size());
- StringPool::FlattenUtf16(pkg_writer.buffer(), type_pool_, diag_);
+ pkg_header->typeStrings = android::util::HostToDevice32(pkg_writer.size());
+ android::StringPool::FlattenUtf16(pkg_writer.buffer(), type_pool_, diag_);
- pkg_header->keyStrings = util::HostToDevice32(pkg_writer.size());
- StringPool::FlattenUtf8(pkg_writer.buffer(), key_pool_, diag_);
+ pkg_header->keyStrings = android::util::HostToDevice32(pkg_writer.size());
+ android::StringPool::FlattenUtf8(pkg_writer.buffer(), key_pool_, diag_);
// Append the types.
buffer->AppendBuffer(std::move(type_buffer));
@@ -297,45 +140,31 @@ class PackageFlattener {
private:
DISALLOW_COPY_AND_ASSIGN(PackageFlattener);
- template <typename T, bool IsItem>
- T* WriteEntry(FlatEntry* entry, BigBuffer* buffer) {
- static_assert(
- std::is_same<ResTable_entry, T>::value || std::is_same<ResTable_entry_ext, T>::value,
- "T must be ResTable_entry or ResTable_entry_ext");
-
- T* result = buffer->NextBlock<T>();
- ResTable_entry* out_entry = (ResTable_entry*)result;
- if (entry->entry->visibility.level == Visibility::Level::kPublic) {
- out_entry->flags |= ResTable_entry::FLAG_PUBLIC;
- }
-
- if (entry->value->IsWeak()) {
- out_entry->flags |= ResTable_entry::FLAG_WEAK;
- }
-
- if (!IsItem) {
- out_entry->flags |= ResTable_entry::FLAG_COMPLEX;
- }
-
- out_entry->flags = util::HostToDevice16(out_entry->flags);
- out_entry->key.index = util::HostToDevice32(entry->entry_key);
- out_entry->size = util::HostToDevice16(sizeof(T));
- return result;
+ // Use compact entries only if
+ // 1) it is enabled, and that
+ // 2) the entries will be accessed on platforms U+, and
+ // 3) all entry keys can be encoded in 16 bits
+ bool UseCompactEntries(const ConfigDescription& config, std::vector<FlatEntry>* entries) const {
+ return compact_entries_ &&
+ (context_->GetMinSdkVersion() > SDK_TIRAMISU || config.sdkVersion > SDK_TIRAMISU) &&
+ std::none_of(entries->cbegin(), entries->cend(),
+ [](const auto& e) { return e.entry_key >= std::numeric_limits<uint16_t>::max(); });
}
- bool FlattenValue(FlatEntry* entry, BigBuffer* buffer) {
- if (const Item* item = ValueCast<Item>(entry->value)) {
- WriteEntry<ResTable_entry, true>(entry, buffer);
- Res_value* outValue = buffer->NextBlock<Res_value>();
- CHECK(item->Flatten(outValue)) << "flatten failed";
- outValue->size = util::HostToDevice16(sizeof(*outValue));
+ std::unique_ptr<ResEntryWriter> GetResEntryWriter(bool dedup, bool compact, BigBuffer* buffer) {
+ if (dedup) {
+ if (compact) {
+ return std::make_unique<DeduplicateItemsResEntryWriter<true>>(buffer);
+ } else {
+ return std::make_unique<DeduplicateItemsResEntryWriter<false>>(buffer);
+ }
} else {
- ResTable_entry_ext* out_entry = WriteEntry<ResTable_entry_ext, false>(entry, buffer);
- MapFlattenVisitor visitor(out_entry, buffer);
- entry->value->Accept(&visitor);
- visitor.Finish();
+ if (compact) {
+ return std::make_unique<SequentialResEntryWriter<true>>(buffer);
+ } else {
+ return std::make_unique<SequentialResEntryWriter<false>>(buffer);
+ }
}
- return true;
}
bool FlattenConfig(const ResourceTableTypeView& type, const ConfigDescription& config,
@@ -353,28 +182,33 @@ class PackageFlattener {
std::vector<uint32_t> offsets;
offsets.resize(num_total_entries, 0xffffffffu);
- BigBuffer values_buffer(512);
+ bool compact_entry = UseCompactEntries(config, entries);
+
+ android::BigBuffer values_buffer(512);
+ auto res_entry_writer = GetResEntryWriter(deduplicate_entry_values_,
+ compact_entry, &values_buffer);
+
for (FlatEntry& flat_entry : *entries) {
CHECK(static_cast<size_t>(flat_entry.entry->id.value()) < num_total_entries);
- offsets[flat_entry.entry->id.value()] = values_buffer.size();
- if (!FlattenValue(&flat_entry, &values_buffer)) {
- diag_->Error(DiagMessage()
- << "failed to flatten resource '"
- << ResourceNameRef(package_.name, type.type, flat_entry.entry->name)
- << "' for configuration '" << config << "'");
- return false;
- }
+ offsets[flat_entry.entry->id.value()] = res_entry_writer->Write(&flat_entry);
}
- bool sparse_encode = use_sparse_entries_;
+ // whether the offsets can be represented in 2 bytes
+ bool short_offsets = (values_buffer.size() / 4u) < std::numeric_limits<uint16_t>::max();
- // Only sparse encode if the entries will be read on platforms O+.
- sparse_encode =
- sparse_encode && (context_->GetMinSdkVersion() >= SDK_O || config.sdkVersion >= SDK_O);
+ bool sparse_encode = sparse_entries_ == SparseEntriesMode::Enabled ||
+ sparse_entries_ == SparseEntriesMode::Forced;
+
+ if (sparse_entries_ == SparseEntriesMode::Forced ||
+ (context_->GetMinSdkVersion() == 0 && config.sdkVersion == 0)) {
+ // Sparse encode if forced or sdk version is not set in context and config.
+ } else {
+ // Otherwise, only sparse encode if the entries will be read on platforms S_V2+.
+ sparse_encode = sparse_encode && (context_->GetMinSdkVersion() >= SDK_S_V2);
+ }
// Only sparse encode if the offsets are representable in 2 bytes.
- sparse_encode =
- sparse_encode && (values_buffer.size() / 4u) <= std::numeric_limits<uint16_t>::max();
+ sparse_encode = sparse_encode && short_offsets;
// Only sparse encode if the ratio of populated entries to total entries is below some
// threshold.
@@ -382,27 +216,37 @@ class PackageFlattener {
sparse_encode && ((100 * entries->size()) / num_total_entries) < kSparseEncodingThreshold;
if (sparse_encode) {
- type_header->entryCount = util::HostToDevice32(entries->size());
+ type_header->entryCount = android::util::HostToDevice32(entries->size());
type_header->flags |= ResTable_type::FLAG_SPARSE;
ResTable_sparseTypeEntry* indices =
type_writer.NextBlock<ResTable_sparseTypeEntry>(entries->size());
for (size_t i = 0; i < num_total_entries; i++) {
if (offsets[i] != ResTable_type::NO_ENTRY) {
CHECK((offsets[i] & 0x03) == 0);
- indices->idx = util::HostToDevice16(i);
- indices->offset = util::HostToDevice16(offsets[i] / 4u);
+ indices->idx = android::util::HostToDevice16(i);
+ indices->offset = android::util::HostToDevice16(offsets[i] / 4u);
indices++;
}
}
} else {
- type_header->entryCount = util::HostToDevice32(num_total_entries);
- uint32_t* indices = type_writer.NextBlock<uint32_t>(num_total_entries);
- for (size_t i = 0; i < num_total_entries; i++) {
- indices[i] = util::HostToDevice32(offsets[i]);
+ type_header->entryCount = android::util::HostToDevice32(num_total_entries);
+ if (compact_entry && short_offsets) {
+ // use 16-bit offset only when compact_entry is true
+ type_header->flags |= ResTable_type::FLAG_OFFSET16;
+ uint16_t* indices = type_writer.NextBlock<uint16_t>(num_total_entries);
+ for (size_t i = 0; i < num_total_entries; i++) {
+ indices[i] = android::util::HostToDevice16(offsets[i] / 4u);
+ }
+ } else {
+ uint32_t* indices = type_writer.NextBlock<uint32_t>(num_total_entries);
+ for (size_t i = 0; i < num_total_entries; i++) {
+ indices[i] = android::util::HostToDevice32(offsets[i]);
+ }
}
}
- type_header->entriesStart = util::HostToDevice32(type_writer.size());
+ type_writer.buffer()->Align4();
+ type_header->entriesStart = android::util::HostToDevice32(type_writer.size());
type_writer.buffer()->AppendBuffer(std::move(values_buffer));
type_writer.Finish();
return true;
@@ -416,12 +260,12 @@ class PackageFlattener {
ChunkWriter alias_writer(buffer);
auto header =
alias_writer.StartChunk<ResTable_staged_alias_header>(RES_TABLE_STAGED_ALIAS_TYPE);
- header->count = util::HostToDevice32(aliases_.size());
+ header->count = android::util::HostToDevice32(aliases_.size());
auto mapping = alias_writer.NextBlock<ResTable_staged_alias_entry>(aliases_.size());
for (auto& p : aliases_) {
- mapping->stagedResId = util::HostToDevice32(p.first);
- mapping->finalizedResId = util::HostToDevice32(p.second);
+ mapping->stagedResId = android::util::HostToDevice32(p.first);
+ mapping->finalizedResId = android::util::HostToDevice32(p.second);
++mapping;
}
alias_writer.Finish();
@@ -447,7 +291,7 @@ class PackageFlattener {
ResourceId id = android::make_resid(package_.id.value(), type.id.value(), entry.id.value());
CHECK(seen_ids.find(id) == seen_ids.end())
<< "multiple overlayable definitions found for resource "
- << ResourceName(package_.name, type.type, entry.name).to_string();
+ << ResourceName(package_.name, type.named_type, entry.name).to_string();
seen_ids.insert(id);
// Find the overlayable chunk with the specified name
@@ -461,11 +305,11 @@ class PackageFlattener {
OverlayableChunk& chunk = iter->second;
if (!(chunk.source == item.overlayable->source)) {
// The name of an overlayable set of resources must be unique
- context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
- << "duplicate overlayable name"
- << item.overlayable->name << "'");
- context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
- << "previous declaration here");
+ context_->GetDiagnostics()->Error(android::DiagMessage(item.overlayable->source)
+ << "duplicate overlayable name"
+ << item.overlayable->name << "'");
+ context_->GetDiagnostics()->Error(android::DiagMessage(chunk.source)
+ << "previous declaration here");
return false;
}
@@ -474,7 +318,7 @@ class PackageFlattener {
}
if (item.policies == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+ context_->GetDiagnostics()->Error(android::DiagMessage(item.overlayable->source)
<< "overlayable " << entry.name
<< " does not specify policy");
return false;
@@ -499,38 +343,36 @@ class PackageFlattener {
auto* overlayable_type =
overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
if (name.size() >= arraysize(overlayable_type->name)) {
- diag_->Error(DiagMessage() << "overlayable name '" << name
- << "' exceeds maximum length ("
- << arraysize(overlayable_type->name)
- << " utf16 characters)");
+ diag_->Error(android::DiagMessage()
+ << "overlayable name '" << name << "' exceeds maximum length ("
+ << arraysize(overlayable_type->name) << " utf16 characters)");
return false;
}
strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
- util::Utf8ToUtf16(name));
+ android::util::Utf8ToUtf16(name));
if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
- diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
- << "' exceeds maximum length ("
- << arraysize(overlayable_type->actor)
- << " utf16 characters)");
+ diag_->Error(android::DiagMessage()
+ << "overlayable name '" << overlayable.actor << "' exceeds maximum length ("
+ << arraysize(overlayable_type->actor) << " utf16 characters)");
return false;
}
strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
- util::Utf8ToUtf16(overlayable.actor));
+ android::util::Utf8ToUtf16(overlayable.actor));
// Write each policy block for the overlayable
for (auto& policy_ids : overlayable.policy_ids) {
ChunkWriter policy_writer(buffer);
auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
RES_TABLE_OVERLAYABLE_POLICY_TYPE);
- policy_type->policy_flags =
- static_cast<PolicyFlags>(util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)));
- policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
- policy_ids.second.size()));
+ policy_type->policy_flags = static_cast<PolicyFlags>(
+ android::util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)));
+ policy_type->entry_count =
+ android::util::HostToDevice32(static_cast<uint32_t>(policy_ids.second.size()));
// Write the ids after the policy header
auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
for (const ResourceId& id : policy_ids.second) {
- id_block->ident = util::HostToDevice32(id.id);
+ id_block->ident = android::util::HostToDevice32(id.id);
id_block++;
}
policy_writer.Finish();
@@ -559,7 +401,7 @@ class PackageFlattener {
// Since the entries are sorted by ID, the last one will be the biggest.
const size_t num_entries = sorted_entries.back().id.value() + 1;
- spec_header->entryCount = util::HostToDevice32(num_entries);
+ spec_header->entryCount = android::util::HostToDevice32(num_entries);
// Reserve space for the masks of each resource in this type. These
// show for which configuration axis the resource changes.
@@ -571,17 +413,18 @@ class PackageFlattener {
// Populate the config masks for this entry.
uint32_t& entry_config_masks = config_masks[entry_id];
if (entry.visibility.level == Visibility::Level::kPublic) {
- entry_config_masks |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
+ entry_config_masks |= android::util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
}
if (entry.visibility.staged_api) {
- entry_config_masks |= util::HostToDevice32(ResTable_typeSpec::SPEC_STAGED_API);
+ entry_config_masks |= android::util::HostToDevice32(ResTable_typeSpec::SPEC_STAGED_API);
}
const size_t config_count = entry.values.size();
for (size_t i = 0; i < config_count; i++) {
const ConfigDescription& config = entry.values[i]->config;
for (size_t j = i + 1; j < config_count; j++) {
- config_masks[entry_id] |= util::HostToDevice32(config.diff(entry.values[j]->config));
+ config_masks[entry_id] |=
+ android::util::HostToDevice32(config.diff(entry.values[j]->config));
}
}
}
@@ -592,7 +435,8 @@ class PackageFlattener {
bool FlattenTypes(BigBuffer* buffer) {
size_t expected_type_id = 1;
for (const ResourceTableTypeView& type : package_.types) {
- if (type.type == ResourceType::kStyleable || type.type == ResourceType::kMacro) {
+ if (type.named_type.type == ResourceType::kStyleable ||
+ type.named_type.type == ResourceType::kMacro) {
// Styleables and macros are not real resource types.
continue;
}
@@ -606,7 +450,7 @@ class PackageFlattener {
expected_type_id++;
}
expected_type_id++;
- type_pool_.MakeRef(to_string(type.type));
+ type_pool_.MakeRef(type.named_type.to_string());
if (!FlattenTypeSpec(type, type.entries, buffer)) {
return false;
@@ -623,9 +467,6 @@ class PackageFlattener {
// table.
std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map;
- // hardcoded string uses characters which make it an invalid resource name
- const std::string obfuscated_resource_name = "0_resource_name_obfuscated";
-
for (const ResourceTableEntryView& entry : type.entries) {
if (entry.staged_id) {
aliases_.insert(std::make_pair(
@@ -634,14 +475,31 @@ class PackageFlattener {
}
uint32_t local_key_index;
- ResourceName resource_name({}, type.type, entry.name);
- if (!collapse_key_stringpool_ ||
- name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) {
- local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
- } else {
- // resource isn't exempt from collapse, add it as obfuscated value
- local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index();
- }
+ auto onObfuscate = [this, &local_key_index, &entry](Obfuscator::Result obfuscatedResult,
+ const ResourceName& resource_name) {
+ if (obfuscatedResult == Obfuscator::Result::Keep_ExemptionList) {
+ local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
+ } else if (obfuscatedResult == Obfuscator::Result::Keep_Overlayable) {
+ // if the resource name of the specific entry is obfuscated and this
+ // entry is in the overlayable list, the overlay can't work on this
+ // overlayable at runtime because the name has been obfuscated in
+ // resources.arsc during flatten operation.
+ const OverlayableItem& item = entry.overlayable_item.value();
+ context_->GetDiagnostics()->Warn(android::DiagMessage(item.overlayable->source)
+ << "The resource name of overlayable entry '"
+ << resource_name.to_string()
+ << "' shouldn't be obfuscated in resources.arsc");
+
+ local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
+ } else {
+ local_key_index =
+ (uint32_t)key_pool_.MakeRef(Obfuscator::kObfuscatedResourceName).index();
+ }
+ };
+
+ Obfuscator::ObfuscateResourceName(collapse_key_stringpool_, name_collapse_exemptions_,
+ type.named_type, entry, onObfuscate);
+
// Group values by configuration.
for (auto& config_value : entry.values) {
config_to_entry_list_map[config_value->config].push_back(
@@ -667,36 +525,38 @@ class PackageFlattener {
const size_t num_entries = (package_.id.value() == 0x00 ? 1 : 0) + shared_libs_->size();
CHECK(num_entries > 0);
- lib_header->count = util::HostToDevice32(num_entries);
+ lib_header->count = android::util::HostToDevice32(num_entries);
ResTable_lib_entry* lib_entry = buffer->NextBlock<ResTable_lib_entry>(num_entries);
if (package_.id.value() == 0x00) {
// Add this package
- lib_entry->packageId = util::HostToDevice32(0x00);
+ lib_entry->packageId = android::util::HostToDevice32(0x00);
strcpy16_htod(lib_entry->packageName, arraysize(lib_entry->packageName),
- util::Utf8ToUtf16(package_.name));
+ android::util::Utf8ToUtf16(package_.name));
++lib_entry;
}
for (auto& map_entry : *shared_libs_) {
- lib_entry->packageId = util::HostToDevice32(map_entry.first);
+ lib_entry->packageId = android::util::HostToDevice32(map_entry.first);
strcpy16_htod(lib_entry->packageName, arraysize(lib_entry->packageName),
- util::Utf8ToUtf16(map_entry.second));
+ android::util::Utf8ToUtf16(map_entry.second));
++lib_entry;
}
lib_writer.Finish();
}
IAaptContext* context_;
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
const ResourceTablePackageView package_;
const std::map<size_t, std::string>* shared_libs_;
- bool use_sparse_entries_;
- StringPool type_pool_;
- StringPool key_pool_;
+ SparseEntriesMode sparse_entries_;
+ bool compact_entries_;
+ android::StringPool type_pool_;
+ android::StringPool key_pool_;
bool collapse_key_stringpool_;
const std::set<ResourceName>& name_collapse_exemptions_;
std::map<uint32_t, uint32_t> aliases_;
+ bool deduplicate_entry_values_;
};
} // namespace
@@ -705,26 +565,27 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
TRACE_CALL();
// We must do this before writing the resources, since the string pool IDs may change.
table->string_pool.Prune();
- table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
- int diff = util::compare(a.priority, b.priority);
- if (diff == 0) {
- diff = a.config.compare(b.config);
- }
- return diff;
- });
+ table->string_pool.Sort(
+ [](const android::StringPool::Context& a, const android::StringPool::Context& b) -> int {
+ int diff = util::compare(a.priority, b.priority);
+ if (diff == 0) {
+ diff = a.config.compare(b.config);
+ }
+ return diff;
+ });
// Write the ResTable header.
const auto& table_view =
table->GetPartitionedView(ResourceTableViewOptions{.create_alias_entries = true});
ChunkWriter table_writer(buffer_);
ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
- table_header->packageCount = util::HostToDevice32(table_view.packages.size());
+ table_header->packageCount = android::util::HostToDevice32(table_view.packages.size());
// Flatten the values string pool.
- StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool,
- context->GetDiagnostics());
+ android::StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool,
+ context->GetDiagnostics());
- BigBuffer package_buffer(1024);
+ android::BigBuffer package_buffer(1024);
// Flatten each package.
for (auto& package : table_view.packages) {
@@ -737,7 +598,7 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
if (!result.second && result.first->second != package.name) {
// A mapping for this package ID already exists, and is a different package. Error!
context->GetDiagnostics()->Error(
- DiagMessage() << android::base::StringPrintf(
+ android::DiagMessage() << android::base::StringPrintf(
"can't map package ID %02x to '%s'. Already mapped to '%s'", package_id,
package.name.c_str(), result.first->second.c_str()));
return false;
@@ -746,8 +607,11 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
}
PackageFlattener flattener(context, package, &table->included_packages_,
- options_.use_sparse_entries, options_.collapse_key_stringpool,
- options_.name_collapse_exemptions);
+ options_.sparse_entries,
+ options_.use_compact_entries,
+ options_.collapse_key_stringpool,
+ options_.name_collapse_exemptions,
+ options_.deduplicate_entry_values);
if (!flattener.FlattenPackage(&package_buffer)) {
return false;
}
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 4360db190146..0633bc81cb25 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -14,15 +14,19 @@
* limitations under the License.
*/
-#ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H
-#define AAPT_FORMAT_BINARY_TABLEFLATTENER_H
+#ifndef TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
+#define TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
-#include "android-base/macros.h"
+#include <map>
+#include <set>
+#include <string>
+#include <unordered_map>
#include "Resource.h"
#include "ResourceTable.h"
+#include "android-base/macros.h"
+#include "androidfw/BigBuffer.h"
#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
namespace aapt {
@@ -30,12 +34,23 @@ namespace aapt {
// preferred.
constexpr const size_t kSparseEncodingThreshold = 60;
+enum class SparseEntriesMode {
+ // Disables sparse encoding for entries.
+ Disabled,
+ // Enables sparse encoding for all entries for APKs with O+ minSdk. For APKs with minSdk less
+ // than O only applies sparse encoding for resource configuration available on O+.
+ Enabled,
+ // Enables sparse encoding for all entries regardless of minSdk.
+ Forced,
+};
+
struct TableFlattenerOptions {
- // When true, types for configurations with a sparse set of entries are encoded
+ // When enabled, types for configurations with a sparse set of entries are encoded
// as a sparse map of entry ID and offset to actual data.
- // This is only available on platforms O+ and will only be respected when
- // minSdk is O+.
- bool use_sparse_entries = false;
+ SparseEntriesMode sparse_entries = SparseEntriesMode::Disabled;
+
+ // When true, use compact entries for simple data
+ bool use_compact_entries = false;
// When true, the key string pool in the final ResTable
// is collapsed to a single entry. All resource entries
@@ -45,25 +60,45 @@ struct TableFlattenerOptions {
// Set of resources to avoid collapsing to a single entry in key stringpool.
std::set<ResourceName> name_collapse_exemptions;
+ // Set of resources to avoid path shortening.
+ std::set<ResourceName> path_shorten_exemptions;
+
// Map from original resource paths to shortened resource paths.
std::map<std::string, std::string> shortened_path_map;
+
+ // When enabled, only unique pairs of entry and value are stored in type chunks.
+ //
+ // By default, all such pairs are unique because a reference to resource name in the string pool
+ // is a part of the pair. But when resource names are collapsed (using 'collapse_key_stringpool'
+ // flag or manually) the same data might be duplicated multiple times in the same type chunk.
+ //
+ // For example: an application has 3 boolean resources with collapsed names and 3 'true' values
+ // are defined for these resources in 'default' configuration. All pairs of entry and value for
+ // these resources will have the same binary representation and stored only once in type chunk
+ // instead of three times when this flag is disabled.
+ //
+ // This applies only to simple entries (entry->flags & ResTable_entry::FLAG_COMPLEX == 0).
+ bool deduplicate_entry_values = false;
+
+ // Map from original resource ids to obfuscated names.
+ std::unordered_map<uint32_t, std::string> id_resource_map;
};
class TableFlattener : public IResourceTableConsumer {
public:
- explicit TableFlattener(const TableFlattenerOptions& options, BigBuffer* buffer)
+ explicit TableFlattener(const TableFlattenerOptions& options, android::BigBuffer* buffer)
: options_(options), buffer_(buffer) {
}
bool Consume(IAaptContext* context, ResourceTable* table) override;
private:
- DISALLOW_COPY_AND_ASSIGN(TableFlattener);
-
TableFlattenerOptions options_;
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(TableFlattener);
};
} // namespace aapt
-#endif /* AAPT_FORMAT_BINARY_TABLEFLATTENER_H */
+#endif // TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index cd1c0af702cf..0f1168514c4a 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -45,7 +45,7 @@ class TableFlattenerTest : public ::testing::Test {
::testing::AssertionResult Flatten(IAaptContext* context, const TableFlattenerOptions& options,
ResourceTable* table, std::string* out_content) {
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
TableFlattener flattener(options, &buffer);
if (!flattener.Consume(context, table)) {
return ::testing::AssertionFailure() << "failed to flatten ResourceTable";
@@ -84,7 +84,7 @@ class TableFlattenerTest : public ::testing::Test {
return ::testing::AssertionSuccess();
}
- ::testing::AssertionResult Exists(ResTable* table, const StringPiece& expected_name,
+ ::testing::AssertionResult Exists(ResTable* table, StringPiece expected_name,
const ResourceId& expected_id,
const ConfigDescription& expected_config,
const uint8_t expected_data_type, const uint32_t expected_data,
@@ -254,13 +254,13 @@ TEST_F(TableFlattenerTest, FlattenArray) {
// Parse the flattened resource table
ResChunkPullParser parser(result.data(), result.size());
ASSERT_TRUE(parser.IsGoodEvent(parser.Next()));
- ASSERT_EQ(util::DeviceToHost16(parser.chunk()->type), RES_TABLE_TYPE);
+ ASSERT_EQ(android::util::DeviceToHost16(parser.chunk()->type), RES_TABLE_TYPE);
// Retrieve the package of the entry
ResChunkPullParser table_parser(GetChunkData(parser.chunk()), GetChunkDataLen(parser.chunk()));
const ResChunk_header* package_chunk = nullptr;
while (table_parser.IsGoodEvent(table_parser.Next())) {
- if (util::DeviceToHost16(table_parser.chunk()->type) == RES_TABLE_PACKAGE_TYPE) {
+ if (android::util::DeviceToHost16(table_parser.chunk()->type) == RES_TABLE_PACKAGE_TYPE) {
package_chunk = table_parser.chunk();
break;
}
@@ -272,7 +272,7 @@ TEST_F(TableFlattenerTest, FlattenArray) {
GetChunkDataLen(table_parser.chunk()));
const ResChunk_header* type_chunk = nullptr;
while (package_parser.IsGoodEvent(package_parser.Next())) {
- if (util::DeviceToHost16(package_parser.chunk()->type) == RES_TABLE_TYPE_TYPE) {
+ if (android::util::DeviceToHost16(package_parser.chunk()->type) == RES_TABLE_TYPE_TYPE) {
type_chunk = package_parser.chunk();
break;
}
@@ -282,7 +282,7 @@ TEST_F(TableFlattenerTest, FlattenArray) {
ASSERT_NE(type_chunk, nullptr);
TypeVariant typeVariant((const ResTable_type*) type_chunk);
auto entry = (const ResTable_map_entry*)*typeVariant.beginEntries();
- ASSERT_EQ(util::DeviceToHost16(entry->count), 2u);
+ ASSERT_EQ(android::util::DeviceToHost16(entry->count), 2u);
// Check that the value and name of the array entries are correct
auto values = (const ResTable_map*)(((const uint8_t *)entry) + entry->size);
@@ -326,18 +326,18 @@ static std::unique_ptr<ResourceTable> BuildTableWithSparseEntries(
return table;
}
-TEST_F(TableFlattenerTest, FlattenSparseEntryWithMinSdkO) {
+TEST_F(TableFlattenerTest, FlattenSparseEntryWithMinSdkSV2) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.SetCompilationPackage("android")
.SetPackageId(0x01)
- .SetMinSdkVersion(SDK_O)
+ .SetMinSdkVersion(SDK_S_V2)
.Build();
const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB");
auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f);
TableFlattenerOptions options;
- options.use_sparse_entries = true;
+ options.sparse_entries = SparseEntriesMode::Enabled;
std::string no_sparse_contents;
ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents));
@@ -369,18 +369,40 @@ TEST_F(TableFlattenerTest, FlattenSparseEntryWithMinSdkO) {
EXPECT_EQ(4u, value->value.data);
}
-TEST_F(TableFlattenerTest, FlattenSparseEntryWithConfigSdkVersionO) {
+TEST_F(TableFlattenerTest, FlattenSparseEntryWithConfigSdkVersionSV2) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+ .SetCompilationPackage("android")
+ .SetPackageId(0x01)
+ .SetMinSdkVersion(SDK_LOLLIPOP)
+ .Build();
+
+ const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB-v32");
+ auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f);
+
+ TableFlattenerOptions options;
+ options.sparse_entries = SparseEntriesMode::Enabled;
+
+ std::string no_sparse_contents;
+ ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents));
+
+ std::string sparse_contents;
+ ASSERT_TRUE(Flatten(context.get(), options, table_in.get(), &sparse_contents));
+
+ EXPECT_EQ(no_sparse_contents.size(), sparse_contents.size());
+}
+
+TEST_F(TableFlattenerTest, FlattenSparseEntryRegardlessOfMinSdkWhenForced) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.SetCompilationPackage("android")
.SetPackageId(0x01)
.SetMinSdkVersion(SDK_LOLLIPOP)
.Build();
- const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB-v26");
+ const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB");
auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f);
TableFlattenerOptions options;
- options.use_sparse_entries = true;
+ options.sparse_entries = SparseEntriesMode::Forced;
std::string no_sparse_contents;
ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents));
@@ -391,6 +413,46 @@ TEST_F(TableFlattenerTest, FlattenSparseEntryWithConfigSdkVersionO) {
EXPECT_GT(no_sparse_contents.size(), sparse_contents.size());
}
+TEST_F(TableFlattenerTest, FlattenSparseEntryWithSdkVersionNotSet) {
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder().SetCompilationPackage("android").SetPackageId(0x01).Build();
+
+ const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB");
+ auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f);
+
+ TableFlattenerOptions options;
+ options.sparse_entries = SparseEntriesMode::Enabled;
+
+ std::string no_sparse_contents;
+ ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents));
+
+ std::string sparse_contents;
+ ASSERT_TRUE(Flatten(context.get(), options, table_in.get(), &sparse_contents));
+
+ EXPECT_GT(no_sparse_contents.size(), sparse_contents.size());
+
+ // Attempt to parse the sparse contents.
+
+ ResourceTable sparse_table;
+ BinaryResourceParser parser(context->GetDiagnostics(), &sparse_table, Source("test.arsc"),
+ sparse_contents.data(), sparse_contents.size());
+ ASSERT_TRUE(parser.Parse());
+
+ auto value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_0",
+ sparse_config);
+ ASSERT_THAT(value, NotNull());
+ EXPECT_EQ(0u, value->value.data);
+
+ ASSERT_THAT(test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_1",
+ sparse_config),
+ IsNull());
+
+ value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_4",
+ sparse_config);
+ ASSERT_THAT(value, NotNull());
+ EXPECT_EQ(4u, value->value.data);
+}
+
TEST_F(TableFlattenerTest, DoNotUseSparseEntryForDenseConfig) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder()
.SetCompilationPackage("android")
@@ -402,7 +464,7 @@ TEST_F(TableFlattenerTest, DoNotUseSparseEntryForDenseConfig) {
auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.80f);
TableFlattenerOptions options;
- options.use_sparse_entries = true;
+ options.sparse_entries = SparseEntriesMode::Enabled;
std::string no_sparse_contents;
ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents));
@@ -607,6 +669,87 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoNameCollapseExemptionsSucce
ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
+TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithDeduplicationSucceeds) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/one", ResourceId(0x7f020000))
+ .AddSimple("com.app.test:id/two", ResourceId(0x7f020001))
+ .AddValue("com.app.test:id/three", ResourceId(0x7f020002),
+ test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000)))
+ .AddValue("com.app.test:integer/one", ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
+ .AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"),
+ ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
+ .AddString("com.app.test:string/test1", ResourceId(0x7f040000), "foo")
+ .AddString("com.app.test:string/test2", ResourceId(0x7f040001), "foo")
+ .AddString("com.app.test:string/test3", ResourceId(0x7f040002), "bar")
+ .AddString("com.app.test:string/test4", ResourceId(0x7f040003), "foo")
+ .AddString("com.app.test:layout/bar1", ResourceId(0x7f050000), "res/layout/bar.xml")
+ .AddString("com.app.test:layout/bar2", ResourceId(0x7f050001), "res/layout/bar.xml")
+ .Build();
+
+ TableFlattenerOptions options;
+ options.collapse_key_stringpool = true;
+ options.deduplicate_entry_values = true;
+
+ ResTable res_table;
+
+ ASSERT_TRUE(Flatten(context_.get(), options, table.get(), &res_table));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020000), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020001), {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/0_resource_name_obfuscated",
+ ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
+ ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u,
+ ResTable_config::CONFIG_VERSION));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/0_resource_name_obfuscated",
+ ResourceId(0x7f030000), test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC,
+ 2u, ResTable_config::CONFIG_VERSION));
+
+ std::u16string foo_str = u"foo";
+ std::u16string bar_str = u"bar";
+ auto foo_idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ auto bar_idx = res_table.getTableStringBlock(0)->indexOfString(bar_str.data(), bar_str.size());
+ ASSERT_TRUE(foo_idx.has_value());
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
+ ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)*foo_idx, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
+ ResourceId(0x7f040001), {}, Res_value::TYPE_STRING, (uint32_t)*foo_idx, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
+ ResourceId(0x7f040002), {}, Res_value::TYPE_STRING, (uint32_t)*bar_idx, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
+ ResourceId(0x7f040003), {}, Res_value::TYPE_STRING, (uint32_t)*foo_idx, 0u));
+
+ std::u16string bar_path = u"res/layout/bar.xml";
+ auto bar_path_idx =
+ res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
+ ASSERT_TRUE(bar_path_idx.has_value());
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*bar_path_idx,
+ 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
+ ResourceId(0x7f050001), {}, Res_value::TYPE_STRING, (uint32_t)*bar_path_idx,
+ 0u));
+
+ std::string deduplicated_output;
+ std::string sequential_output;
+ Flatten(context_.get(), options, table.get(), &deduplicated_output);
+ options.deduplicate_entry_values = false;
+ Flatten(context_.get(), options, table.get(), &sequential_output);
+
+ // We have 4 duplicates: 0x7f020001 id, 0x7f040001 string, 0x7f040003 string, 0x7f050001 layout.
+ EXPECT_EQ(sequential_output.size(),
+ deduplicated_output.size() + 4 * (sizeof(ResTable_entry) + sizeof(Res_value)));
+}
+
TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) {
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
@@ -837,4 +980,93 @@ TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
ASSERT_FALSE(Flatten(context_.get(), {}, table.get(), &output_table));
}
+TEST_F(TableFlattenerTest, FlattenCustomResourceTypes) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/one", ResourceId(0x7f010000))
+ .AddSimple("com.app.test:id.2/two", ResourceId(0x7f020000))
+ .AddValue("com.app.test:integer/one", ResourceId(0x7f030000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 10u))
+ .AddValue("com.app.test:integer.1/one", ResourceId(0x7f040000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
+ .AddValue("com.app.test:integer.1/one", test::ParseConfigOrDie("v1"),
+ ResourceId(0x7f040000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
+ .AddString("com.app.test:layout.custom/bar", ResourceId(0x7f050000), "res/layout/bar.xml")
+ .Build();
+
+ ResTable res_table;
+ ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &res_table));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f010000), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id.2/two", ResourceId(0x7f020000), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one", ResourceId(0x7f030000), {},
+ Res_value::TYPE_INT_DEC, 10u, 0u));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer.1/one", ResourceId(0x7f040000), {},
+ Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION));
+
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer.1/one", ResourceId(0x7f040000),
+ test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u,
+ ResTable_config::CONFIG_VERSION));
+
+ std::u16string bar_path = u"res/layout/bar.xml";
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
+ ASSERT_TRUE(idx.has_value());
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout.custom/bar", ResourceId(0x7f050000), {},
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
+}
+
+TEST_F(TableFlattenerTest, FlattenTypeEntryWithNameCollapseNotInExemption) {
+ OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
+ overlayable_item.policies |= PolicyFlags::PUBLIC;
+
+ std::string name = "com.app.test:color/overlayable_color";
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddValue("com.app.test:color/overlayable_color", ResourceId(0x7f010000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_COLOR_ARGB8),
+ 0xffaabbcc))
+ .SetOverlayable(name, overlayable_item)
+ .Build();
+
+ TableFlattenerOptions options;
+ options.collapse_key_stringpool = true;
+
+ ResTable res_table;
+ EXPECT_THAT(Flatten(context_.get(), options, table.get(), &res_table), testing::IsTrue());
+ EXPECT_THAT(Exists(&res_table, "com.app.test:color/overlayable_color", ResourceId(0x7f010000), {},
+ Res_value::TYPE_INT_COLOR_ARGB8, 0xffaabbcc, 0u),
+ testing::IsTrue());
+}
+
+TEST_F(TableFlattenerTest, FlattenTypeEntryWithNameCollapseInExemption) {
+ OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
+ overlayable_item.policies |= PolicyFlags::PUBLIC;
+
+ std::string name = "com.app.test:color/overlayable_color";
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddValue("com.app.test:color/overlayable_color", ResourceId(0x7f010000),
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_COLOR_ARGB8),
+ 0xffaabbcc))
+ .SetOverlayable(name, overlayable_item)
+ .Build();
+
+ TableFlattenerOptions options;
+ options.collapse_key_stringpool = true;
+ options.name_collapse_exemptions.insert(
+ ResourceName({}, ResourceType::kColor, "overlayable_color"));
+
+ ResTable res_table;
+ EXPECT_THAT(Flatten(context_.get(), options, table.get(), &res_table), testing::IsTrue());
+ EXPECT_THAT(Exists(&res_table, "com.app.test:color/overlayable_color", ResourceId(0x7f010000), {},
+ Res_value::TYPE_INT_COLOR_ARGB8, 0xffaabbcc, 0u),
+ testing::IsTrue());
+}
+
} // namespace aapt
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index cdbe8828b29b..05f975177cd1 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -64,11 +64,11 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
public:
using xml::ConstVisitor::Visit;
- StringPool pool;
- std::map<uint8_t, StringPool> package_pools;
+ android::StringPool pool;
+ std::map<uint8_t, android::StringPool> package_pools;
struct StringFlattenDest {
- StringPool::Ref ref;
+ android::StringPool::Ref ref;
ResStringPool_ref* dest;
};
@@ -79,7 +79,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
}
void Visit(const xml::Text* node) override {
- std::string text = util::TrimWhitespace(node->text).to_string();
+ std::string text(util::TrimWhitespace(node->text));
// Skip whitespace only text nodes.
if (text.empty()) {
@@ -88,16 +88,16 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
// Compact leading and trailing whitespace into a single space
if (isspace(node->text[0])) {
- text = ' ' + text;
+ text.insert(text.begin(), ' ');
}
- if (isspace(node->text[node->text.length() - 1])) {
- text = text + ' ';
+ if (isspace(node->text.back())) {
+ text += ' ';
}
ChunkWriter writer(buffer_);
ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE);
- flat_node->lineNumber = util::HostToDevice32(node->line_number);
- flat_node->comment.index = util::HostToDevice32(-1);
+ flat_node->lineNumber = android::util::HostToDevice32(node->line_number);
+ flat_node->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>();
AddString(text, kLowPriority, &flat_text->data);
@@ -116,8 +116,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter start_writer(buffer_);
ResXMLTree_node* flat_node =
start_writer.StartChunk<ResXMLTree_node>(RES_XML_START_ELEMENT_TYPE);
- flat_node->lineNumber = util::HostToDevice32(node->line_number);
- flat_node->comment.index = util::HostToDevice32(-1);
+ flat_node->lineNumber = android::util::HostToDevice32(node->line_number);
+ flat_node->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_attrExt* flat_elem = start_writer.NextBlock<ResXMLTree_attrExt>();
@@ -126,8 +126,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
true /* treat_empty_string_as_null */);
AddString(node->name, kLowPriority, &flat_elem->name, true /* treat_empty_string_as_null */);
- flat_elem->attributeStart = util::HostToDevice16(sizeof(*flat_elem));
- flat_elem->attributeSize = util::HostToDevice16(sizeof(ResXMLTree_attribute));
+ flat_elem->attributeStart = android::util::HostToDevice16(sizeof(*flat_elem));
+ flat_elem->attributeSize = android::util::HostToDevice16(sizeof(ResXMLTree_attribute));
WriteAttributes(node, flat_elem, &start_writer);
@@ -140,8 +140,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter end_writer(buffer_);
ResXMLTree_node* flat_end_node =
end_writer.StartChunk<ResXMLTree_node>(RES_XML_END_ELEMENT_TYPE);
- flat_end_node->lineNumber = util::HostToDevice32(node->line_number);
- flat_end_node->comment.index = util::HostToDevice32(-1);
+ flat_end_node->lineNumber = android::util::HostToDevice32(node->line_number);
+ flat_end_node->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_endElementExt* flat_end_elem = end_writer.NextBlock<ResXMLTree_endElementExt>();
AddString(node->namespace_uri, kLowPriority, &flat_end_elem->ns,
@@ -165,21 +165,21 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
// We are adding strings to a StringPool whose strings will be sorted and merged with other
// string pools. That means we can't encode the ID of a string directly. Instead, we defer the
// writing of the ID here, until after the StringPool is merged and sorted.
- void AddString(const StringPiece& str, uint32_t priority, android::ResStringPool_ref* dest,
+ void AddString(StringPiece str, uint32_t priority, android::ResStringPool_ref* dest,
bool treat_empty_string_as_null = false) {
if (str.empty() && treat_empty_string_as_null) {
// Some parts of the runtime treat null differently than empty string.
- dest->index = util::DeviceToHost32(-1);
+ dest->index = android::util::DeviceToHost32(-1);
} else {
string_refs.push_back(
- StringFlattenDest{pool.MakeRef(str, StringPool::Context(priority)), dest});
+ StringFlattenDest{pool.MakeRef(str, android::StringPool::Context(priority)), dest});
}
}
// We are adding strings to a StringPool whose strings will be sorted and merged with other
// string pools. That means we can't encode the ID of a string directly. Instead, we defer the
// writing of the ID here, until after the StringPool is merged and sorted.
- void AddString(const StringPool::Ref& ref, android::ResStringPool_ref* dest) {
+ void AddString(const android::StringPool::Ref& ref, android::ResStringPool_ref* dest) {
string_refs.push_back(StringFlattenDest{ref, dest});
}
@@ -187,8 +187,8 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
ChunkWriter writer(buffer_);
ResXMLTree_node* flatNode = writer.StartChunk<ResXMLTree_node>(type);
- flatNode->lineNumber = util::HostToDevice32(decl.line_number);
- flatNode->comment.index = util::HostToDevice32(-1);
+ flatNode->lineNumber = android::util::HostToDevice32(decl.line_number);
+ flatNode->comment.index = android::util::HostToDevice32(-1);
ResXMLTree_namespaceExt* flat_ns = writer.NextBlock<ResXMLTree_namespaceExt>();
AddString(decl.prefix, kLowPriority, &flat_ns->prefix);
@@ -217,7 +217,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
std::sort(filtered_attrs_.begin(), filtered_attrs_.end(), cmp_xml_attribute_by_id);
- flat_elem->attributeCount = util::HostToDevice16(filtered_attrs_.size());
+ flat_elem->attributeCount = android::util::HostToDevice16(filtered_attrs_.size());
ResXMLTree_attribute* flat_attr =
writer->NextBlock<ResXMLTree_attribute>(filtered_attrs_.size());
@@ -226,12 +226,12 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
// Assign the indices for specific attributes.
if (xml_attr->compiled_attribute && xml_attr->compiled_attribute.value().id &&
xml_attr->compiled_attribute.value().id.value() == kIdAttr) {
- flat_elem->idIndex = util::HostToDevice16(attribute_index);
+ flat_elem->idIndex = android::util::HostToDevice16(attribute_index);
} else if (xml_attr->namespace_uri.empty()) {
if (xml_attr->name == "class") {
- flat_elem->classIndex = util::HostToDevice16(attribute_index);
+ flat_elem->classIndex = android::util::HostToDevice16(attribute_index);
} else if (xml_attr->name == "style") {
- flat_elem->styleIndex = util::HostToDevice16(attribute_index);
+ flat_elem->styleIndex = android::util::HostToDevice16(attribute_index);
}
}
attribute_index++;
@@ -241,7 +241,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
AddString(xml_attr->namespace_uri, kLowPriority, &flat_attr->ns,
true /* treat_empty_string_as_null */);
- flat_attr->rawValue.index = util::HostToDevice32(-1);
+ flat_attr->rawValue.index = android::util::HostToDevice32(-1);
if (!xml_attr->compiled_attribute || !xml_attr->compiled_attribute.value().id) {
// The attribute has no associated ResourceID, so the string order doesn't matter.
@@ -256,8 +256,9 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
// Lookup the StringPool for this package and make the reference there.
const xml::AaptAttribute& aapt_attr = xml_attr->compiled_attribute.value();
- StringPool::Ref name_ref = package_pools[aapt_attr.id.value().package_id()].MakeRef(
- xml_attr->name, StringPool::Context(aapt_attr.id.value().id));
+ android::StringPool::Ref name_ref =
+ package_pools[aapt_attr.id.value().package_id()].MakeRef(
+ xml_attr->name, android::StringPool::Context(aapt_attr.id.value().id));
// Add it to the list of strings to flatten.
AddString(name_ref, &flat_attr->name);
@@ -298,7 +299,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
AddString(xml_attr->value, kLowPriority, &flat_attr->rawValue);
}
- flat_attr->typedValue.size = util::HostToDevice16(sizeof(flat_attr->typedValue));
+ flat_attr->typedValue.size = android::util::HostToDevice16(sizeof(flat_attr->typedValue));
flat_attr++;
}
}
@@ -313,7 +314,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
} // namespace
bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
- BigBuffer node_buffer(1024);
+ android::BigBuffer node_buffer(1024);
XmlFlattenerVisitor visitor(&node_buffer, options_);
node->Accept(&visitor);
@@ -323,13 +324,14 @@ bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
}
// Sort the string pool so that attribute resource IDs show up first.
- visitor.pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
- return util::compare(a.priority, b.priority);
- });
+ visitor.pool.Sort(
+ [](const android::StringPool::Context& a, const android::StringPool::Context& b) -> int {
+ return util::compare(a.priority, b.priority);
+ });
// Now we flatten the string pool references into the correct places.
for (const auto& ref_entry : visitor.string_refs) {
- ref_entry.dest->index = util::HostToDevice32(ref_entry.ref.index());
+ ref_entry.dest->index = android::util::HostToDevice32(ref_entry.ref.index());
}
// Write the XML header.
@@ -338,9 +340,9 @@ bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
// Flatten the StringPool.
if (options_.use_utf16) {
- StringPool::FlattenUtf16(buffer_, visitor.pool, context->GetDiagnostics());
+ android::StringPool::FlattenUtf16(buffer_, visitor.pool, context->GetDiagnostics());
} else {
- StringPool::FlattenUtf8(buffer_, visitor.pool, context->GetDiagnostics());
+ android::StringPool::FlattenUtf8(buffer_, visitor.pool, context->GetDiagnostics());
}
{
@@ -353,7 +355,7 @@ bool XmlFlattener::Flatten(IAaptContext* context, const xml::Node* node) {
// When we see the first non-resource ID, we're done.
break;
}
- *res_id_map_writer.NextBlock<uint32_t>() = util::HostToDevice32(id.id);
+ *res_id_map_writer.NextBlock<uint32_t>() = android::util::HostToDevice32(id.id);
}
res_id_map_writer.Finish();
}
diff --git a/tools/aapt2/format/binary/XmlFlattener.h b/tools/aapt2/format/binary/XmlFlattener.h
index 1f9e777f7a1a..e18c1e5b3fe1 100644
--- a/tools/aapt2/format/binary/XmlFlattener.h
+++ b/tools/aapt2/format/binary/XmlFlattener.h
@@ -18,9 +18,8 @@
#define AAPT_FORMAT_BINARY_XMLFLATTENER_H
#include "android-base/macros.h"
-
+#include "androidfw/BigBuffer.h"
#include "process/IResourceTableConsumer.h"
-#include "util/BigBuffer.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -36,7 +35,7 @@ struct XmlFlattenerOptions {
class XmlFlattener {
public:
- XmlFlattener(BigBuffer* buffer, XmlFlattenerOptions options)
+ XmlFlattener(android::BigBuffer* buffer, XmlFlattenerOptions options)
: buffer_(buffer), options_(options) {
}
@@ -47,7 +46,7 @@ class XmlFlattener {
bool Flatten(IAaptContext* context, const xml::Node* node);
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
XmlFlattenerOptions options_;
};
diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp
index d97e8882e5a2..6d0022cad307 100644
--- a/tools/aapt2/format/binary/XmlFlattener_test.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp
@@ -16,11 +16,10 @@
#include "format/binary/XmlFlattener.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
-
#include "link/Linkers.h"
#include "test/Test.h"
-#include "util/BigBuffer.h"
#include "util/Util.h"
using ::aapt::test::StrEq;
@@ -59,13 +58,13 @@ class XmlFlattenerTest : public ::testing::Test {
const XmlFlattenerOptions& options = {}) {
using namespace android; // For NO_ERROR on windows because it is a macro.
- BigBuffer buffer(1024);
+ android::BigBuffer buffer(1024);
XmlFlattener flattener(&buffer, options);
if (!flattener.Consume(context_.get(), doc)) {
return ::testing::AssertionFailure() << "failed to flatten XML Tree";
}
- std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
+ std::unique_ptr<uint8_t[]> data = android::util::Copy(buffer);
if (out_tree->setTo(data.get(), buffer.size(), true) != NO_ERROR) {
return ::testing::AssertionFailure() << "flattened XML is corrupt";
}
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 236c38167545..09ef9bddd3bd 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -16,15 +16,15 @@
#include "format/proto/ProtoDeserialize.h"
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-#include "androidfw/ResourceTypes.h"
-#include "androidfw/Locale.h"
-
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "androidfw/Locale.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/Util.h"
using ::android::ConfigDescription;
using ::android::LocaleValue;
@@ -354,12 +354,13 @@ bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescripti
out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width());
out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height());
out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version());
+ out_config->grammaticalInflection = pb_config.grammatical_gender();
return true;
}
static void DeserializeSourceFromPb(const pb::Source& pb_source, const ResStringPool& src_pool,
- Source* out_source) {
- out_source->path = util::GetString(src_pool, pb_source.path_idx());
+ android::Source* out_source) {
+ out_source->path = android::util::GetString(src_pool, pb_source.path_idx());
out_source->line = static_cast<size_t>(pb_source.position().line_number());
}
@@ -429,8 +430,8 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
ResourceTablePackage* pkg = out_table->FindOrCreatePackage(pb_package.package_name());
for (const pb::Type& pb_type : pb_package.type()) {
- const ResourceType* res_type = ParseResourceType(pb_type.name());
- if (res_type == nullptr) {
+ auto res_type = ParseResourceNamedType(pb_type.name());
+ if (!res_type) {
std::ostringstream error;
error << "unknown type '" << pb_type.name() << "'";
*out_error = error.str();
@@ -515,7 +516,7 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
pb_entry.entry_id().id());
if (resid.is_valid()) {
- id_index[resid] = ResourceNameRef(pkg->name, type->type, entry->name);
+ id_index[resid] = ResourceNameRef(pkg->name, type->named_type, entry->name);
}
for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) {
@@ -562,6 +563,11 @@ bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollecti
}
}
+ for (const pb::DynamicRefTable& dynamic_ref : pb_table.dynamic_ref_table()) {
+ out_table->included_packages_.insert(
+ {dynamic_ref.package_id().id(), dynamic_ref.package_name()});
+ }
+
// Deserialize the overlayable groups of the table
std::vector<std::shared_ptr<Overlayable>> overlayables;
for (const pb::Overlayable& pb_overlayable : pb_table.overlayable()) {
@@ -680,7 +686,7 @@ static bool DeserializeMacroFromPb(const pb::MacroBody& pb_ref, Macro* out_ref,
if (pb_ref.has_style_string()) {
out_ref->style_string.str = pb_ref.style_string().str();
for (const auto& span : pb_ref.style_string().spans()) {
- out_ref->style_string.spans.emplace_back(Span{
+ out_ref->style_string.spans.emplace_back(android::Span{
.name = span.name(), .first_char = span.start_index(), .last_char = span.end_index()});
}
}
@@ -705,7 +711,7 @@ template <typename T>
static void DeserializeItemMetaDataFromPb(const T& pb_item, const android::ResStringPool& src_pool,
Value* out_value) {
if (pb_item.has_source()) {
- Source source;
+ android::Source source;
DeserializeSourceFromPb(pb_item.source(), src_pool, &source);
out_value->SetSource(std::move(source));
}
@@ -733,8 +739,8 @@ static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const ConfigDescription& config,
- StringPool* value_pool, io::IFileCollection* files,
- std::string* out_error) {
+ android::StringPool* value_pool,
+ io::IFileCollection* files, std::string* out_error) {
std::unique_ptr<Value> value;
if (pb_value.has_item()) {
value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, files, out_error);
@@ -774,7 +780,7 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
}
if (pb_style.has_parent_source()) {
- Source parent_source;
+ android::Source parent_source;
DeserializeSourceFromPb(pb_style.parent_source(), src_pool, &parent_source);
style->parent.value().SetSource(std::move(parent_source));
}
@@ -870,7 +876,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
- const ConfigDescription& config, StringPool* value_pool,
+ const ConfigDescription& config,
+ android::StringPool* value_pool,
io::IFileCollection* files, std::string* out_error) {
switch (pb_item.value_case()) {
case pb::Item::kRef: {
@@ -960,29 +967,32 @@ std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
case pb::Item::kStr: {
return util::make_unique<String>(
- value_pool->MakeRef(pb_item.str().value(), StringPool::Context(config)));
+ value_pool->MakeRef(pb_item.str().value(), android::StringPool::Context(config)));
} break;
case pb::Item::kRawStr: {
return util::make_unique<RawString>(
- value_pool->MakeRef(pb_item.raw_str().value(), StringPool::Context(config)));
+ value_pool->MakeRef(pb_item.raw_str().value(), android::StringPool::Context(config)));
} break;
case pb::Item::kStyledStr: {
const pb::StyledString& pb_str = pb_item.styled_str();
- StyleString style_str{pb_str.value()};
+ android::StyleString style_str{pb_str.value()};
for (const pb::StyledString::Span& pb_span : pb_str.span()) {
- style_str.spans.push_back(Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
+ style_str.spans.push_back(
+ android::Span{pb_span.tag(), pb_span.first_char(), pb_span.last_char()});
}
return util::make_unique<StyledString>(value_pool->MakeRef(
- style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
+ style_str,
+ android::StringPool::Context(android::StringPool::Context::kNormalPriority, config)));
} break;
case pb::Item::kFile: {
const pb::FileReference& pb_file = pb_item.file();
std::unique_ptr<FileReference> file_ref =
util::make_unique<FileReference>(value_pool->MakeRef(
- pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
+ pb_file.path(),
+ android::StringPool::Context(android::StringPool::Context::kHighPriority, config)));
file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
if (files != nullptr) {
file_ref->file = files->FindFile(*file_ref->path);
@@ -1011,8 +1021,8 @@ std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode
return resource;
}
-bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
- std::string* out_error) {
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el,
+ android::StringPool* value_pool, std::string* out_error) {
const pb::XmlElement& pb_el = pb_node.element();
out_el->name = pb_el.name();
out_el->namespace_uri = pb_el.namespace_uri();
@@ -1042,7 +1052,7 @@ bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, Stri
if (attr.compiled_value == nullptr) {
return {};
}
- attr.compiled_value->SetSource(Source().WithLine(pb_attr.source().line_number()));
+ attr.compiled_value->SetSource(android::Source().WithLine(pb_attr.source().line_number()));
}
out_el->attributes.push_back(std::move(attr));
}
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
index 723a1c095a50..95de3cb52017 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -17,16 +17,15 @@
#ifndef AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
#define AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-#include "androidfw/ResourceTypes.h"
-
#include "Configuration.pb.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
-#include "StringPool.h"
+#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPool.h"
#include "io/File.h"
#include "xml/XmlDom.h"
@@ -35,20 +34,20 @@ namespace aapt {
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const android::ConfigDescription& config,
- StringPool* value_pool, io::IFileCollection* files,
- std::string* out_error);
+ android::StringPool* value_pool,
+ io::IFileCollection* files, std::string* out_error);
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
const android::ConfigDescription& config,
- StringPool* value_pool, io::IFileCollection* files,
- std::string* out_error);
+ android::StringPool* value_pool,
+ io::IFileCollection* files, std::string* out_error);
std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
std::string* out_error);
-bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, StringPool* value_pool,
- std::string* out_error);
+bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el,
+ android::StringPool* value_pool, std::string* out_error);
bool DeserializeConfigFromPb(const pb::Configuration& pb_config,
android::ConfigDescription* out_config, std::string* out_error);
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index f3b7f758e170..0903205b5eb2 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -17,7 +17,8 @@
#include "format/proto/ProtoSerialize.h"
#include "ValueVisitor.h"
-#include "util/BigBuffer.h"
+#include "androidfw/BigBuffer.h"
+#include "optimize/Obfuscator.h"
using android::ConfigDescription;
@@ -25,22 +26,24 @@ using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace aapt {
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) {
- BigBuffer buffer(1024);
- StringPool::FlattenUtf8(&buffer, pool, diag);
+void SerializeStringPoolToPb(const android::StringPool& pool, pb::StringPool* out_pb_pool,
+ android::IDiagnostics* diag) {
+ android::BigBuffer buffer(1024);
+ android::StringPool::FlattenUtf8(&buffer, pool, diag);
std::string* data = out_pb_pool->mutable_data();
data->reserve(buffer.size());
size_t offset = 0;
- for (const BigBuffer::Block& block : buffer) {
+ for (const android::BigBuffer::Block& block : buffer) {
data->insert(data->begin() + offset, block.buffer.get(), block.buffer.get() + block.size);
offset += block.size;
}
}
-void SerializeSourceToPb(const Source& source, StringPool* src_pool, pb::Source* out_pb_source) {
- StringPool::Ref ref = src_pool->MakeRef(source.path);
+void SerializeSourceToPb(const android::Source& source, android::StringPool* src_pool,
+ pb::Source* out_pb_source) {
+ android::StringPool::Ref ref = src_pool->MakeRef(source.path);
out_pb_source->set_path_idx(static_cast<uint32_t>(ref.index()));
if (source.line) {
out_pb_source->mutable_position()->set_line_number(static_cast<uint32_t>(source.line.value()));
@@ -272,11 +275,15 @@ void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_
}
out_pb_config->set_sdk_version(config.sdkVersion);
+
+ // The constant values are the same across the structs.
+ out_pb_config->set_grammatical_gender(
+ static_cast<pb::Configuration_GrammaticalGender>(config.grammaticalInflection));
}
static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item,
std::vector<Overlayable*>& serialized_overlayables,
- StringPool* source_pool, pb::Entry* pb_entry,
+ android::StringPool* source_pool, pb::Entry* pb_entry,
pb::ResourceTable* pb_table) {
// Retrieve the index of the overlayable in the list of groups that have already been serialized.
size_t i;
@@ -337,13 +344,17 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item
}
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
- IDiagnostics* diag, SerializeTableOptions options) {
- auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<StringPool>();
+ android::IDiagnostics* diag, SerializeTableOptions options) {
+ auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<android::StringPool>();
pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint();
pb_fingerprint->set_tool(util::GetToolName());
pb_fingerprint->set_version(util::GetToolFingerprint());
-
+ for (auto it = table.included_packages_.begin(); it != table.included_packages_.end(); ++it) {
+ pb::DynamicRefTable* pb_dynamic_ref = out_table->add_dynamic_ref_table();
+ pb_dynamic_ref->mutable_package_id()->set_id(it->first);
+ pb_dynamic_ref->set_package_name(it->second);
+ }
std::vector<Overlayable*> overlayables;
auto table_view = table.GetPartitionedView();
for (const auto& package : table_view.packages) {
@@ -358,23 +369,23 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
if (type.id) {
pb_type->mutable_type_id()->set_id(type.id.value());
}
- pb_type->set_name(to_string(type.type).to_string());
+ pb_type->set_name(type.named_type.to_string());
- // hardcoded string uses characters which make it an invalid resource name
- static const char* obfuscated_resource_name = "0_resource_name_obfuscated";
for (const auto& entry : type.entries) {
pb::Entry* pb_entry = pb_type->add_entry();
if (entry.id) {
pb_entry->mutable_entry_id()->set_id(entry.id.value());
}
- ResourceName resource_name({}, type.type, entry.name);
- if (options.collapse_key_stringpool &&
- options.name_collapse_exemptions.find(resource_name) ==
- options.name_collapse_exemptions.end()) {
- pb_entry->set_name(obfuscated_resource_name);
- } else {
- pb_entry->set_name(entry.name);
- }
+ auto onObfuscate = [pb_entry, &entry](Obfuscator::Result obfuscatedResult,
+ const ResourceName& resource_name) {
+ pb_entry->set_name(obfuscatedResult == Obfuscator::Result::Obfuscated
+ ? Obfuscator::kObfuscatedResourceName
+ : entry.name);
+ };
+
+ Obfuscator::ObfuscateResourceName(options.collapse_key_stringpool,
+ options.name_collapse_exemptions, type.named_type, entry,
+ onObfuscate);
// Write the Visibility struct.
pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
@@ -482,7 +493,7 @@ static void SerializeMacroToPb(const Macro& ref, pb::MacroBody* pb_macro) {
}
template <typename T>
-static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, StringPool* src_pool) {
+static void SerializeItemMetaDataToPb(const Item& item, T* pb_item, android::StringPool* src_pool) {
if (src_pool != nullptr) {
SerializeSourceToPb(item.GetSource(), src_pool, pb_item->mutable_source());
}
@@ -526,7 +537,7 @@ class ValueSerializer : public ConstValueVisitor {
public:
using ConstValueVisitor::Visit;
- ValueSerializer(pb::Value* out_value, StringPool* src_pool)
+ ValueSerializer(pb::Value* out_value, android::StringPool* src_pool)
: out_value_(out_value), src_pool_(src_pool) {
}
@@ -545,7 +556,7 @@ class ValueSerializer : public ConstValueVisitor {
void Visit(const StyledString* str) override {
pb::StyledString* pb_str = out_value_->mutable_item()->mutable_styled_str();
pb_str->set_value(str->value->value);
- for (const StringPool::Span& span : str->value->spans) {
+ for (const android::StringPool::Span& span : str->value->spans) {
pb::StyledString::Span* pb_span = pb_str->add_span();
pb_span->set_tag(*span.name);
pb_span->set_first_char(span.first_char);
@@ -693,12 +704,12 @@ class ValueSerializer : public ConstValueVisitor {
private:
pb::Value* out_value_;
- StringPool* src_pool_;
+ android::StringPool* src_pool_;
};
} // namespace
-void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool) {
+void SerializeValueToPb(const Value& value, pb::Value* out_value, android::StringPool* src_pool) {
ValueSerializer serializer(out_value, src_pool);
value.Accept(&serializer);
diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h
index b0d56307fbe4..b0a70d90f1b4 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -17,15 +17,14 @@
#ifndef AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
#define AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
-#include "android-base/macros.h"
-#include "androidfw/ConfigDescription.h"
-
#include "Configuration.pb.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
-#include "StringPool.h"
+#include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/StringPool.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -51,7 +50,8 @@ struct SerializeTableOptions {
// Serializes a Value to its protobuf representation. An optional StringPool will hold the
// source path string.
-void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr);
+void SerializeValueToPb(const Value& value, pb::Value* out_value,
+ android::StringPool* src_pool = nullptr);
// Serialize an Item into its protobuf representation. pb::Item does not store the source path nor
// comments of an Item.
@@ -67,14 +67,15 @@ void SerializeXmlResourceToPb(const xml::XmlResource& resource, pb::XmlNode* out
// Serializes a StringPool into its protobuf representation, which is really just the binary
// ResStringPool representation stuffed into a bytes field.
-void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag);
+void SerializeStringPoolToPb(const android::StringPool& pool, pb::StringPool* out_pb_pool,
+ android::IDiagnostics* diag);
// Serializes a ConfigDescription into its protobuf representation.
void SerializeConfig(const android::ConfigDescription& config, pb::Configuration* out_pb_config);
// Serializes a ResourceTable into its protobuf representation.
void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table,
- IDiagnostics* diag, SerializeTableOptions options = {});
+ android::IDiagnostics* diag, SerializeTableOptions options = {});
// Serializes a ResourceFile into its protobuf representation.
void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file);
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index d1d72e012b31..afb83562b129 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -35,7 +35,7 @@ namespace aapt {
class MockFileCollection : public io::IFileCollection {
public:
- MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
+ MOCK_METHOD1(FindFile, io::IFile*(StringPiece path));
MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
MOCK_METHOD0(GetDirSeparator, char());
};
@@ -127,9 +127,9 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
context->GetDiagnostics()));
// Make a styled string.
- StyleString style_string;
+ android::StyleString style_string;
style_string.str = "hello";
- style_string.spans.push_back(Span{"b", 0u, 4u});
+ style_string.spans.push_back(android::Span{"b", 0u, 4u});
ASSERT_TRUE(table->AddResource(
NewResourceBuilder(test::ParseNameOrDie("com.app.a:string/styled"))
.SetValue(util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)))
@@ -164,8 +164,8 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
// Make an overlayable resource.
OverlayableItem overlayable_item(std::make_shared<Overlayable>(
- "OverlayableName", "overlay://theme", Source("res/values/overlayable.xml", 40)));
- overlayable_item.source = Source("res/values/overlayable.xml", 42);
+ "OverlayableName", "overlay://theme", android::Source("res/values/overlayable.xml", 40)));
+ overlayable_item.source = android::Source("res/values/overlayable.xml", 42);
ASSERT_TRUE(
table->AddResource(NewResourceBuilder(test::ParseNameOrDie("com.app.a:integer/overlayable"))
.SetOverlayable(overlayable_item)
@@ -271,7 +271,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
attr.compiled_value =
ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
- attr.compiled_value->SetSource(Source().WithLine(25));
+ attr.compiled_value->SetSource(android::Source().WithLine(25));
element.attributes.push_back(std::move(attr));
std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
@@ -292,7 +292,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
pb::XmlNode pb_xml;
SerializeXmlToPb(element, &pb_xml);
- StringPool pool;
+ android::StringPool pool;
xml::Element actual_el;
std::string error;
ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
@@ -365,7 +365,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeXmlTrimEmptyWhitepsace) {
options.remove_empty_text_nodes = true;
SerializeXmlToPb(element, &pb_xml, options);
- StringPool pool;
+ android::StringPool pool;
xml::Element actual_el;
std::string error;
ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
@@ -491,7 +491,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializePrimitives) {
EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
}
-static void ExpectConfigSerializes(const StringPiece& config_str) {
+static void ExpectConfigSerializes(StringPiece config_str) {
const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
pb::Configuration pb_config;
SerializeConfig(expected_config, &pb_config);
@@ -581,9 +581,13 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
ExpectConfigSerializes("v8");
+ ExpectConfigSerializes("en-feminine");
+ ExpectConfigSerializes("en-neuter-v34");
+ ExpectConfigSerializes("feminine-v34");
+
ExpectConfigSerializes(
- "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
- "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
+ "mcc123-mnc456-b+en+GB-masculine-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-"
+ "land-car-night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
}
TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
@@ -898,7 +902,8 @@ TEST(ProtoSerializeTest, SerializeMacro) {
auto original = std::make_unique<Macro>();
original->raw_value = "\nThis being human is a guest house.";
original->style_string.str = " This being human is a guest house.";
- original->style_string.spans.emplace_back(Span{.name = "b", .first_char = 12, .last_char = 16});
+ original->style_string.spans.emplace_back(
+ android::Span{.name = "b", .first_char = 12, .last_char = 16});
original->untranslatable_sections.emplace_back(UntranslatableSection{.start = 12, .end = 17});
original->alias_namespaces.emplace_back(
Macro::Namespace{.alias = "prefix", .package_name = "package.name", .is_private = true});
@@ -951,4 +956,100 @@ TEST(ProtoSerializeTest, StagedId) {
EXPECT_THAT(result.value().entry->staged_id.value().id, Eq(ResourceId(0x01ff0001)));
}
+TEST(ProtoSerializeTest, CustomResourceTypes) {
+ const uint32_t id_one_id = 0x7f020000;
+ const uint32_t id_2_two_id = 0x7f030000;
+ const uint32_t integer_three_id = 0x7f030000;
+ const uint32_t integer_1_four_id = 0x7f030000;
+ const uint32_t layout_bar_id = 0x7f050000;
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddSimple("com.app.test:id/one", ResourceId(id_one_id))
+ .AddSimple("com.app.test:id.2/two", ResourceId(id_2_two_id))
+ .AddValue(
+ "com.app.test:integer/one", ResourceId(integer_three_id),
+ util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 10u))
+ .AddValue(
+ "com.app.test:integer.1/one", ResourceId(integer_1_four_id),
+ util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 1u))
+ .AddValue(
+ "com.app.test:integer.1/one", test::ParseConfigOrDie("v1"),
+ ResourceId(integer_1_four_id),
+ util::make_unique<BinaryPrimitive>(uint8_t(android::Res_value::TYPE_INT_DEC), 2u))
+ .AddFileReference("com.app.test:layout.custom/bar", ResourceId(layout_bar_id),
+ "res/layout/bar.xml")
+ .Build();
+
+ test::TestFile file_a("res/layout/bar.xml");
+ MockFileCollection files;
+ EXPECT_CALL(files, FindFile(Eq("res/layout/bar.xml"))).WillRepeatedly(::testing::Return(&file_a));
+
+ ResourceTable new_table;
+ pb::ResourceTable pb_table;
+ std::string error;
+ SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+ DeserializeTableFromPb(pb_table, &files, &new_table, &error);
+ ASSERT_THAT(error, IsEmpty());
+
+ auto bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
+ &new_table, "com.app.test:integer.1/one", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("1")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer.1/one",
+ test::ParseConfigOrDie("v1"), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("2")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer/one",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(bp, NotNull());
+ EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
+ EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("10")->value.data));
+
+ bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "com.app.test:integer/one",
+ test::ParseConfigOrDie("v1"), "");
+ ASSERT_THAT(bp, IsNull());
+
+ auto id = test::GetValueForConfigAndProduct<Id>(&new_table, "com.app.test:id/one",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(id, NotNull());
+
+ id = test::GetValueForConfigAndProduct<Id>(&new_table, "com.app.test:id.2/two",
+ ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(id, NotNull());
+
+ auto custom_layout = test::GetValueForConfigAndProduct<FileReference>(
+ &new_table, "com.app.test:layout.custom/bar", ConfigDescription::DefaultConfig(), "");
+ ASSERT_THAT(custom_layout, NotNull());
+ EXPECT_THAT(*(custom_layout->path), Eq("res/layout/bar.xml"));
+}
+
+TEST(ProtoSerializeTest, SerializeDynamicRef) {
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x7f).Build();
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder().Build();
+ table->included_packages_.insert({20, "foobar"});
+ table->included_packages_.insert({30, "barfoo"});
+
+ ResourceTable new_table;
+ pb::ResourceTable pb_table;
+ MockFileCollection files;
+ std::string error;
+ SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ int result = new_table.included_packages_.size();
+ EXPECT_THAT(result, Eq(2));
+ auto it = new_table.included_packages_.begin();
+ EXPECT_THAT(it->first, Eq(20));
+ EXPECT_THAT(it->second, Eq("foobar"));
+ it++;
+ EXPECT_THAT(it->first, Eq(30));
+ EXPECT_THAT(it->second, Eq("barfoo"));
+}
} // namespace aapt
diff --git a/tools/aapt2/integration-tests/CommandTests/android-28.jar b/tools/aapt2/integration-tests/CommandTests/android-33.jar
index ef7576d17c6d..08cf49d854e2 100644
--- a/tools/aapt2/integration-tests/CommandTests/android-28.jar
+++ b/tools/aapt2/integration-tests/CommandTests/android-33.jar
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/built_with_aapt.apk b/tools/aapt2/integration-tests/DumpTest/built_with_aapt.apk
new file mode 100644
index 000000000000..090ebe5687dd
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/built_with_aapt.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt b/tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt
new file mode 100644
index 000000000000..cc0b3bf5d2fb
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/built_with_aapt_expected.txt
@@ -0,0 +1,11 @@
+package: name='com.aapt.app' versionCode='222' versionName='222' platformBuildVersionName='12' platformBuildVersionCode='32' compileSdkVersion='32' compileSdkVersionCodename='12'
+sdkVersion:'22'
+targetSdkVersion:'32'
+application: label='App' icon=''
+feature-group: label=''
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+supports-screens: 'small' 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+locales:
+densities:
diff --git a/tools/aapt2/integration-tests/DumpTest/components.apk b/tools/aapt2/integration-tests/DumpTest/components.apk
new file mode 100644
index 000000000000..a34ec83f3dae
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected.txt b/tools/aapt2/integration-tests/DumpTest/components_expected.txt
new file mode 100644
index 000000000000..9c81fb83ca15
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected.txt
@@ -0,0 +1,57 @@
+package: name='com.example.bundletool.minimal' versionCode='1' versionName='1.0' platformBuildVersionName='12' platformBuildVersionCode='31' compileSdkVersion='31' compileSdkVersionCodename='12'
+sdkVersion:'21'
+targetSdkVersion:'31'
+uses-configuration: reqTouchScreen='3' reqKeyboardType='2' reqHardKeyboard='-1' reqNavigation='3' reqFiveWayNav='-1'
+supports-gl-texture:'GL_OES_compressed_paletted_texture'
+uses-permission: name='android.permission.BIND_ACCESSIBILITY_SERVICE' maxSdkVersion='24'
+uses-permission-sdk-23: name='android.permission.RECEIVE_SMS'
+uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
+compatible-screens:'500/240','400/160'
+application-label:'minimal'
+application-icon-160:'res/uF.xml'
+application-icon-240:'res/uF.xml'
+application-icon-320:'res/uF.xml'
+application-icon-480:'res/uF.xml'
+application-icon-640:'res/uF.xml'
+application-icon-65534:'res/uF.xml'
+application: label='minimal' icon='res/uF.xml'
+uses-library:'mylib1'
+uses-library-not-required:'my_optional_lib'
+uses-native-library:'native1'
+uses-native-library-not-required:'optional'
+launchable-activity: name='com.example.bundletool.minimal.MainActivity' label='minimal' icon=''
+meta-data: name='android.nfc.cardemulation.host_apdu_service' resource='res/dU.xml'
+uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
+uses-implied-permission: name='android.permission.READ_EXTERNAL_STORAGE' reason='requested WRITE_EXTERNAL_STORAGE'
+feature-group: label=''
+ uses-feature: name='android.hardware.bluetooth'
+ uses-feature: name='android.hardware.camera'
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+ uses-feature-sdk-23: name='android.hardware.telephony'
+ uses-implied-feature-sdk-23: name='android.hardware.telephony' reason='requested a telephony permission'
+provides-component:'app-widget'
+provides-component:'device-admin'
+provides-component:'ime'
+provides-component:'wallpaper'
+provides-component:'accessibility'
+provides-component:'print-service'
+provides-component:'payment'
+provides-component:'search'
+provides-component:'document-provider'
+provides-component:'notification-listener'
+provides-component:'dream'
+provides-component:'camera'
+provides-component:'camera-secure'
+main
+other-receivers
+other-services
+supports-screens: 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+requires-smallest-width:'240'
+compatible-width-limit:'360'
+largest-width-limit:'480'
+locales: '--_--'
+densities: '160' '240' '320' '480' '640' '65534'
+native-code: 'x86_64'
+alt-native-code: 'x86'
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
new file mode 100644
index 000000000000..d866479f04db
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
@@ -0,0 +1,167 @@
+badging {
+ package {
+ package: "com.example.bundletool.minimal"
+ version_code: 1
+ version_name: "1.0"
+ platform_version_name: "12"
+ platform_version_code: "31"
+ compile_sdk_version: 31
+ compile_sdk_version_codename: "12"
+ }
+ application {
+ label: "minimal"
+ icon: "res/uF.xml"
+ density_icons {
+ key: 160
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 240
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 320
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 480
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 640
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 65534
+ value: "res/uF.xml"
+ }
+ }
+ uses_sdk {
+ min_sdk_version: 21
+ target_sdk_version: 31
+ }
+ supports_screen {
+ screens: NORMAL
+ screens: LARGE
+ screens: XLARGE
+ supports_any_densities: true
+ requires_smallest_width_dp: 240
+ compatible_width_limit_dp: 360
+ largest_width_limit_dp: 480
+ }
+ launchable_activity {
+ name: "com.example.bundletool.minimal.MainActivity"
+ label: "minimal"
+ }
+ compatible_screens {
+ screens {
+ size: 500
+ density: 240
+ }
+ screens {
+ size: 400
+ density: 160
+ }
+ }
+ architectures {
+ architectures: "x86_64"
+ alt_architectures: "x86"
+ }
+ supports_gl_texture {
+ name: "GL_OES_compressed_paletted_texture"
+ }
+ components {
+ main: true
+ other_receivers: true
+ other_services: true
+ provided_components: "app-widget"
+ provided_components: "device-admin"
+ provided_components: "ime"
+ provided_components: "wallpaper"
+ provided_components: "accessibility"
+ provided_components: "print-service"
+ provided_components: "payment"
+ provided_components: "search"
+ provided_components: "document-provider"
+ provided_components: "notification-listener"
+ provided_components: "dream"
+ provided_components: "camera"
+ provided_components: "camera-secure"
+ }
+ locales: "--_--"
+ densities: 160
+ densities: 240
+ densities: 320
+ densities: 480
+ densities: 640
+ densities: 65534
+ uses_configurations {
+ req_touch_screen: 3
+ req_keyboard_type: 2
+ req_hard_keyboard: -1
+ req_navigation: 3
+ req_five_way_nav: -1
+ }
+ feature_groups {
+ features {
+ name: "android.hardware.bluetooth"
+ required: true
+ }
+ features {
+ name: "android.hardware.camera"
+ required: true
+ }
+ features {
+ name: "android.hardware.faketouch"
+ implied_data {
+ reasons: "default feature for all apps"
+ }
+ }
+ features {
+ name: "android.hardware.telephony"
+ implied_data {
+ from_sdk_23_permission: true
+ reasons: "requested a telephony permission"
+ }
+ }
+ }
+ uses_permissions {
+ name: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ max_sdk_version: 24
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.RECEIVE_SMS"
+ sdk23_and_above: true
+ }
+ uses_permissions {
+ name: "android.permission.WRITE_EXTERNAL_STORAGE"
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.READ_EXTERNAL_STORAGE"
+ required: true
+ implied: true
+ }
+ permissions {
+ name: "minimal.FIRST_PERMISSION"
+ }
+ uses_libraries {
+ name: "mylib1"
+ required: true
+ }
+ uses_libraries {
+ name: "my_optional_lib"
+ }
+ uses_native_libraries {
+ name: "native1"
+ required: true
+ }
+ uses_native_libraries {
+ name: "optional"
+ }
+ metadata {
+ name: "android.nfc.cardemulation.host_apdu_service"
+ resource_string: "res/dU.xml"
+ }
+}
diff --git a/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
new file mode 100644
index 000000000000..6da6fc6f12c3
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
@@ -0,0 +1,2312 @@
+badging {
+ package {
+ package: "com.example.bundletool.minimal"
+ version_code: 1
+ version_name: "1.0"
+ platform_version_name: "12"
+ platform_version_code: "31"
+ compile_sdk_version: 31
+ compile_sdk_version_codename: "12"
+ }
+ application {
+ label: "minimal"
+ icon: "res/uF.xml"
+ density_icons {
+ key: 160
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 240
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 320
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 480
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 640
+ value: "res/uF.xml"
+ }
+ density_icons {
+ key: 65534
+ value: "res/uF.xml"
+ }
+ }
+ uses_sdk {
+ min_sdk_version: 21
+ target_sdk_version: 31
+ }
+ supports_screen {
+ screens: NORMAL
+ screens: LARGE
+ screens: XLARGE
+ supports_any_densities: true
+ requires_smallest_width_dp: 240
+ compatible_width_limit_dp: 360
+ largest_width_limit_dp: 480
+ }
+ launchable_activity {
+ name: "com.example.bundletool.minimal.MainActivity"
+ label: "minimal"
+ }
+ compatible_screens {
+ screens {
+ size: 500
+ density: 240
+ }
+ screens {
+ size: 400
+ density: 160
+ }
+ }
+ architectures {
+ architectures: "x86_64"
+ alt_architectures: "x86"
+ }
+ supports_gl_texture {
+ name: "GL_OES_compressed_paletted_texture"
+ }
+ components {
+ main: true
+ other_receivers: true
+ other_services: true
+ provided_components: "app-widget"
+ provided_components: "device-admin"
+ provided_components: "ime"
+ provided_components: "wallpaper"
+ provided_components: "accessibility"
+ provided_components: "print-service"
+ provided_components: "payment"
+ provided_components: "search"
+ provided_components: "document-provider"
+ provided_components: "notification-listener"
+ provided_components: "dream"
+ provided_components: "camera"
+ provided_components: "camera-secure"
+ }
+ locales: "--_--"
+ densities: 160
+ densities: 240
+ densities: 320
+ densities: 480
+ densities: 640
+ densities: 65534
+ uses_configurations {
+ req_touch_screen: 3
+ req_keyboard_type: 2
+ req_hard_keyboard: -1
+ req_navigation: 3
+ req_five_way_nav: -1
+ }
+ feature_groups {
+ features {
+ name: "android.hardware.bluetooth"
+ required: true
+ }
+ features {
+ name: "android.hardware.camera"
+ required: true
+ }
+ features {
+ name: "android.hardware.faketouch"
+ implied_data {
+ reasons: "default feature for all apps"
+ }
+ }
+ features {
+ name: "android.hardware.telephony"
+ implied_data {
+ from_sdk_23_permission: true
+ reasons: "requested a telephony permission"
+ }
+ }
+ }
+ uses_permissions {
+ name: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ max_sdk_version: 24
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.RECEIVE_SMS"
+ sdk23_and_above: true
+ }
+ uses_permissions {
+ name: "android.permission.WRITE_EXTERNAL_STORAGE"
+ required: true
+ }
+ uses_permissions {
+ name: "android.permission.READ_EXTERNAL_STORAGE"
+ required: true
+ implied: true
+ }
+ permissions {
+ name: "minimal.FIRST_PERMISSION"
+ }
+ uses_libraries {
+ name: "mylib1"
+ required: true
+ }
+ uses_libraries {
+ name: "my_optional_lib"
+ }
+ uses_native_libraries {
+ name: "native1"
+ required: true
+ }
+ uses_native_libraries {
+ name: "optional"
+ }
+ metadata {
+ name: "android.nfc.cardemulation.host_apdu_service"
+ resource_string: "res/dU.xml"
+ }
+}
+resource_table {
+ source_pool {
+ data: "\001\000\034\000$\000\000\000\001\000\000\000\000\000\000\000\000\001\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ }
+ package {
+ package_id {
+ id: 127
+ }
+ package_name: "com.example.bundletool.minimal"
+ type {
+ type_id {
+ id: 1
+ }
+ name: "color"
+ entry {
+ entry_id {
+ }
+ name: "black"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4278190080
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "purple_200"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4290479868
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 2
+ }
+ name: "purple_500"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4284612846
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 3
+ }
+ name: "purple_700"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4281794739
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 4
+ }
+ name: "teal_200"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4278442693
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 5
+ }
+ name: "teal_700"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4278290310
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 6
+ }
+ name: "white"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ color_argb8_value: 4294967295
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 2
+ }
+ name: "dimen"
+ entry {
+ entry_id {
+ }
+ name: "fab_margin"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ prim {
+ dimension_value: 4097
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 3
+ }
+ name: "drawable"
+ entry {
+ entry_id {
+ }
+ name: "$ic_launcher_foreground__0"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 24
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/Za.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "ic_launcher_background"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/3N.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 2
+ }
+ name: "ic_launcher_foreground"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 24
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/qm.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 4
+ }
+ name: "mipmap"
+ entry {
+ entry_id {
+ }
+ name: "ic_launcher"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 160
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/u3.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 240
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/SD.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 320
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/jy.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 480
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/D2.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 640
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/CG.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 26
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/uF.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "ic_launcher_round"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ density: 160
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/7c.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 240
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/tf.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 320
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/1S.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 480
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/5Q.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 640
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/C9.png"
+ type: PNG
+ }
+ }
+ }
+ }
+ config_value {
+ config {
+ density: 65534
+ sdk_version: 26
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/oy.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 5
+ }
+ name: "string"
+ entry {
+ entry_id {
+ }
+ name: "action_settings"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Settings"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 1
+ }
+ name: "app_name"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "minimal"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 2
+ }
+ name: "first_fragment_label"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "First Fragment"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 3
+ }
+ name: "hello_first_fragment"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Hello first fragment"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 4
+ }
+ name: "hello_second_fragment"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Hello second fragment. Arg: %1$s"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 5
+ }
+ name: "next"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Next"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 6
+ }
+ name: "previous"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Previous"
+ }
+ }
+ }
+ }
+ }
+ entry {
+ entry_id {
+ id: 7
+ }
+ name: "second_fragment_label"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ str {
+ value: "Second Fragment"
+ }
+ }
+ }
+ }
+ }
+ }
+ type {
+ type_id {
+ id: 6
+ }
+ name: "xml"
+ entry {
+ entry_id {
+ }
+ name: "apduservice"
+ visibility {
+ source {
+ }
+ }
+ config_value {
+ config {
+ }
+ value {
+ source {
+ }
+ item {
+ file {
+ path: "res/dU.xml"
+ type: BINARY_XML
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ tool_fingerprint {
+ tool: "Android Asset Packaging Tool (aapt)"
+ version: "2.19-SOONG BUILD NUMBER PLACEHOLDER"
+ }
+}
+xml_files {
+ path: "res/oy.xml"
+ root {
+ element {
+ namespace_declaration {
+ prefix: "android"
+ uri: "http://schemas.android.com/apk/res/android"
+ source {
+ line_number: 2
+ }
+ }
+ name: "adaptive-icon"
+ child {
+ element {
+ name: "background"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "drawable"
+ source {
+ }
+ resource_id: 16843161
+ compiled_item {
+ ref {
+ id: 2130903041
+ }
+ }
+ }
+ }
+ source {
+ line_number: 3
+ }
+ }
+ child {
+ element {
+ name: "foreground"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "drawable"
+ source {
+ }
+ resource_id: 16843161
+ compiled_item {
+ ref {
+ id: 2130903042
+ }
+ }
+ }
+ }
+ source {
+ line_number: 4
+ }
+ }
+ }
+ source {
+ line_number: 2
+ }
+ }
+}
+xml_files {
+ path: "AndroidManifest.xml"
+ root {
+ element {
+ namespace_declaration {
+ prefix: "android"
+ uri: "http://schemas.android.com/apk/res/android"
+ source {
+ line_number: 2
+ }
+ }
+ name: "manifest"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "versionCode"
+ source {
+ }
+ resource_id: 16843291
+ compiled_item {
+ prim {
+ int_decimal_value: 1
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "versionName"
+ value: "1.0"
+ resource_id: 16843292
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "compileSdkVersion"
+ source {
+ }
+ resource_id: 16844146
+ compiled_item {
+ prim {
+ int_decimal_value: 31
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "compileSdkVersionCodename"
+ value: "12"
+ resource_id: 16844147
+ }
+ attribute {
+ name: "package"
+ value: "com.example.bundletool.minimal"
+ }
+ attribute {
+ name: "platformBuildVersionCode"
+ source {
+ }
+ compiled_item {
+ prim {
+ int_decimal_value: 31
+ }
+ }
+ }
+ attribute {
+ name: "platformBuildVersionName"
+ source {
+ }
+ compiled_item {
+ prim {
+ int_decimal_value: 12
+ }
+ }
+ }
+ child {
+ element {
+ name: "uses-sdk"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "minSdkVersion"
+ source {
+ }
+ resource_id: 16843276
+ compiled_item {
+ prim {
+ int_decimal_value: 21
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "targetSdkVersion"
+ source {
+ }
+ resource_id: 16843376
+ compiled_item {
+ prim {
+ int_decimal_value: 31
+ }
+ }
+ }
+ }
+ source {
+ line_number: 7
+ }
+ }
+ child {
+ element {
+ name: "supports-screens"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "anyDensity"
+ source {
+ }
+ resource_id: 16843372
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "smallScreens"
+ source {
+ }
+ resource_id: 16843396
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "normalScreens"
+ source {
+ }
+ resource_id: 16843397
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "largeScreens"
+ source {
+ }
+ resource_id: 16843398
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "requiresSmallestWidthDp"
+ source {
+ }
+ resource_id: 16843620
+ compiled_item {
+ prim {
+ int_decimal_value: 240
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "compatibleWidthLimitDp"
+ source {
+ }
+ resource_id: 16843621
+ compiled_item {
+ prim {
+ int_decimal_value: 360
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "largestWidthLimitDp"
+ source {
+ }
+ resource_id: 16843622
+ compiled_item {
+ prim {
+ int_decimal_value: 480
+ }
+ }
+ }
+ }
+ source {
+ line_number: 11
+ }
+ }
+ child {
+ element {
+ name: "uses-configuration"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqTouchScreen"
+ source {
+ }
+ resource_id: 16843303
+ compiled_item {
+ prim {
+ int_decimal_value: 3
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqKeyboardType"
+ source {
+ }
+ resource_id: 16843304
+ compiled_item {
+ prim {
+ int_decimal_value: 2
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqHardKeyboard"
+ source {
+ }
+ resource_id: 16843305
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqNavigation"
+ source {
+ }
+ resource_id: 16843306
+ compiled_item {
+ prim {
+ int_decimal_value: 3
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "reqFiveWayNav"
+ source {
+ }
+ resource_id: 16843314
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ }
+ source {
+ line_number: 20
+ }
+ }
+ child {
+ element {
+ name: "supports-gl-texture"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "GL_OES_compressed_paletted_texture"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 27
+ }
+ }
+ child {
+ element {
+ name: "permission"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "minimal.FIRST_PERMISSION"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 29
+ }
+ }
+ child {
+ element {
+ name: "uses-feature"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.hardware.camera"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 31
+ }
+ }
+ child {
+ element {
+ name: "uses-feature"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.hardware.bluetooth"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 32
+ }
+ }
+ child {
+ element {
+ name: "uses-permission"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "maxSdkVersion"
+ source {
+ }
+ resource_id: 16843377
+ compiled_item {
+ prim {
+ int_decimal_value: 24
+ }
+ }
+ }
+ }
+ source {
+ line_number: 34
+ }
+ }
+ child {
+ element {
+ name: "uses-permission-sdk-23"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.permission.RECEIVE_SMS"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 38
+ }
+ }
+ child {
+ element {
+ name: "uses-permission"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.permission.WRITE_EXTERNAL_STORAGE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 40
+ }
+ }
+ child {
+ element {
+ name: "compatible-screens"
+ child {
+ element {
+ name: "screen"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenSize"
+ source {
+ }
+ resource_id: 16843466
+ compiled_item {
+ prim {
+ int_decimal_value: 500
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenDensity"
+ source {
+ }
+ resource_id: 16843467
+ compiled_item {
+ prim {
+ int_decimal_value: 240
+ }
+ }
+ }
+ }
+ source {
+ line_number: 43
+ }
+ }
+ child {
+ element {
+ name: "screen"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenSize"
+ source {
+ }
+ resource_id: 16843466
+ compiled_item {
+ prim {
+ int_decimal_value: 400
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "screenDensity"
+ source {
+ }
+ resource_id: 16843467
+ compiled_item {
+ prim {
+ int_decimal_value: 160
+ }
+ }
+ }
+ }
+ source {
+ line_number: 46
+ }
+ }
+ }
+ source {
+ line_number: 42
+ }
+ }
+ child {
+ element {
+ name: "application"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "label"
+ source {
+ }
+ resource_id: 16842753
+ compiled_item {
+ ref {
+ id: 2131034113
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "icon"
+ source {
+ }
+ resource_id: 16842754
+ compiled_item {
+ ref {
+ id: 2130968576
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "allowBackup"
+ source {
+ }
+ resource_id: 16843392
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "supportsRtl"
+ source {
+ }
+ resource_id: 16843695
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "multiArch"
+ source {
+ }
+ resource_id: 16843918
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "roundIcon"
+ source {
+ }
+ resource_id: 16844076
+ compiled_item {
+ ref {
+ id: 2130968577
+ }
+ }
+ }
+ child {
+ element {
+ name: "uses-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "mylib1"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ }
+ source {
+ line_number: 58
+ }
+ }
+ child {
+ element {
+ name: "uses-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "my_optional_lib"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ }
+ source {
+ line_number: 61
+ }
+ }
+ child {
+ element {
+ name: "uses-native-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "native1"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ }
+ source {
+ line_number: 65
+ }
+ }
+ child {
+ element {
+ name: "uses-native-library"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "optional"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "required"
+ source {
+ }
+ resource_id: 16843406
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ }
+ source {
+ line_number: 68
+ }
+ }
+ child {
+ element {
+ name: "activity"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "label"
+ source {
+ }
+ resource_id: 16842753
+ compiled_item {
+ ref {
+ id: 2131034113
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.MainActivity"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.action.MAIN"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 77
+ }
+ }
+ child {
+ element {
+ name: "category"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.category.LAUNCHER"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 79
+ }
+ }
+ }
+ source {
+ line_number: 76
+ }
+ }
+ }
+ source {
+ line_number: 72
+ }
+ }
+ child {
+ element {
+ name: "activity"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "label"
+ source {
+ }
+ resource_id: 16842753
+ compiled_item {
+ ref {
+ id: 2131034113
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.AnotherActivity"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.media.action.VIDEO_CAMERA"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 87
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.media.action.STILL_IMAGE_CAMERA_SECURE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 88
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.intent.action.SEARCH"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 89
+ }
+ }
+ }
+ source {
+ line_number: 86
+ }
+ }
+ }
+ source {
+ line_number: 82
+ }
+ }
+ child {
+ element {
+ name: "receiver"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.OneReceiver"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.appwidget.action.APPWIDGET_UPDATE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 97
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.app.action.DEVICE_ADMIN_ENABLED"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 98
+ }
+ }
+ }
+ source {
+ line_number: 96
+ }
+ }
+ }
+ source {
+ line_number: 93
+ }
+ }
+ child {
+ element {
+ name: "receiver"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.TwoReceiver"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_DEVICE_ADMIN"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.app.action.DEVICE_ADMIN_ENABLED"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 106
+ }
+ }
+ }
+ source {
+ line_number: 105
+ }
+ }
+ }
+ source {
+ line_number: 101
+ }
+ }
+ child {
+ element {
+ name: "receiver"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.ThreeReceiver"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 109
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.OneService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.view.InputMethod"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 115
+ }
+ }
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.service.wallpaper.WallpaperService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 116
+ }
+ }
+ }
+ source {
+ line_number: 114
+ }
+ }
+ }
+ source {
+ line_number: 111
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$TwoService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_ACCESSIBILITY_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.accessibilityservice.AccessibilityService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 124
+ }
+ }
+ }
+ source {
+ line_number: 123
+ }
+ }
+ }
+ source {
+ line_number: 119
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$ThreeService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_PRINT_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.printservice.PrintService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 132
+ }
+ }
+ }
+ source {
+ line_number: 131
+ }
+ }
+ }
+ source {
+ line_number: 127
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$FourService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_NFC_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.nfc.cardemulation.action.HOST_APDU_SERVICE"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 140
+ }
+ }
+ }
+ source {
+ line_number: 139
+ }
+ }
+ child {
+ element {
+ name: "meta-data"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.nfc.cardemulation.host_apdu_service"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "resource"
+ source {
+ }
+ resource_id: 16842789
+ compiled_item {
+ ref {
+ id: 2131099648
+ }
+ }
+ }
+ }
+ source {
+ line_number: 143
+ }
+ }
+ }
+ source {
+ line_number: 135
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$FiveService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.service.notification.NotificationListenerService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 152
+ }
+ }
+ }
+ source {
+ line_number: 151
+ }
+ }
+ }
+ source {
+ line_number: 147
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$SixService"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.BIND_DREAM_SERVICE"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: false
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.service.dreams.DreamService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 160
+ }
+ }
+ }
+ source {
+ line_number: 159
+ }
+ }
+ }
+ source {
+ line_number: 155
+ }
+ }
+ child {
+ element {
+ name: "service"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.Services$SevenService"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 163
+ }
+ }
+ child {
+ element {
+ name: "provider"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "com.example.bundletool.minimal.OneProvider"
+ resource_id: 16842755
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "permission"
+ value: "android.permission.MANAGE_DOCUMENTS"
+ resource_id: 16842758
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "exported"
+ source {
+ }
+ resource_id: 16842768
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "authorities"
+ value: "A"
+ resource_id: 16842776
+ }
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "grantUriPermissions"
+ source {
+ }
+ resource_id: 16842779
+ compiled_item {
+ prim {
+ boolean_value: true
+ }
+ }
+ }
+ child {
+ element {
+ name: "intent-filter"
+ child {
+ element {
+ name: "action"
+ attribute {
+ namespace_uri: "http://schemas.android.com/apk/res/android"
+ name: "name"
+ value: "android.content.action.DOCUMENTS_PROVIDER"
+ resource_id: 16842755
+ }
+ }
+ source {
+ line_number: 172
+ }
+ }
+ }
+ source {
+ line_number: 171
+ }
+ }
+ }
+ source {
+ line_number: 165
+ }
+ }
+ }
+ source {
+ line_number: 51
+ }
+ }
+ }
+ source {
+ line_number: 2
+ }
+ }
+}
diff --git a/tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt b/tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt
new file mode 100644
index 000000000000..f79de5cba11d
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/components_permissions_expected.txt
@@ -0,0 +1,5 @@
+package: com.example.bundletool.minimal
+permission: minimal.FIRST_PERMISSION
+uses-permission: name='android.permission.BIND_ACCESSIBILITY_SERVICE' maxSdkVersion='24'
+uses-permission-sdk-23: name='android.permission.RECEIVE_SMS'
+uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
diff --git a/tools/aapt2/integration-tests/DumpTest/minimal.apk b/tools/aapt2/integration-tests/DumpTest/minimal.apk
new file mode 100644
index 000000000000..a8415faca390
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/minimal.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/minimal_expected.txt b/tools/aapt2/integration-tests/DumpTest/minimal_expected.txt
new file mode 100644
index 000000000000..85ab5d80cd39
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/minimal_expected.txt
@@ -0,0 +1,92 @@
+package: name='com.lato.bubblegirl' versionCode='33' versionName='1.0.0' platformBuildVersionName='8.1.0' platformBuildVersionCode='27'
+sdkVersion:'19'
+targetSdkVersion:'26'
+application-label:'Bubble Girl'
+application-label-ar:'Bubble Girl'
+application-label-az:'Bubble Girl'
+application-label-be:'Bubble Girl'
+application-label-bg:'Bubble Girl'
+application-label-bn:'Bubble Girl'
+application-label-bs:'Bubble Girl'
+application-label-ca:'Bubble Girl'
+application-label-cs:'Bubble Girl'
+application-label-da:'Bubble Girl'
+application-label-de:'Bubble Girl'
+application-label-el:'Bubble Girl'
+application-label-es:'Bubble Girl'
+application-label-es-ES:'Bubble Girl'
+application-label-et:'Bubble Girl'
+application-label-eu:'Bubble Girl'
+application-label-fa:'Bubble Girl'
+application-label-fi:'Bubble Girl'
+application-label-fr:'Bubble Girl'
+application-label-fr-CA:'Bubble Girl'
+application-label-gl:'Bubble Girl'
+application-label-hi:'Bubble Girl'
+application-label-hr:'Bubble Girl'
+application-label-hu:'Bubble Girl'
+application-label-hy:'Bubble Girl'
+application-label-in:'Bubble Girl'
+application-label-is:'Bubble Girl'
+application-label-it:'Bubble Girl'
+application-label-iw:'Bubble Girl'
+application-label-ja:'Bubble Girl'
+application-label-jv:'Bubble Girl'
+application-label-ka:'Bubble Girl'
+application-label-kk:'Bubble Girl'
+application-label-kn:'Bubble Girl'
+application-label-ko:'Bubble Girl'
+application-label-lt:'Bubble Girl'
+application-label-lv:'Bubble Girl'
+application-label-mk:'Bubble Girl'
+application-label-ml:'Bubble Girl'
+application-label-mr:'Bubble Girl'
+application-label-ms:'Bubble Girl'
+application-label-nb:'Bubble Girl'
+application-label-nl:'Bubble Girl'
+application-label-pa:'Bubble Girl'
+application-label-pl:'Bubble Girl'
+application-label-pt-BR:'Bubble Girl'
+application-label-pt-PT:'Bubble Girl'
+application-label-ro:'Bubble Girl'
+application-label-ru:'Bubble Girl'
+application-label-sk:'Bubble Girl'
+application-label-sl:'Bubble Girl'
+application-label-sq:'Bubble Girl'
+application-label-sr:'Bubble Girl'
+application-label-su:'Bubble Girl'
+application-label-sv:'Bubble Girl'
+application-label-ta:'Bubble Girl'
+application-label-te:'Bubble Girl'
+application-label-th:'Bubble Girl'
+application-label-tl:'Bubble Girl'
+application-label-tr:'Bubble Girl'
+application-label-tt:'Bubble Girl'
+application-label-uk:'Bubble Girl'
+application-label-vi:'Bubble Girl'
+application-label-zh-CN:'Bubble Girl'
+application-label-zh-HK:'Bubble Girl'
+application-label-zh-TW:'Bubble Girl'
+application-icon-160:'res/theme/1f.png'
+application-icon-240:'res/theme/1f.png'
+application-icon-320:'res/theme/1f.png'
+application-icon-480:'res/theme/1f.png'
+application-icon-640:'res/theme/1f.png'
+application: label='Bubble Girl' icon='res/theme/1f.png'
+launchable-activity: name='com.sonymobile.runtimeskinning.livewallpaperlib.configactivity.LauncherActivity' label='' icon=''
+uses-library:'com.sony.device'
+uses-permission: name='com.sonymobile.permission.RUNTIME_SKIN'
+feature-group: label=''
+ uses-gl-es: '0x30000'
+ uses-feature: name='android.software.live_wallpaper'
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+ uses-feature: name='android.hardware.screen.portrait'
+ uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'
+provides-component:'wallpaper'
+main
+other-activities
+supports-screens: 'small' 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+locales: '--_--' 'ar' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'el' 'es' 'es-ES' 'et' 'eu' 'fa' 'fi' 'fr' 'fr-CA' 'gl' 'hi' 'hr' 'hu' 'hy' 'in' 'is' 'it' 'iw' 'ja' 'jv' 'ka' 'kk' 'kn' 'ko' 'lt' 'lv' 'mk' 'ml' 'mr' 'ms' 'nb' 'nl' 'pa' 'pl' 'pt-BR' 'pt-PT' 'ro' 'ru' 'sk' 'sl' 'sq' 'sr' 'su' 'sv' 'ta' 'te' 'th' 'tl' 'tr' 'tt' 'uk' 'vi' 'zh-CN' 'zh-HK' 'zh-TW'
+densities: '160' '240' '320' '480' '640'
diff --git a/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apk b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apk
new file mode 100644
index 000000000000..7b269a5b8e5a
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt
new file mode 100644
index 000000000000..85e8d0a3cbba
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt
@@ -0,0 +1,23 @@
+package: name='com.test.e17wmultiapknexus' versionCode='107' versionName='14' platformBuildVersionName='2.3.3' platformBuildVersionCode='10'
+sdkVersion:'1'
+application-label:'w45wmultiapknexus_10'
+application-icon-120:'res/drawable-ldpi-v4/icon.png'
+application-icon-160:'res/drawable-mdpi-v4/icon.png'
+application-icon-240:'res/drawable-hdpi-v4/icon.png'
+application: label='w45wmultiapknexus_10' icon='res/drawable-mdpi-v4/icon.png'
+launchable-activity: name='com.test.e17wmultiapknexus.TestActivity' label='' icon=''
+compatible-screens:'500/320'
+uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
+uses-implied-permission: name='android.permission.WRITE_EXTERNAL_STORAGE' reason='targetSdkVersion < 4'
+uses-permission: name='android.permission.READ_PHONE_STATE'
+uses-implied-permission: name='android.permission.READ_PHONE_STATE' reason='targetSdkVersion < 4'
+uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
+uses-implied-permission: name='android.permission.READ_EXTERNAL_STORAGE' reason='requested WRITE_EXTERNAL_STORAGE'
+feature-group: label=''
+ uses-feature: name='android.hardware.faketouch'
+ uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+main
+supports-screens: 'small' 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+locales: '--_--'
+densities: '120' '160' '240'
diff --git a/tools/aapt2/io/BigBufferStream.h b/tools/aapt2/io/BigBufferStream.h
index 8b5c8b84cd3c..63a5e5756ed4 100644
--- a/tools/aapt2/io/BigBufferStream.h
+++ b/tools/aapt2/io/BigBufferStream.h
@@ -17,15 +17,15 @@
#ifndef AAPT_IO_BIGBUFFERSTREAM_H
#define AAPT_IO_BIGBUFFERSTREAM_H
+#include "androidfw/BigBuffer.h"
#include "io/Io.h"
-#include "util/BigBuffer.h"
namespace aapt {
namespace io {
class BigBufferInputStream : public KnownSizeInputStream {
public:
- inline explicit BigBufferInputStream(const BigBuffer* buffer)
+ inline explicit BigBufferInputStream(const android::BigBuffer* buffer)
: buffer_(buffer), iter_(buffer->begin()) {
}
virtual ~BigBufferInputStream() = default;
@@ -47,15 +47,15 @@ class BigBufferInputStream : public KnownSizeInputStream {
private:
DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream);
- const BigBuffer* buffer_;
- BigBuffer::const_iterator iter_;
+ const android::BigBuffer* buffer_;
+ android::BigBuffer::const_iterator iter_;
size_t offset_ = 0;
size_t bytes_read_ = 0;
};
class BigBufferOutputStream : public OutputStream {
public:
- inline explicit BigBufferOutputStream(BigBuffer* buffer) : buffer_(buffer) {
+ inline explicit BigBufferOutputStream(android::BigBuffer* buffer) : buffer_(buffer) {
}
virtual ~BigBufferOutputStream() = default;
@@ -70,7 +70,7 @@ class BigBufferOutputStream : public OutputStream {
private:
DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
- BigBuffer* buffer_;
+ android::BigBuffer* buffer_;
};
} // namespace io
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 565aad6f2284..08d497def8a4 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -22,8 +22,7 @@
#include <vector>
#include "android-base/macros.h"
-
-#include "Source.h"
+#include "androidfw/Source.h"
#include "io/Data.h"
#include "util/Files.h"
#include "util/Util.h"
@@ -49,7 +48,7 @@ class IFile {
// Returns the source of this file. This is for presentation to the user and
// may not be a valid file system path (for example, it may contain a '@' sign to separate
// the files within a ZIP archive from the path to the containing ZIP archive.
- virtual const Source& GetSource() const = 0;
+ virtual const android::Source& GetSource() const = 0;
IFile* CreateFileSegment(size_t offset, size_t len);
@@ -76,7 +75,7 @@ class FileSegment : public IFile {
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
- const Source& GetSource() const override {
+ const android::Source& GetSource() const override {
return file_->GetSource();
}
@@ -102,7 +101,7 @@ class IFileCollection {
public:
virtual ~IFileCollection() = default;
- virtual IFile* FindFile(const android::StringPiece& path) = 0;
+ virtual IFile* FindFile(android::StringPiece path) = 0;
virtual std::unique_ptr<IFileCollectionIterator> Iterator() = 0;
virtual char GetDirSeparator() = 0;
};
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index fc2e45e74b4d..a64982a7fa5c 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -19,13 +19,12 @@
#include <dirent.h>
#include "android-base/errors.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
-#include "utils/FileMap.h"
-#include "Source.h"
#include "io/FileStream.h"
#include "util/Files.h"
-
#include "util/Util.h"
+#include "utils/FileMap.h"
using ::android::StringPiece;
using ::android::base::SystemErrorCodeToString;
@@ -33,7 +32,8 @@ using ::android::base::SystemErrorCodeToString;
namespace aapt {
namespace io {
-RegularFile::RegularFile(const Source& source) : source_(source) {}
+RegularFile::RegularFile(const android::Source& source) : source_(source) {
+}
std::unique_ptr<IData> RegularFile::OpenAsData() {
android::FileMap map;
@@ -50,7 +50,7 @@ std::unique_ptr<io::InputStream> RegularFile::OpenInputStream() {
return util::make_unique<FileInputStream>(source_.path);
}
-const Source& RegularFile::GetSource() const {
+const android::Source& RegularFile::GetSource() const {
return source_;
}
@@ -67,8 +67,8 @@ IFile* FileCollectionIterator::Next() {
return result;
}
-std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiece& root,
- std::string* outError) {
+std::unique_ptr<FileCollection> FileCollection::Create(android::StringPiece root,
+ std::string* outError) {
std::unique_ptr<FileCollection> collection =
std::unique_ptr<FileCollection>(new FileCollection());
@@ -80,7 +80,7 @@ std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiec
std::vector<std::string> sorted_files;
while (struct dirent *entry = readdir(d.get())) {
- std::string prefix_path = root.to_string();
+ std::string prefix_path(root);
file::AppendPath(&prefix_path, entry->d_name);
// The directory to iterate over looking for files
@@ -117,12 +117,19 @@ std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiec
return collection;
}
-IFile* FileCollection::InsertFile(const StringPiece& path) {
- return (files_[path.to_string()] = util::make_unique<RegularFile>(Source(path))).get();
+IFile* FileCollection::InsertFile(StringPiece path) {
+ auto file = util::make_unique<RegularFile>(android::Source(path));
+ auto it = files_.lower_bound(path);
+ if (it != files_.end() && it->first == path) {
+ it->second = std::move(file);
+ } else {
+ it = files_.emplace_hint(it, path, std::move(file));
+ }
+ return it->second.get();
}
-IFile* FileCollection::FindFile(const StringPiece& path) {
- auto iter = files_.find(path.to_string());
+IFile* FileCollection::FindFile(StringPiece path) {
+ auto iter = files_.find(path);
if (iter != files_.end()) {
return iter->second.get();
}
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index 04c6fa15bc85..0e798fc1b975 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -27,16 +27,16 @@ namespace io {
// A regular file from the file system. Uses mmap to open the data.
class RegularFile : public IFile {
public:
- explicit RegularFile(const Source& source);
+ explicit RegularFile(const android::Source& source);
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
- const Source& GetSource() const override;
+ const android::Source& GetSource() const override;
private:
DISALLOW_COPY_AND_ASSIGN(RegularFile);
- Source source_;
+ android::Source source_;
};
class FileCollection;
@@ -60,12 +60,11 @@ class FileCollection : public IFileCollection {
FileCollection() = default;
/** Creates a file collection containing all files contained in the specified root directory. */
- static std::unique_ptr<FileCollection> Create(const android::StringPiece& path,
- std::string* outError);
+ static std::unique_ptr<FileCollection> Create(android::StringPiece path, std::string* outError);
// Adds a file located at path. Returns the IFile representation of that file.
- IFile* InsertFile(const android::StringPiece& path);
- IFile* FindFile(const android::StringPiece& path) override;
+ IFile* InsertFile(android::StringPiece path);
+ IFile* FindFile(android::StringPiece path) override;
std::unique_ptr<IFileCollectionIterator> Iterator() override;
char GetDirSeparator() override;
@@ -74,7 +73,7 @@ class FileCollection : public IFileCollection {
friend class FileCollectionIterator;
- std::map<std::string, std::unique_ptr<IFile>> files_;
+ std::map<std::string, std::unique_ptr<IFile>, std::less<>> files_;
};
} // namespace io
diff --git a/tools/aapt2/io/StringStream.cpp b/tools/aapt2/io/StringStream.cpp
index 4ca04a8c7477..9c497882b99b 100644
--- a/tools/aapt2/io/StringStream.cpp
+++ b/tools/aapt2/io/StringStream.cpp
@@ -21,7 +21,7 @@ using ::android::StringPiece;
namespace aapt {
namespace io {
-StringInputStream::StringInputStream(const StringPiece& str) : str_(str), offset_(0u) {
+StringInputStream::StringInputStream(StringPiece str) : str_(str), offset_(0u) {
}
bool StringInputStream::Next(const void** data, size_t* size) {
diff --git a/tools/aapt2/io/StringStream.h b/tools/aapt2/io/StringStream.h
index f29890ab7ee5..f7bdecca0dee 100644
--- a/tools/aapt2/io/StringStream.h
+++ b/tools/aapt2/io/StringStream.h
@@ -29,7 +29,7 @@ namespace io {
class StringInputStream : public KnownSizeInputStream {
public:
- explicit StringInputStream(const android::StringPiece& str);
+ explicit StringInputStream(android::StringPiece str);
bool Next(const void** data, size_t* size) override;
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index bb925c9b3f8e..79d8d527fe8b 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -26,44 +26,48 @@ using ::google::protobuf::io::ZeroCopyOutputStream;
namespace aapt {
namespace io {
-bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std::string& out_path,
+bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path,
uint32_t compression_flags, IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive");
+ context->GetDiagnostics()->Note(android::DiagMessage()
+ << "writing " << out_path << " to archive");
}
if (!writer->WriteFile(out_path, compression_flags, in)) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
- << " to archive: " << writer->GetError());
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to write " << out_path
+ << " to archive: " << writer->GetError());
return false;
}
return true;
}
-bool CopyFileToArchive(IAaptContext* context, io::IFile* file, const std::string& out_path,
+bool CopyFileToArchive(IAaptContext* context, io::IFile* file, std::string_view out_path,
uint32_t compression_flags, IArchiveWriter* writer) {
TRACE_CALL();
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "failed to open file");
+ context->GetDiagnostics()->Error(android::DiagMessage(file->GetSource())
+ << "failed to open file");
return false;
}
return CopyInputStreamToArchive(context, data.get(), out_path, compression_flags, writer);
}
bool CopyFileToArchivePreserveCompression(IAaptContext* context, io::IFile* file,
- const std::string& out_path, IArchiveWriter* writer) {
+ std::string_view out_path, IArchiveWriter* writer) {
uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
return CopyFileToArchive(context, file, out_path, compression_flags, writer);
}
bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* proto_msg,
- const std::string& out_path, uint32_t compression_flags,
+ std::string_view out_path, uint32_t compression_flags,
IArchiveWriter* writer) {
TRACE_CALL();
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(DiagMessage() << "writing " << out_path << " to archive");
+ context->GetDiagnostics()->Note(android::DiagMessage()
+ << "writing " << out_path << " to archive");
}
if (writer->StartEntry(out_path, compression_flags)) {
@@ -72,8 +76,8 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot
// Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
::google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
if (!proto_msg->SerializeToZeroCopyStream(&adaptor)) {
- context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
- << " to archive");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "failed to write " << out_path << " to archive");
return false;
}
}
@@ -82,8 +86,8 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot
return true;
}
}
- context->GetDiagnostics()->Error(DiagMessage() << "failed to write " << out_path
- << " to archive: " << writer->GetError());
+ context->GetDiagnostics()->Error(android::DiagMessage() << "failed to write " << out_path
+ << " to archive: " << writer->GetError());
return false;
}
@@ -106,7 +110,7 @@ bool Copy(OutputStream* out, InputStream* in) {
return !in->HadError();
}
-bool Copy(OutputStream* out, const StringPiece& in) {
+bool Copy(OutputStream* out, StringPiece in) {
const char* in_buffer = in.data();
size_t in_len = in.size();
while (in_len != 0) {
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index 1b48a288d255..685f522a2e71 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -17,12 +17,11 @@
#ifndef AAPT_IO_UTIL_H
#define AAPT_IO_UTIL_H
-#include <string>
-
-#include "google/protobuf/message.h"
-#include "google/protobuf/io/coded_stream.h"
+#include <string_view>
#include "format/Archive.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/message.h"
#include "io/File.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
@@ -30,23 +29,23 @@
namespace aapt {
namespace io {
-bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std::string& out_path,
+bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path,
uint32_t compression_flags, IArchiveWriter* writer);
-bool CopyFileToArchive(IAaptContext* context, IFile* file, const std::string& out_path,
+bool CopyFileToArchive(IAaptContext* context, IFile* file, std::string_view out_path,
uint32_t compression_flags, IArchiveWriter* writer);
bool CopyFileToArchivePreserveCompression(IAaptContext* context, IFile* file,
- const std::string& out_path, IArchiveWriter* writer);
+ std::string_view out_path, IArchiveWriter* writer);
bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* proto_msg,
- const std::string& out_path, uint32_t compression_flags,
+ std::string_view out_path, uint32_t compression_flags,
IArchiveWriter* writer);
// Copies the data from in to out. Returns false if there was an error.
// If there was an error, check the individual streams' HadError/GetError methods.
bool Copy(OutputStream* out, InputStream* in);
-bool Copy(OutputStream* out, const ::android::StringPiece& in);
+bool Copy(OutputStream* out, android::StringPiece in);
bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
class OutputStreamAdaptor : public io::OutputStream {
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 4380586b1d3c..4a5385d90d3b 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -16,22 +16,21 @@
#include "io/ZipArchive.h"
-#include "utils/FileMap.h"
-#include "ziparchive/zip_archive.h"
-
-#include "Source.h"
+#include "androidfw/Source.h"
#include "trace/TraceBuffer.h"
#include "util/Files.h"
#include "util/Util.h"
+#include "utils/FileMap.h"
+#include "ziparchive/zip_archive.h"
using ::android::StringPiece;
namespace aapt {
namespace io {
-ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry,
- const Source& source)
- : zip_handle_(handle), zip_entry_(entry), source_(source) {}
+ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const android::Source& source)
+ : zip_handle_(handle), zip_entry_(entry), source_(source) {
+}
std::unique_ptr<IData> ZipFile::OpenAsData() {
// The file will fail to be mmaped if it is empty
@@ -68,7 +67,7 @@ std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() {
return OpenAsData();
}
-const Source& ZipFile::GetSource() const {
+const android::Source& ZipFile::GetSource() const {
return source_;
}
@@ -92,8 +91,8 @@ IFile* ZipFileCollectionIterator::Next() {
ZipFileCollection::ZipFileCollection() : handle_(nullptr) {}
-std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
- const StringPiece& path, std::string* out_error) {
+std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(StringPiece path,
+ std::string* out_error) {
TRACE_CALL();
constexpr static const int32_t kEmptyArchive = -6;
@@ -132,7 +131,7 @@ std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
}
std::unique_ptr<IFile> file = util::make_unique<ZipFile>(collection->handle_, zip_data,
- Source(zip_entry_path, path.to_string()));
+ android::Source(zip_entry_path, path));
collection->files_by_name_[zip_entry_path] = file.get();
collection->files_.push_back(std::move(file));
}
@@ -145,8 +144,8 @@ std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
return collection;
}
-IFile* ZipFileCollection::FindFile(const StringPiece& path) {
- auto iter = files_by_name_.find(path.to_string());
+IFile* ZipFileCollection::FindFile(StringPiece path) {
+ auto iter = files_by_name_.find(path);
if (iter != files_by_name_.end()) {
return iter->second;
}
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index b283e57d4011..c263aa490d22 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -32,17 +32,17 @@ namespace io {
// and copied into memory when opened. Otherwise it is mmapped from the ZIP archive.
class ZipFile : public IFile {
public:
- ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const Source& source);
+ ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const android::Source& source);
std::unique_ptr<IData> OpenAsData() override;
std::unique_ptr<io::InputStream> OpenInputStream() override;
- const Source& GetSource() const override;
+ const android::Source& GetSource() const override;
bool WasCompressed() override;
private:
::ZipArchiveHandle zip_handle_;
::ZipEntry zip_entry_;
- Source source_;
+ android::Source source_;
};
class ZipFileCollection;
@@ -61,10 +61,10 @@ class ZipFileCollectionIterator : public IFileCollectionIterator {
// An IFileCollection that represents a ZIP archive and the entries within it.
class ZipFileCollection : public IFileCollection {
public:
- static std::unique_ptr<ZipFileCollection> Create(const android::StringPiece& path,
+ static std::unique_ptr<ZipFileCollection> Create(android::StringPiece path,
std::string* outError);
- io::IFile* FindFile(const android::StringPiece& path) override;
+ io::IFile* FindFile(android::StringPiece path) override;
std::unique_ptr<IFileCollectionIterator> Iterator() override;
char GetDirSeparator() override;
@@ -76,7 +76,7 @@ class ZipFileCollection : public IFileCollection {
ZipArchiveHandle handle_;
std::vector<std::unique_ptr<IFile>> files_;
- std::map<std::string, IFile*> files_by_name_;
+ std::map<std::string, IFile*, std::less<>> files_by_name_;
};
} // namespace io
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 482d91aeb491..87da09a7b054 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -30,7 +30,7 @@ using ::android::StringPiece;
namespace aapt {
-StringPiece AnnotationProcessor::ExtractFirstSentence(const StringPiece& comment) {
+StringPiece AnnotationProcessor::ExtractFirstSentence(StringPiece comment) {
Utf8Iterator iter(comment);
while (iter.HasNext()) {
const char32_t codepoint = iter.Next();
@@ -62,7 +62,7 @@ static std::array<AnnotationRule, 2> sAnnotationRules = {{
}};
void AnnotationProcessor::AppendCommentLine(std::string comment) {
- static const std::string sDeprecated = "@deprecated";
+ static constexpr std::string_view sDeprecated = "@deprecated";
// Treat deprecated specially, since we don't remove it from the source comment.
if (comment.find(sDeprecated) != std::string::npos) {
@@ -74,7 +74,7 @@ void AnnotationProcessor::AppendCommentLine(std::string comment) {
if (idx != std::string::npos) {
// Captures all parameters associated with the specified annotation rule
// by matching the first pair of parantheses after the rule.
- std::regex re(rule.doc_str.to_string() + "\\s*\\((.+)\\)");
+ std::regex re(std::string(rule.doc_str) += "\\s*\\((.+)\\)");
std::smatch match_result;
const bool is_match = std::regex_search(comment, match_result, re);
// We currently only capture and preserve parameters for SystemApi.
@@ -97,7 +97,7 @@ void AnnotationProcessor::AppendCommentLine(std::string comment) {
// If there was trimming to do, copy the string.
if (trimmed.size() != comment.size()) {
- comment = trimmed.to_string();
+ comment = std::string(trimmed);
}
if (!has_comments_) {
@@ -107,12 +107,12 @@ void AnnotationProcessor::AppendCommentLine(std::string comment) {
comment_ << "\n * " << std::move(comment);
}
-void AnnotationProcessor::AppendComment(const StringPiece& comment) {
+void AnnotationProcessor::AppendComment(StringPiece comment) {
// We need to process line by line to clean-up whitespace and append prefixes.
for (StringPiece line : util::Tokenize(comment, '\n')) {
line = util::TrimWhitespace(line);
if (!line.empty()) {
- AppendCommentLine(line.to_string());
+ AppendCommentLine(std::string(line));
}
}
}
@@ -126,7 +126,7 @@ void AnnotationProcessor::AppendNewLine() {
void AnnotationProcessor::Print(Printer* printer, bool strip_api_annotations) const {
if (has_comments_) {
std::string result = comment_.str();
- for (const StringPiece& line : util::Tokenize(result, '\n')) {
+ for (StringPiece line : util::Tokenize(result, '\n')) {
printer->Println(line);
}
printer->Println(" */");
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index f217afb16f32..db3437e3b5b1 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -56,11 +56,11 @@ class AnnotationProcessor {
// Extracts the first sentence of a comment. The algorithm selects the substring starting from
// the beginning of the string, and ending at the first '.' character that is followed by a
// whitespace character. If these requirements are not met, the whole string is returned.
- static android::StringPiece ExtractFirstSentence(const android::StringPiece& comment);
+ static android::StringPiece ExtractFirstSentence(android::StringPiece comment);
// Adds more comments. Resources can have value definitions for various configurations, and
// each of the definitions may have comments that need to be processed.
- void AppendComment(const android::StringPiece& comment);
+ void AppendComment(android::StringPiece comment);
void AppendNewLine();
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index 3163497f0da6..98f3bd2018b0 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -27,8 +27,8 @@ void ClassMember::Print(bool /*final*/, Printer* printer, bool strip_api_annotat
processor_.Print(printer, strip_api_annotations);
}
-void MethodDefinition::AppendStatement(const StringPiece& statement) {
- statements_.push_back(statement.to_string());
+void MethodDefinition::AppendStatement(StringPiece statement) {
+ statements_.emplace_back(statement);
}
void MethodDefinition::Print(bool final, Printer* printer, bool) const {
@@ -110,8 +110,8 @@ constexpr static const char* sWarningHeader =
" * should not be modified by hand.\n"
" */\n\n";
-void ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
- bool final, bool strip_api_annotations, io::OutputStream* out) {
+void ClassDefinition::WriteJavaFile(const ClassDefinition* def, StringPiece package, bool final,
+ bool strip_api_annotations, io::OutputStream* out) {
Printer printer(out);
printer.Print(sWarningHeader).Print("package ").Print(package).Println(";");
printer.Println();
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 2acdadb3c034..63c99821a836 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -59,8 +59,8 @@ class ClassMember {
template <typename T>
class PrimitiveMember : public ClassMember {
public:
- PrimitiveMember(const android::StringPiece& name, const T& val, bool staged_api = false)
- : name_(name.to_string()), val_(val), staged_api_(staged_api) {
+ PrimitiveMember(android::StringPiece name, const T& val, bool staged_api = false)
+ : name_(name), val_(val), staged_api_(staged_api) {
}
bool empty() const override {
@@ -104,8 +104,8 @@ class PrimitiveMember : public ClassMember {
template <>
class PrimitiveMember<std::string> : public ClassMember {
public:
- PrimitiveMember(const android::StringPiece& name, const std::string& val, bool staged_api = false)
- : name_(name.to_string()), val_(val) {
+ PrimitiveMember(android::StringPiece name, const std::string& val, bool staged_api = false)
+ : name_(name), val_(val) {
}
bool empty() const override {
@@ -141,7 +141,8 @@ using StringMember = PrimitiveMember<std::string>;
template <typename T, typename StringConverter>
class PrimitiveArrayMember : public ClassMember {
public:
- explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
+ explicit PrimitiveArrayMember(android::StringPiece name) : name_(name) {
+ }
void AddElement(const T& val) {
elements_.emplace_back(val);
@@ -209,12 +210,12 @@ using ResourceArrayMember = PrimitiveArrayMember<std::variant<ResourceId, FieldR
class MethodDefinition : public ClassMember {
public:
// Expected method signature example: 'public static void onResourcesLoaded(int p)'.
- explicit MethodDefinition(const android::StringPiece& signature)
- : signature_(signature.to_string()) {}
+ explicit MethodDefinition(android::StringPiece signature) : signature_(signature) {
+ }
// Appends a single statement to the method. It should include no newlines or else
// formatting may be broken.
- void AppendStatement(const android::StringPiece& statement);
+ void AppendStatement(android::StringPiece statement);
// Not quite the same as a name, but good enough.
const std::string& GetName() const override {
@@ -239,11 +240,12 @@ enum class ClassQualifier { kNone, kStatic };
class ClassDefinition : public ClassMember {
public:
- static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
- bool final, bool strip_api_annotations, io::OutputStream* out);
+ static void WriteJavaFile(const ClassDefinition* def, android::StringPiece package, bool final,
+ bool strip_api_annotations, io::OutputStream* out);
- ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
- : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
+ ClassDefinition(android::StringPiece name, ClassQualifier qualifier, bool createIfEmpty)
+ : name_(name), qualifier_(qualifier), create_if_empty_(createIfEmpty) {
+ }
enum class Result {
kAdded,
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index a963d9893f2f..7665d0e8d9cb 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -57,14 +57,14 @@ static const std::set<StringPiece> sJavaIdentifiers = {
"transient", "try", "void", "volatile", "while",
"true", "false", "null"};
-static bool IsValidSymbol(const StringPiece& symbol) {
+static bool IsValidSymbol(StringPiece symbol) {
return sJavaIdentifiers.find(symbol) == sJavaIdentifiers.end();
}
// Java symbols can not contain . or -, but those are valid in a resource name.
// Replace those with '_'.
-std::string JavaClassGenerator::TransformToFieldName(const StringPiece& symbol) {
- std::string output = symbol.to_string();
+std::string JavaClassGenerator::TransformToFieldName(StringPiece symbol) {
+ std::string output(symbol);
for (char& c : output) {
if (c == '.' || c == '-') {
c = '_';
@@ -84,7 +84,7 @@ std::string JavaClassGenerator::TransformToFieldName(const StringPiece& symbol)
// Foo_bar
static std::string TransformNestedAttr(const ResourceNameRef& attr_name,
const std::string& styleable_class_name,
- const StringPiece& package_name_to_generate) {
+ StringPiece package_name_to_generate) {
std::string output = styleable_class_name;
// We may reference IDs from other packages, so prefix the entry name with
@@ -226,16 +226,15 @@ static bool operator<(const StyleableAttr& lhs, const StyleableAttr& rhs) {
static FieldReference GetRFieldReference(const ResourceName& name,
StringPiece fallback_package_name) {
- const std::string package_name =
- name.package.empty() ? fallback_package_name.to_string() : name.package;
+ const std::string_view package_name = name.package.empty() ? fallback_package_name : name.package;
const std::string entry = JavaClassGenerator::TransformToFieldName(name.entry);
- return FieldReference(StringPrintf("%s.R.%s.%s", package_name.c_str(),
- name.type.to_string().data(), entry.c_str()));
+ return FieldReference(
+ StringPrintf("%s.R.%s.%s", package_name.data(), name.type.to_string().data(), entry.c_str()));
}
bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
const Styleable& styleable,
- const StringPiece& package_name_to_generate,
+ StringPiece package_name_to_generate,
ClassDefinition* out_class_def,
MethodDefinition* out_rewrite_method,
Printer* r_txt_printer) {
@@ -314,7 +313,8 @@ bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
return true;
}
const StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment();
- return attr_comment_line.contains("@removed") || attr_comment_line.contains("@hide");
+ return attr_comment_line.find("@removed") != std::string::npos ||
+ attr_comment_line.find("@hide") != std::string::npos;
});
documentation_attrs.erase(documentation_remove_iter, documentation_attrs.end());
@@ -397,7 +397,7 @@ bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
comment = styleable_attr.symbol.value().attribute->GetComment();
}
- if (comment.contains("@removed")) {
+ if (comment.find("@removed") != std::string::npos) {
// Removed attributes are public but hidden from the documentation, so
// don't emit them as part of the class documentation.
continue;
@@ -497,7 +497,7 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
}
if (out_rewrite_method != nullptr) {
- const std::string type_str = name.type.to_string();
+ const auto type_str = name.type.to_string();
out_rewrite_method->AppendStatement(
StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | packageIdBits;", type_str.data(),
field_name.data(), type_str.data(), field_name.data()));
@@ -505,8 +505,7 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
}
std::optional<std::string> JavaClassGenerator::UnmangleResource(
- const StringPiece& package_name, const StringPiece& package_name_to_generate,
- const ResourceEntry& entry) {
+ StringPiece package_name, StringPiece package_name_to_generate, const ResourceEntry& entry) {
if (SkipSymbol(entry.visibility.level)) {
return {};
}
@@ -528,7 +527,7 @@ std::optional<std::string> JavaClassGenerator::UnmangleResource(
return {std::move(unmangled_name)};
}
-bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate,
+bool JavaClassGenerator::ProcessType(StringPiece package_name_to_generate,
const ResourceTablePackage& package,
const ResourceTableType& type,
ClassDefinition* out_type_class_def,
@@ -548,10 +547,11 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
}
// We need to make sure we hide the fact that we are generating kAttrPrivate attributes.
- const ResourceNameRef resource_name(
- package_name_to_generate,
- type.type == ResourceType::kAttrPrivate ? ResourceType::kAttr : type.type,
- unmangled_name.value());
+ const auto target_type = type.named_type.type == ResourceType::kAttrPrivate
+ ? ResourceNamedTypeWithDefaultName(ResourceType::kAttr)
+ : type.named_type;
+ const ResourceNameRef resource_name(package_name_to_generate, target_type,
+ unmangled_name.value());
// Check to see if the unmangled name is a valid Java name (not a keyword).
if (!IsValidSymbol(unmangled_name.value())) {
@@ -576,7 +576,7 @@ bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate
return true;
}
-bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, OutputStream* out,
+bool JavaClassGenerator::Generate(StringPiece package_name_to_generate, OutputStream* out,
OutputStream* out_r_txt) {
return Generate(package_name_to_generate, package_name_to_generate, out, out_r_txt);
}
@@ -590,8 +590,8 @@ static void AppendJavaDocAnnotations(const std::vector<std::string>& annotations
}
}
-bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
- const StringPiece& out_package_name, OutputStream* out,
+bool JavaClassGenerator::Generate(StringPiece package_name_to_generate,
+ StringPiece out_package_name, OutputStream* out,
OutputStream* out_r_txt) {
ClassDefinition r_class("R", ClassQualifier::kNone, true);
std::unique_ptr<MethodDefinition> rewrite_method;
@@ -616,7 +616,8 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
for (const auto& package : table_->packages) {
for (const auto& type : package->types) {
- if (type->type == ResourceType::kAttrPrivate || type->type == ResourceType::kMacro) {
+ if (type->named_type.type == ResourceType::kAttrPrivate ||
+ type->named_type.type == ResourceType::kMacro) {
// We generate kAttrPrivate as part of the kAttr type, so skip them here.
// Macros are not actual resources, so skip them as well.
continue;
@@ -628,7 +629,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
std::unique_ptr<ClassDefinition> class_def;
if (out != nullptr) {
class_def = util::make_unique<ClassDefinition>(
- to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
+ to_string(type->named_type.type), ClassQualifier::kStatic, force_creation_if_empty);
}
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
@@ -636,9 +637,10 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
return false;
}
- if (type->type == ResourceType::kAttr) {
+ if (type->named_type.type == ResourceType::kAttr) {
// Also include private attributes in this same class.
- if (const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate)) {
+ if (const ResourceTableType* priv_type =
+ package->FindTypeWithDefaultName(ResourceType::kAttrPrivate)) {
if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
rewrite_method.get(), r_txt_printer.get())) {
return false;
@@ -646,7 +648,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
}
}
- if (out != nullptr && type->type == ResourceType::kStyleable && is_public) {
+ if (out != nullptr && type->named_type.type == ResourceType::kStyleable && is_public) {
// When generating a public R class, we don't want Styleable to be part
// of the API. It is only emitted for documentation purposes.
class_def->GetCommentBuilder()->AppendComment("@doconly");
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index b45a2f12db35..234df04472ce 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -70,16 +70,16 @@ class JavaClassGenerator {
// All symbols technically belong to a single package, but linked libraries will
// have their names mangled, denoting that they came from a different package.
// We need to generate these symbols in a separate file. Returns true on success.
- bool Generate(const android::StringPiece& package_name_to_generate, io::OutputStream* out,
+ bool Generate(android::StringPiece package_name_to_generate, io::OutputStream* out,
io::OutputStream* out_r_txt = nullptr);
- bool Generate(const android::StringPiece& package_name_to_generate,
- const android::StringPiece& output_package_name, io::OutputStream* out,
+ bool Generate(android::StringPiece package_name_to_generate,
+ android::StringPiece output_package_name, io::OutputStream* out,
io::OutputStream* out_r_txt = nullptr);
const std::string& GetError() const;
- static std::string TransformToFieldName(const android::StringPiece& symbol);
+ static std::string TransformToFieldName(android::StringPiece symbol);
private:
bool SkipSymbol(Visibility::Level state);
@@ -87,11 +87,11 @@ class JavaClassGenerator {
// Returns the unmangled resource entry name if the unmangled package is the same as
// package_name_to_generate. Returns nothing if the resource should be skipped.
- std::optional<std::string> UnmangleResource(const android::StringPiece& package_name,
- const android::StringPiece& package_name_to_generate,
+ std::optional<std::string> UnmangleResource(android::StringPiece package_name,
+ android::StringPiece package_name_to_generate,
const ResourceEntry& entry);
- bool ProcessType(const android::StringPiece& package_name_to_generate,
+ bool ProcessType(android::StringPiece package_name_to_generate,
const ResourceTablePackage& package, const ResourceTableType& type,
ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def,
text::Printer* r_txt_printer);
@@ -106,8 +106,7 @@ class JavaClassGenerator {
// its package ID if `out_rewrite_method` is not nullptr.
// `package_name_to_generate` is the package
bool ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
- const Styleable& styleable,
- const android::StringPiece& package_name_to_generate,
+ const Styleable& styleable, android::StringPiece package_name_to_generate,
ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
text::Printer* r_txt_printer);
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index a0db41baecb4..65b63b7c0c61 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -18,7 +18,7 @@
#include <algorithm>
-#include "Source.h"
+#include "androidfw/Source.h"
#include "java/ClassDefinition.h"
#include "java/JavaClassGenerator.h"
#include "text/Unicode.h"
@@ -28,7 +28,8 @@ using ::aapt::text::IsJavaIdentifier;
namespace aapt {
-static std::optional<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,
+static std::optional<std::string> ExtractJavaIdentifier(android::IDiagnostics* diag,
+ const android::Source& source,
const std::string& value) {
std::string result = value;
size_t pos = value.rfind('.');
@@ -42,22 +43,22 @@ static std::optional<std::string> ExtractJavaIdentifier(IDiagnostics* diag, cons
}
if (result.empty()) {
- diag->Error(DiagMessage(source) << "empty symbol");
+ diag->Error(android::DiagMessage(source) << "empty symbol");
return {};
}
if (!IsJavaIdentifier(result)) {
- diag->Error(DiagMessage(source) << "invalid Java identifier '" << result << "'");
+ diag->Error(android::DiagMessage(source) << "invalid Java identifier '" << result << "'");
return {};
}
return result;
}
-static bool WriteSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
- ClassDefinition* class_def) {
+static bool WriteSymbol(const android::Source& source, android::IDiagnostics* diag,
+ xml::Element* el, ClassDefinition* class_def) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (!attr) {
- diag->Error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
+ diag->Error(android::DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
return false;
}
@@ -72,21 +73,22 @@ static bool WriteSymbol(const Source& source, IDiagnostics* diag, xml::Element*
string_member->GetCommentBuilder()->AppendComment(el->comment);
if (class_def->AddMember(std::move(string_member)) == ClassDefinition::Result::kOverridden) {
- diag->Warn(DiagMessage(source.WithLine(el->line_number))
+ diag->Warn(android::DiagMessage(source.WithLine(el->line_number))
<< "duplicate definitions of '" << result.value() << "', overriding previous");
}
return true;
}
-std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
+std::unique_ptr<ClassDefinition> GenerateManifestClass(android::IDiagnostics* diag,
+ xml::XmlResource* res) {
xml::Element* el = xml::FindRootElement(res->root.get());
if (!el) {
- diag->Error(DiagMessage(res->file.source) << "no root tag defined");
+ diag->Error(android::DiagMessage(res->file.source) << "no root tag defined");
return {};
}
if (el->name != "manifest" && !el->namespace_uri.empty()) {
- diag->Error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
+ diag->Error(android::DiagMessage(res->file.source) << "no <manifest> root tag defined");
return {};
}
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index 3f6645facaa2..3a45ef6d5ecc 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -17,13 +17,14 @@
#ifndef AAPT_JAVA_MANIFESTCLASSGENERATOR_H
#define AAPT_JAVA_MANIFESTCLASSGENERATOR_H
-#include "Diagnostics.h"
+#include "androidfw/IDiagnostics.h"
#include "java/ClassDefinition.h"
#include "xml/XmlDom.h"
namespace aapt {
-std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
+std::unique_ptr<ClassDefinition> GenerateManifestClass(android::IDiagnostics* diag,
+ xml::XmlResource* res);
} // namespace aapt
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index e53e22070b62..80a46d553960 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -517,7 +517,7 @@ bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table
for (auto& type : pkg->types) {
for (auto& entry : type->entries) {
for (auto& config_value : entry->values) {
- ResourceName from(pkg->name, type->type, entry->name);
+ ResourceName from(pkg->name, type->named_type, entry->name);
ReferenceVisitor visitor(context, from, keep_set);
config_value->value->Accept(&visitor);
}
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index a01b64d024d2..267f7ede274a 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -22,12 +22,11 @@
#include <set>
#include <string>
-#include "androidfw/StringPiece.h"
-
#include "Resource.h"
#include "ResourceTable.h"
-#include "Source.h"
#include "ValueVisitor.h"
+#include "androidfw/Source.h"
+#include "androidfw/StringPiece.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
@@ -37,7 +36,7 @@ namespace proguard {
struct UsageLocation {
ResourceName name;
- Source source;
+ android::Source source;
};
struct NameAndSignature {
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index 328ac97090a8..3dbd7e613a3e 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -75,7 +75,7 @@ bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) {
CloningValueTransformer cloner(&table->string_pool);
for (auto& package : table->packages) {
for (auto& type : package->types) {
- if (type->type != ResourceType::kStyle) {
+ if (type->named_type.type != ResourceType::kStyle) {
continue;
}
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index be6c930b9284..44cd276f77a2 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -101,9 +101,10 @@ class ProductFilter : public IResourceTableConsumer {
explicit ProductFilter(std::unordered_set<std::string> products) : products_(products) {
}
- ResourceConfigValueIter SelectProductToKeep(
- const ResourceNameRef& name, const ResourceConfigValueIter begin,
- const ResourceConfigValueIter end, IDiagnostics* diag);
+ ResourceConfigValueIter SelectProductToKeep(const ResourceNameRef& name,
+ const ResourceConfigValueIter begin,
+ const ResourceConfigValueIter end,
+ android::IDiagnostics* diag);
bool Consume(IAaptContext* context, ResourceTable* table) override;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index f8e734724018..c4f6e70c0cc9 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -30,16 +30,104 @@ using android::StringPiece;
namespace aapt {
-static bool RequiredNameIsNotEmpty(xml::Element* el, SourcePathDiagnostics* diag) {
+// This is to detect whether an <intent-filter> contains deeplink.
+// See https://developer.android.com/training/app-links/deep-linking.
+static bool HasDeepLink(xml::Element* intent_filter_el) {
+ xml::Element* action_el = intent_filter_el->FindChild({}, "action");
+ xml::Element* category_el = intent_filter_el->FindChild({}, "category");
+ xml::Element* data_el = intent_filter_el->FindChild({}, "data");
+ if (action_el == nullptr || category_el == nullptr || data_el == nullptr) {
+ return false;
+ }
+
+ // Deeplinks must specify the ACTION_VIEW intent action.
+ constexpr const char* action_view = "android.intent.action.VIEW";
+ if (intent_filter_el->FindChildWithAttribute({}, "action", xml::kSchemaAndroid, "name",
+ action_view) == nullptr) {
+ return false;
+ }
+
+ // Deeplinks must have scheme included in <data> tag.
+ xml::Attribute* data_scheme_attr = data_el->FindAttribute(xml::kSchemaAndroid, "scheme");
+ if (data_scheme_attr == nullptr || data_scheme_attr->value.empty()) {
+ return false;
+ }
+
+ // Deeplinks must include BROWSABLE category.
+ constexpr const char* category_browsable = "android.intent.category.BROWSABLE";
+ if (intent_filter_el->FindChildWithAttribute({}, "category", xml::kSchemaAndroid, "name",
+ category_browsable) == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static bool VerifyDeeplinkPathAttribute(xml::Element* data_el, android::SourcePathDiagnostics* diag,
+ const std::string& attr_name) {
+ xml::Attribute* attr = data_el->FindAttribute(xml::kSchemaAndroid, attr_name);
+ if (attr != nullptr && !attr->value.empty()) {
+ StringPiece attr_value = attr->value;
+ const char* startChar = attr_value.begin();
+ if (attr_name == "pathPattern") {
+ // pathPattern starts with '.' or '*' does not need leading slash.
+ // Reference starts with @ does not need leading slash.
+ if (*startChar == '/' || *startChar == '.' || *startChar == '*' || *startChar == '@') {
+ return true;
+ } else {
+ diag->Error(android::DiagMessage(data_el->line_number)
+ << "attribute 'android:" << attr_name << "' in <" << data_el->name
+ << "> tag has value of '" << attr_value
+ << "', it must be in a pattern start with '.' or '*', otherwise must start "
+ "with a leading slash '/'");
+ return false;
+ }
+ } else {
+ // Reference starts with @ does not need leading slash.
+ if (*startChar == '/' || *startChar == '@') {
+ return true;
+ } else {
+ diag->Error(android::DiagMessage(data_el->line_number)
+ << "attribute 'android:" << attr_name << "' in <" << data_el->name
+ << "> tag has value of '" << attr_value
+ << "', it must start with a leading slash '/'");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool VerifyDeepLinkIntentAction(xml::Element* intent_filter_el,
+ android::SourcePathDiagnostics* diag) {
+ if (!HasDeepLink(intent_filter_el)) {
+ return true;
+ }
+
+ xml::Element* data_el = intent_filter_el->FindChild({}, "data");
+ if (data_el != nullptr) {
+ if (!VerifyDeeplinkPathAttribute(data_el, diag, "path")) {
+ return false;
+ }
+ if (!VerifyDeeplinkPathAttribute(data_el, diag, "pathPrefix")) {
+ return false;
+ }
+ if (!VerifyDeeplinkPathAttribute(data_el, diag, "pathPattern")) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool RequiredNameIsNotEmpty(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
if (attr->value.empty()) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'android:name' in <" << el->name << "> tag must not be empty");
return false;
}
@@ -48,7 +136,7 @@ static bool RequiredNameIsNotEmpty(xml::Element* el, SourcePathDiagnostics* diag
// This is how PackageManager builds class names from AndroidManifest.xml entries.
static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
- SourcePathDiagnostics* diag) {
+ android::SourcePathDiagnostics* diag) {
// We allow unqualified class names (ie: .HelloActivity)
// Since we don't know the package name, we can just make a fake one here and
// the test will be identical as long as the real package name is valid too.
@@ -60,51 +148,50 @@ static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr,
: attr->value;
if (!util::IsJavaClassName(qualified_class_name)) {
- diag->Error(DiagMessage(el->line_number)
- << "attribute 'android:name' in <" << el->name
- << "> tag must be a valid Java class name");
+ diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
+ << "> tag must be a valid Java class name");
return false;
}
return true;
}
-static bool OptionalNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool OptionalNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
return NameIsJavaClassName(el, attr, diag);
}
return true;
}
-static bool RequiredNameIsJavaClassName(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool RequiredNameIsJavaClassName(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
return NameIsJavaClassName(el, attr, diag);
}
-static bool RequiredNameIsJavaPackage(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool RequiredNameIsJavaPackage(xml::Element* el, android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name");
if (attr == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing attribute 'android:name'");
return false;
}
if (!util::IsJavaPackageName(attr->value)) {
- diag->Error(DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
- << "> tag must be a valid Java package name");
+ diag->Error(android::DiagMessage(el->line_number) << "attribute 'android:name' in <" << el->name
+ << "> tag must be a valid Java package name");
return false;
}
return true;
}
static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std::string& attr) {
- return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
+ return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
if (el->FindAttribute(xml::kSchemaAndroid, attr) == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing required attribute 'android:" << attr << "'");
return false;
}
@@ -114,17 +201,17 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std
static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
const std::string& attrName1, const std::string& attrName2) {
- return [=](xml::Element* el, SourcePathDiagnostics* diag) -> bool {
+ return [=](xml::Element* el, android::SourcePathDiagnostics* diag) -> bool {
xml::Attribute* attr1 = el->FindAttribute(xml::kSchemaAndroid, attrName1);
xml::Attribute* attr2 = el->FindAttribute(xml::kSchemaAndroid, attrName2);
if (attr1 == nullptr && attr2 == nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> is missing required attribute 'android:" << attrName1
<< "' or 'android:" << attrName2 << "'");
return false;
}
if (attr1 != nullptr && attr2 != nullptr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<" << el->name << "> can only specify one of attribute 'android:" << attrName1
<< "' or 'android:" << attrName2 << "'");
return false;
@@ -133,7 +220,7 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredOneAndroidAttribute(
};
}
-static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool AutoGenerateIsFeatureSplit(xml::Element* el, android::SourcePathDiagnostics* diag) {
constexpr const char* kFeatureSplit = "featureSplit";
constexpr const char* kIsFeatureSplit = "isFeatureSplit";
@@ -149,7 +236,7 @@ static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics*
if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
// The isFeatureSplit attribute is false, which conflicts with the use
// of "featureSplit".
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' "
"is not 'true'");
return false;
@@ -163,7 +250,7 @@ static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics*
return true;
}
-static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool AutoGenerateIsSplitRequired(xml::Element* el, android::SourcePathDiagnostics* diag) {
constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
constexpr const char* kIsSplitRequired = "isSplitRequired";
@@ -175,7 +262,7 @@ static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics*
if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
// The isFeatureSplit attribute is false, which conflicts with the use
// of "featureSplit".
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'requiredSplitTypes' used in <manifest> but "
"'android:isSplitRequired' is not 'true'");
return false;
@@ -189,18 +276,18 @@ static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics*
}
static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
- SourcePathDiagnostics* diag) {
+ android::SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute({}, "package");
if (!attr) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<manifest> tag is missing 'package' attribute");
return false;
} else if (ResourceUtils::IsReference(attr->value)) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "attribute 'package' in <manifest> tag must not be a reference");
return false;
} else if (!util::IsAndroidPackageName(attr->value)) {
- DiagMessage error_msg(el->line_number);
+ android::DiagMessage error_msg(el->line_number);
error_msg << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
<< attr->value << "'";
if (policy == xml::XmlActionExecutorPolicy::kAllowListWarning) {
@@ -215,8 +302,9 @@ static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy
attr = el->FindAttribute({}, "split");
if (attr) {
if (!util::IsJavaPackageName(attr->value)) {
- diag->Error(DiagMessage(el->line_number) << "attribute 'split' in <manifest> tag is not a "
- "valid split name");
+ diag->Error(android::DiagMessage(el->line_number)
+ << "attribute 'split' in <manifest> tag is not a "
+ "valid split name");
return false;
}
}
@@ -225,11 +313,11 @@ static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy
// The coreApp attribute in <manifest> is not a regular AAPT attribute, so type
// checking on it is manual.
-static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool FixCoreAppAttribute(xml::Element* el, android::SourcePathDiagnostics* diag) {
if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) {
std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value);
if (!result) {
- diag->Error(DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
+ diag->Error(android::DiagMessage(el->line_number) << "attribute coreApp must be a boolean");
return false;
}
attr->compiled_value = std::move(result);
@@ -238,11 +326,11 @@ static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) {
}
// Checks that <uses-feature> has android:glEsVersion or android:name, not both (or neither).
-static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
+static bool VerifyUsesFeature(xml::Element* el, android::SourcePathDiagnostics* diag) {
bool has_name = false;
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
if (attr->value.empty()) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "android:name in <uses-feature> must not be empty");
return false;
}
@@ -252,7 +340,7 @@ static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
bool has_gl_es_version = false;
if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "glEsVersion")) {
if (has_name) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "cannot define both android:name and android:glEsVersion in <uses-feature>");
return false;
}
@@ -260,7 +348,7 @@ static bool VerifyUsesFeature(xml::Element* el, SourcePathDiagnostics* diag) {
}
if (!has_name && !has_gl_es_version) {
- diag->Error(DiagMessage(el->line_number)
+ diag->Error(android::DiagMessage(el->line_number)
<< "<uses-feature> must have either android:name or android:glEsVersion attribute");
return false;
}
@@ -294,40 +382,36 @@ static void EnsureNamespaceIsDeclared(const std::string& prefix, const std::stri
}
}
-bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
- IDiagnostics* diag) {
+bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag) {
// First verify some options.
if (options_.rename_manifest_package) {
if (!util::IsJavaPackageName(options_.rename_manifest_package.value())) {
- diag->Error(DiagMessage() << "invalid manifest package override '"
- << options_.rename_manifest_package.value()
- << "'");
+ diag->Error(android::DiagMessage() << "invalid manifest package override '"
+ << options_.rename_manifest_package.value() << "'");
return false;
}
}
if (options_.rename_instrumentation_target_package) {
if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) {
- diag->Error(DiagMessage()
+ diag->Error(android::DiagMessage()
<< "invalid instrumentation target package override '"
- << options_.rename_instrumentation_target_package.value()
- << "'");
+ << options_.rename_instrumentation_target_package.value() << "'");
return false;
}
}
if (options_.rename_overlay_target_package) {
if (!util::IsJavaPackageName(options_.rename_overlay_target_package.value())) {
- diag->Error(DiagMessage()
- << "invalid overlay target package override '"
- << options_.rename_overlay_target_package.value()
- << "'");
+ diag->Error(android::DiagMessage() << "invalid overlay target package override '"
+ << options_.rename_overlay_target_package.value() << "'");
return false;
}
}
// Common <intent-filter> actions.
xml::XmlNodeAction intent_filter_action;
+ intent_filter_action.Action(VerifyDeepLinkIntentAction);
intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
intent_filter_action["data"];
@@ -562,8 +646,8 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
return true;
}
-static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
- const StringPiece& attr_name, xml::Element* el) {
+static void FullyQualifyClassName(StringPiece package, StringPiece attr_ns, StringPiece attr_name,
+ xml::Element* el) {
xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
if (attr != nullptr) {
if (std::optional<std::string> new_value =
@@ -573,7 +657,7 @@ static void FullyQualifyClassName(const StringPiece& package, const StringPiece&
}
}
-static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
+static bool RenameManifestPackage(StringPiece package_override, xml::Element* manifest_el) {
xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
// We've already verified that the manifest element is present, with a package
@@ -581,7 +665,7 @@ static bool RenameManifestPackage(const StringPiece& package_override, xml::Elem
CHECK(attr != nullptr);
std::string original_package = std::move(attr->value);
- attr->value = package_override.to_string();
+ attr->value.assign(package_override);
xml::Element* application_el = manifest_el->FindChild({}, "application");
if (application_el != nullptr) {
@@ -620,7 +704,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
TRACE_CALL();
xml::Element* root = xml::FindRootElement(doc->root.get());
if (!root || !root->namespace_uri.empty() || root->name != "manifest") {
- context->GetDiagnostics()->Error(DiagMessage(doc->file.source)
+ context->GetDiagnostics()->Error(android::DiagMessage(doc->file.source)
<< "root tag must be <manifest>");
return false;
}
@@ -664,6 +748,23 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
attr->value = options_.compile_sdk_version_codename.value();
}
+ if (!options_.fingerprint_prefixes.empty()) {
+ xml::Element* install_constraints_el = root->FindChild({}, "install-constraints");
+ if (install_constraints_el == nullptr) {
+ std::unique_ptr<xml::Element> install_constraints = std::make_unique<xml::Element>();
+ install_constraints->name = "install-constraints";
+ install_constraints_el = install_constraints.get();
+ root->AppendChild(std::move(install_constraints));
+ }
+ for (const std::string& prefix : options_.fingerprint_prefixes) {
+ std::unique_ptr<xml::Element> prefix_el = std::make_unique<xml::Element>();
+ prefix_el->name = "fingerprint-prefix";
+ xml::Attribute* attr = prefix_el->FindOrCreateAttribute(xml::kSchemaAndroid, "value");
+ attr->value = prefix;
+ install_constraints_el->AppendChild(std::move(prefix_el));
+ }
+ }
+
xml::XmlActionExecutor executor;
if (!BuildRules(&executor, context->GetDiagnostics())) {
return false;
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index 70bfcfc1365a..42938a4f8176 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -18,11 +18,10 @@
#define AAPT_LINK_MANIFESTFIXER_H
#include <string>
+#include <vector>
#include "android-base/macros.h"
-
#include "process/IResourceTableConsumer.h"
-
#include "xml/XmlActionExecutor.h"
#include "xml/XmlDom.h"
@@ -76,6 +75,9 @@ struct ManifestFixerOptions {
// is set.
std::optional<std::string> compile_sdk_version_codename;
+ // The fingerprint prefixes to be added to the <install-constraints> tag.
+ std::vector<std::string> fingerprint_prefixes;
+
// Whether validation errors should be treated only as warnings. If this is 'true', then an
// incorrect node will not result in an error, but only as a warning, and the parsing will
// continue.
@@ -103,7 +105,7 @@ class ManifestFixer : public IXmlResourceConsumer {
private:
DISALLOW_COPY_AND_ASSIGN(ManifestFixer);
- bool BuildRules(xml::XmlActionExecutor* executor, IDiagnostics* diag);
+ bool BuildRules(xml::XmlActionExecutor* executor, android::IDiagnostics* diag);
ManifestFixerOptions options_;
};
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 9204d2276a17..6151a8e910d9 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -61,12 +61,12 @@ struct ManifestFixerTest : public ::testing::Test {
.Build();
}
- std::unique_ptr<xml::XmlResource> Verify(const StringPiece& str) {
+ std::unique_ptr<xml::XmlResource> Verify(StringPiece str) {
return VerifyWithOptions(str, {});
}
- std::unique_ptr<xml::XmlResource> VerifyWithOptions(
- const StringPiece& str, const ManifestFixerOptions& options) {
+ std::unique_ptr<xml::XmlResource> VerifyWithOptions(StringPiece str,
+ const ManifestFixerOptions& options) {
std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(str);
ManifestFixer fixer(options);
if (fixer.Consume(mContext.get(), doc.get())) {
@@ -994,6 +994,63 @@ TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) {
ASSERT_THAT(manifest, IsNull());
}
+TEST_F(ManifestFixerTest, InsertFingerprintPrefixIfNotExist) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ </manifest>)";
+ ManifestFixerOptions options;
+ options.fingerprint_prefixes = {"foo", "bar"};
+
+ std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+ ASSERT_THAT(manifest, NotNull());
+ xml::Element* install_constraints = manifest->root.get()->FindChild({}, "install-constraints");
+ ASSERT_THAT(install_constraints, NotNull());
+ std::vector<xml::Element*> fingerprint_prefixes = install_constraints->GetChildElements();
+ EXPECT_EQ(fingerprint_prefixes.size(), 2);
+ xml::Attribute* attr;
+ EXPECT_THAT(fingerprint_prefixes[0]->name, StrEq("fingerprint-prefix"));
+ attr = fingerprint_prefixes[0]->FindAttribute(xml::kSchemaAndroid, "value");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("foo"));
+ EXPECT_THAT(fingerprint_prefixes[1]->name, StrEq("fingerprint-prefix"));
+ attr = fingerprint_prefixes[1]->FindAttribute(xml::kSchemaAndroid, "value");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("bar"));
+}
+
+TEST_F(ManifestFixerTest, AppendFingerprintPrefixIfExists) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <install-constraints>
+ <fingerprint-prefix android:value="foo" />
+ </install-constraints>
+ </manifest>)";
+ ManifestFixerOptions options;
+ options.fingerprint_prefixes = {"bar", "baz"};
+
+ std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+ ASSERT_THAT(manifest, NotNull());
+ xml::Element* install_constraints = manifest->root.get()->FindChild({}, "install-constraints");
+ ASSERT_THAT(install_constraints, NotNull());
+ std::vector<xml::Element*> fingerprint_prefixes = install_constraints->GetChildElements();
+ EXPECT_EQ(fingerprint_prefixes.size(), 3);
+ xml::Attribute* attr;
+ EXPECT_THAT(fingerprint_prefixes[0]->name, StrEq("fingerprint-prefix"));
+ attr = fingerprint_prefixes[0]->FindAttribute(xml::kSchemaAndroid, "value");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("foo"));
+ EXPECT_THAT(fingerprint_prefixes[1]->name, StrEq("fingerprint-prefix"));
+ attr = fingerprint_prefixes[1]->FindAttribute(xml::kSchemaAndroid, "value");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("bar"));
+ EXPECT_THAT(fingerprint_prefixes[2]->name, StrEq("fingerprint-prefix"));
+ attr = fingerprint_prefixes[2]->FindAttribute(xml::kSchemaAndroid, "value");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("baz"));
+}
+
TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) {
std::string input = R"(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -1097,4 +1154,364 @@ TEST_F(ManifestFixerTest, ComponentPropertyOnlyOneAttributeDefined) {
</manifest>)";
EXPECT_THAT(Verify(input), NotNull());
}
+
+TEST_F(ManifestFixerTest, IntentFilterActionMustHaveNonEmptyName) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+}
+
+TEST_F(ManifestFixerTest, IntentFilterCategoryMustHaveNonEmptyName) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category android:name="" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+}
+
+TEST_F(ManifestFixerTest, IntentFilterPathMustStartWithLeadingSlashOnDeepLinks) {
+ // No DeepLink.
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <data />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // No DeepLink, missing ACTION_VIEW.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink, missing DEFAULT category while DEFAULT is recommended but not required.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // No DeepLink, missing BROWSABLE category.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // No DeepLink, missing 'android:scheme' in <data> tag.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // No DeepLink, <action> is ACTION_MAIN not ACTION_VIEW.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with no leading slash in android:path.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:path="path" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // DeepLink with leading slash in android:path.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:path="/path" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with no leading slash in android:pathPrefix.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="pathPrefix" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // DeepLink with leading slash in android:pathPrefix.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPrefix="/pathPrefix" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with no leading slash in android:pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern="pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), IsNull());
+
+ // DeepLink with leading slash in android:pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern="/pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with '.' start in pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern=".*\\.pathPattern" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with '*' start in pathPattern.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:pathPattern="*" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+
+ // DeepLink with string reference as a path.
+ input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <application>
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com"
+ android:path="@string/startup_uri" />
+ </intent-filter>
+ </activity>
+ </application>
+ </manifest>)";
+ EXPECT_THAT(Verify(input), NotNull());
+}
} // namespace aapt
diff --git a/tools/aapt2/link/NoDefaultResourceRemover.cpp b/tools/aapt2/link/NoDefaultResourceRemover.cpp
index 05990de6a9b3..2a5163f22e17 100644
--- a/tools/aapt2/link/NoDefaultResourceRemover.cpp
+++ b/tools/aapt2/link/NoDefaultResourceRemover.cpp
@@ -76,15 +76,15 @@ bool NoDefaultResourceRemover::Consume(IAaptContext* context, ResourceTable* tab
});
for (auto iter = remove_iter; iter != end_iter; ++iter) {
- const ResourceName name(pkg->name, type->type, (*iter)->name);
- IDiagnostics* diag = context->GetDiagnostics();
- diag->Warn(DiagMessage() << "removing resource " << name
- << " without required default value");
+ const ResourceName name(pkg->name, type->named_type, (*iter)->name);
+ android::IDiagnostics* diag = context->GetDiagnostics();
+ diag->Warn(android::DiagMessage()
+ << "removing resource " << name << " without required default value");
if (context->IsVerbose()) {
- diag->Note(DiagMessage() << " did you forget to remove all definitions?");
+ diag->Note(android::DiagMessage() << " did you forget to remove all definitions?");
for (const auto& config_value : (*iter)->values) {
if (config_value->value != nullptr) {
- diag->Note(DiagMessage(config_value->value->GetSource()) << "defined here");
+ diag->Note(android::DiagMessage(config_value->value->GetSource()) << "defined here");
}
}
}
diff --git a/tools/aapt2/link/PrivateAttributeMover.cpp b/tools/aapt2/link/PrivateAttributeMover.cpp
index 675b02a7e161..8c6c743dfff0 100644
--- a/tools/aapt2/link/PrivateAttributeMover.cpp
+++ b/tools/aapt2/link/PrivateAttributeMover.cpp
@@ -57,7 +57,7 @@ OutputIterator move_if(InputContainer& input_container, OutputIterator result, P
bool PrivateAttributeMover::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
- ResourceTableType* type = package->FindType(ResourceType::kAttr);
+ ResourceTableType* type = package->FindTypeWithDefaultName(ResourceType::kAttr);
if (!type) {
continue;
}
@@ -80,7 +80,8 @@ bool PrivateAttributeMover::Consume(IAaptContext* context, ResourceTable* table)
continue;
}
- ResourceTableType* priv_attr_type = package->FindOrCreateType(ResourceType::kAttrPrivate);
+ auto attr_private_type = ResourceNamedTypeWithDefaultName(ResourceType::kAttrPrivate);
+ ResourceTableType* priv_attr_type = package->FindOrCreateType(attr_private_type);
CHECK(priv_attr_type->entries.empty());
priv_attr_type->entries = std::move(private_attr_entries);
}
diff --git a/tools/aapt2/link/PrivateAttributeMover_test.cpp b/tools/aapt2/link/PrivateAttributeMover_test.cpp
index 168234b36e4a..32335b7f5a9f 100644
--- a/tools/aapt2/link/PrivateAttributeMover_test.cpp
+++ b/tools/aapt2/link/PrivateAttributeMover_test.cpp
@@ -41,13 +41,13 @@ TEST(PrivateAttributeMoverTest, MovePrivateAttributes) {
ResourceTablePackage* package = table->FindPackage("android");
ASSERT_NE(package, nullptr);
- ResourceTableType* type = package->FindType(ResourceType::kAttr);
+ ResourceTableType* type = package->FindTypeWithDefaultName(ResourceType::kAttr);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
EXPECT_NE(type->FindEntry("publicA"), nullptr);
EXPECT_NE(type->FindEntry("publicB"), nullptr);
- type = package->FindType(ResourceType::kAttrPrivate);
+ type = package->FindTypeWithDefaultName(ResourceType::kAttrPrivate);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
EXPECT_NE(type->FindEntry("privateA"), nullptr);
@@ -68,11 +68,11 @@ TEST(PrivateAttributeMoverTest, LeavePrivateAttributesWhenNoPublicAttributesDefi
ResourceTablePackage* package = table->FindPackage("android");
ASSERT_NE(package, nullptr);
- ResourceTableType* type = package->FindType(ResourceType::kAttr);
+ ResourceTableType* type = package->FindTypeWithDefaultName(ResourceType::kAttr);
ASSERT_NE(type, nullptr);
ASSERT_EQ(type->entries.size(), 2u);
- type = package->FindType(ResourceType::kAttrPrivate);
+ type = package->FindTypeWithDefaultName(ResourceType::kAttrPrivate);
ASSERT_EQ(type, nullptr);
}
@@ -87,12 +87,12 @@ TEST(PrivateAttributeMoverTest, DoNotCreatePrivateAttrsIfNoneExist) {
ResourceTablePackage* package = table->FindPackage("android");
ASSERT_NE(nullptr, package);
- ASSERT_EQ(nullptr, package->FindType(ResourceType::kAttrPrivate));
+ ASSERT_EQ(nullptr, package->FindTypeWithDefaultName(ResourceType::kAttrPrivate));
PrivateAttributeMover mover;
ASSERT_TRUE(mover.Consume(context.get(), table.get()));
- ASSERT_EQ(nullptr, package->FindType(ResourceType::kAttrPrivate));
+ ASSERT_EQ(nullptr, package->FindTypeWithDefaultName(ResourceType::kAttrPrivate));
}
} // namespace aapt
diff --git a/tools/aapt2/link/ProductFilter.cpp b/tools/aapt2/link/ProductFilter.cpp
index 793740af3021..9544986fda76 100644
--- a/tools/aapt2/link/ProductFilter.cpp
+++ b/tools/aapt2/link/ProductFilter.cpp
@@ -23,7 +23,7 @@ namespace aapt {
ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
const ResourceNameRef& name, const ResourceConfigValueIter begin,
- const ResourceConfigValueIter end, IDiagnostics* diag) {
+ const ResourceConfigValueIter end, android::IDiagnostics* diag) {
ResourceConfigValueIter default_product_iter = end;
ResourceConfigValueIter selected_product_iter = end;
@@ -32,16 +32,15 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
if (products_.find(config_value->product) != products_.end()) {
if (selected_product_iter != end) {
// We have two possible values for this product!
- diag->Error(DiagMessage(config_value->value->GetSource())
- << "selection of product '" << config_value->product
- << "' for resource " << name << " is ambiguous");
+ diag->Error(android::DiagMessage(config_value->value->GetSource())
+ << "selection of product '" << config_value->product << "' for resource "
+ << name << " is ambiguous");
ResourceConfigValue* previously_selected_config_value =
selected_product_iter->get();
- diag->Note(
- DiagMessage(previously_selected_config_value->value->GetSource())
- << "product '" << previously_selected_config_value->product
- << "' is also a candidate");
+ diag->Note(android::DiagMessage(previously_selected_config_value->value->GetSource())
+ << "product '" << previously_selected_config_value->product
+ << "' is also a candidate");
return end;
}
@@ -52,15 +51,13 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
if (config_value->product.empty() || config_value->product == "default") {
if (default_product_iter != end) {
// We have two possible default values.
- diag->Error(DiagMessage(config_value->value->GetSource())
- << "multiple default products defined for resource "
- << name);
+ diag->Error(android::DiagMessage(config_value->value->GetSource())
+ << "multiple default products defined for resource " << name);
ResourceConfigValue* previously_default_config_value =
default_product_iter->get();
- diag->Note(
- DiagMessage(previously_default_config_value->value->GetSource())
- << "default product also defined here");
+ diag->Note(android::DiagMessage(previously_default_config_value->value->GetSource())
+ << "default product also defined here");
return end;
}
@@ -70,8 +67,7 @@ ProductFilter::ResourceConfigValueIter ProductFilter::SelectProductToKeep(
}
if (default_product_iter == end) {
- diag->Error(DiagMessage() << "no default product defined for resource "
- << name);
+ diag->Error(android::DiagMessage() << "no default product defined for resource " << name);
return end;
}
@@ -98,7 +94,7 @@ bool ProductFilter::Consume(IAaptContext* context, ResourceTable* table) {
// End of the array, or we saw a different config,
// so this must be the end of a range of products.
// Select the product to keep from the set of products defined.
- ResourceNameRef name(pkg->name, type->type, entry->name);
+ ResourceNameRef name(pkg->name, type->named_type, entry->name);
auto value_to_keep = SelectProductToKeep(
name, start_range_iter, iter, context->GetDiagnostics());
if (value_to_keep == iter) {
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
index 4f78bbcece33..2cb9afa05cad 100644
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -31,27 +31,29 @@ TEST(ProductFilterTest, SelectTwoProducts) {
ResourceTable table;
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("land/default.xml")).Build(), land)
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/default.xml")).Build(),
+ land)
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("land/tablet.xml")).Build(), land,
- "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("land/tablet.xml")).Build(),
+ land, "tablet")
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("port/default.xml")).Build(), port)
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/default.xml")).Build(),
+ port)
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("port/tablet.xml")).Build(), port,
- "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("port/tablet.xml")).Build(),
+ port, "tablet")
.Build(),
context->GetDiagnostics()));
@@ -74,13 +76,14 @@ TEST(ProductFilterTest, SelectDefaultProduct) {
ResourceTable table;
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build())
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build())
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("tablet.xml")).Build(), {}, "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("tablet.xml")).Build(), {},
+ "tablet")
.Build(),
context->GetDiagnostics()));
;
@@ -102,20 +105,21 @@ TEST(ProductFilterTest, FailOnAmbiguousProduct) {
ResourceTable table;
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build())
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build())
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("tablet.xml")).Build(), {}, "tablet")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("tablet.xml")).Build(), {},
+ "tablet")
.Build(),
context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("no-sdcard.xml")).Build(), {},
- "no-sdcard")
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("no-sdcard.xml")).Build(),
+ {}, "no-sdcard")
.Build(),
context->GetDiagnostics()));
@@ -127,15 +131,15 @@ TEST(ProductFilterTest, FailOnMultipleDefaults) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
ResourceTable table;
- ASSERT_TRUE(
- table.AddResource(NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source(".xml")).Build())
- .Build(),
- context->GetDiagnostics()));
+ ASSERT_TRUE(table.AddResource(
+ NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source(".xml")).Build())
+ .Build(),
+ context->GetDiagnostics()));
ASSERT_TRUE(table.AddResource(
NewResourceBuilder(test::ParseNameOrDie("android:string/one"))
- .SetValue(test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build(), {},
+ .SetValue(test::ValueBuilder<Id>().SetSource(android::Source("default.xml")).Build(), {},
"default")
.Build(),
context->GetDiagnostics()));
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 5372cf243951..9dadfb26a3f8 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -16,16 +16,15 @@
#include "link/ReferenceLinker.h"
-#include "android-base/logging.h"
-#include "android-base/stringprintf.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "Diagnostics.h"
#include "ResourceParser.h"
#include "ResourceTable.h"
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
#include "link/Linkers.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -82,7 +81,7 @@ std::unique_ptr<Reference> ReferenceLinkerTransformer::TransformDerived(const Re
if (auto ref = ValueCast<Reference>(linked_item_ptr)) {
return std::unique_ptr<Reference>(ref);
}
- context_->GetDiagnostics()->Error(DiagMessage(value->GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(value->GetSource())
<< "value of '"
<< LoggingResourceName(*value, callsite_, package_decls_)
<< "' must be a resource reference");
@@ -130,7 +129,7 @@ std::unique_ptr<Style> ReferenceLinkerTransformer::TransformDerived(const Style*
// check is fast and we avoid creating a DiagMessage when the match is successful.
if (!symbol->attribute->Matches(*entry.value, nullptr)) {
// The actual type of this item is incompatible with the attribute.
- DiagMessage msg(entry.key.GetSource());
+ android::DiagMessage msg(entry.key.GetSource());
// Call the matches method again, this time with a DiagMessage so we fill in the actual
// error message.
@@ -139,7 +138,7 @@ std::unique_ptr<Style> ReferenceLinkerTransformer::TransformDerived(const Style*
error_ = true;
}
} else {
- context_->GetDiagnostics()->Error(DiagMessage(entry.key.GetSource())
+ context_->GetDiagnostics()->Error(android::DiagMessage(entry.key.GetSource())
<< "style attribute '"
<< LoggingResourceName(entry.key, callsite_, package_decls_)
<< "' " << err_str);
@@ -190,8 +189,7 @@ class EmptyDeclStack : public xml::IPackageDeclStack {
public:
EmptyDeclStack() = default;
- std::optional<xml::ExtractedPackage> TransformPackageAlias(
- const StringPiece& alias) const override {
+ std::optional<xml::ExtractedPackage> TransformPackageAlias(StringPiece alias) const override {
if (alias.empty()) {
return xml::ExtractedPackage{{}, true /*private*/};
}
@@ -207,8 +205,7 @@ struct MacroDeclStack : public xml::IPackageDeclStack {
: alias_namespaces_(std::move(namespaces)) {
}
- std::optional<xml::ExtractedPackage> TransformPackageAlias(
- const StringPiece& alias) const override {
+ std::optional<xml::ExtractedPackage> TransformPackageAlias(StringPiece alias) const override {
if (alias.empty()) {
return xml::ExtractedPackage{{}, true /*private*/};
}
@@ -344,7 +341,7 @@ std::optional<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Ref
void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite,
const xml::IPackageDeclStack* decls,
- DiagMessage* out_msg) {
+ android::DiagMessage* out_msg) {
CHECK(out_msg != nullptr);
if (!ref.name) {
*out_msg << ref.id.value();
@@ -393,7 +390,7 @@ std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
auto result = table->FindResource(transformed_reference.name.value());
if (!result || result.value().entry->values.empty()) {
context->GetDiagnostics()->Error(
- DiagMessage(reference.GetSource())
+ android::DiagMessage(reference.GetSource())
<< "failed to find definition for "
<< LoggingResourceName(transformed_reference, callsite, decls));
return {};
@@ -424,7 +421,7 @@ std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
macro_values[0]->config, *context->GetDiagnostics());
if (new_value == nullptr) {
context->GetDiagnostics()->Error(
- DiagMessage(reference.GetSource())
+ android::DiagMessage(reference.GetSource())
<< "failed to substitute macro "
<< LoggingResourceName(transformed_reference, callsite, decls)
<< ": failed to parse contents as one of type(s) " << Attribute::MaskString(type_flags));
@@ -450,7 +447,7 @@ std::unique_ptr<Item> ReferenceLinker::LinkReference(const CallSite& callsite,
return std::move(new_ref);
}
- context->GetDiagnostics()->Error(DiagMessage(reference.GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(reference.GetSource())
<< "resource "
<< LoggingResourceName(transformed_reference, callsite, decls)
<< " " << err_str);
@@ -468,22 +465,21 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& type : package->types) {
for (auto& entry : type->entries) {
// First, unmangle the name if necessary.
- ResourceName name(package->name, type->type, entry->name);
+ ResourceName name(package->name, type->named_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->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) {
- context->GetDiagnostics()->Error(DiagMessage(entry->visibility.source)
- << "no definition for declared symbol '" << name
- << "'");
+ context->GetDiagnostics()->Error(android::DiagMessage(entry->visibility.source)
+ << "no definition for declared symbol '" << name << "'");
error = true;
}
// Ensure that definitions for values declared as overlayable exist
if (entry->overlayable_item && entry->values.empty()) {
- context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_item.value().source)
- << "no definition for overlayable symbol '"
- << name << "'");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(entry->overlayable_item.value().source)
+ << "no definition for overlayable symbol '" << name << "'");
error = true;
}
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index b46085397c52..9fb25e1bc2c9 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -32,7 +32,7 @@ namespace aapt {
class ReferenceLinkerTransformer : public CloningValueTransformer {
public:
ReferenceLinkerTransformer(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
- StringPool* string_pool, ResourceTable* table,
+ android::StringPool* string_pool, ResourceTable* table,
xml::IPackageDeclStack* decl)
: CloningValueTransformer(string_pool),
callsite_(callsite),
@@ -110,7 +110,8 @@ class ReferenceLinker : public IResourceTableConsumer {
// Same as WriteResourceName but omits the 'attr' part.
static void WriteAttributeName(const Reference& ref, const CallSite& callsite,
- const xml::IPackageDeclStack* decls, DiagMessage* out_msg);
+ const xml::IPackageDeclStack* decls,
+ android::DiagMessage* out_msg);
// Returns a fully linked version a resource reference.
//
diff --git a/tools/aapt2/link/ResourceExcluder.cpp b/tools/aapt2/link/ResourceExcluder.cpp
index b3b9dc47fd84..59393cbd0add 100644
--- a/tools/aapt2/link/ResourceExcluder.cpp
+++ b/tools/aapt2/link/ResourceExcluder.cpp
@@ -50,12 +50,9 @@ void RemoveIfExcluded(std::set<std::pair<ConfigDescription, int>>& excluded_conf
if (masked_diff == 0) {
if (context->IsVerbose()) {
- context->GetDiagnostics()->Note(
- DiagMessage(value->value->GetSource())
- << "excluded resource \""
- << entry->name
- << "\" with config "
- << config.toString());
+ context->GetDiagnostics()->Note(android::DiagMessage(value->value->GetSource())
+ << "excluded resource \"" << entry->name
+ << "\" with config " << config.toString());
}
value->value = {};
return;
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index d78f0ac17f67..67a48283e8b6 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,7 +37,7 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
CHECK(main_package_ != nullptr) << "package name or ID already taken";
}
-bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
+bool TableMerger::Merge(const android::Source& src, ResourceTable* table, bool overlay) {
TRACE_CALL();
// We allow adding new resources if this is not an overlay, or if the options allow overlays
// to add new resources.
@@ -45,7 +45,8 @@ bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
}
// This will merge packages with the same package name (or no package name).
-bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overlay, bool allow_new) {
+bool TableMerger::MergeImpl(const android::Source& src, ResourceTable* table, bool overlay,
+ bool allow_new) {
bool error = false;
for (auto& package : table->packages) {
// Only merge an empty package or the package we're building.
@@ -65,13 +66,14 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overla
// This will merge and mangle resources from a static library. It is assumed that all FileReferences
// have correctly set their io::IFile*.
-bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_name,
+bool TableMerger::MergeAndMangle(const android::Source& src, StringPiece package_name,
ResourceTable* table) {
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(android::DiagMessage(src)
+ << "ignoring package " << package->name);
continue;
}
@@ -82,8 +84,8 @@ bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_n
return !error;
}
-static bool MergeType(IAaptContext* context, const Source& src, ResourceTableType* dst_type,
- ResourceTableType* src_type) {
+static bool MergeType(IAaptContext* context, const android::Source& src,
+ ResourceTableType* dst_type, ResourceTableType* src_type) {
if (src_type->visibility_level >= dst_type->visibility_level) {
// The incoming type's visibility is stronger, so we should override the visibility.
dst_type->visibility_level = src_type->visibility_level;
@@ -91,15 +93,15 @@ static bool MergeType(IAaptContext* context, const Source& src, ResourceTableTyp
return true;
}
-static bool MergeEntry(IAaptContext* context, const Source& src,
- ResourceEntry* dst_entry, ResourceEntry* src_entry,
- bool strict_visibility) {
+static bool MergeEntry(IAaptContext* context, const android::Source& src, ResourceEntry* dst_entry,
+ ResourceEntry* src_entry, bool strict_visibility) {
if (strict_visibility
&& dst_entry->visibility.level != Visibility::Level::kUndefined
&& src_entry->visibility.level != dst_entry->visibility.level) {
- context->GetDiagnostics()->Error(
- DiagMessage(src) << "cannot merge resource '" << dst_entry->name << "' with conflicting visibilities: "
- << "public and private");
+ context->GetDiagnostics()->Error(android::DiagMessage(src)
+ << "cannot merge resource '" << dst_entry->name
+ << "' with conflicting visibilities: "
+ << "public and private");
return false;
}
@@ -114,8 +116,9 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
dst_entry->visibility.level == Visibility::Level::kPublic && dst_entry->id &&
src_entry->id && src_entry->id != dst_entry->id) {
// 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(android::DiagMessage(src)
+ << "cannot merge entry '" << src_entry->name
+ << "': conflicting public IDs");
return false;
}
@@ -139,11 +142,12 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
// Do not allow a resource with an overlayable declaration to have that overlayable
// declaration redefined.
- context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable_item.value().source)
- << "duplicate overlayable declaration for resource '"
- << src_entry->name << "'");
- context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable_item.value().source)
- << "previous declaration here");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(src_entry->overlayable_item.value().source)
+ << "duplicate overlayable declaration for resource '" << src_entry->name << "'");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage(dst_entry->overlayable_item.value().source)
+ << "previous declaration here");
return false;
}
}
@@ -154,10 +158,10 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
if (src_entry->staged_id) {
if (dst_entry->staged_id &&
dst_entry->staged_id.value().id != src_entry->staged_id.value().id) {
- context->GetDiagnostics()->Error(DiagMessage(src_entry->staged_id.value().source)
+ context->GetDiagnostics()->Error(android::DiagMessage(src_entry->staged_id.value().source)
<< "conflicting staged id declaration for resource '"
<< src_entry->name << "'");
- context->GetDiagnostics()->Error(DiagMessage(dst_entry->staged_id.value().source)
+ context->GetDiagnostics()->Error(android::DiagMessage(dst_entry->staged_id.value().source)
<< "previous declaration here");
}
dst_entry->staged_id = std::move(src_entry->staged_id);
@@ -174,7 +178,7 @@ static bool MergeEntry(IAaptContext* context, const Source& src,
// If both values are Styleables/Styles, we just merge them into the existing value.
static ResourceTable::CollisionResult ResolveMergeCollision(
bool override_styles_instead_of_overlaying, Value* existing, Value* incoming,
- StringPool* pool) {
+ android::StringPool* pool) {
if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) {
if (Styleable* incoming_styleable = ValueCast<Styleable>(incoming)) {
// Styleables get merged.
@@ -194,13 +198,10 @@ static ResourceTable::CollisionResult ResolveMergeCollision(
return ResourceTable::ResolveValueCollision(existing, incoming);
}
-static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
- const ResourceNameRef& res_name,
- bool overlay,
- bool override_styles_instead_of_overlaying,
- ResourceConfigValue* dst_config_value,
- ResourceConfigValue* src_config_value,
- StringPool* pool) {
+static ResourceTable::CollisionResult MergeConfigValue(
+ IAaptContext* context, const ResourceNameRef& res_name, bool overlay,
+ bool override_styles_instead_of_overlaying, ResourceConfigValue* dst_config_value,
+ ResourceConfigValue* src_config_value, android::StringPool* pool) {
using CollisionResult = ResourceTable::CollisionResult;
Value* dst_value = dst_config_value->value.get();
@@ -220,22 +221,22 @@ static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
}
// Error!
- context->GetDiagnostics()->Error(DiagMessage(src_value->GetSource())
+ context->GetDiagnostics()->Error(android::DiagMessage(src_value->GetSource())
<< "resource '" << res_name << "' has a conflicting value for "
<< "configuration (" << src_config_value->config << ")");
- context->GetDiagnostics()->Note(DiagMessage(dst_value->GetSource())
+ context->GetDiagnostics()->Note(android::DiagMessage(dst_value->GetSource())
<< "originally defined here");
return CollisionResult::kConflict;
}
return collision_result;
}
-bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
- bool overlay, bool allow_new_resources) {
+bool TableMerger::DoMerge(const android::Source& src, ResourceTablePackage* src_package,
+ bool mangle_package, bool overlay, bool allow_new_resources) {
bool error = false;
for (auto& src_type : src_package->types) {
- ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->type);
+ ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->named_type);
if (!MergeType(context_, src, dst_type, src_type.get())) {
error = true;
continue;
@@ -254,14 +255,15 @@ bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package,
dst_entry = dst_type->FindEntry(entry_name);
}
- const ResourceNameRef res_name(src_package->name, src_type->type, src_entry->name);
+ const ResourceNameRef res_name(src_package->name, src_type->named_type, src_entry->name);
if (!dst_entry) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
+ context_->GetDiagnostics()->Error(android::DiagMessage(src)
<< "resource " << res_name
<< " does not override an existing resource");
- context_->GetDiagnostics()->Note(DiagMessage(src) << "define an <add-resource> tag or use "
- << "--auto-add-overlay");
+ context_->GetDiagnostics()->Note(android::DiagMessage(src)
+ << "define an <add-resource> tag or use "
+ << "--auto-add-overlay");
error = true;
continue;
}
@@ -324,8 +326,8 @@ std::unique_ptr<FileReference> TableMerger::CloneAndMangleFile(
const std::string& package, const FileReference& file_ref) {
StringPiece prefix, entry, suffix;
if (util::ExtractResFilePathParts(*file_ref.path, &prefix, &entry, &suffix)) {
- std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string());
- std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string();
+ std::string mangled_entry = NameMangler::MangleEntry(package, entry);
+ std::string newPath = (std::string(prefix) += mangled_entry) += suffix;
std::unique_ptr<FileReference> new_file_ref =
util::make_unique<FileReference>(main_table_->string_pool.MakeRef(newPath));
new_file_ref->SetComment(file_ref.GetComment());
@@ -349,7 +351,7 @@ bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFi
file_ref->file = file;
ResourceTablePackage* pkg = table.FindOrCreatePackage(file_desc.name.package);
- pkg->FindOrCreateType(file_desc.name.type.type)
+ pkg->FindOrCreateType(file_desc.name.type)
->FindOrCreateEntry(file_desc.name.entry)
->FindOrCreateValue(file_desc.config, {})
->value = std::move(file_ref);
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index e01a0c186392..37daf42f51e5 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -61,17 +61,18 @@ class 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 {
+ inline const std::set<std::string, std::less<>>& merged_packages() const {
return merged_packages_;
}
// Merges resources from the same or empty package. This is for local sources.
// If overlay is true, the resources are treated as overlays.
- bool Merge(const Source& src, ResourceTable* table, bool overlay);
+ bool Merge(const android::Source& src, ResourceTable* table, bool overlay);
// Merges resources from the given package, mangling the name. This is for static libraries.
// All FileReference values must have their io::IFile set.
- bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table);
+ bool MergeAndMangle(const android::Source& src, android::StringPiece package,
+ ResourceTable* table);
// Merges a compiled file that belongs to this same or empty package.
bool MergeFile(const ResourceFile& fileDesc, bool overlay, io::IFile* file);
@@ -83,11 +84,12 @@ class TableMerger {
ResourceTable* main_table_;
TableMergerOptions options_;
ResourceTablePackage* main_package_;
- std::set<std::string> merged_packages_;
+ std::set<std::string, std::less<>> merged_packages_;
- bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
+ bool MergeImpl(const android::Source& src, ResourceTable* src_table, bool overlay,
+ bool allow_new);
- bool DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
+ bool DoMerge(const android::Source& src, ResourceTablePackage* src_package, bool mangle_package,
bool overlay, bool allow_new_resources);
std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package,
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 4cbf2d3a826c..56a7c3b55f8d 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -94,7 +94,7 @@ TEST_F(TableMergerTest, MergeFile) {
ResourceFile file_desc;
file_desc.config = test::ParseConfigOrDie("hdpi-v4");
file_desc.name = test::ParseNameOrDie("layout/main");
- file_desc.source = Source("res/layout-hdpi/main.xml");
+ file_desc.source = android::Source("res/layout-hdpi/main.xml");
test::TestFile test_file("path/to/res/layout-hdpi/main.xml.flat");
ASSERT_TRUE(merger.MergeFile(file_desc, false /*overlay*/, &test_file));
diff --git a/tools/aapt2/link/XmlCompatVersioner.cpp b/tools/aapt2/link/XmlCompatVersioner.cpp
index 957b64cd8dbb..482c227a3670 100644
--- a/tools/aapt2/link/XmlCompatVersioner.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner.cpp
@@ -22,7 +22,7 @@
namespace aapt {
-static xml::Attribute CopyAttr(const xml::Attribute& src, StringPool* out_string_pool) {
+static xml::Attribute CopyAttr(const xml::Attribute& src, android::StringPool* out_string_pool) {
CloningValueTransformer cloner(out_string_pool);
xml::Attribute dst{src.namespace_uri, src.name, src.value, src.compiled_attribute};
if (src.compiled_value != nullptr) {
@@ -34,7 +34,7 @@ static xml::Attribute CopyAttr(const xml::Attribute& src, StringPool* out_string
// Returns false if the attribute is not copied because an existing attribute takes precedence
// (came from a rule).
static bool CopyAttribute(const xml::Attribute& src_attr, bool generated, xml::Element* dst_el,
- StringPool* out_string_pool) {
+ android::StringPool* out_string_pool) {
CloningValueTransformer cloner(out_string_pool);
xml::Attribute* dst_attr = dst_el->FindAttribute(src_attr.namespace_uri, src_attr.name);
if (dst_attr != nullptr) {
@@ -58,7 +58,7 @@ void XmlCompatVersioner::ProcessRule(const xml::Element& src_el, const xml::Attr
const util::Range<ApiVersion>& api_range, bool generated,
xml::Element* dst_el,
std::set<ApiVersion>* out_apis_referenced,
- StringPool* out_string_pool) {
+ android::StringPool* out_string_pool) {
if (src_attr_version <= api_range.start) {
// The API is compatible, so don't check the rule and just copy.
if (!CopyAttribute(src_attr, generated, dst_el, out_string_pool)) {
@@ -156,7 +156,7 @@ DegradeToManyRule::DegradeToManyRule(std::vector<ReplacementAttr> attrs)
}
static inline std::unique_ptr<Item> CloneIfNotNull(const std::unique_ptr<Item>& src,
- StringPool* out_string_pool) {
+ android::StringPool* out_string_pool) {
if (src == nullptr) {
return {};
}
@@ -166,7 +166,7 @@ static inline std::unique_ptr<Item> CloneIfNotNull(const std::unique_ptr<Item>&
std::vector<DegradeResult> DegradeToManyRule::Degrade(const xml::Element& src_el,
const xml::Attribute& src_attr,
- StringPool* out_string_pool) const {
+ android::StringPool* out_string_pool) const {
std::vector<DegradeResult> result;
result.reserve(attrs_.size());
for (const ReplacementAttr& attr : attrs_) {
diff --git a/tools/aapt2/link/XmlCompatVersioner.h b/tools/aapt2/link/XmlCompatVersioner.h
index 998061806279..22f98281b7ac 100644
--- a/tools/aapt2/link/XmlCompatVersioner.h
+++ b/tools/aapt2/link/XmlCompatVersioner.h
@@ -45,7 +45,7 @@ class IDegradeRule {
virtual std::vector<DegradeResult> Degrade(const xml::Element& src_el,
const xml::Attribute& src_attr,
- StringPool* out_string_pool) const = 0;
+ android::StringPool* out_string_pool) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(IDegradeRule);
@@ -70,7 +70,7 @@ class XmlCompatVersioner {
void ProcessRule(const xml::Element& src_el, const xml::Attribute& src_attr,
const ApiVersion& src_attr_version, const IDegradeRule* rule,
const util::Range<ApiVersion>& api_range, bool generated, xml::Element* dst_el,
- std::set<ApiVersion>* out_apis_referenced, StringPool* out_string_pool);
+ std::set<ApiVersion>* out_apis_referenced, android::StringPool* out_string_pool);
const Rules* rules_;
};
@@ -87,7 +87,7 @@ class DegradeToManyRule : public IDegradeRule {
virtual ~DegradeToManyRule() = default;
std::vector<DegradeResult> Degrade(const xml::Element& src_el, const xml::Attribute& src_attr,
- StringPool* out_string_pool) const override;
+ android::StringPool* out_string_pool) const override;
private:
DISALLOW_COPY_AND_ASSIGN(DegradeToManyRule);
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index 1f8548b5de75..d2e9bd770a31 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "link/Linkers.h"
-
-#include "androidfw/ResourceTypes.h"
-
-#include "Diagnostics.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/ResourceTypes.h"
+#include "link/Linkers.h"
#include "link/ReferenceLinker.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
@@ -38,7 +36,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
public:
using xml::PackageAwareVisitor::Visit;
- XmlVisitor(const Source& source, StringPool* pool, const CallSite& callsite,
+ XmlVisitor(const android::Source& source, android::StringPool* pool, const CallSite& callsite,
IAaptContext* context, ResourceTable* table, SymbolTable* symbols)
: source_(source),
callsite_(callsite),
@@ -61,7 +59,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
}
}
- const Source source = source_.WithLine(el->line_number);
+ const android::Source source = source_.WithLine(el->line_number);
for (xml::Attribute& attr : el->attributes) {
// If the attribute has no namespace, interpret values as if
// they were assigned to the default Attribute.
@@ -80,7 +78,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, context_, symbols_, &err_str);
if (!attr.compiled_attribute) {
- DiagMessage error_msg(source);
+ android::DiagMessage error_msg(source);
error_msg << "attribute ";
ReferenceLinker::WriteAttributeName(attr_ref, callsite_, this, &error_msg);
error_msg << " " << err_str;
@@ -99,7 +97,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
attr.compiled_value = attr.compiled_value->Transform(reference_transformer_);
} 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);
+ android::DiagMessage msg(source);
msg << "'" << attr.value << "' is incompatible with attribute " << attr.name << " "
<< *attribute;
context_->GetDiagnostics()->Error(msg);
@@ -118,7 +116,7 @@ class XmlVisitor : public xml::PackageAwareVisitor {
private:
DISALLOW_COPY_AND_ASSIGN(XmlVisitor);
- Source source_;
+ android::Source source_;
const CallSite& callsite_;
IAaptContext* context_;
SymbolTable* symbols_;
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index c686a10a3fa9..f01db3ddca2e 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -65,7 +65,7 @@ class ContextWrapper : public IAaptContext {
return context_->GetExternalSymbols();
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
if (source_diag_) {
return source_diag_.get();
}
@@ -97,8 +97,8 @@ class ContextWrapper : public IAaptContext {
}
void SetSource(const std::string& source) {
- source_diag_ =
- util::make_unique<SourcePathDiagnostics>(Source{source}, context_->GetDiagnostics());
+ source_diag_ = util::make_unique<android::SourcePathDiagnostics>(android::Source{source},
+ context_->GetDiagnostics());
}
const std::set<std::string>& GetSplitNameDependencies() override {
@@ -107,18 +107,18 @@ class ContextWrapper : public IAaptContext {
private:
IAaptContext* context_;
- std::unique_ptr<SourcePathDiagnostics> source_diag_;
+ std::unique_ptr<android::SourcePathDiagnostics> source_diag_;
int min_sdk_ = -1;
};
class SignatureFilter : public IPathFilter {
- bool Keep(const std::string& path) override {
+ bool Keep(std::string_view path) override {
static std::regex signature_regex(R"regex(^META-INF/.*\.(RSA|DSA|EC|SF)$)regex");
- if (std::regex_search(path, signature_regex)) {
+ if (std::regex_search(path.begin(), path.end(), signature_regex)) {
return false;
}
- return !(path == "META-INF/MANIFEST.MF");
+ return path != "META-INF/MANIFEST.MF";
}
};
@@ -143,7 +143,8 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
if (it == artifacts_to_keep.end()) {
filtered_artifacts.insert(artifact.name);
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage(artifact.name) << "skipping artifact");
+ context_->GetDiagnostics()->Note(android::DiagMessage(artifact.name)
+ << "skipping artifact");
}
continue;
} else {
@@ -158,28 +159,29 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
return false;
}
- IDiagnostics* diag = wrapped_context.GetDiagnostics();
+ android::IDiagnostics* diag = wrapped_context.GetDiagnostics();
std::unique_ptr<XmlResource> manifest;
if (!UpdateManifest(artifact, &manifest, diag)) {
- diag->Error(DiagMessage() << "could not update AndroidManifest.xml for output artifact");
+ diag->Error(android::DiagMessage()
+ << "could not update AndroidManifest.xml for output artifact");
return false;
}
std::string out = options.out_dir;
if (!file::mkdirs(out)) {
- diag->Warn(DiagMessage() << "could not create out dir: " << out);
+ diag->Warn(android::DiagMessage() << "could not create out dir: " << out);
}
file::AppendPath(&out, artifact.name);
if (context_->IsVerbose()) {
- diag->Note(DiagMessage() << "Generating split: " << out);
+ diag->Note(android::DiagMessage() << "Generating split: " << out);
}
std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(diag, out);
if (context_->IsVerbose()) {
- diag->Note(DiagMessage() << "Writing output: " << out);
+ diag->Note(android::DiagMessage() << "Writing output: " << out);
}
filters.AddFilter(util::make_unique<SignatureFilter>());
@@ -192,22 +194,25 @@ bool MultiApkGenerator::FromBaseApk(const MultiApkGeneratorOptions& options) {
// Make sure all of the requested artifacts were valid. If there are any kept artifacts left,
// either the config or the command line was wrong.
if (!artifacts_to_keep.empty()) {
- context_->GetDiagnostics()->Error(
- DiagMessage() << "The configuration and command line to filter artifacts do not match");
+ context_->GetDiagnostics()
+ ->Error(android::DiagMessage()
+ << "The configuration and command line to filter artifacts do not match");
- context_->GetDiagnostics()->Error(DiagMessage() << kept_artifacts.size() << " kept:");
+ context_->GetDiagnostics()->Error(android::DiagMessage() << kept_artifacts.size() << " kept:");
for (const auto& artifact : kept_artifacts) {
- context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ context_->GetDiagnostics()->Error(android::DiagMessage() << " " << artifact);
}
- context_->GetDiagnostics()->Error(DiagMessage() << filtered_artifacts.size() << " filtered:");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << filtered_artifacts.size() << " filtered:");
for (const auto& artifact : filtered_artifacts) {
- context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ context_->GetDiagnostics()->Error(android::DiagMessage() << " " << artifact);
}
- context_->GetDiagnostics()->Error(DiagMessage() << artifacts_to_keep.size() << " missing:");
+ context_->GetDiagnostics()->Error(android::DiagMessage()
+ << artifacts_to_keep.size() << " missing:");
for (const auto& artifact : artifacts_to_keep) {
- context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ context_->GetDiagnostics()->Error(android::DiagMessage() << " " << artifact);
}
return false;
@@ -250,7 +255,8 @@ std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable(IAaptContext* cont
VersionCollapser collapser;
if (!collapser.Consume(&wrapped_context, table.get())) {
- context->GetDiagnostics()->Error(DiagMessage() << "Failed to strip versioned resources");
+ context->GetDiagnostics()->Error(android::DiagMessage()
+ << "Failed to strip versioned resources");
return {};
}
@@ -261,7 +267,7 @@ std::unique_ptr<ResourceTable> MultiApkGenerator::FilterTable(IAaptContext* cont
bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
std::unique_ptr<XmlResource>* updated_manifest,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
const xml::XmlResource* apk_manifest = apk_->GetManifest();
if (apk_manifest == nullptr) {
return false;
@@ -277,20 +283,21 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
}
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(manifest->file.source) << "root tag must be <manifest>");
+ diag->Error(android::DiagMessage(manifest->file.source) << "root tag must be <manifest>");
return false;
}
// Retrieve the versionCode attribute.
auto version_code = manifest_el->FindAttribute(kSchemaAndroid, "versionCode");
if (!version_code) {
- diag->Error(DiagMessage(manifest->file.source) << "manifest must have a versionCode attribute");
+ diag->Error(android::DiagMessage(manifest->file.source)
+ << "manifest must have a versionCode attribute");
return false;
}
auto version_code_value = ValueCast<BinaryPrimitive>(version_code->compiled_value.get());
if (!version_code_value) {
- diag->Error(DiagMessage(manifest->file.source) << "versionCode is invalid");
+ diag->Error(android::DiagMessage(manifest->file.source) << "versionCode is invalid");
return false;
}
@@ -300,7 +307,7 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
if (version_code_major) {
version_code_major_value = ValueCast<BinaryPrimitive>(version_code_major->compiled_value.get());
if (!version_code_major_value) {
- diag->Error(DiagMessage(manifest->file.source) << "versionCodeMajor is invalid");
+ diag->Error(android::DiagMessage(manifest->file.source) << "versionCodeMajor is invalid");
return false;
}
}
@@ -325,13 +332,15 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
} else {
// There was no minSdkVersion. This is strange since at this point we should have been
// through the manifest fixer which sets the default minSdkVersion.
- diag->Error(DiagMessage(manifest->file.source) << "missing minSdkVersion from <uses-sdk>");
+ diag->Error(android::DiagMessage(manifest->file.source)
+ << "missing minSdkVersion from <uses-sdk>");
return false;
}
} else {
// No uses-sdk present. This is strange since at this point we should have been
// through the manifest fixer which should have added it.
- diag->Error(DiagMessage(manifest->file.source) << "missing <uses-sdk> from <manifest>");
+ diag->Error(android::DiagMessage(manifest->file.source)
+ << "missing <uses-sdk> from <manifest>");
return false;
}
}
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index 4a5a6c3d5915..8d8ed651a763 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -22,10 +22,9 @@
#include <unordered_set>
#include <vector>
-#include "androidfw/ConfigDescription.h"
-
-#include "Diagnostics.h"
#include "LoadedApk.h"
+#include "androidfw/ConfigDescription.h"
+#include "androidfw/IDiagnostics.h"
#include "configuration/ConfigurationParser.h"
namespace aapt {
@@ -58,12 +57,13 @@ class MultiApkGenerator {
FilterChain* chain);
private:
- IDiagnostics* GetDiagnostics() {
+ android::IDiagnostics* GetDiagnostics() {
return context_->GetDiagnostics();
}
bool UpdateManifest(const configuration::OutputArtifact& artifact,
- std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
+ std::unique_ptr<xml::XmlResource>* updated_manifest,
+ android::IDiagnostics* diag);
/**
* Adds the <screen> elements to the parent node for the provided density configuration.
diff --git a/tools/aapt2/optimize/Obfuscator.cpp b/tools/aapt2/optimize/Obfuscator.cpp
new file mode 100644
index 000000000000..8f12f735736e
--- /dev/null
+++ b/tools/aapt2/optimize/Obfuscator.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "optimize/Obfuscator.h"
+
+#include <fstream>
+#include <map>
+#include <set>
+#include <string>
+#include <unordered_set>
+
+#include "ResourceTable.h"
+#include "ValueVisitor.h"
+#include "androidfw/StringPiece.h"
+#include "util/Util.h"
+
+static const char base64_chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-_";
+
+namespace aapt {
+
+Obfuscator::Obfuscator(OptimizeOptions& optimizeOptions)
+ : options_(optimizeOptions.table_flattener_options),
+ shorten_resource_paths_(optimizeOptions.shorten_resource_paths),
+ collapse_key_stringpool_(optimizeOptions.table_flattener_options.collapse_key_stringpool) {
+}
+
+std::string ShortenFileName(android::StringPiece file_path, int output_length) {
+ std::size_t hash_num = std::hash<android::StringPiece>{}(file_path);
+ std::string result = "";
+ // Convert to (modified) base64 so that it is a proper file path.
+ for (int i = 0; i < output_length; i++) {
+ uint8_t sextet = hash_num & 0x3f;
+ hash_num >>= 6;
+ result += base64_chars[sextet];
+ }
+ return result;
+}
+
+// Return the optimal hash length such that at most 10% of resources collide in
+// their shortened path.
+// Reference: http://matt.might.net/articles/counting-hash-collisions/
+int OptimalShortenedLength(int num_resources) {
+ if (num_resources > 4000) {
+ return 3;
+ } else {
+ return 2;
+ }
+}
+
+std::string GetShortenedPath(android::StringPiece shortened_filename,
+ android::StringPiece extension, int collision_count) {
+ std::string shortened_path = std::string("res/") += shortened_filename;
+ if (collision_count > 0) {
+ shortened_path += std::to_string(collision_count);
+ }
+ shortened_path += extension;
+ return shortened_path;
+}
+
+// implement custom comparator of FileReference pointers so as to use the
+// underlying filepath as key rather than the integer address. This is to ensure
+// determinism of output for colliding files.
+struct PathComparator {
+ bool operator()(const FileReference* lhs, const FileReference* rhs) const {
+ return lhs->path->compare(*rhs->path);
+ }
+};
+
+static bool HandleShortenFilePaths(ResourceTable* table,
+ std::map<std::string, std::string>& shortened_path_map,
+ const std::set<ResourceName>& path_shorten_exemptions) {
+ // used to detect collisions
+ std::unordered_set<std::string> shortened_paths;
+ std::set<FileReference*, PathComparator> file_refs;
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto& entry : type->entries) {
+ ResourceName resource_name({}, type->named_type, entry->name);
+ if (path_shorten_exemptions.find(resource_name) != path_shorten_exemptions.end()) {
+ continue;
+ }
+ for (auto& config_value : entry->values) {
+ FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
+ if (file_ref) {
+ file_refs.insert(file_ref);
+ }
+ }
+ }
+ }
+ }
+ int num_chars = OptimalShortenedLength(file_refs.size());
+ for (auto& file_ref : file_refs) {
+ android::StringPiece res_subdir, actual_filename, extension;
+ util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
+
+ // Android detects ColorStateLists via pathname, skip res/color*
+ if (util::StartsWith(res_subdir, "res/color")) continue;
+
+ std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
+ int collision_count = 0;
+ std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+ while (shortened_paths.find(shortened_path) != shortened_paths.end()) {
+ collision_count++;
+ shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+ }
+ shortened_paths.insert(shortened_path);
+ shortened_path_map.insert({*file_ref->path, shortened_path});
+ file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
+ }
+ return true;
+}
+
+void Obfuscator::ObfuscateResourceName(
+ const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions,
+ const ResourceNamedType& type_name, const ResourceTableEntryView& entry,
+ const android::base::function_ref<void(Result obfuscatedResult, const ResourceName&)>
+ onObfuscate) {
+ ResourceName resource_name({}, type_name, entry.name);
+ if (!collapse_key_stringpool ||
+ name_collapse_exemptions.find(resource_name) != name_collapse_exemptions.end()) {
+ onObfuscate(Result::Keep_ExemptionList, resource_name);
+ } else {
+ // resource isn't exempt from collapse, add it as obfuscated value
+ if (entry.overlayable_item) {
+ // if the resource name of the specific entry is obfuscated and this
+ // entry is in the overlayable list, the overlay can't work on this
+ // overlayable at runtime because the name has been obfuscated in
+ // resources.arsc during flatten operation.
+ onObfuscate(Result::Keep_Overlayable, resource_name);
+ } else {
+ onObfuscate(Result::Obfuscated, resource_name);
+ }
+ }
+}
+
+static bool HandleCollapseKeyStringPool(
+ const ResourceTable* table, const bool collapse_key_string_pool,
+ const std::set<ResourceName>& name_collapse_exemptions,
+ std::unordered_map<uint32_t, std::string>& id_resource_map) {
+ if (!collapse_key_string_pool) {
+ return true;
+ }
+
+ int entryResId = 0;
+ auto onObfuscate = [&entryResId, &id_resource_map](const Obfuscator::Result obfuscatedResult,
+ const ResourceName& resource_name) {
+ if (obfuscatedResult == Obfuscator::Result::Obfuscated) {
+ id_resource_map.insert({entryResId, resource_name.entry});
+ }
+ };
+
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto& entry : type->entries) {
+ if (!entry->id.has_value() || entry->name.empty()) {
+ continue;
+ }
+ entryResId = entry->id->id;
+ ResourceTableEntryView entry_view{
+ .name = entry->name,
+ .id = entry->id ? entry->id.value().entry_id() : (std::optional<uint16_t>)std::nullopt,
+ .visibility = entry->visibility,
+ .allow_new = entry->allow_new,
+ .overlayable_item = entry->overlayable_item,
+ .staged_id = entry->staged_id};
+
+ Obfuscator::ObfuscateResourceName(collapse_key_string_pool, name_collapse_exemptions,
+ type->named_type, entry_view, onObfuscate);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
+ HandleCollapseKeyStringPool(table, options_.collapse_key_stringpool,
+ options_.name_collapse_exemptions, options_.id_resource_map);
+ if (shorten_resource_paths_) {
+ return HandleShortenFilePaths(table, options_.shortened_path_map,
+ options_.path_shorten_exemptions);
+ }
+ return true;
+}
+
+bool Obfuscator::WriteObfuscationMap(const std::string& file_path) const {
+ pb::ResourceMappings resourceMappings;
+ for (const auto& [id, name] : options_.id_resource_map) {
+ auto* collapsedNameMapping = resourceMappings.mutable_collapsed_names()->add_resource_names();
+ collapsedNameMapping->set_id(id);
+ collapsedNameMapping->set_name(name);
+ }
+
+ for (const auto& [original_path, shortened_path] : options_.shortened_path_map) {
+ auto* resource_path = resourceMappings.mutable_shortened_paths()->add_resource_paths();
+ resource_path->set_original_path(original_path);
+ resource_path->set_shortened_path(shortened_path);
+ }
+
+ { // RAII style, output the pb content to file and close fout in destructor
+ std::ofstream fout(file_path, std::ios::out | std::ios::trunc | std::ios::binary);
+ if (!fout.is_open()) {
+ return false;
+ }
+ return resourceMappings.SerializeToOstream(&fout);
+ }
+}
+
+/**
+ * Tell the optimizer whether it's needed to dump information for de-obfuscating.
+ *
+ * There are two conditions need to dump the information for de-obfuscating.
+ * * the option of shortening file paths is enabled.
+ * * the option of collapsing resource names is enabled.
+ * @return true if the information needed for de-obfuscating, otherwise false
+ */
+bool Obfuscator::IsEnabled() const {
+ return shorten_resource_paths_ || collapse_key_stringpool_;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/optimize/Obfuscator.h b/tools/aapt2/optimize/Obfuscator.h
new file mode 100644
index 000000000000..5ccf54383aae
--- /dev/null
+++ b/tools/aapt2/optimize/Obfuscator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TOOLS_AAPT2_OPTIMIZE_OBFUSCATOR_H_
+#define TOOLS_AAPT2_OPTIMIZE_OBFUSCATOR_H_
+
+#include <set>
+#include <string>
+
+#include "ResourceMetadata.pb.h"
+#include "ResourceTable.h"
+#include "android-base/function_ref.h"
+#include "android-base/macros.h"
+#include "cmd/Optimize.h"
+#include "format/binary/TableFlattener.h"
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+class ResourceTable;
+
+// Maps resources in the apk to shortened paths.
+class Obfuscator : public IResourceTableConsumer {
+ public:
+ explicit Obfuscator(OptimizeOptions& optimizeOptions);
+
+ bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ bool WriteObfuscationMap(const std::string& file_path) const;
+
+ bool IsEnabled() const;
+
+ enum class Result { Obfuscated, Keep_ExemptionList, Keep_Overlayable };
+
+ // hardcoded string uses characters which make it an invalid resource name
+ static constexpr char kObfuscatedResourceName[] = "0_resource_name_obfuscated";
+
+ static void ObfuscateResourceName(
+ const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions,
+ const ResourceNamedType& type_name, const ResourceTableEntryView& entry,
+ const android::base::function_ref<void(Result, const ResourceName&)> onObfuscate);
+
+ private:
+ TableFlattenerOptions& options_;
+ const bool shorten_resource_paths_;
+ const bool collapse_key_stringpool_;
+ DISALLOW_COPY_AND_ASSIGN(Obfuscator);
+};
+
+} // namespace aapt
+
+#endif // TOOLS_AAPT2_OPTIMIZE_OBFUSCATOR_H_
diff --git a/tools/aapt2/optimize/Obfuscator_test.cpp b/tools/aapt2/optimize/Obfuscator_test.cpp
new file mode 100644
index 000000000000..940cf1096f92
--- /dev/null
+++ b/tools/aapt2/optimize/Obfuscator_test.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "optimize/Obfuscator.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "ResourceTable.h"
+#include "android-base/file.h"
+#include "test/Test.h"
+
+using ::aapt::test::GetValue;
+using ::testing::AnyOf;
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::IsFalse;
+using ::testing::IsTrue;
+using ::testing::Not;
+using ::testing::NotNull;
+
+android::StringPiece GetExtension(android::StringPiece path) {
+ auto iter = std::find(path.begin(), path.end(), '.');
+ return android::StringPiece(iter, path.end() - iter);
+}
+
+void FillTable(aapt::test::ResourceTableBuilder& builder, int start, int end) {
+ for (int i = start; i < end; i++) {
+ builder.AddFileReference("android:drawable/xmlfile" + std::to_string(i),
+ "res/drawable/xmlfile" + std::to_string(i) + ".xml");
+ }
+}
+
+namespace aapt {
+
+TEST(ObfuscatorTest, FileRefPathsChangedInResourceTable) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml")
+ .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml")
+ .AddString("android:string/string", "res/should/still/be/the/same.png")
+ .Build();
+
+ OptimizeOptions options{.shorten_resource_paths = true};
+ std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+ ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
+
+ // Expect that the path map is populated
+ ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end())));
+ ASSERT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end())));
+
+ // The file paths were changed
+ EXPECT_THAT(path_map.at("res/drawables/xmlfile.xml"), Not(Eq("res/drawables/xmlfile.xml")));
+ EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml")));
+
+ // Different file paths should remain different
+ EXPECT_THAT(path_map["res/drawables/xmlfile.xml"],
+ Not(Eq(path_map["res/drawables/xmlfile2.xml"])));
+
+ FileReference* ref = GetValue<FileReference>(table.get(), "android:drawable/xmlfile");
+ ASSERT_THAT(ref, NotNull());
+ // The map correctly points to the new location of the file
+ EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], Eq(*ref->path));
+
+ // Strings should not be affected, only file paths
+ EXPECT_THAT(*GetValue<String>(table.get(), "android:string/string")->value,
+ Eq("res/should/still/be/the/same.png"));
+ EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end()));
+}
+
+TEST(ObfuscatorTest, SkipColorFileRefPaths) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:color/colorlist", "res/color/colorlist.xml")
+ .AddFileReference("android:color/colorlist", "res/color-mdp-v21/colorlist.xml",
+ test::ParseConfigOrDie("mdp-v21"))
+ .Build();
+
+ OptimizeOptions options{.shorten_resource_paths = true};
+ std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+ ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
+
+ // Expect that the path map to not contain the ColorStateList
+ ASSERT_THAT(path_map.find("res/color/colorlist.xml"), Eq(path_map.end()));
+ ASSERT_THAT(path_map.find("res/color-mdp-v21/colorlist.xml"), Eq(path_map.end()));
+}
+
+TEST(ObfuscatorTest, SkipPathShortenExemptions) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml")
+ .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml")
+ .AddString("android:string/string", "res/should/still/be/the/same.png")
+ .Build();
+
+ OptimizeOptions options{.shorten_resource_paths = true};
+ TableFlattenerOptions& flattenerOptions = options.table_flattener_options;
+ flattenerOptions.path_shorten_exemptions.insert(
+ ResourceName({}, ResourceType::kDrawable, "xmlfile"));
+ std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+ ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
+
+ // Expect that the path map to not contain the first drawable which is in exemption set
+ EXPECT_THAT(path_map.find("res/drawables/xmlfile.xml"), Eq(path_map.end()));
+
+ // Expect that the path map to contain the second drawable which is not in exemption set
+ EXPECT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end())));
+
+ FileReference* ref = GetValue<FileReference>(table.get(), "android:drawable/xmlfile");
+ EXPECT_THAT(ref, NotNull());
+ ASSERT_THAT(HasFailure(), IsFalse());
+ // The path of first drawable in exemption was not changed
+ EXPECT_THAT("res/drawables/xmlfile.xml", Eq(*ref->path));
+
+ // The file path of second drawable not in exemption set was changed
+ EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml")));
+
+ FileReference* ref2 = GetValue<FileReference>(table.get(), "android:drawable/xmlfile2");
+ ASSERT_THAT(ref, NotNull());
+ // The map of second drawable not in exemption correctly points to the new location of the file
+ EXPECT_THAT(path_map["res/drawables/xmlfile2.xml"], Eq(*ref2->path));
+}
+
+TEST(ObfuscatorTest, KeepExtensions) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ std::string original_xml_path = "res/drawable/xmlfile.xml";
+ std::string original_png_path = "res/drawable/pngfile.png";
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:color/xmlfile", original_xml_path)
+ .AddFileReference("android:color/pngfile", original_png_path)
+ .Build();
+
+ OptimizeOptions options{.shorten_resource_paths = true};
+ std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+ ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
+
+ // Expect that the path map is populated
+ ASSERT_THAT(path_map.find("res/drawable/xmlfile.xml"), Not(Eq(path_map.end())));
+ ASSERT_THAT(path_map.find("res/drawable/pngfile.png"), Not(Eq(path_map.end())));
+
+ auto shortend_xml_path = path_map[original_xml_path];
+ auto shortend_png_path = path_map[original_png_path];
+
+ EXPECT_THAT(GetExtension(path_map[original_xml_path]), Eq(android::StringPiece(".xml")));
+ EXPECT_THAT(GetExtension(path_map[original_png_path]), Eq(android::StringPiece(".png")));
+}
+
+TEST(ObfuscatorTest, DeterministicallyHandleCollisions) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ // 4000 resources is the limit at which the hash space is expanded to 3
+ // letters to reduce collisions, we want as many collisions as possible thus
+ // N-1.
+ const auto kNumResources = 3999;
+ const auto kNumTries = 5;
+
+ test::ResourceTableBuilder builder1;
+ FillTable(builder1, 0, kNumResources);
+ std::unique_ptr<ResourceTable> table1 = builder1.Build();
+ OptimizeOptions options{.shorten_resource_paths = true};
+ std::map<std::string, std::string>& expected_mapping =
+ options.table_flattener_options.shortened_path_map;
+ ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table1.get()));
+
+ // We are trying to ensure lack of non-determinism, it is not simple to prove
+ // a negative, thus we must try the test a few times so that the test itself
+ // is non-flaky. Basically create the pathmap 5 times from the same set of
+ // resources but a different order of addition and then ensure they are always
+ // mapped to the same short path.
+ for (int i = 0; i < kNumTries; i++) {
+ test::ResourceTableBuilder builder2;
+ // This loop adds resources to the resource table in the range of
+ // [0:kNumResources). Adding the file references in different order makes
+ // non-determinism more likely to surface. Thus we add resources
+ // [start_index:kNumResources) first then [0:start_index). We also use a
+ // different start_index each run.
+ int start_index = (kNumResources / kNumTries) * i;
+ FillTable(builder2, start_index, kNumResources);
+ FillTable(builder2, 0, start_index);
+ std::unique_ptr<ResourceTable> table2 = builder2.Build();
+
+ OptimizeOptions actualOptimizerOptions{.shorten_resource_paths = true};
+ TableFlattenerOptions& actual_options = actualOptimizerOptions.table_flattener_options;
+ std::map<std::string, std::string>& actual_mapping = actual_options.shortened_path_map;
+ ASSERT_TRUE(Obfuscator(actualOptimizerOptions).Consume(context.get(), table2.get()));
+
+ for (auto& item : actual_mapping) {
+ ASSERT_THAT(expected_mapping[item.first], Eq(item.second));
+ }
+ }
+}
+
+TEST(ObfuscatorTest, DumpIdResourceMap) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
+ overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
+ overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION;
+ overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
+
+ std::string original_xml_path = "res/drawable/xmlfile.xml";
+ std::string original_png_path = "res/drawable/pngfile.png";
+
+ std::string name = "com.app.test:string/overlayable";
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:color/xmlfile", original_xml_path)
+ .AddFileReference("android:color/pngfile", original_png_path)
+ .AddValue("com.app.test:color/mycolor", aapt::ResourceId(0x7f020000),
+ aapt::util::make_unique<aapt::BinaryPrimitive>(
+ uint8_t(android::Res_value::TYPE_INT_COLOR_ARGB8), 0xffaabbcc))
+ .AddString("com.app.test:string/mystring", ResourceId(0x7f030000), "hi")
+ .AddString("com.app.test:string/in_exemption", ResourceId(0x7f030001), "Hi")
+ .AddString(name, ResourceId(0x7f030002), "HI")
+ .SetOverlayable(name, overlayable_item)
+ .Build();
+
+ OptimizeOptions options{.shorten_resource_paths = true};
+ TableFlattenerOptions& flattenerOptions = options.table_flattener_options;
+ flattenerOptions.collapse_key_stringpool = true;
+ flattenerOptions.name_collapse_exemptions.insert(
+ ResourceName({}, ResourceType::kString, "in_exemption"));
+ auto& id_resource_map = flattenerOptions.id_resource_map;
+ ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
+
+ // Expect that the id resource name map is populated
+ EXPECT_THAT(id_resource_map.at(0x7f020000), Eq("mycolor"));
+ EXPECT_THAT(id_resource_map.at(0x7f030000), Eq("mystring"));
+ EXPECT_THAT(id_resource_map.find(0x7f030001), Eq(id_resource_map.end()));
+ EXPECT_THAT(id_resource_map.find(0x7f030002), Eq(id_resource_map.end()));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithDefaultOption) {
+ OptimizeOptions options;
+ Obfuscator obfuscatorWithDefaultOption(options);
+ ASSERT_THAT(obfuscatorWithDefaultOption.IsEnabled(), Eq(false));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithShortenPathOption) {
+ OptimizeOptions options{.shorten_resource_paths = true};
+ Obfuscator obfuscatorWithShortenPathOption(options);
+ ASSERT_THAT(obfuscatorWithShortenPathOption.IsEnabled(), Eq(true));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithCollapseStringPoolOption) {
+ OptimizeOptions options;
+ options.table_flattener_options.collapse_key_stringpool = true;
+ Obfuscator obfuscatorWithCollapseStringPoolOption(options);
+ ASSERT_THAT(obfuscatorWithCollapseStringPoolOption.IsEnabled(), Eq(true));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithShortenPathAndCollapseStringPoolOption) {
+ OptimizeOptions options{.shorten_resource_paths = true};
+ options.table_flattener_options.collapse_key_stringpool = true;
+ Obfuscator obfuscatorWithCollapseStringPoolOption(options);
+ ASSERT_THAT(obfuscatorWithCollapseStringPoolOption.IsEnabled(), Eq(true));
+}
+
+static std::unique_ptr<ResourceTable> getProtocolBufferTableUnderTest() {
+ std::string original_xml_path = "res/drawable/xmlfile.xml";
+ std::string original_png_path = "res/drawable/pngfile.png";
+
+ return test::ResourceTableBuilder()
+ .AddFileReference("com.app.test:drawable/xmlfile", original_xml_path)
+ .AddFileReference("com.app.test:drawable/pngfile", original_png_path)
+ .AddValue("com.app.test:color/mycolor", aapt::ResourceId(0x7f020000),
+ aapt::util::make_unique<aapt::BinaryPrimitive>(
+ uint8_t(android::Res_value::TYPE_INT_COLOR_ARGB8), 0xffaabbcc))
+ .AddString("com.app.test:string/mystring", ResourceId(0x7f030000), "hello world")
+ .Build();
+}
+
+TEST(ObfuscatorTest, WriteObfuscationMapInProtocolBufferFormat) {
+ OptimizeOptions options{.shorten_resource_paths = true};
+ options.table_flattener_options.collapse_key_stringpool = true;
+ Obfuscator obfuscator(options);
+ ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
+ getProtocolBufferTableUnderTest().get()));
+
+ obfuscator.WriteObfuscationMap("obfuscated_map.pb");
+
+ std::string pbOut;
+ android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
+ EXPECT_THAT(pbOut, HasSubstr("drawable/xmlfile.xml"));
+ EXPECT_THAT(pbOut, HasSubstr("drawable/pngfile.png"));
+ EXPECT_THAT(pbOut, HasSubstr("mycolor"));
+ EXPECT_THAT(pbOut, HasSubstr("mystring"));
+ pb::ResourceMappings resourceMappings;
+ EXPECT_THAT(resourceMappings.ParseFromString(pbOut), IsTrue());
+ EXPECT_THAT(resourceMappings.collapsed_names().resource_names_size(), Eq(2));
+ auto& resource_names = resourceMappings.collapsed_names().resource_names();
+ EXPECT_THAT(resource_names.at(0).name(), AnyOf(Eq("mycolor"), Eq("mystring")));
+ EXPECT_THAT(resource_names.at(1).name(), AnyOf(Eq("mycolor"), Eq("mystring")));
+ auto& shortened_paths = resourceMappings.shortened_paths();
+ EXPECT_THAT(shortened_paths.resource_paths_size(), Eq(2));
+ EXPECT_THAT(shortened_paths.resource_paths(0).original_path(),
+ AnyOf(Eq("res/drawable/pngfile.png"), Eq("res/drawable/xmlfile.xml")));
+ EXPECT_THAT(shortened_paths.resource_paths(1).original_path(),
+ AnyOf(Eq("res/drawable/pngfile.png"), Eq("res/drawable/xmlfile.xml")));
+}
+
+TEST(ObfuscatorTest, WriteObfuscatingMapWithNonEnabledOption) {
+ OptimizeOptions options;
+ Obfuscator obfuscator(options);
+ ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
+ getProtocolBufferTableUnderTest().get()));
+
+ obfuscator.WriteObfuscationMap("obfuscated_map.pb");
+
+ std::string pbOut;
+ android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
+ ASSERT_THAT(pbOut, Eq(""));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/optimize/ResourceDeduper.cpp b/tools/aapt2/optimize/ResourceDeduper.cpp
index 0278b439cfae..c71cb4c21020 100644
--- a/tools/aapt2/optimize/ResourceDeduper.cpp
+++ b/tools/aapt2/optimize/ResourceDeduper.cpp
@@ -77,12 +77,11 @@ class DominatedKeyValueRemover : public DominatorTree::BottomUpVisitor {
}
}
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(
- DiagMessage(node_value->value->GetSource())
- << "removing dominated duplicate resource with name \""
- << entry_->name << "\"");
- context_->GetDiagnostics()->Note(
- DiagMessage(parent_value->value->GetSource()) << "dominated here");
+ context_->GetDiagnostics()->Note(android::DiagMessage(node_value->value->GetSource())
+ << "removing dominated duplicate resource with name \""
+ << entry_->name << "\"");
+ context_->GetDiagnostics()->Note(android::DiagMessage(parent_value->value->GetSource())
+ << "dominated here");
}
node_value->value = {};
}
diff --git a/tools/aapt2/optimize/ResourceFilter.cpp b/tools/aapt2/optimize/ResourceFilter.cpp
index 08c045bf68f7..db84b66ecd2d 100644
--- a/tools/aapt2/optimize/ResourceFilter.cpp
+++ b/tools/aapt2/optimize/ResourceFilter.cpp
@@ -28,7 +28,7 @@ bool ResourceFilter::Consume(IAaptContext* context, ResourceTable* table) {
for (auto& package : table->packages) {
for (auto& type : package->types) {
for (auto it = type->entries.begin(); it != type->entries.end(); ) {
- ResourceName resource = ResourceName({}, type->type, (*it)->name);
+ ResourceName resource = ResourceName({}, type->named_type, (*it)->name);
if (exclude_list_.find(resource) != exclude_list_.end()) {
it = type->entries.erase(it);
} else {
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
deleted file mode 100644
index 7ff9bf5aa8df..000000000000
--- a/tools/aapt2/optimize/ResourcePathShortener.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "optimize/ResourcePathShortener.h"
-
-#include <set>
-#include <unordered_set>
-
-#include "androidfw/StringPiece.h"
-
-#include "ResourceTable.h"
-#include "ValueVisitor.h"
-#include "util/Util.h"
-
-
-static const std::string base64_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789-_";
-
-namespace aapt {
-
-ResourcePathShortener::ResourcePathShortener(
- std::map<std::string, std::string>& path_map_out)
- : path_map_(path_map_out) {
-}
-
-std::string ShortenFileName(const android::StringPiece& file_path, int output_length) {
- std::size_t hash_num = std::hash<android::StringPiece>{}(file_path);
- std::string result = "";
- // Convert to (modified) base64 so that it is a proper file path.
- for (int i = 0; i < output_length; i++) {
- uint8_t sextet = hash_num & 0x3f;
- hash_num >>= 6;
- result += base64_chars[sextet];
- }
- return result;
-}
-
-
-// Return the optimal hash length such that at most 10% of resources collide in
-// their shortened path.
-// Reference: http://matt.might.net/articles/counting-hash-collisions/
-int OptimalShortenedLength(int num_resources) {
- if (num_resources > 4000) {
- return 3;
- } else {
- return 2;
- }
-}
-
-std::string GetShortenedPath(const android::StringPiece& shortened_filename,
- const android::StringPiece& extension, int collision_count) {
- std::string shortened_path = "res/" + shortened_filename.to_string();
- if (collision_count > 0) {
- shortened_path += std::to_string(collision_count);
- }
- shortened_path += extension;
- return shortened_path;
-}
-
-// implement custom comparator of FileReference pointers so as to use the
-// underlying filepath as key rather than the integer address. This is to ensure
-// determinism of output for colliding files.
-struct PathComparator {
- bool operator() (const FileReference* lhs, const FileReference* rhs) const {
- return lhs->path->compare(*rhs->path);
- }
-};
-
-bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) {
- // used to detect collisions
- std::unordered_set<std::string> shortened_paths;
- std::set<FileReference*, PathComparator> file_refs;
- for (auto& package : table->packages) {
- for (auto& type : package->types) {
- for (auto& entry : type->entries) {
- for (auto& config_value : entry->values) {
- FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
- if (file_ref) {
- file_refs.insert(file_ref);
- }
- }
- }
- }
- }
- int num_chars = OptimalShortenedLength(file_refs.size());
- for (auto& file_ref : file_refs) {
- android::StringPiece res_subdir, actual_filename, extension;
- util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
-
- // Android detects ColorStateLists via pathname, skip res/color*
- if (util::StartsWith(res_subdir, "res/color"))
- continue;
-
- std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
- int collision_count = 0;
- std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
- while (shortened_paths.find(shortened_path) != shortened_paths.end()) {
- collision_count++;
- shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
- }
- shortened_paths.insert(shortened_path);
- path_map_.insert({*file_ref->path, shortened_path});
- file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
- }
- return true;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/optimize/ResourcePathShortener.h b/tools/aapt2/optimize/ResourcePathShortener.h
deleted file mode 100644
index f1074ef083bd..000000000000
--- a/tools/aapt2/optimize/ResourcePathShortener.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
-#define AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
-
-#include <map>
-
-#include "android-base/macros.h"
-
-#include "process/IResourceTableConsumer.h"
-
-namespace aapt {
-
-class ResourceTable;
-
-// Maps resources in the apk to shortened paths.
-class ResourcePathShortener : public IResourceTableConsumer {
- public:
- explicit ResourcePathShortener(std::map<std::string, std::string>& path_map_out);
-
- bool Consume(IAaptContext* context, ResourceTable* table) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ResourcePathShortener);
- std::map<std::string, std::string>& path_map_;
-};
-
-} // namespace aapt
-
-#endif // AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
deleted file mode 100644
index f5a02be0ea5e..000000000000
--- a/tools/aapt2/optimize/ResourcePathShortener_test.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "optimize/ResourcePathShortener.h"
-
-#include "ResourceTable.h"
-#include "test/Test.h"
-
-using ::aapt::test::GetValue;
-using ::testing::Not;
-using ::testing::NotNull;
-using ::testing::Eq;
-
-android::StringPiece GetExtension(android::StringPiece path) {
- auto iter = std::find(path.begin(), path.end(), '.');
- return android::StringPiece(iter, path.end() - iter);
-}
-
-void FillTable(aapt::test::ResourceTableBuilder& builder, int start, int end) {
- for (int i=start; i<end; i++) {
- builder.AddFileReference(
- "android:drawable/xmlfile" + std::to_string(i),
- "res/drawable/xmlfile" + std::to_string(i) + ".xml");
- }
-}
-
-namespace aapt {
-
-TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
- std::unique_ptr<ResourceTable> table =
- test::ResourceTableBuilder()
- .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml")
- .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml")
- .AddString("android:string/string", "res/should/still/be/the/same.png")
- .Build();
-
- std::map<std::string, std::string> path_map;
- ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
-
- // Expect that the path map is populated
- ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end())));
- ASSERT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end())));
-
- // The file paths were changed
- EXPECT_THAT(path_map.at("res/drawables/xmlfile.xml"), Not(Eq("res/drawables/xmlfile.xml")));
- EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml")));
-
- // Different file paths should remain different
- EXPECT_THAT(path_map["res/drawables/xmlfile.xml"],
- Not(Eq(path_map["res/drawables/xmlfile2.xml"])));
-
- FileReference* ref =
- GetValue<FileReference>(table.get(), "android:drawable/xmlfile");
- ASSERT_THAT(ref, NotNull());
- // The map correctly points to the new location of the file
- EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], Eq(*ref->path));
-
- // Strings should not be affected, only file paths
- EXPECT_THAT(
- *GetValue<String>(table.get(), "android:string/string")->value,
- Eq("res/should/still/be/the/same.png"));
- EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end()));
-}
-
-TEST(ResourcePathShortenerTest, SkipColorFileRefPaths) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
- std::unique_ptr<ResourceTable> table =
- test::ResourceTableBuilder()
- .AddFileReference("android:color/colorlist", "res/color/colorlist.xml")
- .AddFileReference("android:color/colorlist",
- "res/color-mdp-v21/colorlist.xml",
- test::ParseConfigOrDie("mdp-v21"))
- .Build();
-
- std::map<std::string, std::string> path_map;
- ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
-
- // Expect that the path map to not contain the ColorStateList
- ASSERT_THAT(path_map.find("res/color/colorlist.xml"), Eq(path_map.end()));
- ASSERT_THAT(path_map.find("res/color-mdp-v21/colorlist.xml"), Eq(path_map.end()));
-}
-
-TEST(ResourcePathShortenerTest, KeepExtensions) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
- std::string original_xml_path = "res/drawable/xmlfile.xml";
- std::string original_png_path = "res/drawable/pngfile.png";
-
- std::unique_ptr<ResourceTable> table =
- test::ResourceTableBuilder()
- .AddFileReference("android:color/xmlfile", original_xml_path)
- .AddFileReference("android:color/pngfile", original_png_path)
- .Build();
-
- std::map<std::string, std::string> path_map;
- ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
-
- // Expect that the path map is populated
- ASSERT_THAT(path_map.find("res/drawable/xmlfile.xml"), Not(Eq(path_map.end())));
- ASSERT_THAT(path_map.find("res/drawable/pngfile.png"), Not(Eq(path_map.end())));
-
- auto shortend_xml_path = path_map[original_xml_path];
- auto shortend_png_path = path_map[original_png_path];
-
- EXPECT_THAT(GetExtension(path_map[original_xml_path]), Eq(android::StringPiece(".xml")));
- EXPECT_THAT(GetExtension(path_map[original_png_path]), Eq(android::StringPiece(".png")));
-}
-
-TEST(ResourcePathShortenerTest, DeterministicallyHandleCollisions) {
- std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-
- // 4000 resources is the limit at which the hash space is expanded to 3
- // letters to reduce collisions, we want as many collisions as possible thus
- // N-1.
- const auto kNumResources = 3999;
- const auto kNumTries = 5;
-
- test::ResourceTableBuilder builder1;
- FillTable(builder1, 0, kNumResources);
- std::unique_ptr<ResourceTable> table1 = builder1.Build();
- std::map<std::string, std::string> expected_mapping;
- ASSERT_TRUE(ResourcePathShortener(expected_mapping).Consume(context.get(), table1.get()));
-
- // We are trying to ensure lack of non-determinism, it is not simple to prove
- // a negative, thus we must try the test a few times so that the test itself
- // is non-flaky. Basically create the pathmap 5 times from the same set of
- // resources but a different order of addition and then ensure they are always
- // mapped to the same short path.
- for (int i=0; i<kNumTries; i++) {
- test::ResourceTableBuilder builder2;
- // This loop adds resources to the resource table in the range of
- // [0:kNumResources). Adding the file references in different order makes
- // non-determinism more likely to surface. Thus we add resources
- // [start_index:kNumResources) first then [0:start_index). We also use a
- // different start_index each run.
- int start_index = (kNumResources/kNumTries)*i;
- FillTable(builder2, start_index, kNumResources);
- FillTable(builder2, 0, start_index);
- std::unique_ptr<ResourceTable> table2 = builder2.Build();
-
- std::map<std::string, std::string> actual_mapping;
- ASSERT_TRUE(ResourcePathShortener(actual_mapping).Consume(context.get(), table2.get()));
-
- for (auto& item : actual_mapping) {
- ASSERT_THAT(expected_mapping[item.first], Eq(item.second));
- }
- }
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/optimize/VersionCollapser_test.cpp b/tools/aapt2/optimize/VersionCollapser_test.cpp
index aa0d0c095f57..18dcd6bace77 100644
--- a/tools/aapt2/optimize/VersionCollapser_test.cpp
+++ b/tools/aapt2/optimize/VersionCollapser_test.cpp
@@ -23,7 +23,7 @@ using android::StringPiece;
namespace aapt {
static std::unique_ptr<ResourceTable> BuildTableWithConfigs(
- const StringPiece& name, std::initializer_list<std::string> list) {
+ StringPiece name, std::initializer_list<std::string> list) {
test::ResourceTableBuilder builder;
for (const std::string& item : list) {
builder.AddSimple(name, test::ParseConfigOrDie(item));
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 9c4b323db433..e41e45a29b3e 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -22,11 +22,11 @@
#include <set>
#include <sstream>
-#include "Diagnostics.h"
#include "NameMangler.h"
#include "Resource.h"
#include "ResourceValues.h"
-#include "Source.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
namespace aapt {
@@ -45,7 +45,7 @@ struct IAaptContext {
virtual PackageType GetPackageType() = 0;
virtual SymbolTable* GetExternalSymbols() = 0;
- virtual IDiagnostics* GetDiagnostics() = 0;
+ virtual android::IDiagnostics* GetDiagnostics() = 0;
virtual const std::string& GetCompilationPackage() = 0;
virtual uint8_t GetPackageId() = 0;
virtual NameMangler* GetNameMangler() = 0;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 92b45c397eed..bca62da447b0 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -218,7 +218,7 @@ std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::FindByName(
return symbol;
}
-bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
+bool AssetManagerSymbolSource::AddAssetPath(StringPiece path) {
TRACE_CALL();
if (std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path.data())) {
apk_assets_.push_back(std::move(apk));
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index c17837c224ab..b09ff702ca58 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -192,7 +192,7 @@ class AssetManagerSymbolSource : public ISymbolSource {
public:
AssetManagerSymbolSource() = default;
- bool AddAssetPath(const android::StringPiece& path);
+ bool AddAssetPath(android::StringPiece path);
std::map<size_t, std::string> GetAssignedPackageIds() const;
bool IsPackageDynamic(uint32_t packageId, const std::string& package_name) const;
diff --git a/tools/aapt2/process/SymbolTable_test.cpp b/tools/aapt2/process/SymbolTable_test.cpp
index ddc210189793..e576709a776d 100644
--- a/tools/aapt2/process/SymbolTable_test.cpp
+++ b/tools/aapt2/process/SymbolTable_test.cpp
@@ -17,9 +17,9 @@
#include "process/SymbolTable.h"
#include "SdkConstants.h"
+#include "androidfw/BigBuffer.h"
#include "format/binary/TableFlattener.h"
#include "test/Test.h"
-#include "util/BigBuffer.h"
using ::testing::Eq;
using ::testing::IsNull;
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 116b2ab9aa98..58f2b1dcdf87 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -160,17 +160,15 @@ bool TableSplitter::VerifySplitConstraints(IAaptContext* context) {
for (size_t i = 0; i < split_constraints_.size(); i++) {
if (split_constraints_[i].configs.size() == 0) {
// For now, treat this as a warning. We may consider aborting processing.
- context->GetDiagnostics()->Warn(DiagMessage()
- << "no configurations for constraint '"
- << split_constraints_[i].name << "'");
+ context->GetDiagnostics()->Warn(android::DiagMessage() << "no configurations for constraint '"
+ << split_constraints_[i].name << "'");
}
for (size_t j = i + 1; j < split_constraints_.size(); j++) {
for (const ConfigDescription& config : split_constraints_[i].configs) {
if (split_constraints_[j].configs.find(config) != split_constraints_[j].configs.end()) {
- context->GetDiagnostics()->Error(DiagMessage()
- << "config '" << config
- << "' appears in multiple splits, "
- << "target split ambiguous");
+ context->GetDiagnostics()->Error(
+ android::DiagMessage() << "config '" << config << "' appears in multiple splits, "
+ << "target split ambiguous");
error = true;
}
}
@@ -189,7 +187,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
}
for (auto& type : pkg->types) {
- if (type->type == ResourceType::kMipmap) {
+ if (type->named_type.type == ResourceType::kMipmap) {
// Always keep mipmaps.
continue;
}
@@ -241,7 +239,7 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
// Create the same resource structure in the split. We do this lazily because we might
// not have actual values for each type/entry.
ResourceTablePackage* split_pkg = split_table->FindPackage(pkg->name);
- ResourceTableType* split_type = split_pkg->FindOrCreateType(type->type);
+ ResourceTableType* split_type = split_pkg->FindOrCreateType(type->named_type);
split_type->visibility_level = type->visibility_level;
ResourceEntry* split_entry = split_type->FindOrCreateEntry(entry->name);
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 23331de02df7..65f63dc68e54 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -16,9 +16,9 @@
#include "test/Builders.h"
+#include "Diagnostics.h"
#include "android-base/logging.h"
#include "androidfw/StringPiece.h"
-
#include "io/StringStream.h"
#include "test/Common.h"
#include "util/Util.h"
@@ -34,61 +34,53 @@ using ::android::StringPiece;
namespace aapt {
namespace test {
-ResourceTableBuilder& ResourceTableBuilder::AddSimple(const StringPiece& name,
- const ResourceId& id) {
+ResourceTableBuilder& ResourceTableBuilder::AddSimple(StringPiece name, const ResourceId& id) {
return AddValue(name, id, util::make_unique<Id>());
}
-ResourceTableBuilder& ResourceTableBuilder::AddSimple(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::AddSimple(StringPiece name,
const ConfigDescription& config,
const ResourceId& id) {
return AddValue(name, config, id, util::make_unique<Id>());
}
-ResourceTableBuilder& ResourceTableBuilder::AddReference(const StringPiece& name,
- const StringPiece& ref) {
+ResourceTableBuilder& ResourceTableBuilder::AddReference(StringPiece name, StringPiece ref) {
return AddReference(name, {}, ref);
}
-ResourceTableBuilder& ResourceTableBuilder::AddReference(const StringPiece& name,
- const ResourceId& id,
- const StringPiece& ref) {
+ResourceTableBuilder& ResourceTableBuilder::AddReference(StringPiece name, const ResourceId& id,
+ StringPiece ref) {
return AddValue(name, id, util::make_unique<Reference>(ParseNameOrDie(ref)));
}
-ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name,
- const StringPiece& str) {
+ResourceTableBuilder& ResourceTableBuilder::AddString(StringPiece name, StringPiece str) {
return AddString(name, {}, str);
}
-ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, const ResourceId& id,
- const StringPiece& str) {
+ResourceTableBuilder& ResourceTableBuilder::AddString(StringPiece name, const ResourceId& id,
+ StringPiece str) {
return AddValue(name, id, util::make_unique<String>(table_->string_pool.MakeRef(str)));
}
-ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, const ResourceId& id,
+ResourceTableBuilder& ResourceTableBuilder::AddString(StringPiece name, const ResourceId& id,
const ConfigDescription& config,
- const StringPiece& str) {
+ StringPiece str) {
return AddValue(name, config, id, util::make_unique<String>(table_->string_pool.MakeRef(str)));
}
-ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
- const StringPiece& path,
+ResourceTableBuilder& ResourceTableBuilder::AddFileReference(StringPiece name, StringPiece path,
io::IFile* file) {
return AddFileReference(name, {}, path, file);
}
-ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
- const ResourceId& id,
- const StringPiece& path,
- io::IFile* file) {
+ResourceTableBuilder& ResourceTableBuilder::AddFileReference(StringPiece name, const ResourceId& id,
+ StringPiece path, io::IFile* file) {
auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
file_ref->file = file;
return AddValue(name, id, std::move(file_ref));
}
-ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
- const StringPiece& path,
+ResourceTableBuilder& ResourceTableBuilder::AddFileReference(StringPiece name, StringPiece path,
const ConfigDescription& config,
io::IFile* file) {
auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
@@ -96,17 +88,17 @@ ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece&
return AddValue(name, config, {}, std::move(file_ref));
}
-ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::AddValue(StringPiece name,
std::unique_ptr<Value> value) {
return AddValue(name, {}, std::move(value));
}
-ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name, const ResourceId& id,
+ResourceTableBuilder& ResourceTableBuilder::AddValue(StringPiece name, const ResourceId& id,
std::unique_ptr<Value> value) {
return AddValue(name, {}, id, std::move(value));
}
-ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::AddValue(StringPiece name,
const ConfigDescription& config,
const ResourceId& id,
std::unique_ptr<Value> value) {
@@ -121,8 +113,7 @@ ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
return *this;
}
-ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& name,
- const ResourceId& id,
+ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(StringPiece name, const ResourceId& id,
Visibility::Level level,
bool allow_new) {
ResourceName res_name = ParseNameOrDie(name);
@@ -136,9 +127,8 @@ ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& na
return *this;
}
-ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(StringPiece name,
const OverlayableItem& overlayable) {
-
ResourceName res_name = ParseNameOrDie(name);
CHECK(table_->AddResource(
NewResourceBuilder(res_name).SetOverlayable(overlayable).SetAllowMangled(true).Build(),
@@ -151,7 +141,7 @@ ResourceTableBuilder& ResourceTableBuilder::Add(NewResource&& res) {
return *this;
}
-StringPool* ResourceTableBuilder::string_pool() {
+android::StringPool* ResourceTableBuilder::string_pool() {
return &table_->string_pool;
}
@@ -159,8 +149,7 @@ std::unique_ptr<ResourceTable> ResourceTableBuilder::Build() {
return std::move(table_);
}
-std::unique_ptr<Reference> BuildReference(const StringPiece& ref,
- const std::optional<ResourceId>& id) {
+std::unique_ptr<Reference> BuildReference(StringPiece ref, const std::optional<ResourceId>& id) {
std::unique_ptr<Reference> reference = util::make_unique<Reference>(ParseNameOrDie(ref));
reference->id = id;
return reference;
@@ -188,7 +177,7 @@ AttributeBuilder& AttributeBuilder::SetWeak(bool weak) {
return *this;
}
-AttributeBuilder& AttributeBuilder::AddItem(const StringPiece& name, uint32_t value) {
+AttributeBuilder& AttributeBuilder::AddItem(StringPiece name, uint32_t value) {
attr_->symbols.push_back(
Attribute::Symbol{Reference(ResourceName({}, ResourceType::kId, name)), value});
return *this;
@@ -198,17 +187,17 @@ std::unique_ptr<Attribute> AttributeBuilder::Build() {
return std::move(attr_);
}
-StyleBuilder& StyleBuilder::SetParent(const StringPiece& str) {
+StyleBuilder& StyleBuilder::SetParent(StringPiece str) {
style_->parent = Reference(ParseNameOrDie(str));
return *this;
}
-StyleBuilder& StyleBuilder::AddItem(const StringPiece& str, std::unique_ptr<Item> value) {
+StyleBuilder& StyleBuilder::AddItem(StringPiece str, std::unique_ptr<Item> value) {
style_->entries.push_back(Style::Entry{Reference(ParseNameOrDie(str)), std::move(value)});
return *this;
}
-StyleBuilder& StyleBuilder::AddItem(const StringPiece& str, const ResourceId& id,
+StyleBuilder& StyleBuilder::AddItem(StringPiece str, const ResourceId& id,
std::unique_ptr<Item> value) {
AddItem(str, std::move(value));
style_->entries.back().key.id = id;
@@ -219,8 +208,7 @@ std::unique_ptr<Style> StyleBuilder::Build() {
return std::move(style_);
}
-StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str,
- const std::optional<ResourceId>& id) {
+StyleableBuilder& StyleableBuilder::AddItem(StringPiece str, const std::optional<ResourceId>& id) {
styleable_->entries.push_back(Reference(ParseNameOrDie(str)));
styleable_->entries.back().id = id;
return *this;
@@ -230,18 +218,18 @@ std::unique_ptr<Styleable> StyleableBuilder::Build() {
return std::move(styleable_);
}
-std::unique_ptr<xml::XmlResource> BuildXmlDom(const StringPiece& str) {
+std::unique_ptr<xml::XmlResource> BuildXmlDom(StringPiece str) {
std::string input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
input.append(str.data(), str.size());
StringInputStream in(input);
StdErrDiagnostics diag;
- std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, &diag, Source("test.xml"));
+ std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, &diag, android::Source("test.xml"));
CHECK(doc != nullptr && doc->root != nullptr) << "failed to parse inline XML string";
return doc;
}
std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(IAaptContext* context,
- const StringPiece& str) {
+ StringPiece str) {
std::unique_ptr<xml::XmlResource> doc = BuildXmlDom(str);
doc->file.name.package = context->GetCompilationPackage();
return doc;
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 55778aea40af..098535d8526f 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -38,44 +38,39 @@ class ResourceTableBuilder {
public:
ResourceTableBuilder() = default;
- ResourceTableBuilder& AddSimple(const android::StringPiece& name, const ResourceId& id = {});
- ResourceTableBuilder& AddSimple(const android::StringPiece& name,
+ ResourceTableBuilder& AddSimple(android::StringPiece name, const ResourceId& id = {});
+ ResourceTableBuilder& AddSimple(android::StringPiece name,
const android::ConfigDescription& config,
const ResourceId& id = {});
- ResourceTableBuilder& AddReference(const android::StringPiece& name,
- const android::StringPiece& ref);
- ResourceTableBuilder& AddReference(const android::StringPiece& name, const ResourceId& id,
- const android::StringPiece& ref);
- ResourceTableBuilder& AddString(const android::StringPiece& name,
- const android::StringPiece& str);
- ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
- const android::StringPiece& str);
- ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
+ ResourceTableBuilder& AddReference(android::StringPiece name, android::StringPiece ref);
+ ResourceTableBuilder& AddReference(android::StringPiece name, const ResourceId& id,
+ android::StringPiece ref);
+ ResourceTableBuilder& AddString(android::StringPiece name, android::StringPiece str);
+ ResourceTableBuilder& AddString(android::StringPiece name, const ResourceId& id,
+ android::StringPiece str);
+ ResourceTableBuilder& AddString(android::StringPiece name, const ResourceId& id,
const android::ConfigDescription& config,
- const android::StringPiece& str);
- ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
- const android::StringPiece& path,
+ android::StringPiece str);
+ ResourceTableBuilder& AddFileReference(android::StringPiece name, android::StringPiece path,
io::IFile* file = nullptr);
- ResourceTableBuilder& AddFileReference(const android::StringPiece& name, const ResourceId& id,
- const android::StringPiece& path,
- io::IFile* file = nullptr);
- ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
- const android::StringPiece& path,
+ ResourceTableBuilder& AddFileReference(android::StringPiece name, const ResourceId& id,
+ android::StringPiece path, io::IFile* file = nullptr);
+ ResourceTableBuilder& AddFileReference(android::StringPiece name, android::StringPiece path,
const android::ConfigDescription& config,
io::IFile* file = nullptr);
- ResourceTableBuilder& AddValue(const android::StringPiece& name, std::unique_ptr<Value> value);
- ResourceTableBuilder& AddValue(const android::StringPiece& name, const ResourceId& id,
+ ResourceTableBuilder& AddValue(android::StringPiece name, std::unique_ptr<Value> value);
+ ResourceTableBuilder& AddValue(android::StringPiece name, const ResourceId& id,
+ std::unique_ptr<Value> value);
+ ResourceTableBuilder& AddValue(android::StringPiece name,
+ const android::ConfigDescription& config, const ResourceId& id,
std::unique_ptr<Value> value);
- ResourceTableBuilder& AddValue(const android::StringPiece& name,
- const android::ConfigDescription& config,
- const ResourceId& id, std::unique_ptr<Value> value);
- ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
+ ResourceTableBuilder& SetSymbolState(android::StringPiece name, const ResourceId& id,
Visibility::Level level, bool allow_new = false);
- ResourceTableBuilder& SetOverlayable(const android::StringPiece& name,
+ ResourceTableBuilder& SetOverlayable(android::StringPiece name,
const OverlayableItem& overlayable);
ResourceTableBuilder& Add(NewResource&& res);
- StringPool* string_pool();
+ android::StringPool* string_pool();
std::unique_ptr<ResourceTable> Build();
private:
@@ -84,7 +79,7 @@ class ResourceTableBuilder {
std::unique_ptr<ResourceTable> table_ = util::make_unique<ResourceTable>();
};
-std::unique_ptr<Reference> BuildReference(const android::StringPiece& ref,
+std::unique_ptr<Reference> BuildReference(android::StringPiece ref,
const std::optional<ResourceId>& id = {});
std::unique_ptr<BinaryPrimitive> BuildPrimitive(uint8_t type, uint32_t data);
@@ -97,11 +92,11 @@ class ValueBuilder {
template <typename... Args>
ValueBuilder& SetSource(Args&&... args) {
- value_->SetSource(Source{std::forward<Args>(args)...});
+ value_->SetSource(android::Source{std::forward<Args>(args)...});
return *this;
}
- ValueBuilder& SetComment(const android::StringPiece& str) {
+ ValueBuilder& SetComment(android::StringPiece str) {
value_->SetComment(str);
return *this;
}
@@ -121,7 +116,7 @@ class AttributeBuilder {
AttributeBuilder();
AttributeBuilder& SetTypeMask(uint32_t typeMask);
AttributeBuilder& SetWeak(bool weak);
- AttributeBuilder& AddItem(const android::StringPiece& name, uint32_t value);
+ AttributeBuilder& AddItem(android::StringPiece name, uint32_t value);
std::unique_ptr<Attribute> Build();
private:
@@ -133,9 +128,9 @@ class AttributeBuilder {
class StyleBuilder {
public:
StyleBuilder() = default;
- StyleBuilder& SetParent(const android::StringPiece& str);
- StyleBuilder& AddItem(const android::StringPiece& str, std::unique_ptr<Item> value);
- StyleBuilder& AddItem(const android::StringPiece& str, const ResourceId& id,
+ StyleBuilder& SetParent(android::StringPiece str);
+ StyleBuilder& AddItem(android::StringPiece str, std::unique_ptr<Item> value);
+ StyleBuilder& AddItem(android::StringPiece str, const ResourceId& id,
std::unique_ptr<Item> value);
std::unique_ptr<Style> Build();
@@ -148,8 +143,7 @@ class StyleBuilder {
class StyleableBuilder {
public:
StyleableBuilder() = default;
- StyleableBuilder& AddItem(const android::StringPiece& str,
- const std::optional<ResourceId>& id = {});
+ StyleableBuilder& AddItem(android::StringPiece str, const std::optional<ResourceId>& id = {});
std::unique_ptr<Styleable> Build();
private:
@@ -158,9 +152,9 @@ class StyleableBuilder {
std::unique_ptr<Styleable> styleable_ = util::make_unique<Styleable>();
};
-std::unique_ptr<xml::XmlResource> BuildXmlDom(const android::StringPiece& str);
+std::unique_ptr<xml::XmlResource> BuildXmlDom(android::StringPiece str);
std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(IAaptContext* context,
- const android::StringPiece& str);
+ android::StringPiece str);
class ArtifactBuilder {
public:
@@ -257,7 +251,11 @@ class ConfigDescriptionBuilder {
return *this;
}
ConfigDescriptionBuilder& setInputPad0(uint8_t inputPad0) {
- config_.inputPad0 = inputPad0;
+ config_.inputFieldPad0 = inputPad0;
+ return *this;
+ }
+ ConfigDescriptionBuilder& setGrammaticalInflection(uint8_t value) {
+ config_.grammaticalInflection = value;
return *this;
}
ConfigDescriptionBuilder& setScreenWidth(uint16_t screenWidth) {
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index e029d025b366..cdf245341844 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -21,8 +21,8 @@ using android::ConfigDescription;
namespace aapt {
namespace test {
-struct TestDiagnosticsImpl : public IDiagnostics {
- void Log(Level level, DiagMessageActual& actual_msg) override {
+struct TestDiagnosticsImpl : public android::IDiagnostics {
+ void Log(Level level, android::DiagMessageActual& actual_msg) override {
switch (level) {
case Level::Note:
return;
@@ -38,16 +38,15 @@ struct TestDiagnosticsImpl : public IDiagnostics {
}
};
-IDiagnostics* GetDiagnostics() {
+android::IDiagnostics* GetDiagnostics() {
static TestDiagnosticsImpl diag;
return &diag;
}
template <>
-Value* GetValueForConfigAndProduct<Value>(ResourceTable* table,
- const android::StringPiece& res_name,
+Value* GetValueForConfigAndProduct<Value>(ResourceTable* table, android::StringPiece res_name,
const ConfigDescription& config,
- const android::StringPiece& product) {
+ android::StringPiece product) {
std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
if (result) {
ResourceConfigValue* config_value = result.value().entry->FindValue(config, product);
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 7006964d6f88..83a0f3f3f652 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -37,24 +37,24 @@
namespace aapt {
namespace test {
-IDiagnostics* GetDiagnostics();
+android::IDiagnostics* GetDiagnostics();
-inline ResourceName ParseNameOrDie(const android::StringPiece& str) {
+inline ResourceName ParseNameOrDie(android::StringPiece str) {
ResourceNameRef ref;
CHECK(ResourceUtils::ParseResourceName(str, &ref)) << "invalid resource name: " << str;
return ref.ToResourceName();
}
-inline android::ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
- android::ConfigDescription config;
+inline android::ConfigDescription ParseConfigOrDie(android::StringPiece str) {
+ android::ConfigDescription config;
CHECK(android::ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str;
return config;
}
template <typename T = Value>
-T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name,
+T* GetValueForConfigAndProduct(ResourceTable* table, android::StringPiece res_name,
const android::ConfigDescription& config,
- const android::StringPiece& product) {
+ android::StringPiece product) {
std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
if (result) {
ResourceConfigValue* config_value = result.value().entry->FindValue(config, product);
@@ -66,25 +66,25 @@ T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece&
}
template <>
-Value* GetValueForConfigAndProduct<Value>(ResourceTable* table,
- const android::StringPiece& res_name,
+Value* GetValueForConfigAndProduct<Value>(ResourceTable* table, android::StringPiece res_name,
const android::ConfigDescription& config,
- const android::StringPiece& product);
+ android::StringPiece product);
template <typename T = Value>
-T* GetValueForConfig(ResourceTable* table, const android::StringPiece& res_name,
+T* GetValueForConfig(ResourceTable* table, android::StringPiece res_name,
const android::ConfigDescription& config) {
return GetValueForConfigAndProduct<T>(table, res_name, config, {});
}
template <typename T = Value>
-T* GetValue(ResourceTable* table, const android::StringPiece& res_name) {
+T* GetValue(ResourceTable* table, android::StringPiece res_name) {
return GetValueForConfig<T>(table, res_name, {});
}
class TestFile : public io::IFile {
public:
- explicit TestFile(const android::StringPiece& path) : source_(path) {}
+ explicit TestFile(android::StringPiece path) : source_(path) {
+ }
std::unique_ptr<io::IData> OpenAsData() override {
return {};
@@ -94,14 +94,14 @@ class TestFile : public io::IFile {
return OpenAsData();
}
- const Source& GetSource() const override {
+ const android::Source& GetSource() const override {
return source_;
}
private:
DISALLOW_COPY_AND_ASSIGN(TestFile);
- Source source_;
+ android::Source source_;
};
} // namespace test
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index e1b8dd5687ff..c5331fb87381 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -19,10 +19,10 @@
#include <list>
+#include "Diagnostics.h"
+#include "NameMangler.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
-
-#include "NameMangler.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
#include "test/Common.h"
@@ -43,7 +43,7 @@ class Context : public IAaptContext {
return &symbols_;
}
- IDiagnostics* GetDiagnostics() override {
+ android::IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -52,8 +52,8 @@ class Context : public IAaptContext {
return compilation_package_.value();
}
- void SetCompilationPackage(const android::StringPiece& package) {
- compilation_package_ = package.to_string();
+ void SetCompilationPackage(android::StringPiece package) {
+ compilation_package_ = std::string(package);
}
uint8_t GetPackageId() override {
@@ -111,8 +111,8 @@ class ContextBuilder {
return *this;
}
- ContextBuilder& SetCompilationPackage(const android::StringPiece& package) {
- context_->compilation_package_ = package.to_string();
+ ContextBuilder& SetCompilationPackage(android::StringPiece package) {
+ context_->compilation_package_ = std::string(package);
return *this;
}
@@ -149,7 +149,7 @@ class ContextBuilder {
class StaticSymbolSourceBuilder {
public:
- StaticSymbolSourceBuilder& AddPublicSymbol(const android::StringPiece& name, ResourceId id,
+ StaticSymbolSourceBuilder& AddPublicSymbol(android::StringPiece name, ResourceId id,
std::unique_ptr<Attribute> attr = {}) {
std::unique_ptr<SymbolTable::Symbol> symbol =
util::make_unique<SymbolTable::Symbol>(id, std::move(attr), true);
@@ -159,7 +159,7 @@ class StaticSymbolSourceBuilder {
return *this;
}
- StaticSymbolSourceBuilder& AddSymbol(const android::StringPiece& name, ResourceId id,
+ StaticSymbolSourceBuilder& AddSymbol(android::StringPiece name, ResourceId id,
std::unique_ptr<Attribute> attr = {}) {
std::unique_ptr<SymbolTable::Symbol> symbol =
util::make_unique<SymbolTable::Symbol>(id, std::move(attr), false);
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index ddc1853ca13c..428372f31d0d 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -16,16 +16,16 @@
#include "test/Fixture.h"
-#include <dirent.h>
-
#include <android-base/errors.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/utf8.h>
#include <androidfw/StringPiece.h>
+#include <dirent.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "Diagnostics.h"
#include "cmd/Compile.h"
#include "cmd/Link.h"
#include "io/FileStream.h"
@@ -38,11 +38,12 @@ namespace aapt {
const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
-void ClearDirectory(const android::StringPiece& path) {
- const std::string root_dir = path.to_string();
+void ClearDirectory(android::StringPiece path) {
+ const std::string root_dir(path);
std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
if (!dir) {
- StdErrDiagnostics().Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
+ StdErrDiagnostics().Error(android::DiagMessage()
+ << android::base::SystemErrorCodeToString(errno));
return;
}
@@ -90,38 +91,38 @@ void TestDirectoryFixture::WriteFile(const std::string& path, const std::string&
}
bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
- const android::StringPiece& out_dir, IDiagnostics* diag) {
+ android::StringPiece out_dir, android::IDiagnostics* diag) {
WriteFile(path, contents);
CHECK(file::mkdirs(out_dir.data()));
return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
}
-bool CommandTestFixture::Link(const std::vector<std::string>& args, IDiagnostics* diag) {
+bool CommandTestFixture::Link(const std::vector<std::string>& args, android::IDiagnostics* diag) {
std::vector<android::StringPiece> link_args;
for(const std::string& arg : args) {
link_args.emplace_back(arg);
}
// Link against the android SDK
- std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
- "integration-tests", "CommandTests",
- "android-28.jar"});
+ std::string android_sdk =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests",
+ "android-33.jar"});
link_args.insert(link_args.end(), {"-I", android_sdk});
return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
}
-bool CommandTestFixture::Link(const std::vector<std::string>& args,
- const android::StringPiece& flat_dir, IDiagnostics* diag) {
+bool CommandTestFixture::Link(const std::vector<std::string>& args, android::StringPiece flat_dir,
+ android::IDiagnostics* diag) {
std::vector<android::StringPiece> link_args;
for(const std::string& arg : args) {
link_args.emplace_back(arg);
}
// Link against the android SDK
- std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
- "integration-tests", "CommandTests",
- "android-28.jar"});
+ std::string android_sdk =
+ file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests",
+ "android-33.jar"});
link_args.insert(link_args.end(), {"-I", android_sdk});
// Add the files from the compiled resources directory to the link file arguments
@@ -146,7 +147,7 @@ std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
}
std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk,
- const android::StringPiece& path) {
+ android::StringPiece path) {
return apk
->GetFileCollection()
->FindFile(path)
@@ -210,7 +211,7 @@ LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) {
}
LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir,
- IDiagnostics* diag) {
+ android::IDiagnostics* diag) {
if (auto files = file::FindFiles(dir, diag)) {
for (std::string& compile_file : files.value()) {
args_.emplace_back(file::BuildPath({dir, compile_file}));
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index f8c4889aee3b..ba4a734e03bb 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -48,7 +48,7 @@ class TestDirectoryFixture : public ::testing::Test {
// Retrieves the absolute path of the specified relative path in the test directory. Directories
// should be separated using forward slashes ('/'), and these slashes will be translated to
// backslashes when running Windows tests.
- std::string GetTestPath(const android::StringPiece& path) {
+ std::string GetTestPath(android::StringPiece path) {
std::string base = temp_dir_;
for (android::StringPiece part : util::Split(path, '/')) {
file::AppendPath(&base, part);
@@ -73,22 +73,21 @@ class CommandTestFixture : public TestDirectoryFixture {
// Wries the contents of the file to the specified path. The file is compiled and the flattened
// file is written to the out directory.
bool CompileFile(const std::string& path, const std::string& contents,
- const android::StringPiece& flat_out_dir, IDiagnostics* diag);
+ android::StringPiece flat_out_dir, android::IDiagnostics* diag);
// Executes the link command with the specified arguments.
- bool Link(const std::vector<std::string>& args, IDiagnostics* diag);
+ bool Link(const std::vector<std::string>& args, android::IDiagnostics* diag);
// Executes the link command with the specified arguments. The flattened files residing in the
// flat directory will be added to the link command as file arguments.
- bool Link(const std::vector<std::string>& args, const android::StringPiece& flat_dir,
- IDiagnostics* diag);
+ bool Link(const std::vector<std::string>& args, android::StringPiece flat_dir,
+ android::IDiagnostics* diag);
// Creates a minimal android manifest within the test directory and returns the file path.
std::string GetDefaultManifest(const char* package_name = kDefaultPackageName);
// Returns pointer to data inside APK files
- std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk,
- const android::StringPiece& path);
+ std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk, android::StringPiece path);
// Asserts that loading the tree from the specified file in the apk succeeds.
void AssertLoadXml(LoadedApk* apk, const io::IData* data,
@@ -114,7 +113,7 @@ struct ManifestBuilder {
struct LinkCommandBuilder {
explicit LinkCommandBuilder(CommandTestFixture* fixture);
- LinkCommandBuilder& AddCompiledResDir(const std::string& dir, IDiagnostics* diag);
+ LinkCommandBuilder& AddCompiledResDir(const std::string& dir, android::IDiagnostics* diag);
LinkCommandBuilder& AddFlag(const std::string& flag);
LinkCommandBuilder& AddParameter(const std::string& param, const std::string& value);
LinkCommandBuilder& SetManifestFile(const std::string& manifest_path);
diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp
index 243800c9385f..8e491aca794d 100644
--- a/tools/aapt2/text/Printer.cpp
+++ b/tools/aapt2/text/Printer.cpp
@@ -26,7 +26,7 @@ using ::android::StringPiece;
namespace aapt {
namespace text {
-Printer& Printer::Println(const StringPiece& str) {
+Printer& Printer::Println(StringPiece str) {
Print(str);
return Print("\n");
}
@@ -35,7 +35,7 @@ Printer& Printer::Println() {
return Print("\n");
}
-Printer& Printer::Print(const StringPiece& str) {
+Printer& Printer::Print(StringPiece str) {
if (error_) {
return *this;
}
@@ -47,7 +47,7 @@ Printer& Printer::Print(const StringPiece& str) {
const auto new_line_iter = std::find(remaining_str_begin, remaining_str_end, '\n');
// We will copy the string up until the next new-line (or end of string).
- const StringPiece str_to_copy = str.substr(remaining_str_begin, new_line_iter);
+ const StringPiece str_to_copy(remaining_str_begin, new_line_iter - remaining_str_begin);
if (!str_to_copy.empty()) {
if (needs_indent_) {
for (int i = 0; i < indent_level_; i++) {
diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h
index f399f8ea5e0f..f7ad98bfd981 100644
--- a/tools/aapt2/text/Printer.h
+++ b/tools/aapt2/text/Printer.h
@@ -31,8 +31,8 @@ class Printer {
explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
}
- Printer& Print(const ::android::StringPiece& str);
- Printer& Println(const ::android::StringPiece& str);
+ Printer& Print(android::StringPiece str);
+ Printer& Println(android::StringPiece str);
Printer& Println();
void Indent();
diff --git a/tools/aapt2/text/Unicode.cpp b/tools/aapt2/text/Unicode.cpp
index 3735b3e841e0..5e25be3e2812 100644
--- a/tools/aapt2/text/Unicode.cpp
+++ b/tools/aapt2/text/Unicode.cpp
@@ -77,7 +77,7 @@ bool IsWhitespace(char32_t codepoint) {
(codepoint == 0x3000);
}
-bool IsJavaIdentifier(const StringPiece& str) {
+bool IsJavaIdentifier(StringPiece str) {
Utf8Iterator iter(str);
// Check the first character.
@@ -99,7 +99,7 @@ bool IsJavaIdentifier(const StringPiece& str) {
return true;
}
-bool IsValidResourceEntryName(const StringPiece& str) {
+bool IsValidResourceEntryName(StringPiece str) {
Utf8Iterator iter(str);
// Check the first character.
diff --git a/tools/aapt2/text/Unicode.h b/tools/aapt2/text/Unicode.h
index 546714e9a290..ab3e82b00f08 100644
--- a/tools/aapt2/text/Unicode.h
+++ b/tools/aapt2/text/Unicode.h
@@ -46,11 +46,11 @@ bool IsWhitespace(char32_t codepoint);
// Returns true if the UTF8 string can be used as a Java identifier.
// NOTE: This does not check against the set of reserved Java keywords.
-bool IsJavaIdentifier(const android::StringPiece& str);
+bool IsJavaIdentifier(android::StringPiece str);
// Returns true if the UTF8 string can be used as the entry name of a resource name.
// This is the `entry` part of package:type/entry.
-bool IsValidResourceEntryName(const android::StringPiece& str);
+bool IsValidResourceEntryName(android::StringPiece str);
} // namespace text
} // namespace aapt
diff --git a/tools/aapt2/text/Utf8Iterator.cpp b/tools/aapt2/text/Utf8Iterator.cpp
index 20b9073b9a26..0bd8a375a255 100644
--- a/tools/aapt2/text/Utf8Iterator.cpp
+++ b/tools/aapt2/text/Utf8Iterator.cpp
@@ -24,7 +24,7 @@ using ::android::StringPiece;
namespace aapt {
namespace text {
-Utf8Iterator::Utf8Iterator(const StringPiece& str)
+Utf8Iterator::Utf8Iterator(StringPiece str)
: str_(str), current_pos_(0), next_pos_(0), current_codepoint_(0) {
DoNext();
}
diff --git a/tools/aapt2/text/Utf8Iterator.h b/tools/aapt2/text/Utf8Iterator.h
index 9318401876d1..2bba1984a8ce 100644
--- a/tools/aapt2/text/Utf8Iterator.h
+++ b/tools/aapt2/text/Utf8Iterator.h
@@ -25,7 +25,7 @@ namespace text {
class Utf8Iterator {
public:
- explicit Utf8Iterator(const android::StringPiece& str);
+ explicit Utf8Iterator(android::StringPiece str);
bool HasNext() const;
diff --git a/tools/aapt2/trace/TraceBuffer.cpp b/tools/aapt2/trace/TraceBuffer.cpp
index b4b31d9daf6e..da5373936306 100644
--- a/tools/aapt2/trace/TraceBuffer.cpp
+++ b/tools/aapt2/trace/TraceBuffer.cpp
@@ -103,7 +103,7 @@ Trace::Trace(const std::string& tag, const std::vector<android::StringPiece>& ar
s << tag;
s << " ";
for (auto& arg : args) {
- s << arg.to_string();
+ s << arg;
s << " ";
}
tracebuffer::Add(s.str(), tracebuffer::kBegin);
@@ -124,7 +124,7 @@ FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag,
s << tag;
s << " ";
for (auto& arg : args) {
- s << arg.to_string();
+ s << arg;
s << " ";
}
tracebuffer::Add(s.str(), tracebuffer::kBegin);
diff --git a/tools/aapt2/util/BigBuffer.cpp b/tools/aapt2/util/BigBuffer.cpp
deleted file mode 100644
index 75fa78915b65..000000000000
--- a/tools/aapt2/util/BigBuffer.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/BigBuffer.h"
-
-#include <algorithm>
-#include <memory>
-#include <vector>
-
-#include "android-base/logging.h"
-
-namespace aapt {
-
-void* BigBuffer::NextBlockImpl(size_t size) {
- if (!blocks_.empty()) {
- Block& block = blocks_.back();
- if (block.block_size_ - block.size >= size) {
- void* out_buffer = block.buffer.get() + block.size;
- block.size += size;
- size_ += size;
- return out_buffer;
- }
- }
-
- const size_t actual_size = std::max(block_size_, size);
-
- Block block = {};
-
- // Zero-allocate the block's buffer.
- block.buffer = std::unique_ptr<uint8_t[]>(new uint8_t[actual_size]());
- CHECK(block.buffer);
-
- block.size = size;
- block.block_size_ = actual_size;
-
- blocks_.push_back(std::move(block));
- size_ += size;
- return blocks_.back().buffer.get();
-}
-
-void* BigBuffer::NextBlock(size_t* out_size) {
- if (!blocks_.empty()) {
- Block& block = blocks_.back();
- if (block.size != block.block_size_) {
- void* out_buffer = block.buffer.get() + block.size;
- size_t size = block.block_size_ - block.size;
- block.size = block.block_size_;
- size_ += size;
- *out_size = size;
- return out_buffer;
- }
- }
-
- // Zero-allocate the block's buffer.
- Block block = {};
- block.buffer = std::unique_ptr<uint8_t[]>(new uint8_t[block_size_]());
- CHECK(block.buffer);
- block.size = block_size_;
- block.block_size_ = block_size_;
- blocks_.push_back(std::move(block));
- size_ += block_size_;
- *out_size = block_size_;
- return blocks_.back().buffer.get();
-}
-
-std::string BigBuffer::to_string() const {
- std::string result;
- for (const Block& block : blocks_) {
- result.append(block.buffer.get(), block.buffer.get() + block.size);
- }
- return result;
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/util/BigBuffer.h b/tools/aapt2/util/BigBuffer.h
deleted file mode 100644
index d4b3abce68a7..000000000000
--- a/tools/aapt2/util/BigBuffer.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_BIG_BUFFER_H
-#define AAPT_BIG_BUFFER_H
-
-#include <cstring>
-#include <memory>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include "android-base/logging.h"
-#include "android-base/macros.h"
-
-namespace aapt {
-
-/**
- * Inspired by protobuf's ZeroCopyOutputStream, offers blocks of memory
- * in which to write without knowing the full size of the entire payload.
- * This is essentially a list of memory blocks. As one fills up, another
- * block is allocated and appended to the end of the list.
- */
-class BigBuffer {
- public:
- /**
- * A contiguous block of allocated memory.
- */
- struct Block {
- /**
- * Pointer to the memory.
- */
- std::unique_ptr<uint8_t[]> buffer;
-
- /**
- * Size of memory that is currently occupied. The actual
- * allocation may be larger.
- */
- size_t size;
-
- private:
- friend class BigBuffer;
-
- /**
- * The size of the memory block allocation.
- */
- size_t block_size_;
- };
-
- typedef std::vector<Block>::const_iterator const_iterator;
-
- /**
- * Create a BigBuffer with block allocation sizes
- * of block_size.
- */
- explicit BigBuffer(size_t block_size);
-
- BigBuffer(BigBuffer&& rhs) noexcept;
-
- /**
- * Number of occupied bytes in all the allocated blocks.
- */
- size_t size() const;
-
- /**
- * Returns a pointer to an array of T, where T is
- * a POD type. The elements are zero-initialized.
- */
- template <typename T>
- T* NextBlock(size_t count = 1);
-
- /**
- * Returns the next block available and puts the size in out_count.
- * This is useful for grabbing blocks where the size doesn't matter.
- * Use BackUp() to give back any bytes that were not used.
- */
- void* NextBlock(size_t* out_count);
-
- /**
- * Backs up count bytes. This must only be called after NextBlock()
- * and can not be larger than sizeof(T) * count of the last NextBlock()
- * call.
- */
- void BackUp(size_t count);
-
- /**
- * Moves the specified BigBuffer into this one. When this method
- * returns, buffer is empty.
- */
- void AppendBuffer(BigBuffer&& buffer);
-
- /**
- * Pads the block with 'bytes' bytes of zero values.
- */
- void Pad(size_t bytes);
-
- /**
- * Pads the block so that it aligns on a 4 byte boundary.
- */
- void Align4();
-
- size_t block_size() const;
-
- const_iterator begin() const;
- const_iterator end() const;
-
- std::string to_string() const;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BigBuffer);
-
- /**
- * Returns a pointer to a buffer of the requested size.
- * The buffer is zero-initialized.
- */
- void* NextBlockImpl(size_t size);
-
- size_t block_size_;
- size_t size_;
- std::vector<Block> blocks_;
-};
-
-inline BigBuffer::BigBuffer(size_t block_size)
- : block_size_(block_size), size_(0) {}
-
-inline BigBuffer::BigBuffer(BigBuffer&& rhs) noexcept
- : block_size_(rhs.block_size_),
- size_(rhs.size_),
- blocks_(std::move(rhs.blocks_)) {}
-
-inline size_t BigBuffer::size() const { return size_; }
-
-inline size_t BigBuffer::block_size() const { return block_size_; }
-
-template <typename T>
-inline T* BigBuffer::NextBlock(size_t count) {
- static_assert(std::is_standard_layout<T>::value,
- "T must be standard_layout type");
- CHECK(count != 0);
- return reinterpret_cast<T*>(NextBlockImpl(sizeof(T) * count));
-}
-
-inline void BigBuffer::BackUp(size_t count) {
- Block& block = blocks_.back();
- block.size -= count;
- size_ -= count;
-}
-
-inline void BigBuffer::AppendBuffer(BigBuffer&& buffer) {
- std::move(buffer.blocks_.begin(), buffer.blocks_.end(),
- std::back_inserter(blocks_));
- size_ += buffer.size_;
- buffer.blocks_.clear();
- buffer.size_ = 0;
-}
-
-inline void BigBuffer::Pad(size_t bytes) { NextBlock<char>(bytes); }
-
-inline void BigBuffer::Align4() {
- const size_t unaligned = size_ % 4;
- if (unaligned != 0) {
- Pad(4 - unaligned);
- }
-}
-
-inline BigBuffer::const_iterator BigBuffer::begin() const {
- return blocks_.begin();
-}
-
-inline BigBuffer::const_iterator BigBuffer::end() const {
- return blocks_.end();
-}
-
-} // namespace aapt
-
-#endif // AAPT_BIG_BUFFER_H
diff --git a/tools/aapt2/util/BigBuffer_test.cpp b/tools/aapt2/util/BigBuffer_test.cpp
deleted file mode 100644
index 64dcc1dad9a2..000000000000
--- a/tools/aapt2/util/BigBuffer_test.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/BigBuffer.h"
-
-#include "test/Test.h"
-
-using ::testing::NotNull;
-
-namespace aapt {
-
-TEST(BigBufferTest, AllocateSingleBlock) {
- BigBuffer buffer(4);
-
- EXPECT_THAT(buffer.NextBlock<char>(2), NotNull());
- EXPECT_EQ(2u, buffer.size());
-}
-
-TEST(BigBufferTest, ReturnSameBlockIfNextAllocationFits) {
- BigBuffer buffer(16);
-
- char* b1 = buffer.NextBlock<char>(8);
- EXPECT_THAT(b1, NotNull());
-
- char* b2 = buffer.NextBlock<char>(4);
- EXPECT_THAT(b2, NotNull());
-
- EXPECT_EQ(b1 + 8, b2);
-}
-
-TEST(BigBufferTest, AllocateExactSizeBlockIfLargerThanBlockSize) {
- BigBuffer buffer(16);
-
- EXPECT_THAT(buffer.NextBlock<char>(32), NotNull());
- EXPECT_EQ(32u, buffer.size());
-}
-
-TEST(BigBufferTest, AppendAndMoveBlock) {
- BigBuffer buffer(16);
-
- uint32_t* b1 = buffer.NextBlock<uint32_t>();
- ASSERT_THAT(b1, NotNull());
- *b1 = 33;
-
- {
- BigBuffer buffer2(16);
- b1 = buffer2.NextBlock<uint32_t>();
- ASSERT_THAT(b1, NotNull());
- *b1 = 44;
-
- buffer.AppendBuffer(std::move(buffer2));
- EXPECT_EQ(0u, buffer2.size()); // NOLINT
- EXPECT_EQ(buffer2.begin(), buffer2.end());
- }
-
- EXPECT_EQ(2 * sizeof(uint32_t), buffer.size());
-
- auto b = buffer.begin();
- ASSERT_NE(b, buffer.end());
- ASSERT_EQ(sizeof(uint32_t), b->size);
- ASSERT_EQ(33u, *reinterpret_cast<uint32_t*>(b->buffer.get()));
- ++b;
-
- ASSERT_NE(b, buffer.end());
- ASSERT_EQ(sizeof(uint32_t), b->size);
- ASSERT_EQ(44u, *reinterpret_cast<uint32_t*>(b->buffer.get()));
- ++b;
-
- ASSERT_EQ(b, buffer.end());
-}
-
-TEST(BigBufferTest, PadAndAlignProperly) {
- BigBuffer buffer(16);
-
- ASSERT_THAT(buffer.NextBlock<char>(2), NotNull());
- ASSERT_EQ(2u, buffer.size());
- buffer.Pad(2);
- ASSERT_EQ(4u, buffer.size());
- buffer.Align4();
- ASSERT_EQ(4u, buffer.size());
- buffer.Pad(2);
- ASSERT_EQ(6u, buffer.size());
- buffer.Align4();
- ASSERT_EQ(8u, buffer.size());
-}
-
-} // namespace aapt
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 3285d8bafa4d..93c1b61f9a57 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -139,7 +139,7 @@ bool mkdirs(const std::string& path) {
return ::android::base::utf8::mkdir(path.c_str(), mode) == 0 || errno == EEXIST;
}
-StringPiece GetStem(const StringPiece& path) {
+StringPiece GetStem(StringPiece path) {
const char* start = path.begin();
const char* end = path.end();
for (const char* current = end - 1; current != start - 1; --current) {
@@ -150,7 +150,7 @@ StringPiece GetStem(const StringPiece& path) {
return {};
}
-StringPiece GetFilename(const StringPiece& path) {
+StringPiece GetFilename(StringPiece path) {
const char* end = path.end();
const char* last_dir_sep = path.begin();
for (const char* c = path.begin(); c != end; ++c) {
@@ -161,7 +161,7 @@ StringPiece GetFilename(const StringPiece& path) {
return StringPiece(last_dir_sep, end - last_dir_sep);
}
-StringPiece GetExtension(const StringPiece& path) {
+StringPiece GetExtension(StringPiece path) {
StringPiece filename = GetFilename(path);
const char* const end = filename.end();
const char* c = std::find(filename.begin(), end, '.');
@@ -171,7 +171,7 @@ StringPiece GetExtension(const StringPiece& path) {
return {};
}
-bool IsHidden(const android::StringPiece& path) {
+bool IsHidden(android::StringPiece path) {
return util::StartsWith(GetFilename(path), ".");
}
@@ -193,16 +193,16 @@ std::string BuildPath(std::vector<const StringPiece>&& args) {
if (args.empty()) {
return "";
}
- std::string out = args[0].to_string();
+ std::string out{args[0]};
for (int i = 1; i < args.size(); i++) {
file::AppendPath(&out, args[i]);
}
return out;
}
-std::string PackageToPath(const StringPiece& package) {
+std::string PackageToPath(StringPiece package) {
std::string out_path;
- for (const StringPiece& part : util::Tokenize(package, '.')) {
+ for (StringPiece part : util::Tokenize(package, '.')) {
AppendPath(&out_path, part);
}
return out_path;
@@ -241,10 +241,10 @@ std::optional<FileMap> MmapPath(const std::string& path, std::string* out_error)
return std::move(filemap);
}
-bool AppendArgsFromFile(const StringPiece& path, std::vector<std::string>* out_arglist,
+bool AppendArgsFromFile(StringPiece path, std::vector<std::string>* out_arglist,
std::string* out_error) {
std::string contents;
- if (!ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) {
+ if (!ReadFileToString(std::string(path), &contents, true /*follow_symlinks*/)) {
if (out_error) {
*out_error = "failed to read argument-list file";
}
@@ -254,16 +254,16 @@ bool AppendArgsFromFile(const StringPiece& path, std::vector<std::string>* out_a
for (StringPiece line : util::Tokenize(contents, ' ')) {
line = util::TrimWhitespace(line);
if (!line.empty()) {
- out_arglist->push_back(line.to_string());
+ out_arglist->emplace_back(line);
}
}
return true;
}
-bool AppendSetArgsFromFile(const StringPiece& path, std::unordered_set<std::string>* out_argset,
+bool AppendSetArgsFromFile(StringPiece path, std::unordered_set<std::string>* out_argset,
std::string* out_error) {
std::string contents;
- if(!ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) {
+ if (!ReadFileToString(std::string(path), &contents, true /*follow_symlinks*/)) {
if (out_error) {
*out_error = "failed to read argument-list file";
}
@@ -273,13 +273,13 @@ bool AppendSetArgsFromFile(const StringPiece& path, std::unordered_set<std::stri
for (StringPiece line : util::Tokenize(contents, ' ')) {
line = util::TrimWhitespace(line);
if (!line.empty()) {
- out_argset->insert(line.to_string());
+ out_argset->emplace(line);
}
}
return true;
}
-bool FileFilter::SetPattern(const StringPiece& pattern) {
+bool FileFilter::SetPattern(StringPiece pattern) {
pattern_tokens_ = util::SplitAndLowercase(pattern, ':');
return true;
}
@@ -333,9 +333,8 @@ bool FileFilter::operator()(const std::string& filename, FileType type) const {
if (ignore) {
if (chatty) {
- diag_->Warn(DiagMessage()
- << "skipping "
- << (type == FileType::kDirectory ? "dir '" : "file '")
+ diag_->Warn(android::DiagMessage()
+ << "skipping " << (type == FileType::kDirectory ? "dir '" : "file '")
<< filename << "' due to ignore pattern '" << token << "'");
}
return false;
@@ -344,12 +343,13 @@ bool FileFilter::operator()(const std::string& filename, FileType type) const {
return true;
}
-std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
- IDiagnostics* diag, const FileFilter* filter) {
- const std::string root_dir = path.to_string();
+std::optional<std::vector<std::string>> FindFiles(android::StringPiece path,
+ android::IDiagnostics* diag,
+ const FileFilter* filter) {
+ const auto& root_dir = path;
std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
if (!d) {
- diag->Error(DiagMessage() << SystemErrorCodeToString(errno) << ": " << root_dir);
+ diag->Error(android::DiagMessage() << SystemErrorCodeToString(errno) << ": " << root_dir);
return {};
}
@@ -361,7 +361,7 @@ std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& pa
}
std::string file_name = entry->d_name;
- std::string full_path = root_dir;
+ std::string full_path{root_dir};
AppendPath(&full_path, file_name);
const FileType file_type = GetFileType(full_path);
@@ -380,7 +380,7 @@ std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& pa
// Now process subdirs.
for (const std::string& subdir : subdirs) {
- std::string full_subdir = root_dir;
+ std::string full_subdir{root_dir};
AppendPath(&full_subdir, subdir);
std::optional<std::vector<std::string>> subfiles = FindFiles(full_subdir, diag, filter);
if (!subfiles) {
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index a2b1b58e5d4f..42eeaf2d2e2a 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -24,12 +24,11 @@
#include <vector>
#include "android-base/macros.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/Source.h"
#include "androidfw/StringPiece.h"
#include "utils/FileMap.h"
-#include "Diagnostics.h"
-#include "Source.h"
-
namespace aapt {
namespace file {
@@ -67,38 +66,39 @@ std::string BuildPath(std::vector<const android::StringPiece>&& args);
bool mkdirs(const std::string& path);
// Returns all but the last part of the path.
-android::StringPiece GetStem(const android::StringPiece& path);
+android::StringPiece GetStem(android::StringPiece path);
// Returns the last part of the path with extension.
-android::StringPiece GetFilename(const android::StringPiece& path);
+android::StringPiece GetFilename(android::StringPiece path);
// Returns the extension of the path. This is the entire string after the first '.' of the last part
// of the path.
-android::StringPiece GetExtension(const android::StringPiece& path);
+android::StringPiece GetExtension(android::StringPiece path);
// Returns whether or not the name of the file or directory is a hidden file name
-bool IsHidden(const android::StringPiece& path);
+bool IsHidden(android::StringPiece path);
// Converts a package name (com.android.app) to a path: com/android/app
-std::string PackageToPath(const android::StringPiece& package);
+std::string PackageToPath(android::StringPiece package);
// Creates a FileMap for the file at path.
std::optional<android::FileMap> MmapPath(const std::string& path, std::string* out_error);
// Reads the file at path and appends each line to the outArgList vector.
-bool AppendArgsFromFile(const android::StringPiece& path, std::vector<std::string>* out_arglist,
+bool AppendArgsFromFile(android::StringPiece path, std::vector<std::string>* out_arglist,
std::string* out_error);
// Reads the file at path and appends each line to the outargset set.
-bool AppendSetArgsFromFile(const android::StringPiece& path,
- std::unordered_set<std::string>* out_argset, std::string* out_error);
+bool AppendSetArgsFromFile(android::StringPiece path, std::unordered_set<std::string>* out_argset,
+ std::string* out_error);
// Filter that determines which resource files/directories are
// processed by AAPT. Takes a pattern string supplied by the user.
// Pattern format is specified in the FileFilter::SetPattern() method.
class FileFilter {
public:
- explicit FileFilter(IDiagnostics* diag) : diag_(diag) {}
+ explicit FileFilter(android::IDiagnostics* diag) : diag_(diag) {
+ }
// Patterns syntax:
// - Delimiter is :
@@ -112,7 +112,7 @@ class FileFilter {
// - The special filenames "." and ".." are always ignored.
// - Otherwise the full string is matched.
// - match is not case-sensitive.
- bool SetPattern(const android::StringPiece& pattern);
+ bool SetPattern(android::StringPiece pattern);
// Applies the filter, returning true for pass, false for fail.
bool operator()(const std::string& filename, FileType type) const;
@@ -120,14 +120,14 @@ class FileFilter {
private:
DISALLOW_COPY_AND_ASSIGN(FileFilter);
- IDiagnostics* diag_;
+ android::IDiagnostics* diag_;
std::vector<std::string> pattern_tokens_;
};
// Returns a list of files relative to the directory identified by `path`.
// An optional FileFilter filters out any files that don't pass.
-std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
- IDiagnostics* diag,
+std::optional<std::vector<std::string>> FindFiles(android::StringPiece path,
+ android::IDiagnostics* diag,
const FileFilter* filter = nullptr);
} // namespace file
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index efbbf8ebe013..be877660ef72 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -23,11 +23,12 @@
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
+#include "androidfw/BigBuffer.h"
#include "androidfw/StringPiece.h"
+#include "androidfw/Util.h"
#include "build/version.h"
#include "text/Unicode.h"
#include "text/Utf8Iterator.h"
-#include "util/BigBuffer.h"
#include "utils/Unicode.h"
using ::aapt::text::Utf8Iterator;
@@ -42,15 +43,14 @@ namespace util {
// See frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
constexpr static const size_t kMaxPackageNameSize = 223;
-static std::vector<std::string> SplitAndTransform(
- const StringPiece& str, char sep, const std::function<char(char)>& f) {
+static std::vector<std::string> SplitAndTransform(StringPiece str, char sep, char (*f)(char)) {
std::vector<std::string> parts;
const StringPiece::const_iterator end = std::end(str);
StringPiece::const_iterator start = std::begin(str);
StringPiece::const_iterator current;
do {
current = std::find(start, end, sep);
- parts.emplace_back(str.substr(start, current).to_string());
+ parts.emplace_back(start, current);
if (f) {
std::string& part = parts.back();
std::transform(part.begin(), part.end(), part.begin(), f);
@@ -60,29 +60,29 @@ static std::vector<std::string> SplitAndTransform(
return parts;
}
-std::vector<std::string> Split(const StringPiece& str, char sep) {
+std::vector<std::string> Split(StringPiece str, char sep) {
return SplitAndTransform(str, sep, nullptr);
}
-std::vector<std::string> SplitAndLowercase(const StringPiece& str, char sep) {
- return SplitAndTransform(str, sep, ::tolower);
+std::vector<std::string> SplitAndLowercase(StringPiece str, char sep) {
+ return SplitAndTransform(str, sep, [](char c) -> char { return ::tolower(c); });
}
-bool StartsWith(const StringPiece& str, const StringPiece& prefix) {
+bool StartsWith(StringPiece str, StringPiece prefix) {
if (str.size() < prefix.size()) {
return false;
}
return str.substr(0, prefix.size()) == prefix;
}
-bool EndsWith(const StringPiece& str, const StringPiece& suffix) {
+bool EndsWith(StringPiece str, StringPiece suffix) {
if (str.size() < suffix.size()) {
return false;
}
return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
}
-StringPiece TrimLeadingWhitespace(const StringPiece& str) {
+StringPiece TrimLeadingWhitespace(StringPiece str) {
if (str.size() == 0 || str.data() == nullptr) {
return str;
}
@@ -96,7 +96,7 @@ StringPiece TrimLeadingWhitespace(const StringPiece& str) {
return StringPiece(start, end - start);
}
-StringPiece TrimTrailingWhitespace(const StringPiece& str) {
+StringPiece TrimTrailingWhitespace(StringPiece str) {
if (str.size() == 0 || str.data() == nullptr) {
return str;
}
@@ -110,7 +110,7 @@ StringPiece TrimTrailingWhitespace(const StringPiece& str) {
return StringPiece(start, end - start);
}
-StringPiece TrimWhitespace(const StringPiece& str) {
+StringPiece TrimWhitespace(StringPiece str) {
if (str.size() == 0 || str.data() == nullptr) {
return str;
}
@@ -129,9 +129,9 @@ StringPiece TrimWhitespace(const StringPiece& str) {
return StringPiece(start, end - start);
}
-static int IsJavaNameImpl(const StringPiece& str) {
+static int IsJavaNameImpl(StringPiece str) {
int pieces = 0;
- for (const StringPiece& piece : Tokenize(str, '.')) {
+ for (StringPiece piece : Tokenize(str, '.')) {
pieces++;
if (!text::IsJavaIdentifier(piece)) {
return -1;
@@ -140,17 +140,17 @@ static int IsJavaNameImpl(const StringPiece& str) {
return pieces;
}
-bool IsJavaClassName(const StringPiece& str) {
+bool IsJavaClassName(StringPiece str) {
return IsJavaNameImpl(str) >= 2;
}
-bool IsJavaPackageName(const StringPiece& str) {
+bool IsJavaPackageName(StringPiece str) {
return IsJavaNameImpl(str) >= 1;
}
-static int IsAndroidNameImpl(const StringPiece& str) {
+static int IsAndroidNameImpl(StringPiece str) {
int pieces = 0;
- for (const StringPiece& piece : Tokenize(str, '.')) {
+ for (StringPiece piece : Tokenize(str, '.')) {
if (piece.empty()) {
return -1;
}
@@ -172,15 +172,14 @@ static int IsAndroidNameImpl(const StringPiece& str) {
return pieces;
}
-bool IsAndroidPackageName(const StringPiece& str) {
+bool IsAndroidPackageName(StringPiece str) {
if (str.size() > kMaxPackageNameSize) {
return false;
}
return IsAndroidNameImpl(str) > 1 || str == "android";
}
-bool IsAndroidSharedUserId(const android::StringPiece& package_name,
- const android::StringPiece& shared_user_id) {
+bool IsAndroidSharedUserId(android::StringPiece package_name, android::StringPiece shared_user_id) {
if (shared_user_id.size() > kMaxPackageNameSize) {
return false;
}
@@ -188,25 +187,24 @@ bool IsAndroidSharedUserId(const android::StringPiece& package_name,
package_name == "android";
}
-bool IsAndroidSplitName(const StringPiece& str) {
+bool IsAndroidSplitName(StringPiece str) {
return IsAndroidNameImpl(str) > 0;
}
-std::optional<std::string> GetFullyQualifiedClassName(const StringPiece& package,
- const StringPiece& classname) {
+std::optional<std::string> GetFullyQualifiedClassName(StringPiece package, StringPiece classname) {
if (classname.empty()) {
return {};
}
if (util::IsJavaClassName(classname)) {
- return classname.to_string();
+ return std::string(classname);
}
if (package.empty()) {
return {};
}
- std::string result = package.to_string();
+ std::string result{package};
if (classname.data()[0] != '.') {
result += '.';
}
@@ -250,7 +248,7 @@ static size_t ConsumeDigits(const char* start, const char* end) {
return static_cast<size_t>(c - start);
}
-bool VerifyJavaStringFormat(const StringPiece& str) {
+bool VerifyJavaStringFormat(StringPiece str) {
const char* c = str.begin();
const char* const end = str.end();
@@ -340,108 +338,7 @@ bool VerifyJavaStringFormat(const StringPiece& str) {
return true;
}
-std::string Utf8ToModifiedUtf8(const std::string& utf8) {
- // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode
- // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format
- // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8
- // codepoints replaced with 2 3 byte surrogate pairs
- size_t modified_size = 0;
- const size_t size = utf8.size();
- for (size_t i = 0; i < size; i++) {
- if (((uint8_t) utf8[i] >> 4) == 0xF) {
- modified_size += 6;
- i += 3;
- } else {
- modified_size++;
- }
- }
-
- // Early out if no 4 byte codepoints are found
- if (size == modified_size) {
- return utf8;
- }
-
- std::string output;
- output.reserve(modified_size);
- for (size_t i = 0; i < size; i++) {
- if (((uint8_t) utf8[i] >> 4) == 0xF) {
- int32_t codepoint = utf32_from_utf8_at(utf8.data(), size, i, nullptr);
-
- // Calculate the high and low surrogates as UTF-16 would
- int32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
- int32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
-
- // Encode each surrogate in UTF-8
- output.push_back((char) (0xE4 | ((high >> 12) & 0xF)));
- output.push_back((char) (0x80 | ((high >> 6) & 0x3F)));
- output.push_back((char) (0x80 | (high & 0x3F)));
- output.push_back((char) (0xE4 | ((low >> 12) & 0xF)));
- output.push_back((char) (0x80 | ((low >> 6) & 0x3F)));
- output.push_back((char) (0x80 | (low & 0x3F)));
- i += 3;
- } else {
- output.push_back(utf8[i]);
- }
- }
-
- return output;
-}
-
-std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) {
- // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8
- // representation.
- std::string output;
- output.reserve(modified_utf8.size());
-
- size_t index = 0;
- const size_t modified_size = modified_utf8.size();
- while (index < modified_size) {
- size_t next_index;
- int32_t high_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, index,
- &next_index);
- if (high_surrogate < 0) {
- return {};
- }
-
- // Check that the first codepoint is within the high surrogate range
- if (high_surrogate >= 0xD800 && high_surrogate <= 0xDB7F) {
- int32_t low_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, next_index,
- &next_index);
- if (low_surrogate < 0) {
- return {};
- }
-
- // Check that the second codepoint is within the low surrogate range
- if (low_surrogate >= 0xDC00 && low_surrogate <= 0xDFFF) {
- const char32_t codepoint = (char32_t) (((high_surrogate - 0xD800) * 0x400)
- + (low_surrogate - 0xDC00) + 0x10000);
-
- // The decoded codepoint should represent a 4 byte, UTF-8 character
- const size_t utf8_length = (size_t) utf32_to_utf8_length(&codepoint, 1);
- if (utf8_length != 4) {
- return {};
- }
-
- // Encode the UTF-8 representation of the codepoint into the string
- char* start = &output[output.size()];
- output.resize(output.size() + utf8_length);
- utf32_to_utf8((char32_t*) &codepoint, 1, start, utf8_length + 1);
-
- index = next_index;
- continue;
- }
- }
-
- // Append non-surrogate pairs to the output string
- for (size_t i = index; i < next_index; i++) {
- output.push_back(modified_utf8[i]);
- }
- index = next_index;
- }
- return output;
-}
-
-std::u16string Utf8ToUtf16(const StringPiece& utf8) {
+std::u16string Utf8ToUtf16(StringPiece utf8) {
ssize_t utf16_length = utf8_to_utf16_length(
reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
if (utf16_length <= 0) {
@@ -467,7 +364,7 @@ std::string Utf16ToUtf8(const StringPiece16& utf16) {
return utf8;
}
-bool WriteAll(std::ostream& out, const BigBuffer& buffer) {
+bool WriteAll(std::ostream& out, const android::BigBuffer& buffer) {
for (const auto& b : buffer) {
if (!out.write(reinterpret_cast<const char*>(b.buffer.get()), b.size)) {
return false;
@@ -476,23 +373,12 @@ bool WriteAll(std::ostream& out, const BigBuffer& buffer) {
return true;
}
-std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer) {
- std::unique_ptr<uint8_t[]> data =
- std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
- uint8_t* p = data.get();
- for (const auto& block : buffer) {
- memcpy(p, block.buffer.get(), block.size);
- p += block.size;
- }
- return data;
-}
-
typename Tokenizer::iterator& Tokenizer::iterator::operator++() {
const char* start = token_.end();
const char* end = str_.end();
if (start == end) {
end_ = true;
- token_.assign(token_.end(), 0);
+ token_ = StringPiece(token_.end(), 0);
return *this;
}
@@ -500,12 +386,12 @@ typename Tokenizer::iterator& Tokenizer::iterator::operator++() {
const char* current = start;
while (current != end) {
if (*current == separator_) {
- token_.assign(start, current - start);
+ token_ = StringPiece(start, current - start);
return *this;
}
++current;
}
- token_.assign(start, end - start);
+ token_ = StringPiece(start, end - start);
return *this;
}
@@ -520,15 +406,17 @@ bool Tokenizer::iterator::operator!=(const iterator& rhs) const {
return !(*this == rhs);
}
-Tokenizer::iterator::iterator(const StringPiece& s, char sep, const StringPiece& tok, bool end)
- : str_(s), separator_(sep), token_(tok), end_(end) {}
+Tokenizer::iterator::iterator(StringPiece s, char sep, StringPiece tok, bool end)
+ : str_(s), separator_(sep), token_(tok), end_(end) {
+}
-Tokenizer::Tokenizer(const StringPiece& str, char sep)
+Tokenizer::Tokenizer(StringPiece str, char sep)
: begin_(++iterator(str, sep, StringPiece(str.begin() - 1, 0), false)),
- end_(str, sep, StringPiece(str.end(), 0), true) {}
+ end_(str, sep, StringPiece(str.end(), 0), true) {
+}
-bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix,
- StringPiece* out_entry, StringPiece* out_suffix) {
+bool ExtractResFilePathParts(StringPiece path, StringPiece* out_prefix, StringPiece* out_entry,
+ StringPiece* out_suffix) {
const StringPiece res_prefix("res/");
if (!StartsWith(path, res_prefix)) {
return false;
@@ -553,19 +441,5 @@ bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix,
return true;
}
-StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
- if (auto str = pool.stringAt(idx); str.ok()) {
- return *str;
- }
- return StringPiece16();
-}
-
-std::string GetString(const android::ResStringPool& pool, size_t idx) {
- if (auto str = pool.string8At(idx); str.ok()) {
- return ModifiedUtf8ToUtf8(str->to_string());
- }
- return Utf16ToUtf8(GetString16(pool, idx));
-}
-
} // namespace util
} // namespace aapt
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index c3efe6a63feb..40ff5b633d97 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -23,12 +23,11 @@
#include <string>
#include <vector>
+#include "androidfw/BigBuffer.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
#include "utils/ByteOrder.h"
-#include "util/BigBuffer.h"
-
#ifdef _WIN32
// TODO(adamlesinski): remove once http://b/32447322 is resolved.
// utils/ByteOrder.h includes winsock2.h on WIN32,
@@ -49,44 +48,44 @@ struct Range {
T end;
};
-std::vector<std::string> Split(const android::StringPiece& str, char sep);
-std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
+std::vector<std::string> Split(android::StringPiece str, char sep);
+std::vector<std::string> SplitAndLowercase(android::StringPiece str, char sep);
// Returns true if the string starts with prefix.
-bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);
+bool StartsWith(android::StringPiece str, android::StringPiece prefix);
// Returns true if the string ends with suffix.
-bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
+bool EndsWith(android::StringPiece str, android::StringPiece suffix);
// Creates a new StringPiece that points to a substring of the original string without leading
// whitespace.
-android::StringPiece TrimLeadingWhitespace(const android::StringPiece& str);
+android::StringPiece TrimLeadingWhitespace(android::StringPiece str);
// Creates a new StringPiece that points to a substring of the original string without trailing
// whitespace.
-android::StringPiece TrimTrailingWhitespace(const android::StringPiece& str);
+android::StringPiece TrimTrailingWhitespace(android::StringPiece str);
// Creates a new StringPiece that points to a substring of the original string without leading or
// trailing whitespace.
-android::StringPiece TrimWhitespace(const android::StringPiece& str);
+android::StringPiece TrimWhitespace(android::StringPiece str);
// Tests that the string is a valid Java class name.
-bool IsJavaClassName(const android::StringPiece& str);
+bool IsJavaClassName(android::StringPiece str);
// Tests that the string is a valid Java package name.
-bool IsJavaPackageName(const android::StringPiece& str);
+bool IsJavaPackageName(android::StringPiece str);
// Tests that the string is a valid Android package name. More strict than a Java package name.
// - First character of each component (separated by '.') must be an ASCII letter.
// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
// - Package must contain at least two components, unless it is 'android'.
// - The maximum package name length is 223.
-bool IsAndroidPackageName(const android::StringPiece& str);
+bool IsAndroidPackageName(android::StringPiece str);
// Tests that the string is a valid Android split name.
// - First character of each component (separated by '.') must be an ASCII letter.
// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
-bool IsAndroidSplitName(const android::StringPiece& str);
+bool IsAndroidSplitName(android::StringPiece str);
// Tests that the string is a valid Android shared user id.
// - First character of each component (separated by '.') must be an ASCII letter.
@@ -94,8 +93,7 @@ bool IsAndroidSplitName(const android::StringPiece& str);
// - Must contain at least two components, unless package name is 'android'.
// - The maximum shared user id length is 223.
// - Treat empty string as valid, it's the case of no shared user id.
-bool IsAndroidSharedUserId(const android::StringPiece& package_name,
- const android::StringPiece& shared_user_id);
+bool IsAndroidSharedUserId(android::StringPiece package_name, android::StringPiece shared_user_id);
// Converts the class name to a fully qualified class name from the given
// `package`. Ex:
@@ -104,8 +102,8 @@ bool IsAndroidSharedUserId(const android::StringPiece& package_name,
// .asdf --> package.asdf
// .a.b --> package.a.b
// asdf.adsf --> asdf.adsf
-std::optional<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
- const android::StringPiece& class_name);
+std::optional<std::string> GetFullyQualifiedClassName(android::StringPiece package,
+ android::StringPiece class_name);
// Retrieves the formatted name of aapt2.
const char* GetToolName();
@@ -149,29 +147,20 @@ template <typename Container>
};
}
-// Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
-// the conversion to UTF-16 happens within ResStringPool.
-android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
-
-// Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
-// the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
-// which maintains no state or cache. This means we must return an std::string copy.
-std::string GetString(const android::ResStringPool& pool, size_t idx);
-
// Checks that the Java string format contains no non-positional arguments (arguments without
// explicitly specifying an index) when there are more than one argument. This is an error
// because translations may rearrange the order of the arguments in the string, which will
// break the string interpolation.
-bool VerifyJavaStringFormat(const android::StringPiece& str);
+bool VerifyJavaStringFormat(android::StringPiece str);
-bool AppendStyledString(const android::StringPiece& input, bool preserve_spaces,
- std::string* out_str, std::string* out_error);
+bool AppendStyledString(android::StringPiece input, bool preserve_spaces, std::string* out_str,
+ std::string* out_error);
class StringBuilder {
public:
StringBuilder() = default;
- StringBuilder& Append(const android::StringPiece& str);
+ StringBuilder& Append(android::StringPiece str);
const std::string& ToString() const;
const std::string& Error() const;
bool IsEmpty() const;
@@ -212,19 +201,8 @@ inline StringBuilder::operator bool() const {
return error_.empty();
}
-// Converts a UTF8 string into Modified UTF8
-std::string Utf8ToModifiedUtf8(const std::string& utf8);
-std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8);
-
-// Converts a UTF8 string to a UTF16 string.
-std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
-std::string Utf16ToUtf8(const android::StringPiece16& utf16);
-
// Writes the entire BigBuffer to the output stream.
-bool WriteAll(std::ostream& out, const BigBuffer& buffer);
-
-// Copies the entire BigBuffer into a single buffer.
-std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer);
+bool WriteAll(std::ostream& out, const android::BigBuffer& buffer);
// A Tokenizer implemented as an iterable collection. It does not allocate any memory on the heap
// nor use standard containers.
@@ -250,7 +228,7 @@ class Tokenizer {
private:
friend class Tokenizer;
- iterator(const android::StringPiece& s, char sep, const android::StringPiece& tok, bool end);
+ iterator(android::StringPiece s, char sep, android::StringPiece tok, bool end);
android::StringPiece str_;
char separator_;
@@ -258,7 +236,7 @@ class Tokenizer {
bool end_;
};
- Tokenizer(const android::StringPiece& str, char sep);
+ Tokenizer(android::StringPiece str, char sep);
iterator begin() const {
return begin_;
@@ -273,26 +251,10 @@ class Tokenizer {
const iterator end_;
};
-inline Tokenizer Tokenize(const android::StringPiece& str, char sep) {
+inline Tokenizer Tokenize(android::StringPiece str, char sep) {
return Tokenizer(str, sep);
}
-inline uint16_t HostToDevice16(uint16_t value) {
- return htods(value);
-}
-
-inline uint32_t HostToDevice32(uint32_t value) {
- return htodl(value);
-}
-
-inline uint16_t DeviceToHost16(uint16_t value) {
- return dtohs(value);
-}
-
-inline uint32_t DeviceToHost32(uint32_t value) {
- return dtohl(value);
-}
-
// Given a path like: res/xml-sw600dp/foo.xml
//
// Extracts "res/xml-sw600dp/" into outPrefix.
@@ -300,18 +262,20 @@ inline uint32_t DeviceToHost32(uint32_t value) {
// Extracts ".xml" into outSuffix.
//
// Returns true if successful.
-bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
+bool ExtractResFilePathParts(android::StringPiece path, android::StringPiece* out_prefix,
android::StringPiece* out_entry, android::StringPiece* out_suffix);
} // namespace util
+} // namespace aapt
+
+namespace std {
// Stream operator for functions. Calls the function with the stream as an argument.
// In the aapt namespace for lookup.
inline ::std::ostream& operator<<(::std::ostream& out,
const ::std::function<::std::ostream&(::std::ostream&)>& f) {
return f(out);
}
-
-} // namespace aapt
+} // namespace std
#endif // AAPT_UTIL_H
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index 4ebcb115306f..15135690d0de 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -84,6 +84,14 @@ TEST(UtilTest, TokenizeAtEnd) {
ASSERT_THAT(*iter, Eq(StringPiece()));
}
+TEST(UtilTest, TokenizeNone) {
+ auto tokenizer = util::Tokenize(StringPiece("none"), '.');
+ auto iter = tokenizer.begin();
+ ASSERT_THAT(*iter, Eq("none"));
+ ++iter;
+ ASSERT_THAT(iter, Eq(tokenizer.end()));
+}
+
TEST(UtilTest, IsJavaClassName) {
EXPECT_TRUE(util::IsJavaClassName("android.test.Class"));
EXPECT_TRUE(util::IsJavaClassName("android.test.Class$Inner"));
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index ea42d26358a8..3ccbaa2a4b6c 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -22,17 +22,19 @@ namespace aapt {
namespace xml {
static bool wrapper_one(const XmlNodeAction::ActionFunc& f, Element* el,
- const XmlActionExecutorPolicy& policy, SourcePathDiagnostics*) {
+ const XmlActionExecutorPolicy& policy, android::SourcePathDiagnostics*) {
return f(el);
}
static bool wrapper_two(const XmlNodeAction::ActionFuncWithDiag& f, Element* el,
- const XmlActionExecutorPolicy& policy, SourcePathDiagnostics* diag) {
+ const XmlActionExecutorPolicy& policy,
+ android::SourcePathDiagnostics* diag) {
return f(el, diag);
}
static bool wrapper_three(const XmlNodeAction::ActionFuncWithPolicyAndDiag& f, Element* el,
- const XmlActionExecutorPolicy& policy, SourcePathDiagnostics* diag) {
+ const XmlActionExecutorPolicy& policy,
+ android::SourcePathDiagnostics* diag) {
return f(el, policy, diag);
}
@@ -51,7 +53,7 @@ void XmlNodeAction::Action(XmlNodeAction::ActionFuncWithPolicyAndDiag f) {
std::placeholders::_2, std::placeholders::_3));
}
-static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) {
+static void PrintElementToDiagMessage(const Element* el, android::DiagMessage* msg) {
*msg << "<";
if (!el->namespace_uri.empty()) {
*msg << el->namespace_uri << ":";
@@ -60,7 +62,7 @@ static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) {
}
bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb,
- SourcePathDiagnostics* diag, Element* el) const {
+ android::SourcePathDiagnostics* diag, Element* el) const {
bool error = false;
for (const ActionFuncWithPolicyAndDiag& action : actions_) {
error |= !action(el, policy, diag);
@@ -78,11 +80,11 @@ bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPi
}
if (policy != XmlActionExecutorPolicy::kNone) {
- DiagMessage error_msg(child_el->line_number);
+ android::DiagMessage error_msg(child_el->line_number);
error_msg << "unexpected element ";
PrintElementToDiagMessage(child_el, &error_msg);
error_msg << " found in ";
- for (const StringPiece& element : *bread_crumb) {
+ for (StringPiece element : *bread_crumb) {
error_msg << "<" << element << ">";
}
if (policy == XmlActionExecutorPolicy::kAllowListWarning) {
@@ -99,14 +101,14 @@ bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPi
return !error;
}
-bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag,
+bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, android::IDiagnostics* diag,
XmlResource* doc) const {
- SourcePathDiagnostics source_diag(doc->file.source, diag);
+ android::SourcePathDiagnostics source_diag(doc->file.source, diag);
Element* el = doc->root.get();
if (!el) {
if (policy == XmlActionExecutorPolicy::kAllowList) {
- source_diag.Error(DiagMessage() << "no root XML tag found");
+ source_diag.Error(android::DiagMessage() << "no root XML tag found");
return false;
}
return true;
@@ -121,7 +123,7 @@ bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* di
}
if (policy == XmlActionExecutorPolicy::kAllowList) {
- DiagMessage error_msg(el->line_number);
+ android::DiagMessage error_msg(el->line_number);
error_msg << "unexpected root element ";
PrintElementToDiagMessage(el, &error_msg);
source_diag.Error(error_msg);
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 78c43345deb7..8cc4573d2c45 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -23,8 +23,7 @@
#include <vector>
#include "android-base/macros.h"
-
-#include "Diagnostics.h"
+#include "androidfw/IDiagnostics.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -50,8 +49,8 @@ enum class XmlActionExecutorPolicy {
class XmlNodeAction {
public:
using ActionFuncWithPolicyAndDiag =
- std::function<bool(Element*, XmlActionExecutorPolicy, SourcePathDiagnostics*)>;
- using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
+ std::function<bool(Element*, XmlActionExecutorPolicy, android::SourcePathDiagnostics*)>;
+ using ActionFuncWithDiag = std::function<bool(Element*, android::SourcePathDiagnostics*)>;
using ActionFunc = std::function<bool(Element*)>;
// Find or create a child XmlNodeAction that will be performed for the child element with the
@@ -69,7 +68,7 @@ class XmlNodeAction {
friend class XmlActionExecutor;
bool Execute(XmlActionExecutorPolicy policy, std::vector<::android::StringPiece>* bread_crumb,
- SourcePathDiagnostics* diag, Element* el) const;
+ android::SourcePathDiagnostics* diag, Element* el) const;
std::map<std::string, XmlNodeAction> map_;
std::vector<ActionFuncWithPolicyAndDiag> actions_;
@@ -88,7 +87,7 @@ class XmlActionExecutor {
// Execute the defined actions for this XmlResource.
// Returns true if all actions return true, otherwise returns false.
- bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
+ bool Execute(XmlActionExecutorPolicy policy, android::IDiagnostics* diag, XmlResource* doc) const;
private:
std::map<std::string, XmlNodeAction> map_;
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 8b7eadf9fac9..8dea8ea52f92 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -169,7 +169,7 @@ static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len
stack->last_text_node = util::make_unique<Text>();
stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
- stack->last_text_node->text = str.to_string();
+ stack->last_text_node->text.assign(str);
}
static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
@@ -183,7 +183,8 @@ static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
stack->pending_comment += comment;
}
-std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
+std::unique_ptr<XmlResource> Inflate(InputStream* in, android::IDiagnostics* diag,
+ const android::Source& source) {
Stack stack;
std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
@@ -199,28 +200,29 @@ std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const
size_t buffer_size = 0;
while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
- diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
+ diag->Error(android::DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
<< XML_ErrorString(XML_GetErrorCode(parser.get())));
return {};
}
}
if (in->HadError()) {
- diag->Error(DiagMessage(source) << in->GetError());
+ diag->Error(android::DiagMessage(source) << in->GetError());
return {};
} else {
// Finish off the parsing.
if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
- diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
+ diag->Error(android::DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
<< XML_ErrorString(XML_GetErrorCode(parser.get())));
return {};
}
}
return util::make_unique<XmlResource>(ResourceFile{{}, {}, ResourceFile::Type::kUnknown, source},
- StringPool{}, std::move(stack.root));
+ android::StringPool{}, std::move(stack.root));
}
-static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
+static void CopyAttributes(Element* el, android::ResXMLParser* parser,
+ android::StringPool* out_pool) {
const size_t attr_count = parser->getAttributeCount();
if (attr_count > 0) {
el->attributes.reserve(attr_count);
@@ -229,12 +231,12 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
size_t len;
const char16_t* str16 = parser->getAttributeNamespace(i, &len);
if (str16) {
- attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ attr.namespace_uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = parser->getAttributeName(i, &len);
if (str16) {
- attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
+ attr.name = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
uint32_t res_id = parser->getAttributeNameResID(i);
@@ -244,7 +246,7 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
str16 = parser->getAttributeStringValue(i, &len);
if (str16) {
- attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
+ attr.value = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
android::Res_value res_value;
@@ -294,12 +296,12 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
size_t len;
const char16_t* str16 = tree.getNamespacePrefix(&len);
if (str16) {
- decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
+ decl.prefix = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getNamespaceUri(&len);
if (str16) {
- decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ decl.uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
if (pending_element == nullptr) {
@@ -323,12 +325,12 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
size_t len;
const char16_t* str16 = tree.getElementNamespace(&len);
if (str16) {
- el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ el->namespace_uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getElementName(&len);
if (str16) {
- el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
+ el->name = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
Element* this_el = el.get();
@@ -349,7 +351,7 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string*
size_t len;
const char16_t* str16 = tree.getText(&len);
if (str16) {
- text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
+ text->text = android::util::Utf16ToUtf8(StringPiece16(str16, len));
}
CHECK(!node_stack.empty());
node_stack.top()->AppendChild(std::move(text));
@@ -415,11 +417,11 @@ void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
children.insert(children.begin() + index, std::move(child));
}
-Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
+Attribute* Element::FindAttribute(StringPiece ns, StringPiece name) {
return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
}
-const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
+const Attribute* Element::FindAttribute(StringPiece ns, StringPiece name) const {
for (const auto& attr : attributes) {
if (ns == attr.namespace_uri && name == attr.name) {
return &attr;
@@ -428,7 +430,7 @@ const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece
return nullptr;
}
-void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
+void Element::RemoveAttribute(StringPiece ns, StringPiece name) {
auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
[&](const Attribute& attr) -> bool {
return ns == attr.namespace_uri && name == attr.name;
@@ -437,34 +439,32 @@ void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
attributes.erase(new_attr_end, attributes.end());
}
-Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
+Attribute* Element::FindOrCreateAttribute(StringPiece ns, StringPiece name) {
Attribute* attr = FindAttribute(ns, name);
if (attr == nullptr) {
- attributes.push_back(Attribute{ns.to_string(), name.to_string()});
+ attributes.push_back(Attribute{std::string(ns), std::string(name)});
attr = &attributes.back();
}
return attr;
}
-Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
+Element* Element::FindChild(StringPiece ns, StringPiece name) {
return FindChildWithAttribute(ns, name, {}, {}, {});
}
-const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
+const Element* Element::FindChild(StringPiece ns, StringPiece name) const {
return FindChildWithAttribute(ns, name, {}, {}, {});
}
-Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
- const StringPiece& attr_ns, const StringPiece& attr_name,
- const StringPiece& attr_value) {
+Element* Element::FindChildWithAttribute(StringPiece ns, StringPiece name, StringPiece attr_ns,
+ StringPiece attr_name, StringPiece attr_value) {
return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
ns, name, attr_ns, attr_name, attr_value));
}
-const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
- const StringPiece& attr_ns,
- const StringPiece& attr_name,
- const StringPiece& attr_value) const {
+const Element* Element::FindChildWithAttribute(StringPiece ns, StringPiece name,
+ StringPiece attr_ns, StringPiece attr_name,
+ StringPiece attr_value) const {
for (const auto& child : children) {
if (const Element* el = NodeCast<Element>(child.get())) {
if (ns == el->namespace_uri && name == el->name) {
@@ -557,7 +557,7 @@ void PackageAwareVisitor::AfterVisitElement(Element* el) {
}
std::optional<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
- const StringPiece& alias) const {
+ StringPiece alias) const {
if (alias.empty()) {
return ExtractedPackage{{}, false /*private*/};
}
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 5d31804d43b7..c253b0a1f4a9 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -21,11 +21,10 @@
#include <string>
#include <vector>
-#include "androidfw/StringPiece.h"
-
-#include "Diagnostics.h"
#include "Resource.h"
#include "ResourceValues.h"
+#include "androidfw/IDiagnostics.h"
+#include "androidfw/StringPiece.h"
#include "io/Io.h"
#include "util/Util.h"
#include "xml/XmlUtil.h"
@@ -97,27 +96,22 @@ class Element : public Node {
void AppendChild(std::unique_ptr<Node> child);
void InsertChild(size_t index, std::unique_ptr<Node> child);
- Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
- const Attribute* FindAttribute(const android::StringPiece& ns,
- const android::StringPiece& name) const;
- Attribute* FindOrCreateAttribute(const android::StringPiece& ns,
- const android::StringPiece& name);
- void RemoveAttribute(const android::StringPiece& ns,
- const android::StringPiece& name);
+ Attribute* FindAttribute(android::StringPiece ns, android::StringPiece name);
+ const Attribute* FindAttribute(android::StringPiece ns, android::StringPiece name) const;
+ Attribute* FindOrCreateAttribute(android::StringPiece ns, android::StringPiece name);
+ void RemoveAttribute(android::StringPiece ns, android::StringPiece name);
- Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
- const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;
+ Element* FindChild(android::StringPiece ns, android::StringPiece name);
+ const Element* FindChild(android::StringPiece ns, android::StringPiece name) const;
- Element* FindChildWithAttribute(const android::StringPiece& ns, const android::StringPiece& name,
- const android::StringPiece& attr_ns,
- const android::StringPiece& attr_name,
- const android::StringPiece& attr_value);
+ Element* FindChildWithAttribute(android::StringPiece ns, android::StringPiece name,
+ android::StringPiece attr_ns, android::StringPiece attr_name,
+ android::StringPiece attr_value);
- const Element* FindChildWithAttribute(const android::StringPiece& ns,
- const android::StringPiece& name,
- const android::StringPiece& attr_ns,
- const android::StringPiece& attr_name,
- const android::StringPiece& attr_value) const;
+ const Element* FindChildWithAttribute(android::StringPiece ns, android::StringPiece name,
+ android::StringPiece attr_ns,
+ android::StringPiece attr_name,
+ android::StringPiece attr_value) const;
std::vector<Element*> GetChildElements();
@@ -150,7 +144,7 @@ class XmlResource {
// StringPool must come before the xml::Node. Destructors are called in reverse order, and
// the xml::Node may have StringPool references that need to be destroyed before the StringPool
// is destroyed.
- StringPool string_pool;
+ android::StringPool string_pool;
std::unique_ptr<xml::Element> root;
@@ -158,7 +152,8 @@ class XmlResource {
};
// Inflates an XML DOM from an InputStream, logging errors to the logger.
-std::unique_ptr<XmlResource> Inflate(io::InputStream* in, IDiagnostics* diag, const Source& source);
+std::unique_ptr<XmlResource> Inflate(io::InputStream* in, android::IDiagnostics* diag,
+ const android::Source& source);
// Inflates an XML DOM from a binary ResXMLTree.
std::unique_ptr<XmlResource> Inflate(const void* data, size_t len,
@@ -235,8 +230,7 @@ class PackageAwareVisitor : public Visitor, public IPackageDeclStack {
public:
using Visitor::Visit;
- std::optional<ExtractedPackage> TransformPackageAlias(
- const android::StringPiece& alias) const override;
+ std::optional<ExtractedPackage> TransformPackageAlias(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 6c717dcd84c8..c50333894099 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -45,7 +45,7 @@ TEST(XmlDomTest, Inflate) {
StdErrDiagnostics diag;
StringInputStream in(input);
- std::unique_ptr<XmlResource> doc = Inflate(&in, &diag, Source("test.xml"));
+ std::unique_ptr<XmlResource> doc = Inflate(&in, &diag, android::Source("test.xml"));
ASSERT_THAT(doc, NotNull());
Element* el = doc->root.get();
@@ -77,13 +77,13 @@ TEST(XmlDomTest, BinaryInflate) {
decl.line_number = 2u;
doc->root->namespace_decls.push_back(decl);
- BigBuffer buffer(4096);
+ android::BigBuffer buffer(4096);
XmlFlattenerOptions options;
options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
- auto block = util::Copy(buffer);
+ auto block = android::util::Copy(buffer);
std::unique_ptr<XmlResource> new_doc = Inflate(block.get(), buffer.size(), nullptr);
ASSERT_THAT(new_doc, NotNull());
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index bfa07490b9c0..d79446bfae6f 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -140,8 +140,7 @@ const std::string& XmlPullParser::namespace_uri() const {
return event_queue_.front().data2;
}
-std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias(
- const StringPiece& alias) const {
+std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias(StringPiece alias) const {
if (alias.empty()) {
return ExtractedPackage{{}, false /*private*/};
}
@@ -307,7 +306,7 @@ void XMLCALL XmlPullParser::EndCdataSectionHandler(void* user_data) {
parser->depth_ });
}
-std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, const StringPiece& name) {
+std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, StringPiece name) {
auto iter = parser->FindAttribute("", name);
if (iter != parser->end_attributes()) {
return StringPiece(util::TrimWhitespace(iter->value));
@@ -315,8 +314,7 @@ std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, const Stri
return {};
}
-std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
- const StringPiece& name) {
+std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, StringPiece name) {
auto iter = parser->FindAttribute("", name);
if (iter != parser->end_attributes()) {
StringPiece trimmed = util::TrimWhitespace(iter->value);
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index ab347728ae4b..fe4cd018d808 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -120,8 +120,7 @@ class XmlPullParser : public IPackageDeclStack {
* If xmlns:app="http://schemas.android.com/apk/res-auto", then
* 'package' will be set to 'defaultPackage'.
*/
- std::optional<ExtractedPackage> TransformPackageAlias(
- const android::StringPiece& alias) const override;
+ std::optional<ExtractedPackage> TransformPackageAlias(android::StringPiece alias) const override;
struct PackageDecl {
std::string prefix;
@@ -194,7 +193,7 @@ class XmlPullParser : public IPackageDeclStack {
* Finds the attribute in the current element within the global namespace.
*/
std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser,
- const android::StringPiece& name);
+ android::StringPiece name);
/**
* Finds the attribute in the current element within the global namespace. The
@@ -202,7 +201,7 @@ std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser,
* must not be the empty string.
*/
std::optional<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
- const android::StringPiece& name);
+ android::StringPiece name);
//
// Implementation
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index 114b5ba7ab1a..709755e69292 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -27,7 +27,7 @@ using ::android::StringPiece;
namespace aapt {
namespace xml {
-std::string BuildPackageNamespace(const StringPiece& package, bool private_reference) {
+std::string BuildPackageNamespace(StringPiece package, bool private_reference) {
std::string result = private_reference ? kSchemaPrivatePrefix : kSchemaPublicPrefix;
result.append(package.data(), package.size());
return result;
@@ -41,7 +41,7 @@ std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& n
if (package.empty()) {
return {};
}
- return ExtractedPackage{package.to_string(), false /* is_private */};
+ return ExtractedPackage{std::string(package), false /* is_private */};
} else if (util::StartsWith(namespace_uri, kSchemaPrivatePrefix)) {
StringPiece schema_prefix = kSchemaPrivatePrefix;
@@ -50,7 +50,7 @@ std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& n
if (package.empty()) {
return {};
}
- return ExtractedPackage{package.to_string(), true /* is_private */};
+ return ExtractedPackage{std::string(package), true /* is_private */};
} else if (namespace_uri == kSchemaAuto) {
return ExtractedPackage{std::string(), true /* is_private */};
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 1ab05a93d314..ad676ca91886 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -59,8 +59,7 @@ std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& n
//
// If privateReference == true, the package will be of the form:
// http://schemas.android.com/apk/prv/res/<package>
-std::string BuildPackageNamespace(const android::StringPiece& package,
- bool private_reference = false);
+std::string BuildPackageNamespace(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.
@@ -69,7 +68,7 @@ struct IPackageDeclStack {
// Returns an ExtractedPackage struct if the alias given corresponds with a package declaration.
virtual std::optional<ExtractedPackage> TransformPackageAlias(
- const android::StringPiece& alias) const = 0;
+ android::StringPiece alias) const = 0;
};
// Helper function for transforming the original Reference inRef to a fully qualified reference
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 5fc800b09ee9..685733386cae 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -393,7 +393,7 @@ private fun ClassPrinter.generateBuilderBuild() {
fun ClassPrinter.generateParcelable() {
val booleanFields = fields.filter { it.Type == "boolean" }
val objectFields = fields.filter { it.Type !in PRIMITIVE_TYPES }
- val nullableFields = objectFields.filter { it.mayBeNull }
+ val nullableFields = objectFields.filter { it.mayBeNull && it.Type !in PRIMITIVE_ARRAY_TYPES }
val nonBooleanFields = fields - booleanFields
@@ -457,7 +457,7 @@ fun ClassPrinter.generateParcelable() {
hasAnnotation("@$DataClassEnum") ->
+"dest.writeInt($internalGetter == null ? -1 : $internalGetter.ordinal());"
else -> {
- if (mayBeNull) !"if ($internalGetter != null) "
+ if (mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) !"if ($internalGetter != null) "
var args = internalGetter
if (ParcelMethodsSuffix.startsWith("Parcelable")
|| ParcelMethodsSuffix.startsWith("TypedObject")
@@ -529,7 +529,7 @@ fun ClassPrinter.generateParcelable() {
if (passContainer) {
methodArgs.add(_name)
!"$Type $_name = "
- if (mayBeNull) {
+ if (mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) {
+"null;"
!"if ((flg & $fieldBit) != 0) {"
pushIndent()
@@ -539,7 +539,9 @@ fun ClassPrinter.generateParcelable() {
+"$containerInitExpr;"
} else {
!"$Type $_name = "
- if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : "
+ if (mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) {
+ !"(flg & $fieldBit) == 0 ? null : "
+ }
if (ParcelMethodsSuffix == "StrongInterface") {
!"$FieldClass.Stub.asInterface("
} else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" &&
@@ -578,7 +580,7 @@ fun ClassPrinter.generateParcelable() {
+";"
// Cleanup if passContainer
- if (passContainer && mayBeNull) {
+ if (passContainer && mayBeNull && Type !in PRIMITIVE_ARRAY_TYPES) {
popIndent()
rmEmptyLine()
+"\n}"
@@ -949,4 +951,4 @@ fun ClassPrinter.generateMetadata(file: File) {
+""
+"@Deprecated"
+"private void __metadata() {}\n"
-} \ No newline at end of file
+}
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index 4b508d022991..bcc6230fd53f 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -10,6 +10,7 @@ const val GENERATED_END = "// End of generated code"
const val INDENT_SINGLE = " "
val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean")
+val PRIMITIVE_ARRAY_TYPES = listOf("byte[]", "short[]", "int[]", "long[]", "char[]", "float[]", "double[]", "boolean[]")
val BOXED_PRIMITIVE_TYPES = PRIMITIVE_TYPES.map { it.capitalize() } - "Int" + "Integer" - "Char" + "Character"
val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern")
@@ -133,4 +134,4 @@ private fun handleUpdateFlag(cliArgs: Array<String>, sourceLines: List<String>):
System.exit(0)
}
return cliArgs - "--update-only"
-} \ No newline at end of file
+}
diff --git a/tools/fonts/font-scaling-array-generator.js b/tools/fonts/font-scaling-array-generator.js
new file mode 100644
index 000000000000..59fd2e69764b
--- /dev/null
+++ b/tools/fonts/font-scaling-array-generator.js
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ Generates arrays for non-linear font scaling, to be pasted into
+ frameworks/base/core/java/android/content/res/FontScaleConverterFactory.java
+
+ To use:
+ `node font-scaling-array-generator.js`
+ or just open a browser, open DevTools, and paste into the Console.
+*/
+
+/**
+ * Modify this to match your
+ * frameworks/base/packages/SettingsLib/res/values/arrays.xml#entryvalues_font_size
+ * array so that all possible scales are generated.
+ */
+const scales = [1.15, 1.30, 1.5, 1.8, 2];
+
+const commonSpSizes = [8, 10, 12, 14, 18, 20, 24, 30, 100];
+
+/**
+ * Enum for GENERATION_STYLE which determines how to generate the arrays.
+ */
+const GenerationStyle = {
+ /**
+ * Interpolates between hand-tweaked curves. This is the best option and
+ * shouldn't require any additional tweaking.
+ */
+ CUSTOM_TWEAKED: 'CUSTOM_TWEAKED',
+
+ /**
+ * Uses a curve equation that is mostly correct, but will need manual tweaking
+ * at some scales.
+ */
+ CURVE: 'CURVE',
+
+ /**
+ * Uses straight linear multiplication. Good starting point for manual
+ * tweaking.
+ */
+ LINEAR: 'LINEAR'
+}
+
+/**
+ * Determines how arrays are generated. Must be one of the GenerationStyle
+ * values.
+ */
+const GENERATION_STYLE = GenerationStyle.CUSTOM_TWEAKED;
+
+// These are hand-tweaked curves from which we will derive the other
+// interstitial curves using linear interpolation, in the case of using
+// GenerationStyle.CUSTOM_TWEAKED.
+const interpolationTargets = {
+ 1.0: commonSpSizes,
+ 1.5: [12, 15, 18, 22, 24, 26, 28, 30, 100],
+ 2.0: [16, 20, 24, 26, 30, 34, 36, 38, 100]
+};
+
+/**
+ * Interpolate a value with specified extrema, to a new value between new
+ * extrema.
+ *
+ * @param value the current value
+ * @param inputMin minimum the input value can reach
+ * @param inputMax maximum the input value can reach
+ * @param outputMin minimum the output value can reach
+ * @param outputMax maximum the output value can reach
+ */
+function map(value, inputMin, inputMax, outputMin, outputMax) {
+ return outputMin + (outputMax - outputMin) * ((value - inputMin) / (inputMax - inputMin));
+}
+
+/***
+ * Interpolate between values a and b.
+ */
+function lerp(a, b, fraction) {
+ return (a * (1.0 - fraction)) + (b * fraction);
+}
+
+function generateRatios(scale) {
+ // Find the best two arrays to interpolate between.
+ let startTarget, endTarget;
+ let startTargetScale, endTargetScale;
+ const targetScales = Object.keys(interpolationTargets).sort();
+ for (let i = 0; i < targetScales.length - 1; i++) {
+ const targetScaleKey = targetScales[i];
+ const targetScale = parseFloat(targetScaleKey, 10);
+ const startTargetScaleKey = targetScaleKey;
+ const endTargetScaleKey = targetScales[i + 1];
+
+ if (scale < parseFloat(startTargetScaleKey, 10)) {
+ break;
+ }
+
+ startTargetScale = parseFloat(startTargetScaleKey, 10);
+ endTargetScale = parseFloat(endTargetScaleKey, 10);
+ startTarget = interpolationTargets[startTargetScaleKey];
+ endTarget = interpolationTargets[endTargetScaleKey];
+ }
+ const interpolationProgress = map(scale, startTargetScale, endTargetScale, 0, 1);
+
+ return commonSpSizes.map((sp, i) => {
+ const originalSizeDp = sp;
+ let newSizeDp;
+ switch (GENERATION_STYLE) {
+ case GenerationStyle.CUSTOM_TWEAKED:
+ newSizeDp = lerp(startTarget[i], endTarget[i], interpolationProgress);
+ break;
+ case GenerationStyle.CURVE: {
+ let coeff1;
+ let coeff2;
+ if (scale < 1) {
+ // \left(1.22^{-\left(x+5\right)}+0.5\right)\cdot x
+ coeff1 = -5;
+ coeff2 = scale;
+ } else {
+ // (1.22^{-\left(x-10\right)}+1\right)\cdot x
+ coeff1 = map(scale, 1, 2, 2, 8);
+ coeff2 = 1;
+ }
+ newSizeDp = ((Math.pow(1.22, (-(originalSizeDp - coeff1))) + coeff2) * originalSizeDp);
+ break;
+ }
+ case GenerationStyle.LINEAR:
+ newSizeDp = originalSizeDp * scale;
+ break;
+ default:
+ throw new Error('Invalid GENERATION_STYLE');
+ }
+ return {
+ fromSp: sp,
+ toDp: newSizeDp
+ }
+ });
+}
+
+const scaleArrays =
+ scales
+ .map(scale => {
+ const scaleString = (scale * 100).toFixed(0);
+ return {
+ scale,
+ name: `font_size_original_sp_to_scaled_dp_${scaleString}_percent`
+ }
+ })
+ .map(scaleArray => {
+ const items = generateRatios(scaleArray.scale);
+
+ return {
+ ...scaleArray,
+ items
+ }
+ });
+
+function formatDigit(d) {
+ const twoSignificantDigits = Math.round(d * 100) / 100;
+ return String(twoSignificantDigits).padStart(4, ' ');
+}
+
+console.log(
+ '' +
+ scaleArrays.reduce(
+ (previousScaleArray, currentScaleArray) => {
+ const itemsFromSp = currentScaleArray.items.map(d => d.fromSp)
+ .map(formatDigit)
+ .join('f, ');
+ const itemsToDp = currentScaleArray.items.map(d => d.toDp)
+ .map(formatDigit)
+ .join('f, ');
+
+ return previousScaleArray + `
+ put(
+ /* scaleKey= */ ${currentScaleArray.scale}f,
+ new FontScaleConverter(
+ /* fromSp= */
+ new float[] {${itemsFromSp}},
+ /* toDp= */
+ new float[] {${itemsToDp}})
+ );
+ `;
+ },
+ ''));
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index 50fce57add39..006a02908643 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -54,6 +54,7 @@ LANG_TO_SCRIPT = {
'or': 'Orya',
'pa': 'Guru',
'pt': 'Latn',
+ 'pl': 'Latn',
'ru': 'Latn',
'sk': 'Latn',
'sl': 'Latn',
@@ -388,7 +389,7 @@ def check_emoji_not_compat(all_emoji, equivalent_emoji):
psname = get_psname(ttf)
if "meta" in ttf:
- assert 'Emji' not in ttf["meta"].data, 'NotoColorEmoji MUST NOT be a compat font'
+ assert 'Emji' not in ttf["meta"].data, 'NotoColorEmoji MUST be a compat font'
def check_emoji_font_coverage(emoji_fonts, all_emoji, equivalent_emoji):
diff --git a/tools/preload-check/device/src/com/android/preload/check/Util.java b/tools/preload-check/device/src/com/android/preload/check/Util.java
index fccea0a0c107..f521c95839f1 100644
--- a/tools/preload-check/device/src/com/android/preload/check/Util.java
+++ b/tools/preload-check/device/src/com/android/preload/check/Util.java
@@ -25,8 +25,8 @@ import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.LinkedList;
import java.util.List;
public class Util {
@@ -48,7 +48,7 @@ public class Util {
Class<?> vmClassLoaderClass = Class.forName("java.lang.VMClassLoader");
Method getResources = vmClassLoaderClass.getDeclaredMethod("getResources", String.class);
getResources.setAccessible(true);
- LinkedList<DexFile> res = new LinkedList<>();
+ ArrayList<DexFile> res = new ArrayList<>();
for (int i = 1;; i++) {
try {
String name = "classes" + (i > 1 ? String.valueOf(i) : "") + ".dex";
diff --git a/tools/processors/immutability/Android.bp b/tools/processors/immutability/Android.bp
new file mode 100644
index 000000000000..a7d69039fcb0
--- /dev/null
+++ b/tools/processors/immutability/Android.bp
@@ -0,0 +1,80 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library_host {
+ name: "ImmutabilityAnnotationProcessorHostLibrary",
+ srcs: [
+ "src/**/*.kt",
+ "src/**/*.java",
+ ],
+ use_tools_jar: true,
+ javacflags: [
+ "--add-modules=jdk.compiler",
+ "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ ],
+}
+
+java_plugin {
+ name: "ImmutabilityAnnotationProcessor",
+ processor_class: "android.processor.immutability.ImmutabilityProcessor",
+ static_libs: ["ImmutabilityAnnotationProcessorHostLibrary"],
+ javacflags: [
+ "--add-modules=jdk.compiler",
+ "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ ],
+}
+
+java_library {
+ name: "ImmutabilityAnnotation",
+ srcs: ["src/**/Immutable.java"],
+ sdk_version: "core_current",
+ host_supported: true,
+}
+
+java_test_host {
+ name: "ImmutabilityAnnotationProcessorUnitTests",
+
+ srcs: ["test/**/*.kt"],
+
+ static_libs: [
+ "compile-testing-prebuilt",
+ "truth-prebuilt",
+ "junit",
+ "kotlin-reflect",
+ "ImmutabilityAnnotationProcessorHostLibrary",
+ ],
+
+ // Bundle the source file so it can be loaded into the test compiler
+ java_resources: [":ImmutabilityAnnotationJavaSource"],
+
+ test_suites: ["general-tests"],
+ test_options: {
+ unit_test: true,
+ },
+ javacflags: [
+ "--add-modules=jdk.compiler",
+ "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ ],
+ test_config_template: "AndroidTestTemplate.xml",
+}
+
+filegroup {
+ name: "ImmutabilityAnnotationJavaSource",
+ srcs: ["src/android/processor/immutability/Immutable.java"],
+ path: "src/android/processor/immutability/",
+}
diff --git a/tools/processors/immutability/AndroidTestTemplate.xml b/tools/processors/immutability/AndroidTestTemplate.xml
new file mode 100644
index 000000000000..b9cf62f5ca5b
--- /dev/null
+++ b/tools/processors/immutability/AndroidTestTemplate.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs {MODULE}">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-unit-tests" />
+ <option name="config-descriptor:metadata" key="component" value="{MODULE}" />
+
+ {EXTRA_CONFIGS}
+
+ <test class="com.android.tradefed.testtype.IsolatedHostTest" >
+ <option name="jar" value="{MODULE}.jar" />
+ <option name="java-flags" value="--add-modules=jdk.compiler"/>
+ <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"/>
+ <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED"/>
+ <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED"/>
+ <option name="java-flags" value="--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED"/>
+ </test>
+</configuration>
diff --git a/tools/processors/immutability/OWNERS b/tools/processors/immutability/OWNERS
new file mode 100644
index 000000000000..86ae5818e91c
--- /dev/null
+++ b/tools/processors/immutability/OWNERS
@@ -0,0 +1 @@
+include /PACKAGE_MANAGER_OWNERS
diff --git a/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt b/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt
new file mode 100644
index 000000000000..c6f6d45215fe
--- /dev/null
+++ b/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
+
+package android.processor.immutability
+
+import com.sun.tools.javac.code.Symbol
+import com.sun.tools.javac.code.Type
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.ProcessingEnvironment
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.Element
+import javax.lang.model.element.ElementKind
+import javax.lang.model.element.Modifier
+import javax.lang.model.element.TypeElement
+import javax.lang.model.type.TypeKind
+import javax.lang.model.type.TypeMirror
+import javax.tools.Diagnostic
+
+val IMMUTABLE_ANNOTATION_NAME = Immutable::class.qualifiedName
+
+class ImmutabilityProcessor : AbstractProcessor() {
+
+ companion object {
+
+ /**
+ * Types that are already immutable. Will also ignore subclasses.
+ */
+ private val IGNORED_SUPER_TYPES = listOf(
+ "java.io.File",
+ "java.lang.Boolean",
+ "java.lang.Byte",
+ "java.lang.CharSequence",
+ "java.lang.Character",
+ "java.lang.Double",
+ "java.lang.Float",
+ "java.lang.Integer",
+ "java.lang.Long",
+ "java.lang.Short",
+ "java.lang.String",
+ "java.lang.Void",
+ "java.util.UUID",
+ "android.os.Parcelable.Creator",
+ )
+
+ /**
+ * Types that are already immutable. Must be an exact match, does not include any super
+ * or sub classes.
+ */
+ private val IGNORED_EXACT_TYPES = listOf(
+ "java.lang.Class",
+ "java.lang.Object",
+ )
+
+ private val IGNORED_METHODS = listOf(
+ "writeToParcel",
+ )
+ }
+
+ private lateinit var collectionType: TypeMirror
+ private lateinit var mapType: TypeMirror
+
+ private lateinit var ignoredSuperTypes: List<TypeMirror>
+ private lateinit var ignoredExactTypes: List<TypeMirror>
+
+ private val seenTypesByPolicy = mutableMapOf<Set<Immutable.Policy.Exception>, Set<Type>>()
+
+ override fun getSupportedSourceVersion() = SourceVersion.latest()!!
+
+ override fun getSupportedAnnotationTypes() = setOf(Immutable::class.qualifiedName)
+
+ override fun init(processingEnv: ProcessingEnvironment) {
+ super.init(processingEnv)
+ collectionType = processingEnv.erasedType("java.util.Collection")!!
+ mapType = processingEnv.erasedType("java.util.Map")!!
+ ignoredSuperTypes = IGNORED_SUPER_TYPES.mapNotNull { processingEnv.erasedType(it) }
+ ignoredExactTypes = IGNORED_EXACT_TYPES.mapNotNull { processingEnv.erasedType(it) }
+ }
+
+ override fun process(
+ annotations: MutableSet<out TypeElement>,
+ roundEnvironment: RoundEnvironment
+ ): Boolean {
+ annotations.find {
+ it.qualifiedName.toString() == IMMUTABLE_ANNOTATION_NAME
+ } ?: return false
+ roundEnvironment.getElementsAnnotatedWith(Immutable::class.java)
+ .forEach {
+ visitClass(
+ parentChain = emptyList(),
+ seenTypesByPolicy = seenTypesByPolicy,
+ elementToPrint = it,
+ classType = it as Symbol.TypeSymbol,
+ parentPolicyExceptions = emptySet()
+ )
+ }
+ return true
+ }
+
+ /**
+ * @return true if any error was encountered at this level or any child level
+ */
+ private fun visitClass(
+ parentChain: List<String>,
+ seenTypesByPolicy: MutableMap<Set<Immutable.Policy.Exception>, Set<Type>>,
+ elementToPrint: Element,
+ classType: Symbol.TypeSymbol,
+ parentPolicyExceptions: Set<Immutable.Policy.Exception>,
+ ): Boolean {
+ if (isIgnored(classType)) return false
+
+ val policyAnnotation = classType.getAnnotation(Immutable.Policy::class.java)
+ val newPolicyExceptions = parentPolicyExceptions + policyAnnotation?.exceptions.orEmpty()
+
+ // If already seen this type with the same policies applied, skip it
+ val seenTypes = seenTypesByPolicy[newPolicyExceptions]
+ val type = classType.asType()
+ if (seenTypes?.contains(type) == true) return false
+ seenTypesByPolicy[newPolicyExceptions] = seenTypes.orEmpty() + type
+
+ val allowFinalClassesFinalFields =
+ newPolicyExceptions.contains(Immutable.Policy.Exception.FINAL_CLASSES_WITH_FINAL_FIELDS)
+
+ val filteredElements = classType.enclosedElements
+ .filterNot(::isIgnored)
+
+ val hasFieldError = filteredElements
+ .filter { it.getKind() == ElementKind.FIELD }
+ .fold(false) { anyError, field ->
+ if (field.isStatic) {
+ if (!field.isPrivate) {
+ val finalityError = !field.modifiers.contains(Modifier.FINAL)
+ if (finalityError) {
+ printError(parentChain, field, MessageUtils.staticNonFinalFailure())
+ }
+
+ // Must call visitType first so it doesn't get short circuited by the ||
+ visitType(
+ parentChain = parentChain,
+ seenTypesByPolicy = seenTypesByPolicy,
+ symbol = field,
+ type = field.type,
+ parentPolicyExceptions = parentPolicyExceptions
+ ) || anyError || finalityError
+ }
+ return@fold anyError
+ } else {
+ val isFinal = field.modifiers.contains(Modifier.FINAL)
+ if (!isFinal || !allowFinalClassesFinalFields) {
+ printError(parentChain, field, MessageUtils.memberNotMethodFailure())
+ return@fold true
+ }
+
+ return@fold anyError
+ }
+ }
+
+ // Scan inner classes before methods so that any violations isolated to the file prints
+ // the error on the class declaration rather than on the method that returns the type.
+ // Although it doesn't matter too much either way.
+ val hasClassError = filteredElements
+ .filter { it.getKind() == ElementKind.CLASS }
+ .map { it as Symbol.ClassSymbol }
+ .fold(false) { anyError, innerClass ->
+ // Must call visitClass first so it doesn't get short circuited by the ||
+ visitClass(
+ parentChain,
+ seenTypesByPolicy,
+ innerClass,
+ innerClass,
+ newPolicyExceptions
+ ) || anyError
+ }
+
+ val newChain = parentChain + "$classType"
+
+ val hasMethodError = filteredElements
+ .asSequence()
+ .filter { it.getKind() == ElementKind.METHOD }
+ .map { it as Symbol.MethodSymbol }
+ .filterNot { it.isStatic }
+ .filterNot { IGNORED_METHODS.contains(it.name.toString()) }
+ .fold(false) { anyError, method ->
+ // Must call visitMethod first so it doesn't get short circuited by the ||
+ visitMethod(newChain, seenTypesByPolicy, method, newPolicyExceptions) || anyError
+ }
+
+ val className = classType.simpleName.toString()
+ val isRegularClass = classType.getKind() == ElementKind.CLASS
+
+ var anyError = hasFieldError || hasClassError || hasMethodError
+
+ // If final classes are not considered OR there's a non-field failure, also check for
+ // interface/@Immutable, assuming the class is malformed
+ if ((isRegularClass && !allowFinalClassesFinalFields) || hasMethodError || hasClassError) {
+ if (classType.getAnnotation(Immutable::class.java) == null) {
+ printError(
+ parentChain,
+ elementToPrint,
+ MessageUtils.classNotImmutableFailure(className)
+ )
+ anyError = true
+ }
+
+ if (classType.getKind() != ElementKind.INTERFACE) {
+ printError(parentChain, elementToPrint, MessageUtils.nonInterfaceClassFailure())
+ anyError = true
+ }
+ }
+
+ // Check all of the super classes, since methods in those classes are also accessible
+ (classType as? Symbol.ClassSymbol)?.run {
+ (interfaces + superclass).forEach {
+ val element = it.asElement() ?: return@forEach
+ visitClass(parentChain, seenTypesByPolicy, element, element, newPolicyExceptions)
+ }
+ }
+
+ if (isRegularClass && !anyError && allowFinalClassesFinalFields &&
+ !classType.modifiers.contains(Modifier.FINAL)
+ ) {
+ printError(parentChain, elementToPrint, MessageUtils.classNotFinalFailure(className))
+ return true
+ }
+
+ return anyError
+ }
+
+ /**
+ * @return true if any error was encountered at this level or any child level
+ */
+ private fun visitMethod(
+ parentChain: List<String>,
+ seenTypesByPolicy: MutableMap<Set<Immutable.Policy.Exception>, Set<Type>>,
+ method: Symbol.MethodSymbol,
+ parentPolicyExceptions: Set<Immutable.Policy.Exception>,
+ ): Boolean {
+ val returnType = method.returnType
+ val typeName = returnType.toString()
+ when (returnType.kind) {
+ TypeKind.BOOLEAN,
+ TypeKind.BYTE,
+ TypeKind.SHORT,
+ TypeKind.INT,
+ TypeKind.LONG,
+ TypeKind.CHAR,
+ TypeKind.FLOAT,
+ TypeKind.DOUBLE,
+ TypeKind.NONE,
+ TypeKind.NULL -> {
+ // Do nothing
+ }
+ TypeKind.VOID -> {
+ if (!method.isConstructor) {
+ printError(parentChain, method, MessageUtils.voidReturnFailure())
+ return true
+ }
+ }
+ TypeKind.ARRAY -> {
+ printError(parentChain, method, MessageUtils.arrayFailure())
+ return true
+ }
+ TypeKind.DECLARED -> {
+ return visitType(
+ parentChain,
+ seenTypesByPolicy,
+ method,
+ method.returnType,
+ parentPolicyExceptions
+ )
+ }
+ TypeKind.ERROR,
+ TypeKind.TYPEVAR,
+ TypeKind.WILDCARD,
+ TypeKind.PACKAGE,
+ TypeKind.EXECUTABLE,
+ TypeKind.OTHER,
+ TypeKind.UNION,
+ TypeKind.INTERSECTION,
+ // Java 9+
+ // TypeKind.MODULE,
+ null -> {
+ printError(
+ parentChain, method,
+ MessageUtils.genericTypeKindFailure(typeName = typeName)
+ )
+ return true
+ }
+ else -> {
+ printError(
+ parentChain, method,
+ MessageUtils.genericTypeKindFailure(typeName = typeName)
+ )
+ return true
+ }
+ }
+
+ return false
+ }
+
+ /**
+ * @return true if any error was encountered at this level or any child level
+ */
+ private fun visitType(
+ parentChain: List<String>,
+ seenTypesByPolicy: MutableMap<Set<Immutable.Policy.Exception>, Set<Type>>,
+ symbol: Symbol,
+ type: Type,
+ parentPolicyExceptions: Set<Immutable.Policy.Exception>,
+ nonInterfaceClassFailure: () -> String = { MessageUtils.nonInterfaceReturnFailure() },
+ ): Boolean {
+ // Skip if the symbol being considered is itself ignored
+ if (isIgnored(symbol)) return false
+
+ // Skip if the type being checked, like for a typeArg or return type, is ignored
+ if (isIgnored(type)) return false
+
+ // Skip if that typeArg is itself ignored when inspected at the class header level
+ if (isIgnored(type.asElement())) return false
+
+ if (type.isPrimitive) return false
+ if (type.isPrimitiveOrVoid) {
+ printError(parentChain, symbol, MessageUtils.voidReturnFailure())
+ return true
+ }
+
+ val policyAnnotation = symbol.getAnnotation(Immutable.Policy::class.java)
+ val newPolicyExceptions = parentPolicyExceptions + policyAnnotation?.exceptions.orEmpty()
+
+ // Collection (and Map) types are ignored for the interface check as they have immutability
+ // enforced through a runtime exception which must be verified in a separate runtime test
+ val isMap = processingEnv.typeUtils.isAssignable(type, mapType)
+ if (!processingEnv.typeUtils.isAssignable(type, collectionType) && !isMap) {
+ if (!type.isInterface && !newPolicyExceptions
+ .contains(Immutable.Policy.Exception.FINAL_CLASSES_WITH_FINAL_FIELDS)
+ ) {
+ printError(parentChain, symbol, nonInterfaceClassFailure())
+ return true
+ } else {
+ return visitClass(
+ parentChain, seenTypesByPolicy, symbol,
+ processingEnv.typeUtils.asElement(type) as Symbol.TypeSymbol,
+ newPolicyExceptions,
+ )
+ }
+ }
+
+ var anyError = false
+
+ type.typeArguments.forEachIndexed { index, typeArg ->
+ if (isIgnored(typeArg.asElement())) return@forEachIndexed
+
+ val argError =
+ visitType(parentChain, seenTypesByPolicy, symbol, typeArg, newPolicyExceptions) {
+ MessageUtils.nonInterfaceReturnFailure(
+ prefix = when {
+ !isMap -> ""
+ index == 0 -> "Key " + typeArg.asElement().simpleName
+ else -> "Value " + typeArg.asElement().simpleName
+ }, index = index
+ )
+ }
+ anyError = anyError || argError
+ }
+
+ return anyError
+ }
+
+ private fun printError(
+ parentChain: List<String>,
+ element: Element,
+ message: String,
+ ) = processingEnv.messager.printMessage(
+ Diagnostic.Kind.ERROR,
+ parentChain.plus(element.simpleName).joinToString() + "\n\t " + message,
+ element,
+ )
+
+ private fun ProcessingEnvironment.erasedType(typeName: String) =
+ elementUtils.getTypeElement(typeName)?.asType()?.let(typeUtils::erasure)
+
+ private fun isIgnored(type: Type) =
+ (type.getAnnotation(Immutable.Ignore::class.java) != null)
+ || (ignoredSuperTypes.any { type.isAssignable(it) })
+ || (ignoredExactTypes.any { type.isSameType(it) })
+
+ private fun isIgnored(symbol: Symbol) = when {
+ // Anything annotated as @Ignore is always ignored
+ symbol.getAnnotation(Immutable.Ignore::class.java) != null -> true
+ // Then ignore exact types, regardless of what kind they are
+ ignoredExactTypes.any { symbol.type.isSameType(it) } -> true
+ // Then only allow methods through, since other types (fields) are usually a failure
+ symbol.getKind() != ElementKind.METHOD -> false
+ // Finally, check for any ignored super types
+ else -> ignoredSuperTypes.any { symbol.type.isAssignable(it) }
+ }
+
+ private fun TypeMirror.isAssignable(type: TypeMirror) = try {
+ processingEnv.typeUtils.isAssignable(this, type)
+ } catch (ignored: Exception) {
+ false
+ }
+
+ private fun TypeMirror.isSameType(type: TypeMirror) = try {
+ processingEnv.typeUtils.isSameType(this, type)
+ } catch (ignored: Exception) {
+ false
+ }
+}
diff --git a/tools/processors/immutability/src/android/processor/immutability/Immutable.java b/tools/processors/immutability/src/android/processor/immutability/Immutable.java
new file mode 100644
index 000000000000..ba822ba562ee
--- /dev/null
+++ b/tools/processors/immutability/src/android/processor/immutability/Immutable.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.processor.immutability;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Marks a class as immutable. When used with the Immutability processor, verifies at compile that
+ * the class is truly immutable. Immutable is defined as:
+ * <ul>
+ * <li>Only exposes methods and/or static final constants</li>
+ * <li>Every exposed type is an @Immutable interface or otherwise immutable class</li>
+ * <ul>
+ * <li>Implicitly immutable types like {@link String} are ignored</li>
+ * <li>{@link Collection} and {@link Map} and their subclasses where immutability is
+ * enforced at runtime are ignored</li>
+ * </ul>
+ * <li>Every method must return a type (no void methods allowed)</li>
+ * <li>All inner classes must be @Immutable interfaces</li>
+ * </ul>
+ */
+public @interface Immutable {
+
+ /**
+ * Marks a specific class, field, or method as ignored for immutability validation.
+ */
+ @Retention(RetentionPolicy.CLASS) // Not SOURCE as that isn't retained for some reason
+ @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
+ @interface Ignore {
+ String reason() default "";
+ }
+
+ /**
+ * Marks an element and its reachable children with a specific policy.
+ */
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
+ @interface Policy {
+ Exception[] exceptions() default {};
+
+ enum Exception {
+ /**
+ * Allow final classes with only final fields. By default these are not allowed because
+ * direct field access disallows hard removal of APIs (by having their getters return
+ * mocks/stubs) and also prevents field compaction, which can occur with booleans
+ * stuffed into a number as flags.
+ *
+ * This exception is allowed though because several framework classes are built around
+ * the final field access model and it would be unnecessarily difficult to migrate or
+ * wrap each type.
+ */
+ FINAL_CLASSES_WITH_FINAL_FIELDS,
+ }
+ }
+}
diff --git a/tools/processors/immutability/src/android/processor/immutability/MessageUtils.kt b/tools/processors/immutability/src/android/processor/immutability/MessageUtils.kt
new file mode 100644
index 000000000000..7fa2fb56deb1
--- /dev/null
+++ b/tools/processors/immutability/src/android/processor/immutability/MessageUtils.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.processor.immutability
+
+object MessageUtils {
+
+ fun classNotImmutableFailure(className: String) = "$className should be marked @Immutable"
+
+ fun classNotFinalFailure(className: String) = "$className should be marked final"
+
+ fun memberNotMethodFailure() = "Member must be a method"
+
+ fun nonInterfaceClassFailure() = "Class was not an interface"
+
+ fun nonInterfaceReturnFailure(prefix: String, index: Int = -1) =
+ if (prefix.isEmpty()) {
+ "Type at index $index was not an interface"
+ } else {
+ "$prefix was not an interface"
+ }
+
+ fun genericTypeKindFailure(typeName: CharSequence) = "TypeKind $typeName unsupported"
+
+ fun arrayFailure() = "Array types are not supported as they can be mutated by callers"
+
+ fun nonInterfaceReturnFailure() = "Must return an interface"
+
+ fun voidReturnFailure() = "Cannot return void"
+
+ fun staticNonFinalFailure() = "Static member must be final"
+} \ No newline at end of file
diff --git a/tools/processors/immutability/test/android/processor/ImmutabilityProcessorTest.kt b/tools/processors/immutability/test/android/processor/ImmutabilityProcessorTest.kt
new file mode 100644
index 000000000000..43caa456a093
--- /dev/null
+++ b/tools/processors/immutability/test/android/processor/ImmutabilityProcessorTest.kt
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.processor
+
+import android.processor.immutability.IMMUTABLE_ANNOTATION_NAME
+import android.processor.immutability.ImmutabilityProcessor
+import android.processor.immutability.MessageUtils
+import com.google.common.truth.Expect
+import com.google.testing.compile.CompilationSubject.assertThat
+import com.google.testing.compile.Compiler.javac
+import com.google.testing.compile.JavaFileObjects
+import org.junit.Rule
+import org.junit.Test
+import java.util.*
+import javax.tools.JavaFileObject
+
+class ImmutabilityProcessorTest {
+
+ companion object {
+ private const val PACKAGE_PREFIX = "android.processor.immutability"
+ private const val DATA_CLASS_NAME = "DataClass"
+ private val ANNOTATION = JavaFileObjects.forResource("Immutable.java")
+
+ private val FINAL_CLASSES = listOf(
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.NonFinalClassFinalFields",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ public class NonFinalClassFinalFields {
+ private final String finalField;
+ public NonFinalClassFinalFields(String value) {
+ this.finalField = value;
+ }
+ }
+ """.trimIndent()
+ ),
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.NonFinalClassNonFinalFields",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ public class NonFinalClassNonFinalFields {
+ private String nonFinalField;
+ }
+ """.trimIndent()
+ ),
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.FinalClassFinalFields",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ public final class FinalClassFinalFields {
+ private final String finalField;
+ public FinalClassFinalFields(String value) {
+ this.finalField = value;
+ }
+ }
+ """.trimIndent()
+ ),
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.FinalClassNonFinalFields",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ public final class FinalClassNonFinalFields {
+ private String nonFinalField;
+ }
+ """.trimIndent()
+ )
+ )
+ }
+
+ @get:Rule
+ val expect = Expect.create()
+
+ @Test
+ fun validInterface() = test(
+ source = JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.$DATA_CLASS_NAME",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ import $IMMUTABLE_ANNOTATION_NAME;
+ import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.List;
+
+ @Immutable
+ public interface $DATA_CLASS_NAME {
+ InnerInterface DEFAULT = new InnerInterface() {
+ @Override
+ public String getValue() {
+ return "";
+ }
+ @Override
+ public List<String> getArray() {
+ return Collections.emptyList();
+ }
+ };
+
+ String getValue();
+ ArrayList<String> getArray();
+ InnerInterface getInnerInterface();
+
+ @Immutable
+ interface InnerInterface {
+ String getValue();
+ List<String> getArray();
+ }
+ }
+ """.trimIndent()
+ ), errors = emptyList()
+ )
+
+ @Test
+ fun abstractClass() = test(
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.$DATA_CLASS_NAME",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ import $IMMUTABLE_ANNOTATION_NAME;
+ import java.util.Map;
+
+ @Immutable
+ public abstract class $DATA_CLASS_NAME {
+ public static final String IMMUTABLE = "";
+ public static final InnerClass NOT_IMMUTABLE = null;
+ public static InnerClass NOT_FINAL = null;
+
+ // Field finality doesn't matter, methods are always enforced so that future
+ // field compaction or deprecation is possible
+ private final String fieldFinal = "";
+ private String fieldNonFinal;
+ public abstract void sideEffect();
+ public abstract String[] getArray();
+ public abstract InnerClass getInnerClassOne();
+ public abstract InnerClass getInnerClassTwo();
+ @Immutable.Ignore
+ public abstract InnerClass getIgnored();
+ public abstract InnerInterface getInnerInterface();
+
+ public abstract Map<String, String> getValidMap();
+ public abstract Map<InnerClass, InnerClass> getInvalidMap();
+
+ public static final class InnerClass {
+ public String innerField;
+ public String[] getArray() { return null; }
+ }
+
+ public interface InnerInterface {
+ String[] getArray();
+ InnerClass getInnerClass();
+ }
+ }
+ """.trimIndent()
+ ), errors = listOf(
+ nonInterfaceClassFailure(line = 7),
+ nonInterfaceReturnFailure(line = 9),
+ staticNonFinalFailure(line = 10),
+ nonInterfaceReturnFailure(line = 10),
+ memberNotMethodFailure(line = 14),
+ memberNotMethodFailure(line = 15),
+ voidReturnFailure(line = 16),
+ arrayFailure(line = 17),
+ nonInterfaceReturnFailure(line = 18),
+ nonInterfaceReturnFailure(line = 19),
+ classNotImmutableFailure(line = 22, className = "InnerInterface"),
+ nonInterfaceReturnFailure(line = 25, prefix = "Key InnerClass"),
+ nonInterfaceReturnFailure(line = 25, prefix = "Value InnerClass"),
+ classNotImmutableFailure(line = 27, className = "InnerClass"),
+ nonInterfaceClassFailure(line = 27),
+ memberNotMethodFailure(line = 28),
+ arrayFailure(line = 29),
+ arrayFailure(line = 33),
+ nonInterfaceReturnFailure(line = 34),
+ )
+ )
+
+ @Test
+ fun finalClasses() = test(
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.$DATA_CLASS_NAME",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ import java.util.List;
+
+ @Immutable
+ public interface $DATA_CLASS_NAME {
+ NonFinalClassFinalFields getNonFinalFinal();
+ List<NonFinalClassNonFinalFields> getNonFinalNonFinal();
+ FinalClassFinalFields getFinalFinal();
+ List<FinalClassNonFinalFields> getFinalNonFinal();
+
+ @Immutable.Policy(exceptions = {Immutable.Policy.Exception.FINAL_CLASSES_WITH_FINAL_FIELDS})
+ NonFinalClassFinalFields getPolicyNonFinalFinal();
+
+ @Immutable.Policy(exceptions = {Immutable.Policy.Exception.FINAL_CLASSES_WITH_FINAL_FIELDS})
+ List<NonFinalClassNonFinalFields> getPolicyNonFinalNonFinal();
+
+ @Immutable.Policy(exceptions = {Immutable.Policy.Exception.FINAL_CLASSES_WITH_FINAL_FIELDS})
+ FinalClassFinalFields getPolicyFinalFinal();
+
+ @Immutable.Policy(exceptions = {Immutable.Policy.Exception.FINAL_CLASSES_WITH_FINAL_FIELDS})
+ List<FinalClassNonFinalFields> getPolicyFinalNonFinal();
+ }
+ """.trimIndent()
+ ), errors = listOf(
+ nonInterfaceReturnFailure(line = 7),
+ nonInterfaceReturnFailure(line = 8, index = 0),
+ nonInterfaceReturnFailure(line = 9),
+ nonInterfaceReturnFailure(line = 10, index = 0),
+ classNotFinalFailure(line = 13, "NonFinalClassFinalFields"),
+ ), otherErrors = mapOf(
+ FINAL_CLASSES[1] to listOf(
+ memberNotMethodFailure(line = 4),
+ ),
+ FINAL_CLASSES[3] to listOf(
+ memberNotMethodFailure(line = 4),
+ ),
+ )
+ )
+
+ @Test
+ fun superClass() {
+ val superClass = JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.SuperClass",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ import java.util.List;
+
+ public interface SuperClass {
+ InnerClass getInnerClassOne();
+
+ final class InnerClass {
+ public String innerField;
+ }
+ }
+ """.trimIndent()
+ )
+
+ val dataClass = JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.$DATA_CLASS_NAME",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ import java.util.List;
+
+ @Immutable
+ public interface $DATA_CLASS_NAME extends SuperClass {
+ String[] getArray();
+ }
+ """.trimIndent()
+ )
+
+ test(
+ sources = arrayOf(superClass, dataClass),
+ fileToErrors = mapOf(
+ superClass to listOf(
+ classNotImmutableFailure(line = 5, className = "SuperClass"),
+ nonInterfaceReturnFailure(line = 6),
+ nonInterfaceClassFailure(8),
+ classNotImmutableFailure(line = 8, className = "InnerClass"),
+ memberNotMethodFailure(line = 9),
+ ),
+ dataClass to listOf(
+ arrayFailure(line = 7),
+ )
+ )
+ )
+ }
+
+ @Test
+ fun ignoredClass() = test(
+ JavaFileObjects.forSourceString(
+ "$PACKAGE_PREFIX.$DATA_CLASS_NAME",
+ /* language=JAVA */ """
+ package $PACKAGE_PREFIX;
+
+ import java.util.List;
+ import java.util.Map;
+
+ @Immutable
+ public interface $DATA_CLASS_NAME {
+ IgnoredClass getInnerClassOne();
+ NotIgnoredClass getInnerClassTwo();
+ Map<String, IgnoredClass> getInnerClassThree();
+ Map<String, NotIgnoredClass> getInnerClassFour();
+
+ @Immutable.Ignore
+ final class IgnoredClass {
+ public String innerField;
+ }
+
+ final class NotIgnoredClass {
+ public String innerField;
+ }
+ }
+ """.trimIndent()
+ ), errors = listOf(
+ nonInterfaceReturnFailure(line = 9),
+ nonInterfaceReturnFailure(line = 11, prefix = "Value NotIgnoredClass"),
+ classNotImmutableFailure(line = 18, className = "NotIgnoredClass"),
+ nonInterfaceClassFailure(line = 18),
+ memberNotMethodFailure(line = 19),
+ )
+ )
+
+ private fun test(
+ source: JavaFileObject,
+ errors: List<CompilationError>,
+ otherErrors: Map<JavaFileObject, List<CompilationError>> = emptyMap(),
+ ) = test(
+ sources = arrayOf(source),
+ fileToErrors = otherErrors + (source to errors),
+ )
+
+ private fun test(
+ vararg sources: JavaFileObject,
+ fileToErrors: Map<JavaFileObject, List<CompilationError>> = emptyMap(),
+ ) {
+ val compilation = javac()
+ .withProcessors(ImmutabilityProcessor())
+ .compile(FINAL_CLASSES + ANNOTATION + sources)
+
+ fileToErrors.forEach { (file, errors) ->
+ errors.forEach { error ->
+ try {
+ assertThat(compilation)
+ .hadErrorContaining(error.message)
+ .inFile(file)
+ .onLine(error.line)
+ } catch (e: AssertionError) {
+ // Wrap the exception so that the line number is logged
+ val wrapped = AssertionError("Expected $error, ${e.message}").apply {
+ stackTrace = e.stackTrace
+ }
+
+ // Wrap again with Expect so that all errors are reported. This is very bad code
+ // but can only be fixed by updating compile-testing with a better Truth Subject
+ // implementation.
+ expect.that(wrapped).isNull()
+ }
+ }
+ }
+
+ expect.that(compilation.errors().size).isEqualTo(fileToErrors.values.sumOf { it.size })
+
+ if (expect.hasFailures()) {
+ expect.withMessage(
+ compilation.errors()
+ .sortedBy { it.lineNumber }
+ .joinToString(separator = "\n") {
+ "${it.lineNumber}: ${it.getMessage(Locale.ENGLISH)?.trim()}"
+ }
+ ).fail()
+ }
+ }
+
+ private fun classNotImmutableFailure(line: Long, className: String) =
+ CompilationError(line = line, message = MessageUtils.classNotImmutableFailure(className))
+
+ private fun nonInterfaceClassFailure(line: Long) =
+ CompilationError(line = line, message = MessageUtils.nonInterfaceClassFailure())
+
+ private fun nonInterfaceReturnFailure(line: Long) =
+ CompilationError(line = line, message = MessageUtils.nonInterfaceReturnFailure())
+
+ private fun nonInterfaceReturnFailure(line: Long, prefix: String = "", index: Int = -1) =
+ CompilationError(
+ line = line,
+ message = MessageUtils.nonInterfaceReturnFailure(prefix = prefix, index = index)
+ )
+
+ private fun memberNotMethodFailure(line: Long) =
+ CompilationError(line = line, message = MessageUtils.memberNotMethodFailure())
+
+ private fun voidReturnFailure(line: Long) =
+ CompilationError(line = line, message = MessageUtils.voidReturnFailure())
+
+ private fun staticNonFinalFailure(line: Long) =
+ CompilationError(line = line, message = MessageUtils.staticNonFinalFailure())
+
+ private fun arrayFailure(line: Long) =
+ CompilationError(line = line, message = MessageUtils.arrayFailure())
+
+ private fun classNotFinalFailure(line: Long, className: String) =
+ CompilationError(line = line, message = MessageUtils.classNotFinalFailure(className))
+
+ data class CompilationError(
+ val line: Long,
+ val message: String,
+ )
+}
diff --git a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
index 67a31da87081..512d90c725fe 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
@@ -84,8 +84,8 @@ class LogParserTest {
@Test
fun parse_formatting() {
- config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %% %o" +
- " %x %e %g %s %f", "ERROR", "WindowManager")
+ config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %%" +
+ " %x %s %f", "ERROR", "WindowManager")
val logBuilder = ProtoLogFileProto.newBuilder()
val logMessageBuilder = ProtoLogMessage.newBuilder()
@@ -93,21 +93,21 @@ class LogParserTest {
.setMessageHash(123)
.setElapsedRealtimeNanos(0)
.addBooleanParams(true)
- .addAllSint64Params(listOf(1000, 20000, 300000))
- .addAllDoubleParams(listOf(0.1, 0.00001, 1000.1))
+ .addAllSint64Params(listOf(1000, 20000))
+ .addDoubleParams(1000.1)
.addStrParams("test")
logBuilder.addLog(logMessageBuilder.build())
parser.parse(buildProtoInput(logBuilder), getConfigDummyStream(), printStream)
assertEquals("${testDate(0)} ERROR WindowManager: Test completed successfully: " +
- "true 1000 % 47040 493e0 1.000000e-01 1.00000e-05 test 1000.100000\n",
+ "true 1000 % 4e20 test 1000.100000\n",
outStream.toString())
}
@Test
fun parse_invalidParamsTooMany() {
- config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %% %o",
+ config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %%",
"ERROR", "WindowManager")
val logBuilder = ProtoLogFileProto.newBuilder()
@@ -129,8 +129,8 @@ class LogParserTest {
@Test
fun parse_invalidParamsNotEnough() {
- config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %% %o" +
- " %x %e %g %s %f", "ERROR", "WindowManager")
+ config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %%" +
+ " %x %s %f", "ERROR", "WindowManager")
val logBuilder = ProtoLogFileProto.newBuilder()
val logMessageBuilder = ProtoLogMessage.newBuilder()
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 25373f9e9e2f..554f64e73b74 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -15,7 +15,7 @@ package {
cc_binary_host {
name: "validatekeymaps",
-
+ cpp_std: "c++20",
srcs: ["Main.cpp"],
cflags: [
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 0d7d5f949a08..0fa13b81c4ea 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -167,8 +167,8 @@ static bool validateFile(const char* filename) {
android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
PropertyMap::load(String8(filename));
if (!propertyMap.ok()) {
- error("Error %d parsing input device configuration file.\n\n",
- propertyMap.error().code());
+ error("Error parsing input device configuration file: %s.\n\n",
+ propertyMap.error().message().c_str());
return false;
}
break;