• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "format/binary/ResEntryWriter.h"
18 
19 #include "androidfw/BigBuffer.h"
20 #include "format/binary/ResourceTypeExtensions.h"
21 #include "test/Test.h"
22 #include "util/Util.h"
23 
24 using ::android::BigBuffer;
25 using ::android::Res_value;
26 using ::android::ResTable_map;
27 using ::testing::Eq;
28 using ::testing::Ge;
29 using ::testing::IsNull;
30 using ::testing::Ne;
31 using ::testing::NotNull;
32 
33 namespace aapt {
34 
35 using SequentialResEntryWriterTest = CommandTestFixture;
36 using DeduplicateItemsResEntryWriterTest = CommandTestFixture;
37 
WriteAllEntries(const ResourceTableView & table,ResEntryWriter & writer)38 std::vector<int32_t> WriteAllEntries(const ResourceTableView& table, ResEntryWriter& writer) {
39   std::vector<int32_t> result = {};
40   for (const auto& type : table.packages[0].types) {
41     for (const auto& entry : type.entries) {
42       for (const auto& value : entry.values) {
43         auto flat_entry = FlatEntry{&entry, value->value.get(), 0};
44         result.push_back(writer.Write(&flat_entry));
45       }
46     }
47   }
48   return result;
49 }
50 
TEST_F(SequentialResEntryWriterTest,WriteEntriesOneByOne)51 TEST_F(SequentialResEntryWriterTest, WriteEntriesOneByOne) {
52   std::unique_ptr<ResourceTable> table =
53       test::ResourceTableBuilder()
54           .AddSimple("com.app.test:id/id1", ResourceId(0x7f010000))
55           .AddSimple("com.app.test:id/id2", ResourceId(0x7f010001))
56           .AddSimple("com.app.test:id/id3", ResourceId(0x7f010002))
57           .Build();
58 
59   {
60     BigBuffer out(512);
61     SequentialResEntryWriter<false> writer(&out);
62     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
63 
64     std::vector<int32_t> expected_offsets{0, sizeof(ResEntryValuePair),
65                                           2 * sizeof(ResEntryValuePair)};
66     EXPECT_EQ(out.size(), 3 * sizeof(ResEntryValuePair));
67     EXPECT_EQ(offsets, expected_offsets);
68   }
69 
70   {
71     /* expect a compact entry to only take sizeof(ResTable_entry) */
72     BigBuffer out(512);
73     SequentialResEntryWriter<true> writer(&out);
74     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
75 
76     std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry),
77                                           2 * sizeof(ResTable_entry)};
78     EXPECT_EQ(out.size(), 3 * sizeof(ResTable_entry));
79     EXPECT_EQ(offsets, expected_offsets);
80   }
81 };
82 
TEST_F(SequentialResEntryWriterTest,WriteMapEntriesOneByOne)83 TEST_F(SequentialResEntryWriterTest, WriteMapEntriesOneByOne) {
84   std::unique_ptr<Array> array1 = util::make_unique<Array>();
85   array1->elements.push_back(
86       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
87   array1->elements.push_back(
88       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
89   std::unique_ptr<Array> array2 = util::make_unique<Array>();
90   array2->elements.push_back(
91       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
92   array2->elements.push_back(
93       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
94 
95   std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
96                                              .AddValue("com.app.test:array/arr1", std::move(array1))
97                                              .AddValue("com.app.test:array/arr2", std::move(array2))
98                                              .Build();
99 
100   {
101     BigBuffer out(512);
102     SequentialResEntryWriter<false> writer(&out);
103     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
104 
105     std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
106     EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
107     EXPECT_EQ(offsets, expected_offsets);
108   }
109 
110   {
111     /* compact_entry should have no impact to map items */
112     BigBuffer out(512);
113     SequentialResEntryWriter<true> writer(&out);
114     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
115 
116     std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
117     EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
118     EXPECT_EQ(offsets, expected_offsets);
119   }
120 };
121 
TEST_F(DeduplicateItemsResEntryWriterTest,DeduplicateItemEntries)122 TEST_F(DeduplicateItemsResEntryWriterTest, DeduplicateItemEntries) {
123   std::unique_ptr<ResourceTable> table =
124       test::ResourceTableBuilder()
125           .AddSimple("com.app.test:id/id1", ResourceId(0x7f010000))
126           .AddSimple("com.app.test:id/id2", ResourceId(0x7f010001))
127           .AddSimple("com.app.test:id/id3", ResourceId(0x7f010002))
128           .Build();
129 
130   {
131     BigBuffer out(512);
132     DeduplicateItemsResEntryWriter<false> writer(&out);
133     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
134 
135     std::vector<int32_t> expected_offsets{0, 0, 0};
136     EXPECT_EQ(out.size(), sizeof(ResEntryValuePair));
137     EXPECT_EQ(offsets, expected_offsets);
138   }
139 
140   {
141     /* expect a compact entry to only take sizeof(ResTable_entry) */
142     BigBuffer out(512);
143     DeduplicateItemsResEntryWriter<true> writer(&out);
144     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
145 
146     std::vector<int32_t> expected_offsets{0, 0, 0};
147     EXPECT_EQ(out.size(), sizeof(ResTable_entry));
148     EXPECT_EQ(offsets, expected_offsets);
149   }
150 };
151 
TEST_F(DeduplicateItemsResEntryWriterTest,WriteMapEntriesOneByOne)152 TEST_F(DeduplicateItemsResEntryWriterTest, WriteMapEntriesOneByOne) {
153   std::unique_ptr<Array> array1 = util::make_unique<Array>();
154   array1->elements.push_back(
155       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
156   array1->elements.push_back(
157       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
158   std::unique_ptr<Array> array2 = util::make_unique<Array>();
159   array2->elements.push_back(
160       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u));
161   array2->elements.push_back(
162       util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u));
163 
164   std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
165                                              .AddValue("com.app.test:array/arr1", std::move(array1))
166                                              .AddValue("com.app.test:array/arr2", std::move(array2))
167                                              .Build();
168 
169   {
170     BigBuffer out(512);
171     DeduplicateItemsResEntryWriter<false> writer(&out);
172     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
173 
174     std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
175     EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
176     EXPECT_EQ(offsets, expected_offsets);
177   }
178 
179   {
180     /* compact_entry should have no impact to map items */
181     BigBuffer out(512);
182     DeduplicateItemsResEntryWriter<true> writer(&out);
183     auto offsets = WriteAllEntries(table->GetPartitionedView(), writer);
184 
185     std::vector<int32_t> expected_offsets{0, sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)};
186     EXPECT_EQ(out.size(), 2 * (sizeof(ResTable_entry_ext) + 2 * sizeof(ResTable_map)));
187     EXPECT_EQ(offsets, expected_offsets);
188   }
189  };
190 
191 }  // namespace aapt