• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 "androidfw/AssetManager2.h"
18 
19 #include "android-base/logging.h"
20 
21 #include "TestHelpers.h"
22 #include "androidfw/ResourceUtils.h"
23 #include "data/lib_one/R.h"
24 #include "data/lib_two/R.h"
25 #include "data/libclient/R.h"
26 #include "data/styles/R.h"
27 #include "data/system/R.h"
28 
29 namespace app = com::android::app;
30 namespace lib_one = com::android::lib_one;
31 namespace lib_two = com::android::lib_two;
32 namespace libclient = com::android::libclient;
33 
34 namespace android {
35 
36 class ThemeTest : public ::testing::Test {
37  public:
SetUp()38   void SetUp() override {
39     system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", PROPERTY_SYSTEM);
40     ASSERT_NE(nullptr, system_assets_);
41 
42     style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
43     ASSERT_NE(nullptr, style_assets_);
44 
45     libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
46     ASSERT_NE(nullptr, libclient_assets_);
47 
48     lib_one_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_one/lib_one.apk");
49     ASSERT_NE(nullptr, lib_one_assets_);
50 
51     lib_two_assets_ = ApkAssets::Load(GetTestDataPath() + "/lib_two/lib_two.apk");
52     ASSERT_NE(nullptr, lib_two_assets_);
53   }
54 
55  protected:
56   AssetManager2::ApkAssetsPtr system_assets_;
57   AssetManager2::ApkAssetsPtr style_assets_;
58   AssetManager2::ApkAssetsPtr libclient_assets_;
59   AssetManager2::ApkAssetsPtr lib_one_assets_;
60   AssetManager2::ApkAssetsPtr lib_two_assets_;
61 };
62 
TEST_F(ThemeTest,EmptyTheme)63 TEST_F(ThemeTest, EmptyTheme) {
64   AssetManager2 assetmanager;
65   assetmanager.SetApkAssets({style_assets_});
66 
67   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
68   EXPECT_EQ(0u, theme->GetChangingConfigurations());
69   EXPECT_EQ(&assetmanager, theme->GetAssetManager());
70   EXPECT_FALSE(theme->GetAttribute(app::R::attr::attr_one).has_value());
71 }
72 
TEST_F(ThemeTest,SingleThemeNoParent)73 TEST_F(ThemeTest, SingleThemeNoParent) {
74   AssetManager2 assetmanager;
75   assetmanager.SetApkAssets({style_assets_});
76 
77   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
78   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne).has_value());
79 
80   auto value = theme->GetAttribute(app::R::attr::attr_one);
81   ASSERT_TRUE(value);
82   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
83   EXPECT_EQ(1u, value->data);
84   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
85 
86   value = theme->GetAttribute(app::R::attr::attr_two);
87   ASSERT_TRUE(value);
88   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
89   EXPECT_EQ(2u, value->data);
90   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
91 }
92 
TEST_F(ThemeTest,SingleThemeWithParent)93 TEST_F(ThemeTest, SingleThemeWithParent) {
94   AssetManager2 assetmanager;
95   assetmanager.SetApkAssets({style_assets_});
96 
97   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
98   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
99 
100   auto value = theme->GetAttribute(app::R::attr::attr_one);
101   ASSERT_TRUE(value);
102   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
103   EXPECT_EQ(1u, value->data);
104   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
105 
106   value = theme->GetAttribute(app::R::attr::attr_two);
107   ASSERT_TRUE(value);
108   EXPECT_EQ(Res_value::TYPE_STRING, value->type);
109   EXPECT_EQ(0, value->cookie);
110   EXPECT_EQ(std::string("string"),
111             GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value->data));
112   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
113 
114   // This attribute should point to an attr_indirect, so the result should be 3.
115   value = theme->GetAttribute(app::R::attr::attr_three);
116   ASSERT_TRUE(value);
117   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
118   EXPECT_EQ(3u, value->data);
119   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
120 }
121 
TEST_F(ThemeTest,TryToUseBadResourceId)122 TEST_F(ThemeTest, TryToUseBadResourceId) {
123   AssetManager2 assetmanager;
124   assetmanager.SetApkAssets({style_assets_});
125 
126   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
127   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
128   ASSERT_FALSE(theme->GetAttribute(0x7f000001));
129 }
130 
TEST_F(ThemeTest,MultipleThemesOverlaidNotForce)131 TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
132   AssetManager2 assetmanager;
133   assetmanager.SetApkAssets({style_assets_});
134 
135   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
136   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
137   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree).has_value());
138 
139   // attr_one is still here from the base.
140   auto value = theme->GetAttribute(app::R::attr::attr_one);
141   ASSERT_TRUE(value);
142   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
143   EXPECT_EQ(1u, value->data);
144   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
145 
146   // check for the new attr_six
147   value = theme->GetAttribute(app::R::attr::attr_six);
148   ASSERT_TRUE(value);
149   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
150   EXPECT_EQ(6u, value->data);
151   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
152 
153   // check for the old attr_five (force=true was not used).
154   value = theme->GetAttribute(app::R::attr::attr_five);
155   ASSERT_TRUE(value);
156   EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
157   EXPECT_EQ(app::R::string::string_one, value->data);
158   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
159 }
160 
TEST_F(ThemeTest,MultipleThemesOverlaidForced)161 TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
162   AssetManager2 assetmanager;
163   assetmanager.SetApkAssets({style_assets_});
164 
165   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
166   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
167   ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */).has_value());
168 
169   // attr_one is still here from the base.
170   auto value = theme->GetAttribute(app::R::attr::attr_one);
171   ASSERT_TRUE(value);
172   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
173   EXPECT_EQ(1u, value->data);
174   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
175 
176   // check for the new attr_six
177   value = theme->GetAttribute(app::R::attr::attr_six);
178   ASSERT_TRUE(value);
179   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
180   EXPECT_EQ(6u, value->data);
181   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
182 
183   // check for the new attr_five (force=true was used).
184   value = theme->GetAttribute(app::R::attr::attr_five);
185   ASSERT_TRUE(value);
186   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
187   EXPECT_EQ(5u, value->data);
188   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
189 }
190 
TEST_F(ThemeTest,ResolveDynamicAttributesAndReferencesToSharedLibrary)191 TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
192   AssetManager2 assetmanager;
193   assetmanager.SetApkAssets({lib_two_assets_, lib_one_assets_, libclient_assets_});
194 
195   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
196   ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/).has_value());
197 
198   // The attribute should be resolved to the final value.
199   auto value = theme->GetAttribute(libclient::R::attr::foo);
200   ASSERT_TRUE(value);
201   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
202   EXPECT_EQ(700u, value->data);
203   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
204 
205   // The reference should be resolved to a TYPE_REFERENCE.
206   value = theme->GetAttribute(libclient::R::attr::bar);
207   ASSERT_TRUE(value);
208   EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
209 
210   // lib_one is assigned package ID 0x03.
211   EXPECT_EQ(3u, get_package_id(value->data));
212   EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value->data));
213   EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value->data));
214 }
215 
TEST_F(ThemeTest,CopyThemeSameAssetManager)216 TEST_F(ThemeTest, CopyThemeSameAssetManager) {
217   AssetManager2 assetmanager;
218   assetmanager.SetApkAssets({style_assets_});
219 
220   std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
221   ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne).has_value());
222 
223   // attr_one is still here from the base.
224   auto value = theme_one->GetAttribute(app::R::attr::attr_one);
225   ASSERT_TRUE(value);
226   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
227   EXPECT_EQ(1u, value->data);
228   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
229 
230   // attr_six is not here.
231   ASSERT_FALSE(theme_one->GetAttribute(app::R::attr::attr_six).has_value());
232 
233   std::unique_ptr<Theme> theme_two = assetmanager.NewTheme();
234   ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree).has_value());
235 
236   // Copy the theme to theme_one.
237   theme_one->SetTo(*theme_two);
238 
239   // Clear theme_two to make sure we test that there WAS a copy.
240   theme_two->Clear();
241 
242   // attr_one is now not here.
243   ASSERT_FALSE(theme_one->GetAttribute(app::R::attr::attr_one).has_value());
244 
245   // attr_six is now here because it was copied.
246   value = theme_one->GetAttribute(app::R::attr::attr_six);
247   ASSERT_TRUE(value);
248   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
249   EXPECT_EQ(6u, value->data);
250   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
251 }
252 
TEST_F(ThemeTest,ThemeRebase)253 TEST_F(ThemeTest, ThemeRebase) {
254   AssetManager2 am;
255   am.SetApkAssets({style_assets_});
256 
257   AssetManager2 am_night;
258   am_night.SetApkAssets({style_assets_});
259 
260   ResTable_config night{};
261   night.uiMode = ResTable_config::UI_MODE_NIGHT_YES;
262   night.version = 8u;
263   am_night.SetConfigurations({night});
264 
265   auto theme = am.NewTheme();
266   {
267     const uint32_t styles[] = {app::R::style::StyleOne, app::R::style::StyleDayNight};
268     const uint8_t force[] = {true, true};
269     theme->Rebase(&am, styles, force, arraysize(styles));
270   }
271 
272   // attr_one in StyleDayNight force overrides StyleOne. attr_one is defined in the StyleOne.
273   auto value = theme->GetAttribute(app::R::attr::attr_one);
274   ASSERT_TRUE(value);
275   EXPECT_EQ(10u, value->data);
276   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_UI_MODE |
277             ResTable_config::CONFIG_VERSION), value->flags);
278 
279   // attr_two is defined in the StyleOne.
280   value = theme->GetAttribute(app::R::attr::attr_two);
281   ASSERT_TRUE(value);
282   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
283   EXPECT_EQ(2u, value->data);
284   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
285 
286   {
287     const uint32_t styles[] = {app::R::style::StyleOne, app::R::style::StyleDayNight};
288     const uint8_t force[] = {false, false};
289     theme->Rebase(&am, styles, force, arraysize(styles));
290   }
291 
292   // attr_one in StyleDayNight does not override StyleOne because `force` is false.
293   value = theme->GetAttribute(app::R::attr::attr_one);
294   ASSERT_TRUE(value);
295   EXPECT_EQ(1u, value->data);
296   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
297 
298   // attr_two is defined in the StyleOne.
299   value = theme->GetAttribute(app::R::attr::attr_two);
300   ASSERT_TRUE(value);
301   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
302   EXPECT_EQ(2u, value->data);
303   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
304 
305   {
306     const uint32_t styles[] = {app::R::style::StyleOne, app::R::style::StyleDayNight};
307     const uint8_t force[] = {false, true};
308     theme->Rebase(&am_night, styles, force, arraysize(styles));
309   }
310 
311   // attr_one is defined in the StyleDayNight.
312   value = theme->GetAttribute(app::R::attr::attr_one);
313   ASSERT_TRUE(value);
314   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
315   EXPECT_EQ(100u, value->data);
316   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_UI_MODE |
317             ResTable_config::CONFIG_VERSION), value->flags);
318 
319   // attr_two is now not here.
320   value = theme->GetAttribute(app::R::attr::attr_two);
321   ASSERT_TRUE(value);
322   EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
323   EXPECT_EQ(2u, value->data);
324   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
325 }
326 
TEST_F(ThemeTest,OnlyCopySameAssetsThemeWhenAssetManagersDiffer)327 TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
328   AssetManager2 assetmanager_dst;
329   assetmanager_dst.SetApkAssets(
330       {system_assets_, lib_one_assets_, style_assets_, libclient_assets_});
331 
332   AssetManager2 assetmanager_src;
333   assetmanager_src.SetApkAssets({system_assets_, lib_two_assets_, lib_one_assets_, style_assets_});
334 
335   auto theme_dst = assetmanager_dst.NewTheme();
336   ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne).has_value());
337 
338   auto theme_src = assetmanager_src.NewTheme();
339   ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One).has_value());
340   ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo).has_value());
341   ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
342                                     false /*force*/).has_value());
343   ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
344                                     false /*force*/).has_value());
345 
346   theme_dst->SetTo(*theme_src);
347 
348   // System resources (present in destination asset manager).
349   auto value = theme_dst->GetAttribute(R::attr::foreground);
350   ASSERT_TRUE(value.has_value());
351   EXPECT_EQ(0, value->cookie);
352 
353   // The cookie of the style asset is 3 in the source and 2 in the destination.
354   // Check that the cookie has been rewritten to the destination values.
355   value = theme_dst->GetAttribute(app::R::attr::attr_one);
356   ASSERT_TRUE(value.has_value());
357   EXPECT_EQ(2, value->cookie);
358 
359   // The cookie of the lib_one asset is 2 in the source and 1 in the destination.
360   // The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
361   // Check that the cookie and packages have been rewritten to the destination values.
362   value = theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02));
363   ASSERT_TRUE(value.has_value());
364   EXPECT_EQ(1, value->cookie);
365 
366   value = theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02));
367   ASSERT_TRUE(value.has_value());
368   EXPECT_EQ(1, value->cookie);
369 
370   // attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
371   // correct after the value of attr2 had its package id rewritten to the destination package id.
372   EXPECT_EQ(700, value->data);
373 }
374 
TEST_F(ThemeTest,CopyNonReferencesWhenPackagesDiffer)375 TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
376   AssetManager2 assetmanager_dst;
377   assetmanager_dst.SetApkAssets({system_assets_});
378 
379   AssetManager2 assetmanager_src;
380   assetmanager_src.SetApkAssets({system_assets_, style_assets_});
381 
382   auto theme_dst = assetmanager_dst.NewTheme();
383   auto theme_src = assetmanager_src.NewTheme();
384   ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven).has_value());
385   theme_dst->SetTo(*theme_src);
386 
387   // Allow inline resource values to be copied even if the source apk asset is not present in the
388   // destination.
389   auto value = theme_dst->GetAttribute(0x0101021b /* android:versionCode */);
390   ASSERT_TRUE(value.has_value());
391   EXPECT_EQ(0, value->cookie);
392 
393   // Do not copy strings since the data is an index into the values string pool of the source apk
394   // asset.
395   EXPECT_FALSE(theme_dst->GetAttribute(0x01010001 /* android:label */).has_value());
396 
397   // Do not copy values that reference another resource if the resource is not present in the
398   // destination.
399   EXPECT_FALSE(theme_dst->GetAttribute(0x01010002 /* android:icon */).has_value());
400   EXPECT_FALSE(theme_dst->GetAttribute(0x010100d1 /* android:tag */).has_value());
401 
402   // Allow @empty to and @null to be copied.
403   value = theme_dst->GetAttribute(0x010100d0 /* android:id */);
404   ASSERT_TRUE(value.has_value());
405   EXPECT_EQ(0, value->cookie);
406 
407   value = theme_dst->GetAttribute(0x01010000 /* android:theme */);
408   ASSERT_TRUE(value.has_value());
409   EXPECT_EQ(0, value->cookie);
410 }
411 
412 }  // namespace android
413