blob: 83c72d89bb62cd2a6b6ba341cb83f87d9ffb26c5 [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 Wharton98100c32018-06-11 15:46:03 -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 Wharton98100c32018-06-11 15:46:03 -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 Wharton98100c32018-06-11 15:46:03 -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 Whartoncc65b8d2018-06-11 17:05:35 -0400155 EXPECT_THAT(actual, HasSubstr(
156 "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700157}
158
159TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
160 std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"(
161 <View xmlns:android="http://schemas.android.com/apk/res/android">
162 <com.foo.Bar />
163 </View>)");
164 bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar");
165
166 ResourceTable table;
167 StdErrDiagnostics errDiagnostics;
168 table.AddResource(bar_layout->file.name, ConfigDescription::DefaultConfig(), "",
169 util::make_unique<FileReference>(), &errDiagnostics);
170
171 std::unique_ptr<IAaptContext> context =
172 test::ContextBuilder()
173 .SetCompilationPackage("com.foo")
174 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table))
175 .Build();
176
177 std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"(
178 <View xmlns:android="http://schemas.android.com/apk/res/android">
179 <include layout="@layout/bar" />
180 </View>)");
181 foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo");
182
183 XmlReferenceLinker xml_linker;
184 ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get()));
185 ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));
186
187 proguard::KeepSet set = proguard::KeepSet(true);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700188 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), bar_layout.get(), &set));
189 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), foo_layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700190
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800191 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700192
Adam Koski09ef94e2017-11-10 11:15:55 -0800193 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Jake Whartoncc65b8d2018-06-11 17:05:35 -0400194 EXPECT_THAT(actual, HasSubstr(
195 "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700196 EXPECT_THAT(actual, HasSubstr("int foo"));
197 EXPECT_THAT(actual, HasSubstr("int bar"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700198}
199
200TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
201 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
202 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
203 <View xmlns:android="http://schemas.android.com/apk/res/android">
204 <com.foo.Bar />
205 </View>)");
206 layout->file.name = test::ParseNameOrDie("layout/foo");
207
208 proguard::KeepSet set = proguard::KeepSet(true);
209 set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700210 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700211
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800212 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700213
Jake Whartoncc65b8d2018-06-11 17:05:35 -0400214 EXPECT_THAT(actual, HasSubstr(
215 "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
Adam Koski09ef94e2017-11-10 11:15:55 -0800216 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700217 EXPECT_THAT(actual, HasSubstr("int foo"));
218 EXPECT_THAT(actual, HasSubstr("int bar"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700219}
220
221TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
222 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
223 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
224 <View xmlns:android="http://schemas.android.com/apk/res/android">
225 <com.foo.Bar />
226 </View>)");
227 layout->file.name = test::ParseNameOrDie("layout/foo");
228
229 proguard::KeepSet set = proguard::KeepSet(true);
230 set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700231 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700232
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800233 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700234
Adam Koski09ef94e2017-11-10 11:15:55 -0800235 EXPECT_THAT(actual, Not(HasSubstr("-if")));
Jake Whartoncc65b8d2018-06-11 17:05:35 -0400236 EXPECT_THAT(actual, HasSubstr(
237 "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700238}
239
Adam Lesinskif762df22017-06-26 16:39:03 -0700240TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
241 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
242 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
243 <View xmlns:android="http://schemas.android.com/apk/res/android"
244 android:onClick="bar_method" />)");
245 layout->file.name = test::ParseNameOrDie("layout/foo");
246
247 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700248 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700249
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800250 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700251
Jake Wharton3001f032018-06-11 12:24:11 -0400252 EXPECT_THAT(actual, HasSubstr(
253 "-keepclassmembers class * { *** bar_method(android.view.View); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700254}
255
256TEST(ProguardRulesTest, MenuRulesAreEmitted) {
257 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
258 std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
259 <menu xmlns:android="http://schemas.android.com/apk/res/android">
260 <item android:onClick="on_click"
261 android:actionViewClass="com.foo.Bar"
262 android:actionProviderClass="com.foo.Baz"
263 android:name="com.foo.Bat" />
264 </menu>)");
265 menu->file.name = test::ParseNameOrDie("menu/foo");
266
267 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700268 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700269
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800270 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700271
Jake Wharton3001f032018-06-11 12:24:11 -0400272 EXPECT_THAT(actual, HasSubstr(
273 "-keepclassmembers class * { *** on_click(android.view.MenuItem); }"));
Jake Wharton98100c32018-06-11 15:46:03 -0400274 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(android.content.Context); }"));
275 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(android.content.Context); }"));
Adam Lesinskif762df22017-06-26 16:39:03 -0700276 EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
277}
278
Jake Wharton420785e2018-06-11 15:40:48 -0400279TEST(ProguardRulesTest, TransitionPathMotionRulesAreEmitted) {
280 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
281 std::unique_ptr<xml::XmlResource> transition = test::BuildXmlDom(R"(
282 <changeBounds>
283 <pathMotion class="com.foo.Bar"/>
284 </changeBounds>)");
285 transition->file.name = test::ParseNameOrDie("transition/foo");
286
287 proguard::KeepSet set;
288 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transition.get(), &set));
289
290 std::string actual = GetKeepSetString(set);
291
Jake Wharton98100c32018-06-11 15:46:03 -0400292 EXPECT_THAT(actual, HasSubstr(
293 "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
Jake Wharton420785e2018-06-11 15:40:48 -0400294}
295
296TEST(ProguardRulesTest, TransitionRulesAreEmitted) {
297 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
298 std::unique_ptr<xml::XmlResource> transitionSet = test::BuildXmlDom(R"(
299 <transitionSet>
300 <transition class="com.foo.Bar"/>
301 </transitionSet>)");
302 transitionSet->file.name = test::ParseNameOrDie("transition/foo");
303
304 proguard::KeepSet set;
305 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transitionSet.get(), &set));
306
307 std::string actual = GetKeepSetString(set);
308
Jake Wharton98100c32018-06-11 15:46:03 -0400309 EXPECT_THAT(actual, HasSubstr(
310 "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
Jake Wharton420785e2018-06-11 15:40:48 -0400311}
312
Adam Lesinskif762df22017-06-26 16:39:03 -0700313} // namespace aapt