• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Convert.h"
18 
19 #include "LoadedApk.h"
20 #include "test/Common.h"
21 #include "test/Test.h"
22 #include "ziparchive/zip_archive.h"
23 
24 using testing::AnyOfArray;
25 using testing::Eq;
26 using testing::Ne;
27 using testing::Not;
28 using testing::SizeIs;
29 
30 namespace aapt {
31 using namespace aapt::test;
32 
33 using ConvertTest = CommandTestFixture;
34 
TEST_F(ConvertTest,RemoveRawXmlStrings)35 TEST_F(ConvertTest, RemoveRawXmlStrings) {
36   StdErrDiagnostics diag;
37   const std::string compiled_files_dir = GetTestPath("compiled");
38   ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
39                           compiled_files_dir, &diag));
40 
41   const std::string out_apk = GetTestPath("out.apk");
42   std::vector<std::string> link_args = {
43       "--manifest", GetDefaultManifest(),
44       "-o", out_apk,
45       "--keep-raw-values",
46       "--proto-format"
47   };
48 
49   ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
50 
51   const std::string out_convert_apk = GetTestPath("out_convert.apk");
52   std::vector<android::StringPiece> convert_args = {
53       "-o", out_convert_apk,
54       "--output-format", "binary",
55       out_apk,
56   };
57   ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
58 
59   // Load the binary xml tree
60   android::ResXMLTree tree;
61   std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
62 
63   std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
64   ASSERT_THAT(data, Ne(nullptr));
65 
66   AssertLoadXml(apk.get(), data.get(), &tree);
67 
68   // Check that the raw string index has not been assigned
69   EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
70 }
71 
TEST_F(ConvertTest,KeepRawXmlStrings)72 TEST_F(ConvertTest, KeepRawXmlStrings) {
73   StdErrDiagnostics diag;
74   const std::string compiled_files_dir = GetTestPath("compiled");
75   ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
76                           compiled_files_dir, &diag));
77 
78   const std::string out_apk = GetTestPath("out.apk");
79   std::vector<std::string> link_args = {
80       "--manifest", GetDefaultManifest(),
81       "-o", out_apk,
82       "--keep-raw-values",
83       "--proto-format"
84   };
85 
86   ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
87 
88   const std::string out_convert_apk = GetTestPath("out_convert.apk");
89   std::vector<android::StringPiece> convert_args = {
90       "-o", out_convert_apk,
91       "--output-format", "binary",
92       "--keep-raw-values",
93       out_apk,
94   };
95   ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
96 
97   // Load the binary xml tree
98   android::ResXMLTree tree;
99   std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
100 
101   std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
102   ASSERT_THAT(data, Ne(nullptr));
103 
104   AssertLoadXml(apk.get(), data.get(), &tree);
105 
106   // Check that the raw string index has been set to the correct string pool entry
107   int32_t raw_index = tree.getAttributeValueStringID(0);
108   ASSERT_THAT(raw_index, Ne(-1));
109   EXPECT_THAT(android::util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)),
110               Eq("007"));
111 }
112 
TEST_F(ConvertTest,DuplicateEntriesWrittenOnce)113 TEST_F(ConvertTest, DuplicateEntriesWrittenOnce) {
114   StdErrDiagnostics diag;
115   const std::string apk_path =
116       file::BuildPath({android::base::GetExecutableDirectory(),
117                        "integration-tests", "ConvertTest", "duplicate_entries.apk"});
118 
119   const std::string out_convert_apk = GetTestPath("out_convert.apk");
120   std::vector<android::StringPiece> convert_args = {
121       "-o", out_convert_apk,
122       "--output-format", "proto",
123       apk_path
124   };
125   ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
126 
127   ZipArchiveHandle handle;
128   ASSERT_THAT(OpenArchive(out_convert_apk.c_str(), &handle), Eq(0));
129 
130   void* cookie = nullptr;
131 
132   int32_t result = StartIteration(handle, &cookie, "res/theme/10", "");
133 
134   // If this is -5, that means we've found a duplicate entry and this test has failed
135   EXPECT_THAT(result, Eq(0));
136 
137   // But if read succeeds, verify only one res/theme/10 entry
138   int count = 0;
139 
140   // Can't pass nullptrs into Next()
141   std::string zip_name;
142   ZipEntry zip_data;
143 
144   while ((result = Next(cookie, &zip_data, &zip_name)) == 0) {
145     count++;
146   }
147 
148   EndIteration(cookie);
149 
150   EXPECT_THAT(count, Eq(1));
151 }
152 
TEST_F(ConvertTest,ConvertWithResourceNameCollapsing)153 TEST_F(ConvertTest, ConvertWithResourceNameCollapsing) {
154   StdErrDiagnostics diag;
155   const std::string compiled_files_dir = GetTestPath("compiled");
156   ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
157                           R"(<resources>
158                                <string name="first">string</string>
159                                <string name="second">string</string>
160                                <string name="third">another string</string>
161 
162                                <bool name="bool1">true</bool>
163                                <bool name="bool2">true</bool>
164                                <bool name="bool3">true</bool>
165 
166                                <integer name="int1">10</integer>
167                                <integer name="int2">10</integer>
168                              </resources>)",
169                           compiled_files_dir, &diag));
170   std::string resource_config_path = GetTestPath("resource-config");
171   WriteFile(resource_config_path, "integer/int1#no_collapse\ninteger/int2#no_collapse");
172 
173   const std::string proto_apk = GetTestPath("proto.apk");
174   std::vector<std::string> link_args = {
175       "--proto-format", "--manifest", GetDefaultManifest(kDefaultPackageName), "-o", proto_apk,
176   };
177   ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
178 
179   const std::string binary_apk = GetTestPath("binary.apk");
180   std::vector<android::StringPiece> convert_args = {"-o",
181                                                     binary_apk,
182                                                     "--output-format",
183                                                     "binary",
184                                                     "--collapse-resource-names",
185                                                     "--deduplicate-entry-values",
186                                                     "--resources-config-path",
187                                                     resource_config_path,
188                                                     proto_apk};
189   ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
190 
191   std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(binary_apk, &diag);
192   for (const auto& package : apk->GetResourceTable()->packages) {
193     for (const auto& type : package->types) {
194       switch (type->named_type.type) {
195         case ResourceType::kBool:
196           EXPECT_THAT(type->entries, SizeIs(3));
197           for (const auto& entry : type->entries) {
198             auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
199             EXPECT_THAT(value.data, Eq(0xffffffffu));
200           }
201           break;
202         case ResourceType::kString:
203           EXPECT_THAT(type->entries, SizeIs(3));
204           for (const auto& entry : type->entries) {
205             auto value = ValueCast<String>(entry->FindValue({})->value.get())->value;
206             EXPECT_THAT(entry->name, Not(AnyOfArray({"first", "second", "third"})));
207             EXPECT_THAT(*value, AnyOfArray({"string", "another string"}));
208           }
209           break;
210         case ResourceType::kInteger:
211           EXPECT_THAT(type->entries, SizeIs(2));
212           for (const auto& entry : type->entries) {
213             auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
214             EXPECT_THAT(entry->name, AnyOfArray({"int1", "int2"}));
215             EXPECT_THAT(value.data, Eq(10));
216           }
217           break;
218         default:
219           break;
220       }
221     }
222   }
223 }
224 
225 }  // namespace aapt
226