blob: aeb9eb6e91c45eed32aae4b5f885e355e0df7c02 [file] [log] [blame]
Adam Lesinskif762df22017-06-26 16:39:03 -07001/*
2 * Copyright (C) 2017 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 "java/ProguardRules.h"
Adam Koskidc21dea2017-07-21 10:55:27 -070018#include "link/Linkers.h"
Adam Lesinskif762df22017-06-26 16:39:03 -070019
Adam Lesinskia693c4a2017-11-09 11:29:39 -080020#include "io/StringStream.h"
Adam Lesinskif762df22017-06-26 16:39:03 -070021#include "test/Test.h"
22
Adam Lesinskia693c4a2017-11-09 11:29:39 -080023using ::aapt::io::StringOutputStream;
Adam Lesinskif762df22017-06-26 16:39:03 -070024using ::testing::HasSubstr;
25using ::testing::Not;
26
27namespace aapt {
28
Adam Lesinskia693c4a2017-11-09 11:29:39 -080029std::string GetKeepSetString(const proguard::KeepSet& set) {
30 std::string out;
31 StringOutputStream sout(&out);
32 proguard::WriteKeepSet(set, &sout);
33 sout.Flush();
34 return out;
35}
36
Jake Whartonab660a72018-06-08 17:56:55 -040037TEST(ProguardRulesTest, ManifestRuleDefaultConstructorOnly) {
38 std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
39 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
Jake Whartoncfbc7672018-06-12 09:26:13 -040040 <application
Jake Whartone4bd1602018-06-12 09:39:14 -040041 android:appComponentFactory="com.foo.BarAppComponentFactory"
Jake Whartoncfbc7672018-06-12 09:26:13 -040042 android:backupAgent="com.foo.BarBackupAgent"
43 android:name="com.foo.BarApplication"
44 >
Jake Whartonab660a72018-06-08 17:56:55 -040045 <activity android:name="com.foo.BarActivity"/>
46 <service android:name="com.foo.BarService"/>
47 <receiver android:name="com.foo.BarReceiver"/>
48 <provider android:name="com.foo.BarProvider"/>
49 </application>
50 <instrumentation android:name="com.foo.BarInstrumentation"/>
51 </manifest>)");
52
53 proguard::KeepSet set;
54 ASSERT_TRUE(proguard::CollectProguardRulesForManifest(manifest.get(), &set, false));
55
56 std::string actual = GetKeepSetString(set);
57
Jake Whartone4bd1602018-06-12 09:39:14 -040058 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarAppComponentFactory { <init>(); }"));
Jake Whartonab660a72018-06-08 17:56:55 -040059 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarBackupAgent { <init>(); }"));
Jake Whartoncfbc7672018-06-12 09:26:13 -040060 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarApplication { <init>(); }"));
Jake Whartonab660a72018-06-08 17:56:55 -040061 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarActivity { <init>(); }"));
62 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarService { <init>(); }"));
63 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarReceiver { <init>(); }"));
64 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarProvider { <init>(); }"));
65 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarInstrumentation { <init>(); }"));
66}
67
Adam Lesinskif762df22017-06-26 16:39:03 -070068TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
69 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
70 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
71 <fragment xmlns:android="http://schemas.android.com/apk/res/android"
72 android:name="com.foo.Bar"/>)");
73 layout->file.name = test::ParseNameOrDie("layout/foo");
74
75 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070076 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070077
Adam Lesinskia693c4a2017-11-09 11:29:39 -080078 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070079
Jake Wharton420785e2018-06-11 15:40:48 -040080 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -070081}
82
83TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
84 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
85 std::unique_ptr<xml::XmlResource> layout =
86 test::BuildXmlDom(R"(<fragment class="com.foo.Bar"/>)");
87 layout->file.name = test::ParseNameOrDie("layout/foo");
88
89 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070090 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070091
Adam Lesinskia693c4a2017-11-09 11:29:39 -080092 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070093
Jake Wharton420785e2018-06-11 15:40:48 -040094 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -070095}
96
97TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
98 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
99 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
100 <fragment xmlns:android="http://schemas.android.com/apk/res/android"
101 android:name="com.foo.Baz"
102 class="com.foo.Bar"/>)");
103 layout->file.name = test::ParseNameOrDie("layout/foo");
104
105 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700106 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700107
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800108 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700109
Jake Wharton420785e2018-06-11 15:40:48 -0400110 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
111 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700112}
113
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700114TEST(ProguardRulesTest, NavigationFragmentNameAndClassRulesAreEmitted) {
115 std::unique_ptr<IAaptContext> context = test::ContextBuilder()
116 .SetCompilationPackage("com.base").Build();
117 std::unique_ptr<xml::XmlResource> navigation = test::BuildXmlDom(R"(
118 <navigation
119 xmlns:android="http://schemas.android.com/apk/res/android"
120 xmlns:app="http://schemas.android.com/apk/res-auto">
121 <custom android:id="@id/foo"
122 android:name="com.package.Foo"/>
123 <fragment android:id="@id/bar"
124 android:name="com.package.Bar">
125 <nested android:id="@id/nested"
126 android:name=".Nested"/>
127 </fragment>
128 </navigation>
129 )");
130
131 navigation->file.name = test::ParseNameOrDie("navigation/graph.xml");
132
133 proguard::KeepSet set;
134 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), navigation.get(), &set));
135
136 std::string actual = GetKeepSetString(set);
Jake Wharton420785e2018-06-11 15:40:48 -0400137 EXPECT_THAT(actual, HasSubstr("-keep class com.package.Foo { <init>(...); }"));
138 EXPECT_THAT(actual, HasSubstr("-keep class com.package.Bar { <init>(...); }"));
139 EXPECT_THAT(actual, HasSubstr("-keep class com.base.Nested { <init>(...); }"));
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700140}
141
Adam Koskidc21dea2017-07-21 10:55:27 -0700142TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
143 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
144 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
145 <View xmlns:android="http://schemas.android.com/apk/res/android">
146 <com.foo.Bar />
147 </View>)");
148 layout->file.name = test::ParseNameOrDie("layout/foo");
149
150 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700151 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700152
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800153 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700154
Jake Wharton420785e2018-06-11 15:40:48 -0400155 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700156}
157
158TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
159 std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"(
160 <View xmlns:android="http://schemas.android.com/apk/res/android">
161 <com.foo.Bar />
162 </View>)");
163 bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar");
164
165 ResourceTable table;
166 StdErrDiagnostics errDiagnostics;
167 table.AddResource(bar_layout->file.name, ConfigDescription::DefaultConfig(), "",
168 util::make_unique<FileReference>(), &errDiagnostics);
169
170 std::unique_ptr<IAaptContext> context =
171 test::ContextBuilder()
172 .SetCompilationPackage("com.foo")
173 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table))
174 .Build();
175
176 std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"(
177 <View xmlns:android="http://schemas.android.com/apk/res/android">
178 <include layout="@layout/bar" />
179 </View>)");
180 foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo");
181
182 XmlReferenceLinker xml_linker;
183 ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get()));
184 ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));
185
186 proguard::KeepSet set = proguard::KeepSet(true);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700187 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), bar_layout.get(), &set));
188 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), foo_layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700189
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800190 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700191
Adam Koski09ef94e2017-11-10 11:15:55 -0800192 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800193 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700194 EXPECT_THAT(actual, HasSubstr("int foo"));
195 EXPECT_THAT(actual, HasSubstr("int bar"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700196}
197
198TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
199 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
200 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
201 <View xmlns:android="http://schemas.android.com/apk/res/android">
202 <com.foo.Bar />
203 </View>)");
204 layout->file.name = test::ParseNameOrDie("layout/foo");
205
206 proguard::KeepSet set = proguard::KeepSet(true);
207 set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700208 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700209
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800210 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700211
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800212 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koski09ef94e2017-11-10 11:15:55 -0800213 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700214 EXPECT_THAT(actual, HasSubstr("int foo"));
215 EXPECT_THAT(actual, HasSubstr("int bar"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700216}
217
218TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
219 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
220 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
221 <View xmlns:android="http://schemas.android.com/apk/res/android">
222 <com.foo.Bar />
223 </View>)");
224 layout->file.name = test::ParseNameOrDie("layout/foo");
225
226 proguard::KeepSet set = proguard::KeepSet(true);
227 set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700228 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700229
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800230 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700231
Adam Koski09ef94e2017-11-10 11:15:55 -0800232 EXPECT_THAT(actual, Not(HasSubstr("-if")));
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800233 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700234}
235
Adam Lesinskif762df22017-06-26 16:39:03 -0700236TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
237 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
238 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
239 <View xmlns:android="http://schemas.android.com/apk/res/android"
240 android:onClick="bar_method" />)");
241 layout->file.name = test::ParseNameOrDie("layout/foo");
242
243 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700244 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700245
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800246 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700247
Jake Wharton3001f032018-06-11 12:24:11 -0400248 EXPECT_THAT(actual, HasSubstr(
249 "-keepclassmembers class * { *** bar_method(android.view.View); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700250}
251
252TEST(ProguardRulesTest, MenuRulesAreEmitted) {
253 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
254 std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
255 <menu xmlns:android="http://schemas.android.com/apk/res/android">
256 <item android:onClick="on_click"
257 android:actionViewClass="com.foo.Bar"
258 android:actionProviderClass="com.foo.Baz"
259 android:name="com.foo.Bat" />
260 </menu>)");
261 menu->file.name = test::ParseNameOrDie("menu/foo");
262
263 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700264 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700265
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800266 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700267
Jake Wharton3001f032018-06-11 12:24:11 -0400268 EXPECT_THAT(actual, HasSubstr(
269 "-keepclassmembers class * { *** on_click(android.view.MenuItem); }"));
Jake Wharton420785e2018-06-11 15:40:48 -0400270 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
271 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700272 EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
273}
274
Jake Wharton420785e2018-06-11 15:40:48 -0400275TEST(ProguardRulesTest, TransitionPathMotionRulesAreEmitted) {
276 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
277 std::unique_ptr<xml::XmlResource> transition = test::BuildXmlDom(R"(
278 <changeBounds>
279 <pathMotion class="com.foo.Bar"/>
280 </changeBounds>)");
281 transition->file.name = test::ParseNameOrDie("transition/foo");
282
283 proguard::KeepSet set;
284 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transition.get(), &set));
285
286 std::string actual = GetKeepSetString(set);
287
288 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
289}
290
291TEST(ProguardRulesTest, TransitionRulesAreEmitted) {
292 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
293 std::unique_ptr<xml::XmlResource> transitionSet = test::BuildXmlDom(R"(
294 <transitionSet>
295 <transition class="com.foo.Bar"/>
296 </transitionSet>)");
297 transitionSet->file.name = test::ParseNameOrDie("transition/foo");
298
299 proguard::KeepSet set;
300 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transitionSet.get(), &set));
301
302 std::string actual = GetKeepSetString(set);
303
304 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
305}
306
Adam Lesinskif762df22017-06-26 16:39:03 -0700307} // namespace aapt