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