blob: 3f0c7cbc8ffc4f8654c48efa4990345e0bc3ad41 [file] [log] [blame]
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -07001/*
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
Ryan Mitchell8a891d82019-07-01 09:48:23 -070017#include "android-base/file.h"
18#include "androidfw/ApkAssets.h"
19#include "androidfw/AssetManager2.h"
Adam Lesinski4c67a472016-11-10 16:43:59 -080020#include "androidfw/ResourceTypes.h"
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070021
Adam Lesinski4c67a472016-11-10 16:43:59 -080022#include "utils/String16.h"
23#include "utils/String8.h"
24
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070025#include "TestHelpers.h"
Ryan Mitchell8a891d82019-07-01 09:48:23 -070026#include "data/overlay/R.h"
27#include "data/overlayable/R.h"
28#include "data/system/R.h"
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070029
Ryan Mitchell8a891d82019-07-01 09:48:23 -070030namespace overlay = com::android::overlay;
31namespace overlayable = com::android::overlayable;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070032
Adam Lesinski4c67a472016-11-10 16:43:59 -080033namespace android {
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070034
Ryan Mitchell8a891d82019-07-01 09:48:23 -070035namespace {
36
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070037class IdmapTest : public ::testing::Test {
Adam Lesinski4c67a472016-11-10 16:43:59 -080038 protected:
39 void SetUp() override {
Ryan Mitchell8a891d82019-07-01 09:48:23 -070040 // Move to the test data directory so the idmap can locate the overlay APK.
Ryan Mitchella9093052020-03-26 17:15:01 -070041 original_path = base::GetExecutableDirectory();
Ryan Mitchell8a891d82019-07-01 09:48:23 -070042 chdir(GetTestDataPath().c_str());
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070043
Ryan Mitchell8a891d82019-07-01 09:48:23 -070044 system_assets_ = ApkAssets::Load("system/system.apk");
45 ASSERT_NE(nullptr, system_assets_);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070046
Ryan Mitchell8a891d82019-07-01 09:48:23 -070047 overlay_assets_ = ApkAssets::LoadOverlay("overlay/overlay.idmap");
48 ASSERT_NE(nullptr, overlay_assets_);
49
50 overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk");
51 ASSERT_NE(nullptr, overlayable_assets_);
Ryan Mitchella9093052020-03-26 17:15:01 -070052 }
53
54 void TearDown() override {
Ryan Mitchell8a891d82019-07-01 09:48:23 -070055 chdir(original_path.c_str());
Adam Lesinski4c67a472016-11-10 16:43:59 -080056 }
57
Ryan Mitchell8a891d82019-07-01 09:48:23 -070058 protected:
Ryan Mitchella9093052020-03-26 17:15:01 -070059 std::string original_path;
Ryan Mitchell8a891d82019-07-01 09:48:23 -070060 std::unique_ptr<const ApkAssets> system_assets_;
61 std::unique_ptr<const ApkAssets> overlay_assets_;
62 std::unique_ptr<const ApkAssets> overlayable_assets_;
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070063};
64
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070065std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
66 const AssetManager2::SelectedValue& value) {
Ryan Mitchell8a891d82019-07-01 09:48:23 -070067 auto assets = asset_manager.GetApkAssets();
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070068 const ResStringPool* string_pool = assets[value.cookie]->GetLoadedArsc()->GetStringPool();
Ryan Mitchell8a891d82019-07-01 09:48:23 -070069 return GetStringFromPool(string_pool, value.data);
70}
71
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070072}
73
Adam Lesinskied69ce82017-03-20 10:55:01 -070074TEST_F(IdmapTest, OverlayOverridesResourceValue) {
Ryan Mitchell8a891d82019-07-01 09:48:23 -070075 AssetManager2 asset_manager;
76 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
77 overlay_assets_.get()});
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070078
79 auto value = asset_manager.GetResource(overlayable::R::string::overlayable5);
80 ASSERT_TRUE(value.has_value());
81 ASSERT_EQ(value->cookie, 2U);
82 ASSERT_EQ(value->type, Res_value::TYPE_STRING);
83 ASSERT_EQ("Overlay One", GetStringFromApkAssets(asset_manager, *value));
Ryan Mitchell8a891d82019-07-01 09:48:23 -070084}
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070085
Ryan Mitchell8a891d82019-07-01 09:48:23 -070086TEST_F(IdmapTest, OverlayOverridesResourceValueUsingDifferentPackage) {
87 AssetManager2 asset_manager;
88 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
89 overlay_assets_.get()});
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070090
91 auto value = asset_manager.GetResource(overlayable::R::string::overlayable10);
92 ASSERT_TRUE(value.has_value());
93 ASSERT_EQ(value->cookie, 0U);
94 ASSERT_EQ(value->type, Res_value::TYPE_STRING);
95 ASSERT_EQ("yes", GetStringFromApkAssets(asset_manager, *value));
Ryan Mitchell8a891d82019-07-01 09:48:23 -070096}
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -070097
Ryan Mitchell8a891d82019-07-01 09:48:23 -070098TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInternalResource) {
99 AssetManager2 asset_manager;
100 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
101 overlay_assets_.get()});
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700102
103 auto value = asset_manager.GetResource(overlayable::R::string::overlayable8);
104 ASSERT_TRUE(value.has_value());
105 ASSERT_EQ(value->cookie, 2U);
106 ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
107 ASSERT_EQ(value->data, (overlay::R::string::internal & 0x00ffffffU) | (0x02U << 24));
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700108}
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700109
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700110TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineInteger) {
111 AssetManager2 asset_manager;
112 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
113 overlay_assets_.get()});
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700114
115 auto value = asset_manager.GetResource(overlayable::R::integer::config_integer);
116 ASSERT_TRUE(value.has_value());
117 ASSERT_EQ(value->cookie, 2U);
118 ASSERT_EQ(value->type, Res_value::TYPE_INT_DEC);
119 ASSERT_EQ(value->data, 42);
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700120}
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700121
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700122TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineString) {
123 AssetManager2 asset_manager;
124 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
125 overlay_assets_.get()});
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700126
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700127 auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
128 ASSERT_TRUE(value.has_value());
129 ASSERT_EQ(value->cookie, 2U);
130 ASSERT_EQ(value->type, Res_value::TYPE_STRING);
131 ASSERT_EQ("Hardcoded string", GetStringFromApkAssets(asset_manager, *value));
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700132}
133
134TEST_F(IdmapTest, OverlayOverridesResourceValueUsingOverlayingResource) {
135 AssetManager2 asset_manager;
136 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
137 overlay_assets_.get()});
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700138
139 auto value = asset_manager.GetResource(overlayable::R::string::overlayable9);
140 ASSERT_TRUE(value.has_value());
141 ASSERT_EQ(value->cookie, 2U);
142 ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
143 ASSERT_EQ(value->data, overlayable::R::string::overlayable7);
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700144}
145
146TEST_F(IdmapTest, OverlayOverridesXmlParser) {
147 AssetManager2 asset_manager;
148 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
149 overlay_assets_.get()});
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700150
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700151 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,
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700158 Asset::ACCESS_RANDOM);
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700159 auto dynamic_ref_table = asset_manager.GetDynamicRefTableForCookie(value->cookie);
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700160 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);
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700183}
184
Adam Lesinskied69ce82017-03-20 10:55:01 -0700185TEST_F(IdmapTest, OverlaidResourceHasSameName) {
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700186 AssetManager2 asset_manager;
187 asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
188 overlay_assets_.get()});
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700189
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700190 auto name = asset_manager.GetResourceName(overlayable::R::string::overlayable9);
191 ASSERT_TRUE(name.has_value());
192 ASSERT_EQ("com.android.overlayable", std::string(name->package));
193 ASSERT_EQ(std::u16string(u"string"), std::u16string(name->type16));
194 ASSERT_EQ("overlayable9", std::string(name->entry));
Adam Lesinskied69ce82017-03-20 10:55:01 -0700195}
196
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700197TEST_F(IdmapTest, OverlayLoaderInterop) {
Ryan Mitchella9093052020-03-26 17:15:01 -0700198 auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER);
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700199 AssetManager2 asset_manager;
200 asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
201 overlay_assets_.get()});
Adam Lesinskied69ce82017-03-20 10:55:01 -0700202
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700203 auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
204 ASSERT_TRUE(value.has_value());
205 ASSERT_EQ(1U, value->cookie);
206 ASSERT_EQ(Res_value::TYPE_STRING, value->type);
207 ASSERT_EQ("loader", GetStringFromApkAssets(asset_manager, *value));
Adam Lesinskif90f2f8d2014-06-06 14:27:00 -0700208}
209
Ryan Mitchella9093052020-03-26 17:15:01 -0700210TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
211 std::string idmap_contents;
212 ASSERT_TRUE(base::ReadFileToString("overlay/overlay.idmap", &idmap_contents));
213
214 TemporaryFile temp_file;
215 ASSERT_TRUE(base::WriteStringToFile(idmap_contents, temp_file.path));
216
217 auto apk_assets = ApkAssets::LoadOverlay(temp_file.path);
218 ASSERT_NE(nullptr, apk_assets);
219 ASSERT_TRUE(apk_assets->IsUpToDate());
220
221 unlink(temp_file.path);
222 ASSERT_FALSE(apk_assets->IsUpToDate());
223 sleep(2);
224
225 base::WriteStringToFile("hello", temp_file.path);
226 sleep(2);
227
228 ASSERT_FALSE(apk_assets->IsUpToDate());
229}
230
Adam Lesinski4c67a472016-11-10 16:43:59 -0800231} // namespace