Allow AssetFileDescriptors to be used to create FRROs
Before this change, if a (system) app tried to use an image from its
assets to create an FRRO it would succeed but no image would display.
That is because when it is an asset we have an AssetFileDescriptor which
internally has a file descriptor, offset, and size and the file
descriptor would point at the apk itself. When this would get passed to
the native layer to create the frro only the file descriptor would get
passed so we would copy the whole apk, not just the image.
This allows apps to pass in an AssetFileDescriptor directly which we can
then use to also pass down the offset and size to the native layer and
only copy the image part.
Fixes: 289739832
Test: atest FabricatedOverlayTest
Change-Id: I80dceb19229a6a3c02851a5451ea6d46798981b3
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index b94b3b4..d76ca5b 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -265,7 +265,8 @@
res.configuration.value_or(std::string()));
} else if (res.binaryData.has_value()) {
builder.SetResourceValue(res.resourceName, res.binaryData->get(),
- res.configuration.value_or(std::string()));
+ res.binaryDataOffset, res.binaryDataSize,
+ res.configuration.value_or(std::string()));
} else {
builder.SetResourceValue(res.resourceName, res.dataType, res.data,
res.configuration.value_or(std::string()));
diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
index 3ad6d58..8ebd454 100644
--- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
+++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
@@ -26,4 +26,6 @@
@nullable @utf8InCpp String stringData;
@nullable ParcelFileDescriptor binaryData;
@nullable @utf8InCpp String configuration;
+ long binaryDataOffset;
+ long binaryDataSize;
}
\ No newline at end of file
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
index a29fa8f..1e7d4c2 100644
--- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -49,6 +49,8 @@
Builder& SetResourceValue(const std::string& resource_name,
std::optional<android::base::borrowed_fd>&& binary_value,
+ off64_t data_binary_offset,
+ size_t data_binary_size,
const std::string& configuration);
inline Builder& setFrroPath(std::string frro_path) {
@@ -65,6 +67,8 @@
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t data_binary_offset;
+ size_t data_binary_size;
std::string configuration;
};
@@ -76,6 +80,12 @@
std::vector<Entry> entries_;
};
+ struct BinaryData {
+ android::base::borrowed_fd file_descriptor;
+ off64_t offset;
+ size_t size;
+ };
+
Result<Unit> ToBinaryStream(std::ostream& stream) const;
static Result<FabricatedOverlay> FromBinaryStream(std::istream& stream);
@@ -92,13 +102,13 @@
explicit FabricatedOverlay(pb::FabricatedOverlay&& overlay,
std::string&& string_pool_data_,
- std::vector<android::base::borrowed_fd> binary_files_,
+ std::vector<FabricatedOverlay::BinaryData> binary_files_,
off_t total_binary_bytes_,
std::optional<uint32_t> crc_from_disk = {});
pb::FabricatedOverlay overlay_pb_;
std::string string_pool_data_;
- std::vector<android::base::borrowed_fd> binary_files_;
+ std::vector<FabricatedOverlay::BinaryData> binary_files_;
uint32_t total_binary_bytes_;
std::optional<uint32_t> crc_from_disk_;
mutable std::optional<SerializedData> data_;
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index c2b0abe..d4490ef4 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -43,6 +43,8 @@
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t data_binary_offset;
+ size_t data_binary_size;
};
struct TargetValueWithConfig {
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index dd5be21c..47daf23 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -55,7 +55,7 @@
FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
std::string&& string_pool_data,
- std::vector<android::base::borrowed_fd> binary_files,
+ std::vector<FabricatedOverlay::BinaryData> binary_files,
off_t total_binary_bytes,
std::optional<uint32_t> crc_from_disk)
: overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)),
@@ -81,7 +81,7 @@
const std::string& resource_name, uint8_t data_type, uint32_t data_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, data_value, "", std::nullopt, configuration});
+ Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration});
return *this;
}
@@ -89,14 +89,15 @@
const std::string& resource_name, uint8_t data_type, const std::string& data_string_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, 0, data_string_value, std::nullopt, configuration});
+ Entry{resource_name, data_type, 0, data_string_value, std::nullopt, 0, 0, configuration});
return *this;
}
FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, std::optional<android::base::borrowed_fd>&& binary_value,
- const std::string& configuration) {
- entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value, configuration});
+ off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration) {
+ entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value,
+ data_binary_offset, data_binary_size, configuration});
return *this;
}
@@ -148,7 +149,8 @@
}
value->second = TargetValue{res_entry.data_type, res_entry.data_value,
- res_entry.data_string_value, res_entry.data_binary_value};
+ res_entry.data_string_value, res_entry.data_binary_value,
+ res_entry.data_binary_offset, res_entry.data_binary_size};
}
pb::FabricatedOverlay overlay_pb;
@@ -157,7 +159,7 @@
overlay_pb.set_target_package_name(target_package_name_);
overlay_pb.set_target_overlayable(target_overlayable_);
- std::vector<android::base::borrowed_fd> binary_files;
+ std::vector<FabricatedOverlay::BinaryData> binary_files;
size_t total_binary_bytes = 0;
// 16 for the number of bytes in the frro file before the binary data
const size_t FRRO_HEADER_SIZE = 16;
@@ -182,16 +184,15 @@
pb_value->set_data_value(ref.index());
} else if (value.second.data_binary_value.has_value()) {
pb_value->set_data_type(Res_value::TYPE_STRING);
- struct stat s;
- if (fstat(value.second.data_binary_value->get(), &s) == -1) {
- return Error("unable to get size of binary file: %d", errno);
- }
std::string uri
= StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(),
static_cast<int> (FRRO_HEADER_SIZE + total_binary_bytes),
- static_cast<int> (s.st_size));
- total_binary_bytes += s.st_size;
- binary_files.emplace_back(value.second.data_binary_value->get());
+ static_cast<int> (value.second.data_binary_size));
+ total_binary_bytes += value.second.data_binary_size;
+ binary_files.emplace_back(FabricatedOverlay::BinaryData{
+ value.second.data_binary_value->get(),
+ value.second.data_binary_offset,
+ value.second.data_binary_size});
auto ref = string_pool.MakeRef(std::move(uri));
pb_value->set_data_value(ref.index());
} else {
@@ -310,8 +311,9 @@
Write32(stream, (*data)->pb_crc);
Write32(stream, total_binary_bytes_);
std::string file_contents;
- for (const android::base::borrowed_fd fd : binary_files_) {
- if (!ReadFdToString(fd, &file_contents)) {
+ for (const FabricatedOverlay::BinaryData fd : binary_files_) {
+ file_contents.resize(fd.size);
+ if (!ReadFullyAtOffset(fd.file_descriptor, file_contents.data(), fd.size, fd.offset)) {
return Error("Failed to read binary file data.");
}
stream.write(file_contents.data(), file_contents.length());
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
index a8aa033..c7f5cf3 100644
--- a/cmds/idmap2/self_targeting/SelfTargeting.cpp
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -52,6 +52,7 @@
const auto dataType = entry_params.data_type;
if (entry_params.data_binary_value.has_value()) {
builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
+ entry_params.binary_data_offset, entry_params.binary_data_size,
entry_params.configuration);
} else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
builder.SetResourceValue(entry_params.resource_name, dataType,
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index e13a0eb..b460bb3 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -59,7 +59,7 @@
Res_value::TYPE_STRING,
"foobar",
"en-rUS-normal-xxhdpi-v21")
- .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7")
+ .SetResourceValue("com.example.target:drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
.setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(overlay);
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index f6e48ba..a3448fd 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -269,7 +269,7 @@
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7")
- .SetResourceValue("drawable/dr1", fd, "port-xxhdpi-v7")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
.setFrroPath("/foo/bar/biz.frro")
.Build();
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 380e462..40f98c2 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -212,7 +212,7 @@
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "")
- .SetResourceValue("drawable/dr1", fd, "")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "")
.setFrroPath("/foo/bar/biz.frro")
.Build();