blob: 6e0df50bd9c40e8d27a7c8e9e515d102dbb4cfe8 [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
41 android:backupAgent="com.foo.BarBackupAgent"
42 android:name="com.foo.BarApplication"
43 >
Jake Whartonab660a72018-06-08 17:56:55 -040044 <activity android:name="com.foo.BarActivity"/>
45 <service android:name="com.foo.BarService"/>
46 <receiver android:name="com.foo.BarReceiver"/>
47 <provider android:name="com.foo.BarProvider"/>
48 </application>
49 <instrumentation android:name="com.foo.BarInstrumentation"/>
50 </manifest>)");
51
52 proguard::KeepSet set;
53 ASSERT_TRUE(proguard::CollectProguardRulesForManifest(manifest.get(), &set, false));
54
55 std::string actual = GetKeepSetString(set);
56
57 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarBackupAgent { <init>(); }"));
Jake Whartoncfbc7672018-06-12 09:26:13 -040058 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarApplication { <init>(); }"));
Jake Whartonab660a72018-06-08 17:56:55 -040059 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarActivity { <init>(); }"));
60 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarService { <init>(); }"));
61 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarReceiver { <init>(); }"));
62 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarProvider { <init>(); }"));
63 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarInstrumentation { <init>(); }"));
64}
65
Adam Lesinskif762df22017-06-26 16:39:03 -070066TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
67 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
68 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
69 <fragment xmlns:android="http://schemas.android.com/apk/res/android"
70 android:name="com.foo.Bar"/>)");
71 layout->file.name = test::ParseNameOrDie("layout/foo");
72
73 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070074 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070075
Adam Lesinskia693c4a2017-11-09 11:29:39 -080076 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070077
Jake Wharton420785e2018-06-11 15:40:48 -040078 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -070079}
80
81TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
82 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
83 std::unique_ptr<xml::XmlResource> layout =
84 test::BuildXmlDom(R"(<fragment class="com.foo.Bar"/>)");
85 layout->file.name = test::ParseNameOrDie("layout/foo");
86
87 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070088 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070089
Adam Lesinskia693c4a2017-11-09 11:29:39 -080090 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070091
Jake Wharton420785e2018-06-11 15:40:48 -040092 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -070093}
94
95TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
96 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
97 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
98 <fragment xmlns:android="http://schemas.android.com/apk/res/android"
99 android:name="com.foo.Baz"
100 class="com.foo.Bar"/>)");
101 layout->file.name = test::ParseNameOrDie("layout/foo");
102
103 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700104 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700105
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800106 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700107
Jake Wharton420785e2018-06-11 15:40:48 -0400108 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
109 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700110}
111
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700112TEST(ProguardRulesTest, NavigationFragmentNameAndClassRulesAreEmitted) {
113 std::unique_ptr<IAaptContext> context = test::ContextBuilder()
114 .SetCompilationPackage("com.base").Build();
115 std::unique_ptr<xml::XmlResource> navigation = test::BuildXmlDom(R"(
116 <navigation
117 xmlns:android="http://schemas.android.com/apk/res/android"
118 xmlns:app="http://schemas.android.com/apk/res-auto">
119 <custom android:id="@id/foo"
120 android:name="com.package.Foo"/>
121 <fragment android:id="@id/bar"
122 android:name="com.package.Bar">
123 <nested android:id="@id/nested"
124 android:name=".Nested"/>
125 </fragment>
126 </navigation>
127 )");
128
129 navigation->file.name = test::ParseNameOrDie("navigation/graph.xml");
130
131 proguard::KeepSet set;
132 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), navigation.get(), &set));
133
134 std::string actual = GetKeepSetString(set);
Jake Wharton420785e2018-06-11 15:40:48 -0400135 EXPECT_THAT(actual, HasSubstr("-keep class com.package.Foo { <init>(...); }"));
136 EXPECT_THAT(actual, HasSubstr("-keep class com.package.Bar { <init>(...); }"));
137 EXPECT_THAT(actual, HasSubstr("-keep class com.base.Nested { <init>(...); }"));
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700138}
139
Adam Koskidc21dea2017-07-21 10:55:27 -0700140TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
141 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
142 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
143 <View xmlns:android="http://schemas.android.com/apk/res/android">
144 <com.foo.Bar />
145 </View>)");
146 layout->file.name = test::ParseNameOrDie("layout/foo");
147
148 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700149 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700150
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800151 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700152
Jake Wharton420785e2018-06-11 15:40:48 -0400153 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700154}
155
156TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
157 std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"(
158 <View xmlns:android="http://schemas.android.com/apk/res/android">
159 <com.foo.Bar />
160 </View>)");
161 bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar");
162
163 ResourceTable table;
164 StdErrDiagnostics errDiagnostics;
165 table.AddResource(bar_layout->file.name, ConfigDescription::DefaultConfig(), "",
166 util::make_unique<FileReference>(), &errDiagnostics);
167
168 std::unique_ptr<IAaptContext> context =
169 test::ContextBuilder()
170 .SetCompilationPackage("com.foo")
171 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table))
172 .Build();
173
174 std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"(
175 <View xmlns:android="http://schemas.android.com/apk/res/android">
176 <include layout="@layout/bar" />
177 </View>)");
178 foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo");
179
180 XmlReferenceLinker xml_linker;
181 ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get()));
182 ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));
183
184 proguard::KeepSet set = proguard::KeepSet(true);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700185 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), bar_layout.get(), &set));
186 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), foo_layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700187
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800188 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700189
Adam Koski09ef94e2017-11-10 11:15:55 -0800190 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800191 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700192 EXPECT_THAT(actual, HasSubstr("int foo"));
193 EXPECT_THAT(actual, HasSubstr("int bar"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700194}
195
196TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
197 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
198 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
199 <View xmlns:android="http://schemas.android.com/apk/res/android">
200 <com.foo.Bar />
201 </View>)");
202 layout->file.name = test::ParseNameOrDie("layout/foo");
203
204 proguard::KeepSet set = proguard::KeepSet(true);
205 set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700206 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700207
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800208 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700209
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800210 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koski09ef94e2017-11-10 11:15:55 -0800211 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700212 EXPECT_THAT(actual, HasSubstr("int foo"));
213 EXPECT_THAT(actual, HasSubstr("int bar"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700214}
215
216TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
217 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
218 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
219 <View xmlns:android="http://schemas.android.com/apk/res/android">
220 <com.foo.Bar />
221 </View>)");
222 layout->file.name = test::ParseNameOrDie("layout/foo");
223
224 proguard::KeepSet set = proguard::KeepSet(true);
225 set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700226 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700227
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800228 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700229
Adam Koski09ef94e2017-11-10 11:15:55 -0800230 EXPECT_THAT(actual, Not(HasSubstr("-if")));
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800231 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700232}
233
Adam Lesinskif762df22017-06-26 16:39:03 -0700234TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
235 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
236 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
237 <View xmlns:android="http://schemas.android.com/apk/res/android"
238 android:onClick="bar_method" />)");
239 layout->file.name = test::ParseNameOrDie("layout/foo");
240
241 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700242 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700243
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800244 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700245
Jake Wharton3001f032018-06-11 12:24:11 -0400246 EXPECT_THAT(actual, HasSubstr(
247 "-keepclassmembers class * { *** bar_method(android.view.View); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700248}
249
250TEST(ProguardRulesTest, MenuRulesAreEmitted) {
251 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
252 std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
253 <menu xmlns:android="http://schemas.android.com/apk/res/android">
254 <item android:onClick="on_click"
255 android:actionViewClass="com.foo.Bar"
256 android:actionProviderClass="com.foo.Baz"
257 android:name="com.foo.Bat" />
258 </menu>)");
259 menu->file.name = test::ParseNameOrDie("menu/foo");
260
261 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700262 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700263
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800264 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700265
Jake Wharton3001f032018-06-11 12:24:11 -0400266 EXPECT_THAT(actual, HasSubstr(
267 "-keepclassmembers class * { *** on_click(android.view.MenuItem); }"));
Jake Wharton420785e2018-06-11 15:40:48 -0400268 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
269 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700270 EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
271}
272
Jake Wharton420785e2018-06-11 15:40:48 -0400273TEST(ProguardRulesTest, TransitionPathMotionRulesAreEmitted) {
274 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
275 std::unique_ptr<xml::XmlResource> transition = test::BuildXmlDom(R"(
276 <changeBounds>
277 <pathMotion class="com.foo.Bar"/>
278 </changeBounds>)");
279 transition->file.name = test::ParseNameOrDie("transition/foo");
280
281 proguard::KeepSet set;
282 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transition.get(), &set));
283
284 std::string actual = GetKeepSetString(set);
285
286 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
287}
288
289TEST(ProguardRulesTest, TransitionRulesAreEmitted) {
290 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
291 std::unique_ptr<xml::XmlResource> transitionSet = test::BuildXmlDom(R"(
292 <transitionSet>
293 <transition class="com.foo.Bar"/>
294 </transitionSet>)");
295 transitionSet->file.name = test::ParseNameOrDie("transition/foo");
296
297 proguard::KeepSet set;
298 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transitionSet.get(), &set));
299
300 std::string actual = GetKeepSetString(set);
301
302 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
303}
304
Adam Lesinskif762df22017-06-26 16:39:03 -0700305} // namespace aapt