• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 <chrono>
18 #include <thread>
19 
20 #include "android-base/file.h"
21 #include "androidfw/ApkAssets.h"
22 #include "androidfw/AssetManager2.h"
23 #include "androidfw/ResourceTypes.h"
24 
25 #include "utils/String16.h"
26 #include "utils/String8.h"
27 
28 #include "TestHelpers.h"
29 #include "data/overlay/R.h"
30 #include "data/overlayable/R.h"
31 #include "data/system/R.h"
32 
33 using namespace std::chrono_literals;
34 using ::testing::NotNull;
35 
36 namespace overlay = com::android::overlay;
37 namespace overlayable = com::android::overlayable;
38 
39 namespace android {
40 
41 namespace {
42 
43 class IdmapTest : public ::testing::Test {
44  protected:
SetUp()45   void SetUp() override {
46     // Move to the test data directory so the idmap can locate the overlay APK.
47     original_path = base::GetExecutableDirectory();
48     chdir(GetTestDataPath().c_str());
49 
50     system_assets_ = ApkAssets::Load("system/system.apk");
51     ASSERT_NE(nullptr, system_assets_);
52 
53     overlay_assets_ = ApkAssets::LoadOverlay("overlay/overlay.idmap");
54     ASSERT_NE(nullptr, overlay_assets_);
55 
56     overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk");
57     ASSERT_NE(nullptr, overlayable_assets_);
58   }
59 
TearDown()60   void TearDown() override {
61     chdir(original_path.c_str());
62   }
63 
64  protected:
65   std::string original_path;
66   AssetManager2::ApkAssetsPtr system_assets_;
67   AssetManager2::ApkAssetsPtr overlay_assets_;
68   AssetManager2::ApkAssetsPtr overlayable_assets_;
69 };
70 
GetStringFromApkAssets(const AssetManager2 & asset_manager,const AssetManager2::SelectedValue & value)71 std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
72                                    const AssetManager2::SelectedValue& value) {
73   auto op = asset_manager.StartOperation();
74   const ResStringPool* string_pool =
75       asset_manager.GetApkAssets(value.cookie)->GetLoadedArsc()->GetStringPool();
76   return GetStringFromPool(string_pool, value.data);
77 }
78 
79 }
80 
TEST_F(IdmapTest,OverlayOverridesResourceValue)81 TEST_F(IdmapTest, OverlayOverridesResourceValue) {
82   AssetManager2 asset_manager;
83   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
84 
85   auto value = asset_manager.GetResource(overlayable::R::string::overlayable5);
86   ASSERT_TRUE(value.has_value());
87   ASSERT_EQ(value->cookie, 2U);
88   ASSERT_EQ(value->type, Res_value::TYPE_STRING);
89   ASSERT_EQ("Overlay One", GetStringFromApkAssets(asset_manager, *value));
90 }
91 
TEST_F(IdmapTest,OverlayOverridesResourceValueUsingDifferentPackage)92 TEST_F(IdmapTest, OverlayOverridesResourceValueUsingDifferentPackage) {
93   AssetManager2 asset_manager;
94   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
95 
96   auto value = asset_manager.GetResource(overlayable::R::string::overlayable10);
97   ASSERT_TRUE(value.has_value());
98   ASSERT_EQ(value->cookie, 0U);
99   ASSERT_EQ(value->type, Res_value::TYPE_STRING);
100   ASSERT_EQ("yes", GetStringFromApkAssets(asset_manager, *value));
101 }
102 
TEST_F(IdmapTest,OverlayOverridesResourceValueUsingInternalResource)103 TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInternalResource) {
104   AssetManager2 asset_manager;
105   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
106 
107   auto value = asset_manager.GetResource(overlayable::R::string::overlayable8);
108   ASSERT_TRUE(value.has_value());
109   ASSERT_EQ(value->cookie, 2U);
110   ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
111   ASSERT_EQ(value->data, (overlay::R::string::internal & 0x00ffffffU) | (0x02U << 24));
112 }
113 
TEST_F(IdmapTest,OverlayOverridesResourceValueUsingInlineInteger)114 TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineInteger) {
115   AssetManager2 asset_manager;
116   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
117 
118   auto value = asset_manager.GetResource(overlayable::R::integer::config_integer);
119   ASSERT_TRUE(value.has_value());
120   ASSERT_EQ(value->cookie, 2U);
121   ASSERT_EQ(value->type, Res_value::TYPE_INT_DEC);
122   ASSERT_EQ(value->data, 42);
123 }
124 
TEST_F(IdmapTest,OverlayOverridesResourceValueUsingInlineString)125 TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineString) {
126   AssetManager2 asset_manager;
127   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
128 
129   auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
130   ASSERT_TRUE(value.has_value());
131   ASSERT_EQ(value->cookie, 2U);
132   ASSERT_EQ(value->type, Res_value::TYPE_STRING);
133   ASSERT_EQ("Hardcoded string", GetStringFromApkAssets(asset_manager, *value));
134 }
135 
TEST_F(IdmapTest,OverlayOverridesResourceValueUsingOverlayingResource)136 TEST_F(IdmapTest, OverlayOverridesResourceValueUsingOverlayingResource) {
137   AssetManager2 asset_manager;
138   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
139 
140   auto value = asset_manager.GetResource(overlayable::R::string::overlayable9);
141   ASSERT_TRUE(value.has_value());
142   ASSERT_EQ(value->cookie, 2U);
143   ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
144   ASSERT_EQ(value->data, overlayable::R::string::overlayable7);
145 }
146 
TEST_F(IdmapTest,OverlayOverridesXmlParser)147 TEST_F(IdmapTest, OverlayOverridesXmlParser) {
148   AssetManager2 asset_manager;
149   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
150 
151   auto value = asset_manager.GetResource(overlayable::R::layout::hello_view);
152   ASSERT_TRUE(value.has_value());
153   ASSERT_EQ(value->cookie, 2U);
154   ASSERT_EQ(value->type, Res_value::TYPE_STRING);
155   ASSERT_EQ("res/layout/hello_view.xml", GetStringFromApkAssets(asset_manager, *value));
156 
157   auto asset = asset_manager.OpenNonAsset("res/layout/hello_view.xml", value->cookie,
158                                           Asset::ACCESS_RANDOM);
159   auto dynamic_ref_table = asset_manager.GetDynamicRefTableForCookie(value->cookie);
160   auto xml_tree = util::make_unique<ResXMLTree>(std::move(dynamic_ref_table));
161   status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), false);
162   ASSERT_EQ(err, NO_ERROR);
163 
164   while (xml_tree->next() != ResXMLParser::START_TAG) { }
165 
166   // The resource id of @id/hello_view should be rewritten to the resource id/hello_view within the
167   // target.
168   ASSERT_EQ(xml_tree->getAttributeNameResID(0), 0x010100d0 /* android:attr/id */);
169   ASSERT_EQ(xml_tree->getAttributeDataType(0), Res_value::TYPE_REFERENCE);
170   ASSERT_EQ(xml_tree->getAttributeData(0), overlayable::R::id::hello_view);
171 
172   // The resource id of @android:string/yes should not be rewritten even though it overlays
173   // string/overlayable10 in the target.
174   ASSERT_EQ(xml_tree->getAttributeNameResID(1), 0x0101014f /* android:attr/text */);
175   ASSERT_EQ(xml_tree->getAttributeDataType(1), Res_value::TYPE_REFERENCE);
176   ASSERT_EQ(xml_tree->getAttributeData(1), 0x01040013 /* android:string/yes */);
177 
178   // The resource id of the attribute within the overlay should be rewritten to the resource id of
179   // the attribute in the target.
180   ASSERT_EQ(xml_tree->getAttributeNameResID(2), overlayable::R::attr::max_lines);
181   ASSERT_EQ(xml_tree->getAttributeDataType(2), Res_value::TYPE_INT_DEC);
182   ASSERT_EQ(xml_tree->getAttributeData(2), 4);
183 }
184 
TEST_F(IdmapTest,OverlaidResourceHasSameName)185 TEST_F(IdmapTest, OverlaidResourceHasSameName) {
186   AssetManager2 asset_manager;
187   asset_manager.SetApkAssets({system_assets_, overlayable_assets_, overlay_assets_});
188 
189   auto name = asset_manager.GetResourceName(overlayable::R::string::overlayable9);
190   ASSERT_TRUE(name.has_value());
191   ASSERT_EQ("com.android.overlayable", std::string(name->package));
192   ASSERT_EQ(std::u16string(u"string"), std::u16string(name->type16));
193   ASSERT_EQ("overlayable9", std::string(name->entry));
194 }
195 
TEST_F(IdmapTest,OverlayLoaderInterop)196 TEST_F(IdmapTest, OverlayLoaderInterop) {
197   auto asset = AssetsProvider::CreateAssetFromFile(GetTestDataPath() + "/loader/resources.arsc");
198   ASSERT_THAT(asset, NotNull());
199 
200   auto loader_assets = ApkAssets::LoadTable(std::move(asset), EmptyAssetsProvider::Create(),
201       PROPERTY_LOADER);
202   AssetManager2 asset_manager;
203   asset_manager.SetApkAssets({overlayable_assets_, loader_assets, overlay_assets_});
204 
205   auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
206   ASSERT_TRUE(value.has_value());
207   ASSERT_EQ(1U, value->cookie);
208   ASSERT_EQ(Res_value::TYPE_STRING, value->type);
209   ASSERT_EQ("loader", GetStringFromApkAssets(asset_manager, *value));
210 }
211 
TEST_F(IdmapTest,OverlayAssetsIsUpToDate)212 TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
213   std::string idmap_contents;
214   ASSERT_TRUE(base::ReadFileToString("overlay/overlay.idmap", &idmap_contents));
215 
216   TemporaryFile temp_file;
217   ASSERT_TRUE(base::WriteStringToFile(idmap_contents, temp_file.path));
218 
219   auto apk_assets = ApkAssets::LoadOverlay(temp_file.path);
220   ASSERT_NE(nullptr, apk_assets);
221   ASSERT_TRUE(apk_assets->IsOverlay());
222   ASSERT_EQ(UpToDate::True, apk_assets->IsUpToDate());
223 
224   unlink(temp_file.path);
225   ASSERT_EQ(UpToDate::False, apk_assets->IsUpToDate());
226 
227   const auto sleep_duration =
228       std::chrono::nanoseconds(std::max(kModDateResolutionNs, 1'000'000ull));
229   std::this_thread::sleep_for(sleep_duration);
230 
231   base::WriteStringToFile("hello", temp_file.path);
232   std::this_thread::sleep_for(sleep_duration);
233 
234   ASSERT_EQ(UpToDate::False, apk_assets->IsUpToDate());
235 }
236 
TEST(IdmapTestUpToDate,Combine)237 TEST(IdmapTestUpToDate, Combine) {
238   ASSERT_EQ(UpToDate::False, combine(UpToDate::False, [] {
239               ADD_FAILURE();  // Shouldn't get called at all.
240               return UpToDate::False;
241             }));
242 
243   ASSERT_EQ(UpToDate::False, combine(UpToDate::True, [] { return UpToDate::False; }));
244 
245   ASSERT_EQ(UpToDate::True, combine(UpToDate::True, [] { return UpToDate::True; }));
246   ASSERT_EQ(UpToDate::True, combine(UpToDate::True, [] { return UpToDate::Always; }));
247   ASSERT_EQ(UpToDate::True, combine(UpToDate::Always, [] { return UpToDate::True; }));
248 
249   ASSERT_EQ(UpToDate::Always, combine(UpToDate::Always, [] { return UpToDate::Always; }));
250 }
251 
TEST(IdmapTestUpToDate,FromBool)252 TEST(IdmapTestUpToDate, FromBool) {
253   ASSERT_EQ(UpToDate::False, fromBool(false));
254   ASSERT_EQ(UpToDate::True, fromBool(true));
255 }
256 
257 }  // namespace
258