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/AttributeResolution.h"
18 
19 #include <array>
20 
21 #include "android-base/file.h"
22 #include "android-base/logging.h"
23 #include "android-base/macros.h"
24 #include "androidfw/AssetManager2.h"
25 #include "androidfw/ResourceUtils.h"
26 
27 #include "TestHelpers.h"
28 #include "data/styles/R.h"
29 
30 using com::android::app::R;
31 
32 namespace android {
33 
34 class AttributeResolutionTest : public ::testing::Test {
35  public:
SetUp()36   virtual void SetUp() override {
37     styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
38     ASSERT_NE(nullptr, styles_assets_);
39     assetmanager_.SetApkAssets({styles_assets_.get()});
40   }
41 
42  protected:
43   std::unique_ptr<const ApkAssets> styles_assets_;
44   AssetManager2 assetmanager_;
45 };
46 
47 class AttributeResolutionXmlTest : public AttributeResolutionTest {
48  public:
SetUp()49   virtual void SetUp() override {
50     AttributeResolutionTest::SetUp();
51 
52     std::unique_ptr<Asset> asset =
53         assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
54     ASSERT_NE(nullptr, asset);
55 
56     ASSERT_EQ(NO_ERROR,
57               xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/));
58 
59     // Skip to the first tag.
60     while (xml_parser_.next() != ResXMLParser::START_TAG) {
61     }
62   }
63 
64  protected:
65   ResXMLTree xml_parser_;
66 };
67 
TEST(AttributeResolutionLibraryTest,ApplyStyleWithDefaultStyleResId)68 TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
69   AssetManager2 assetmanager;
70   auto apk_assets = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk", PROPERTY_DYNAMIC);
71   ASSERT_NE(nullptr, apk_assets);
72   assetmanager.SetApkAssets({apk_assets.get()});
73 
74   std::unique_ptr<Theme> theme = assetmanager.NewTheme();
75 
76   std::array<uint32_t, 2> attrs{
77       {fix_package_id(R::attr::attr_one, 0x02), fix_package_id(R::attr::attr_two, 0x02)}};
78   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
79   std::array<uint32_t, attrs.size() + 1> indices;
80   ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
81              fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(), values.data(),
82              indices.data());
83 
84   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
85 
86   const uint32_t* values_cursor = values.data();
87   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
88   EXPECT_EQ(1u, values_cursor[STYLE_DATA]);
89   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
90   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
91   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
92   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
93 
94   values_cursor += STYLE_NUM_ENTRIES;
95   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
96   EXPECT_EQ(2u, values_cursor[STYLE_DATA]);
97   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
98   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
99   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
100   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
101 }
102 
TEST_F(AttributeResolutionTest,Theme)103 TEST_F(AttributeResolutionTest, Theme) {
104   std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
105   ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
106 
107   std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
108                                  R::attr::attr_four, R::attr::attr_empty}};
109   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
110 
111   ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
112                            nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
113                            attrs.size(), values.data(), nullptr /*out_indices*/));
114 
115   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
116 
117   const uint32_t* values_cursor = values.data();
118   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
119   EXPECT_EQ(1u, values_cursor[STYLE_DATA]);
120   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
121   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
122   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
123   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
124 
125   values_cursor += STYLE_NUM_ENTRIES;
126   EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]);
127   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
128   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
129   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
130   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
131 
132   values_cursor += STYLE_NUM_ENTRIES;
133   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
134   EXPECT_EQ(3u, values_cursor[STYLE_DATA]);
135   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
136   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
137   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
138   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
139 
140   values_cursor += STYLE_NUM_ENTRIES;
141   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
142   EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]);
143   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
144   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
145   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
146   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
147 
148   // @empty comes from the theme, so it has the same asset cookie and changing configurations flags
149   // as the theme.
150   values_cursor += STYLE_NUM_ENTRIES;
151   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
152   EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
153   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
154   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
155   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
156   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
157 }
158 
TEST_F(AttributeResolutionXmlTest,XmlParser)159 TEST_F(AttributeResolutionXmlTest, XmlParser) {
160   std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
161                                  R::attr::attr_four, R::attr::attr_empty}};
162   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
163 
164   ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
165                                  values.data(), nullptr /*out_indices*/));
166 
167   uint32_t* values_cursor = values.data();
168   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
169   EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
170   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
171   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
172   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
173   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
174 
175   values_cursor += STYLE_NUM_ENTRIES;
176   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
177   EXPECT_EQ(0u, values_cursor[STYLE_DATA]);
178   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
179   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
180   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
181   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
182 
183   values_cursor += STYLE_NUM_ENTRIES;
184   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
185   EXPECT_EQ(10u, values_cursor[STYLE_DATA]);
186   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
187   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
188   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
189   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
190 
191   values_cursor += STYLE_NUM_ENTRIES;
192   EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, values_cursor[STYLE_TYPE]);
193   EXPECT_EQ(R::attr::attr_indirect, values_cursor[STYLE_DATA]);
194   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
195   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
196   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
197   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
198 
199   values_cursor += STYLE_NUM_ENTRIES;
200   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
201   EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]);
202   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
203   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
204   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
205   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
206 }
207 
TEST_F(AttributeResolutionXmlTest,ThemeAndXmlParser)208 TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
209   std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
210   ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
211 
212   std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
213                                  R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
214   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
215   std::array<uint32_t, attrs.size() + 1> indices;
216 
217   ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
218              attrs.size(), values.data(), indices.data());
219 
220   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
221 
222   uint32_t* values_cursor = values.data();
223   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
224   EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
225   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
226   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
227   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
228   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
229 
230   values_cursor += STYLE_NUM_ENTRIES;
231   EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]);
232   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
233   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
234   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
235   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
236 
237   values_cursor += STYLE_NUM_ENTRIES;
238   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
239   EXPECT_EQ(10u, values_cursor[STYLE_DATA]);
240   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
241   EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
242   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
243   EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
244 
245   values_cursor += STYLE_NUM_ENTRIES;
246   EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
247   EXPECT_EQ(3u, values_cursor[STYLE_DATA]);
248   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
249   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
250   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
251   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
252 
253   values_cursor += STYLE_NUM_ENTRIES;
254   EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]);
255   EXPECT_EQ(R::string::string_one, values_cursor[STYLE_RESOURCE_ID]);
256   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
257   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
258   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
259 
260   // @empty comes from the theme, so it has the same asset cookie and changing configurations flags
261   // as the theme.
262   values_cursor += STYLE_NUM_ENTRIES;
263   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
264   EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
265   EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
266   EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
267   EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
268   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
269 
270   // The first element of indices contains the number of indices.
271   std::array<uint32_t, 7> expected_indices = {{6u, 0u, 1u, 2u, 3u, 4u, 5u}};
272   EXPECT_EQ(expected_indices, indices);
273 }
274 
275 } // namespace android
276 
277