blob: 73072a963d097d6345c25f185f0190a1ff04e2b6 [file] [log] [blame]
Ryan Mitchell479fa392019-01-02 17:15:39 -08001/*
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 "Link.h"
18
Ryan Mitchell5855de72021-02-24 14:39:13 -080019#include <android-base/file.h>
20
21#include "AppInfo.h"
Ryan Mitchell479fa392019-01-02 17:15:39 -080022#include "LoadedApk.h"
23#include "test/Test.h"
24
25using testing::Eq;
Ryan Mitchell5855de72021-02-24 14:39:13 -080026using testing::HasSubstr;
Ryan Mitchell479fa392019-01-02 17:15:39 -080027using testing::Ne;
28
29namespace aapt {
30
31using LinkTest = CommandTestFixture;
32
33TEST_F(LinkTest, RemoveRawXmlStrings) {
34 StdErrDiagnostics diag;
35 const std::string compiled_files_dir = GetTestPath("compiled");
36 ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
37 compiled_files_dir, &diag));
38
39 const std::string out_apk = GetTestPath("out.apk");
40 std::vector<std::string> link_args = {
41 "--manifest", GetDefaultManifest(),
42 "-o", out_apk,
43 };
44
45 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
46
47 // Load the binary xml tree
48 android::ResXMLTree tree;
49 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
Winsonb7be7932019-01-23 11:10:52 -080050 std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
51 ASSERT_THAT(data, Ne(nullptr));
Winsonb7be7932019-01-23 11:10:52 -080052 AssertLoadXml(apk.get(), data.get(), &tree);
Ryan Mitchell479fa392019-01-02 17:15:39 -080053
54 // Check that the raw string index has not been assigned
55 EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
56}
57
58TEST_F(LinkTest, KeepRawXmlStrings) {
59 StdErrDiagnostics diag;
60 const std::string compiled_files_dir = GetTestPath("compiled");
61 ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
62 compiled_files_dir, &diag));
63
64 const std::string out_apk = GetTestPath("out.apk");
65 std::vector<std::string> link_args = {
66 "--manifest", GetDefaultManifest(),
67 "-o", out_apk,
68 "--keep-raw-values"
69 };
70
71 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
72
73 // Load the binary xml tree
74 android::ResXMLTree tree;
75 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
Winsonb7be7932019-01-23 11:10:52 -080076 std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
77 ASSERT_THAT(data, Ne(nullptr));
Winsonb7be7932019-01-23 11:10:52 -080078 AssertLoadXml(apk.get(), data.get(), &tree);
Ryan Mitchell479fa392019-01-02 17:15:39 -080079
80 // Check that the raw string index has been set to the correct string pool entry
81 int32_t raw_index = tree.getAttributeValueStringID(0);
82 ASSERT_THAT(raw_index, Ne(-1));
83 EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
84}
85
Ryan Mitchell81dfca02019-06-07 10:20:27 -070086TEST_F(LinkTest, NoCompressAssets) {
87 StdErrDiagnostics diag;
88 std::string content(500, 'a');
89 WriteFile(GetTestPath("assets/testtxt"), content);
90 WriteFile(GetTestPath("assets/testtxt2"), content);
91 WriteFile(GetTestPath("assets/test.txt"), content);
92 WriteFile(GetTestPath("assets/test.hello.txt"), content);
93 WriteFile(GetTestPath("assets/test.hello.xml"), content);
94
95 const std::string out_apk = GetTestPath("out.apk");
96 std::vector<std::string> link_args = {
97 "--manifest", GetDefaultManifest(),
98 "-o", out_apk,
99 "-0", ".txt",
100 "-0", "txt2",
101 "-0", ".hello.txt",
102 "-0", "hello.xml",
103 "-A", GetTestPath("assets")
104 };
105
106 ASSERT_TRUE(Link(link_args, &diag));
107
108 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
109 ASSERT_THAT(apk, Ne(nullptr));
110 io::IFileCollection* zip = apk->GetFileCollection();
111 ASSERT_THAT(zip, Ne(nullptr));
112
113 auto file = zip->FindFile("assets/testtxt");
114 ASSERT_THAT(file, Ne(nullptr));
115 EXPECT_TRUE(file->WasCompressed());
116
117 file = zip->FindFile("assets/testtxt2");
118 ASSERT_THAT(file, Ne(nullptr));
119 EXPECT_FALSE(file->WasCompressed());
120
121 file = zip->FindFile("assets/test.txt");
122 ASSERT_THAT(file, Ne(nullptr));
123 EXPECT_FALSE(file->WasCompressed());
124
125 file = zip->FindFile("assets/test.hello.txt");
126 ASSERT_THAT(file, Ne(nullptr));
127 EXPECT_FALSE(file->WasCompressed());
128
129 file = zip->FindFile("assets/test.hello.xml");
130 ASSERT_THAT(file, Ne(nullptr));
131 EXPECT_FALSE(file->WasCompressed());
132}
133
134TEST_F(LinkTest, NoCompressResources) {
135 StdErrDiagnostics diag;
136 std::string content(500, 'a');
137 const std::string compiled_files_dir = GetTestPath("compiled");
138 ASSERT_TRUE(CompileFile(GetTestPath("res/raw/testtxt"), content, compiled_files_dir, &diag));
139 ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test.txt"), content, compiled_files_dir, &diag));
140 ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test1.hello.txt"), content, compiled_files_dir,
141 &diag));
142 ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test2.goodbye.xml"), content, compiled_files_dir,
143 &diag));
144
145 const std::string out_apk = GetTestPath("out.apk");
146 std::vector<std::string> link_args = {
147 "--manifest", GetDefaultManifest(),
148 "-o", out_apk,
149 "-0", ".txt",
150 "-0", ".hello.txt",
151 "-0", "goodbye.xml",
152 };
153
154 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
155
156 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
157 ASSERT_THAT(apk, Ne(nullptr));
158 io::IFileCollection* zip = apk->GetFileCollection();
159 ASSERT_THAT(zip, Ne(nullptr));
160
161 auto file = zip->FindFile("res/raw/testtxt");
162 ASSERT_THAT(file, Ne(nullptr));
163 EXPECT_TRUE(file->WasCompressed());
164
165 file = zip->FindFile("res/raw/test.txt");
166 ASSERT_THAT(file, Ne(nullptr));
167 EXPECT_FALSE(file->WasCompressed());
168
169 file = zip->FindFile("res/raw/test1.hello.hello.txt");
170 ASSERT_THAT(file, Ne(nullptr));
171 EXPECT_FALSE(file->WasCompressed());
172
173 file = zip->FindFile("res/raw/test2.goodbye.goodbye.xml");
174 ASSERT_THAT(file, Ne(nullptr));
175 EXPECT_FALSE(file->WasCompressed());
176}
177
Donald Chai121c6e82019-06-12 12:51:57 -0700178TEST_F(LinkTest, OverlayStyles) {
179 StdErrDiagnostics diag;
180 const std::string compiled_files_dir = GetTestPath("compiled");
181 const std::string override_files_dir = GetTestPath("compiled-override");
182 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
183 R"(<resources>
184 <style name="MyStyle">
185 <item name="android:textColor">#123</item>
186 </style>
187 </resources>)",
188 compiled_files_dir, &diag));
189 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values-override.xml"),
190 R"(<resources>
191 <style name="MyStyle">
192 <item name="android:background">#456</item>
193 </style>
194 </resources>)",
195 override_files_dir, &diag));
196
197
198 const std::string out_apk = GetTestPath("out.apk");
199 std::vector<std::string> link_args = {
200 "--manifest", GetDefaultManifest(kDefaultPackageName),
201 "-o", out_apk,
202 };
203 const auto override_files = file::FindFiles(override_files_dir, &diag);
204 for (const auto &override_file : override_files.value()) {
205 link_args.push_back("-R");
206 link_args.push_back(file::BuildPath({override_files_dir, override_file}));
207 }
208 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
209
210 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
211 const Style* actual_style = test::GetValue<Style>(
212 apk->GetResourceTable(), std::string(kDefaultPackageName) + ":style/MyStyle");
213 ASSERT_NE(actual_style, nullptr);
214 ASSERT_EQ(actual_style->entries.size(), 2);
215 EXPECT_EQ(actual_style->entries[0].key.id, 0x01010098); // android:textColor
216 EXPECT_EQ(actual_style->entries[1].key.id, 0x010100d4); // android:background
217}
218
219TEST_F(LinkTest, OverrideStylesInsteadOfOverlaying) {
220 StdErrDiagnostics diag;
221 const std::string compiled_files_dir = GetTestPath("compiled");
222 const std::string override_files_dir = GetTestPath("compiled-override");
223 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
224 R"(<resources>
225 <style name="MyStyle">
226 <item name="android:textColor">#123</item>
227 </style>
228 </resources>)",
229 compiled_files_dir, &diag));
230 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values-override.xml"),
231 R"(<resources>
232 <style name="MyStyle">
233 <item name="android:background">#456</item>
234 </style>
235 </resources>)",
236 override_files_dir, &diag));
237
238
239 const std::string out_apk = GetTestPath("out.apk");
240 std::vector<std::string> link_args = {
241 "--manifest", GetDefaultManifest(kDefaultPackageName),
242 "--override-styles-instead-of-overlaying",
243 "-o", out_apk,
244 };
245 const auto override_files = file::FindFiles(override_files_dir, &diag);
246 for (const auto &override_file : override_files.value()) {
247 link_args.push_back("-R");
248 link_args.push_back(file::BuildPath({override_files_dir, override_file}));
249 }
250 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
251
252 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
253 const Style* actual_style = test::GetValue<Style>(
254 apk->GetResourceTable(), std::string(kDefaultPackageName) + ":style/MyStyle");
255 ASSERT_NE(actual_style, nullptr);
256 ASSERT_EQ(actual_style->entries.size(), 1);
257 EXPECT_EQ(actual_style->entries[0].key.id, 0x010100d4); // android:background
258}
259
Udam Sainib228df32019-06-18 16:50:34 -0700260TEST_F(LinkTest, AppInfoWithUsesSplit) {
261 StdErrDiagnostics diag;
262 const std::string base_files_dir = GetTestPath("base");
263 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
264 R"(<resources>
265 <string name="bar">bar</string>
266 </resources>)",
267 base_files_dir, &diag));
268 const std::string base_apk = GetTestPath("base.apk");
269 std::vector<std::string> link_args = {
270 "--manifest", GetDefaultManifest("com.aapt2.app"),
271 "-o", base_apk,
272 };
273 ASSERT_TRUE(Link(link_args, base_files_dir, &diag));
274
275 const std::string feature_manifest = GetTestPath("feature_manifest.xml");
276 WriteFile(feature_manifest, android::base::StringPrintf(R"(
277 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
278 package="com.aapt2.app" split="feature1">
279 </manifest>)"));
280 const std::string feature_files_dir = GetTestPath("feature");
281 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
282 R"(<resources>
283 <string name="foo">foo</string>
284 </resources>)",
285 feature_files_dir, &diag));
286 const std::string feature_apk = GetTestPath("feature.apk");
287 const std::string feature_package_id = "0x80";
288 link_args = {
289 "--manifest", feature_manifest,
290 "-I", base_apk,
291 "--package-id", feature_package_id,
292 "-o", feature_apk,
293 };
294 ASSERT_TRUE(Link(link_args, feature_files_dir, &diag));
295
296 const std::string feature2_manifest = GetTestPath("feature2_manifest.xml");
297 WriteFile(feature2_manifest, android::base::StringPrintf(R"(
298 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
299 package="com.aapt2.app" split="feature2">
300 <uses-split android:name="feature1"/>
301 </manifest>)"));
302 const std::string feature2_files_dir = GetTestPath("feature2");
303 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
304 R"(<resources>
305 <string-array name="string_array">
306 <item>@string/bar</item>
307 <item>@string/foo</item>
308 </string-array>
309 </resources>)",
310 feature2_files_dir, &diag));
311 const std::string feature2_apk = GetTestPath("feature2.apk");
312 const std::string feature2_package_id = "0x81";
313 link_args = {
314 "--manifest", feature2_manifest,
315 "-I", base_apk,
316 "-I", feature_apk,
317 "--package-id", feature2_package_id,
318 "-o", feature2_apk,
319 };
320 ASSERT_TRUE(Link(link_args, feature2_files_dir, &diag));
321}
322
Ryan Mitchell5855de72021-02-24 14:39:13 -0800323TEST_F(LinkTest, SharedLibraryAttributeRJava) {
324 StdErrDiagnostics diag;
325 const std::string lib_values =
326 R"(<resources>
327 <attr name="foo"/>
328 <public type="attr" name="foo" id="0x00010001"/>
329 <declare-styleable name="LibraryStyleable">
330 <attr name="foo" />
331 </declare-styleable>
332 </resources>)";
333
334 const std::string client_values =
335 R"(<resources>
336 <attr name="bar" />
337 <declare-styleable name="ClientStyleable">
338 <attr name="com.example.lib:foo" />
339 <attr name="bar" />
340 </declare-styleable>
341 </resources>)";
342
343 // Build a library with a public attribute
344 const std::string lib_res = GetTestPath("library-res");
345 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), lib_values, lib_res, &diag));
346
347 const std::string lib_apk = GetTestPath("library.apk");
348 const std::string lib_java = GetTestPath("library_java");
349 // clang-format off
350 auto lib_manifest = ManifestBuilder(this)
351 .SetPackageName("com.example.lib")
352 .Build();
353
354 auto lib_link_args = LinkCommandBuilder(this)
355 .SetManifestFile(lib_manifest)
356 .AddFlag("--shared-lib")
357 .AddParameter("--java", lib_java)
358 .AddCompiledResDir(lib_res, &diag)
359 .Build(lib_apk);
360 // clang-format on
361 ASSERT_TRUE(Link(lib_link_args, &diag));
362
363 const std::string lib_r_java = lib_java + "/com/example/lib/R.java";
364 std::string lib_r_contents;
365 ASSERT_TRUE(android::base::ReadFileToString(lib_r_java, &lib_r_contents));
366 EXPECT_THAT(lib_r_contents, HasSubstr(" public static int foo=0x00010001;"));
367 EXPECT_THAT(lib_r_contents, HasSubstr(" com.example.lib.R.attr.foo"));
368
369 // Build a client that uses the library attribute in a declare-styleable
370 const std::string client_res = GetTestPath("client-res");
371 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), client_values, client_res, &diag));
372
373 const std::string client_apk = GetTestPath("client.apk");
374 const std::string client_java = GetTestPath("client_java");
375 // clang-format off
376 auto client_manifest = ManifestBuilder(this)
377 .SetPackageName("com.example.client")
378 .Build();
379
380 auto client_link_args = LinkCommandBuilder(this)
381 .SetManifestFile(client_manifest)
382 .AddParameter("--java", client_java)
383 .AddParameter("-I", lib_apk)
384 .AddCompiledResDir(client_res, &diag)
385 .Build(client_apk);
386 // clang-format on
387 ASSERT_TRUE(Link(client_link_args, &diag));
388
389 const std::string client_r_java = client_java + "/com/example/client/R.java";
390 std::string client_r_contents;
391 ASSERT_TRUE(android::base::ReadFileToString(client_r_java, &client_r_contents));
392 EXPECT_THAT(client_r_contents, HasSubstr(" com.example.lib.R.attr.foo, 0x7f010000"));
393}
394
Donald Chai121c6e82019-06-12 12:51:57 -0700395} // namespace aapt