diff options
author | 2023-07-27 22:49:14 +0000 | |
---|---|---|
committer | 2023-08-09 17:38:31 +0000 | |
commit | c04bcb390105fbddad590968d739bb317dd1baa4 (patch) | |
tree | 2983a743d9e66089bf768ebad035766bb08393a9 | |
parent | 5e483b0490a0658b5204e9cbd374fa3f4dafb1b2 (diff) |
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
-rw-r--r-- | cmds/idmap2/idmap2d/Idmap2Service.cpp | 3 | ||||
-rw-r--r-- | cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl | 2 | ||||
-rw-r--r-- | cmds/idmap2/include/idmap2/FabricatedOverlay.h | 14 | ||||
-rw-r--r-- | cmds/idmap2/include/idmap2/ResourceUtils.h | 2 | ||||
-rw-r--r-- | cmds/idmap2/libidmap2/FabricatedOverlay.cpp | 34 | ||||
-rw-r--r-- | cmds/idmap2/self_targeting/SelfTargeting.cpp | 1 | ||||
-rw-r--r-- | cmds/idmap2/tests/FabricatedOverlayTests.cpp | 2 | ||||
-rw-r--r-- | cmds/idmap2/tests/IdmapTests.cpp | 2 | ||||
-rw-r--r-- | cmds/idmap2/tests/ResourceMappingTests.cpp | 2 | ||||
-rw-r--r-- | core/api/current.txt | 1 | ||||
-rw-r--r-- | core/java/android/content/om/FabricatedOverlay.java | 61 | ||||
-rw-r--r-- | core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp | 15 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 2 |
13 files changed, 118 insertions, 23 deletions
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index b94b3b458065..d76ca5bdce42 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -265,7 +265,8 @@ Status Idmap2Service::createFabricatedOverlay( 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 3ad6d58e8253..8ebd454705f0 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 @@ parcelable FabricatedOverlayInternalEntry { @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 a29fa8f3e1ab..1e7d4c28f45c 100644 --- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h +++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h @@ -49,6 +49,8 @@ struct FabricatedOverlay { 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 @@ struct FabricatedOverlay { 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 @@ struct FabricatedOverlay { 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 @@ struct FabricatedOverlay { 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 c2b0abed442c..d4490ef47b25 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -43,6 +43,8 @@ struct TargetValue { 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 dd5be21cd164..47daf23c6381 100644 --- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp +++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp @@ -55,7 +55,7 @@ void Write32(std::ostream& stream, uint32_t value) { 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 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( 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 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( 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 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() { } 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 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() { 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 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() { 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 @@ Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const { 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 a8aa03309b16..c7f5cf3632c5 100644 --- a/cmds/idmap2/self_targeting/SelfTargeting.cpp +++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp @@ -52,6 +52,7 @@ CreateFrroFile(std::string& out_err_result, const std::string& packageName, 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 e13a0eb5d488..b460bb33f559 100644 --- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp +++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp @@ -59,7 +59,7 @@ TEST(FabricatedOverlayTests, SetResourceValue) { 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 f6e48ba7a1f4..a3448fda60d9 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -269,7 +269,7 @@ TEST(IdmapTests, FabricatedOverlay) { .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 380e462a3aba..40f98c2f351b 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -212,7 +212,7 @@ TEST(ResourceMappingTests, FabricatedOverlay) { .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(); diff --git a/core/api/current.txt b/core/api/current.txt index 3392d250d426..347bfc8d0386 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11699,6 +11699,7 @@ package android.content.om { method @NonNull public void setResourceValue(@NonNull String, @IntRange(from=android.util.TypedValue.TYPE_FIRST_INT, to=android.util.TypedValue.TYPE_LAST_INT) int, int, @Nullable String); method @NonNull public void setResourceValue(@NonNull String, int, @NonNull String, @Nullable String); method @NonNull public void setResourceValue(@NonNull String, @NonNull android.os.ParcelFileDescriptor, @Nullable String); + method @NonNull public void setResourceValue(@NonNull String, @NonNull android.content.res.AssetFileDescriptor, @Nullable String); method public void setTargetOverlayable(@Nullable String); } diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java index 7e787c9c3a8c..c4547b8acc2b 100644 --- a/core/java/android/content/om/FabricatedOverlay.java +++ b/core/java/android/content/om/FabricatedOverlay.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.res.AssetFileDescriptor; import android.os.FabricatedOverlayInternal; import android.os.FabricatedOverlayInternalEntry; import android.os.ParcelFileDescriptor; @@ -269,7 +270,7 @@ public class FabricatedOverlay { * @param configuration The string representation of the config this overlay is enabled for * @return the builder itself * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, - ParcelFileDescriptor, String)} instead. + ParcelFileDescriptor, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @@ -285,6 +286,30 @@ public class FabricatedOverlay { } /** + * Sets the value of the fabricated overlay for the file descriptor type. + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param value the file descriptor whose contents are the value of the frro + * @param configuration The string representation of the config this overlay is enabled for + * @return the builder itself + * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, + ParcelFileDescriptor, String)} instead. + * @hide + */ + @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") + @NonNull + public Builder setResourceValue( + @NonNull String resourceName, + @NonNull AssetFileDescriptor value, + @Nullable String configuration) { + ensureValidResourceName(resourceName); + mEntries.add( + generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); + return this; + } + + /** * Builds an immutable fabricated overlay. * * @return the fabricated overlay @@ -421,6 +446,21 @@ public class FabricatedOverlay { entry.resourceName = resourceName; entry.binaryData = Objects.requireNonNull(parcelFileDescriptor); entry.configuration = configuration; + entry.binaryDataOffset = 0; + entry.binaryDataSize = parcelFileDescriptor.getStatSize(); + return entry; + } + + @NonNull + private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( + @NonNull String resourceName, @NonNull AssetFileDescriptor assetFileDescriptor, + @Nullable String configuration) { + final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); + entry.resourceName = resourceName; + entry.binaryData = Objects.requireNonNull(assetFileDescriptor.getParcelFileDescriptor()); + entry.binaryDataOffset = assetFileDescriptor.getStartOffset(); + entry.binaryDataSize = assetFileDescriptor.getLength(); + entry.configuration = configuration; return entry; } @@ -495,4 +535,23 @@ public class FabricatedOverlay { mOverlay.entries.add( generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); } + + /** + * Sets the resource value in the fabricated overlay for the file descriptor type with the + * configuration. + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param value the file descriptor whose contents are the value of the frro + * @param configuration The string representation of the config this overlay is enabled for + */ + @NonNull + public void setResourceValue( + @NonNull String resourceName, + @NonNull AssetFileDescriptor value, + @Nullable String configuration) { + ensureValidResourceName(resourceName); + mOverlay.entries.add( + generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); + } } diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp index bba1760bc45c..d4f6e1868695 100644 --- a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp +++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp @@ -44,6 +44,8 @@ static struct fabricated_overlay_internal_entry_offsets_t { jfieldID stringData; jfieldID binaryData; jfieldID configuration; + jfieldID binaryDataOffset; + jfieldID binaryDataSize; } gFabricatedOverlayInternalEntryOffsets; static struct parcel_file_descriptor_offsets_t { @@ -281,10 +283,17 @@ static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath auto binary_data = getNullableFileDescriptor(env, entry, gFabricatedOverlayInternalEntryOffsets.binaryData); + + const auto data_offset = + env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataOffset); + const auto data_size = + env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataSize); entries_params.push_back( FabricatedOverlayEntryParameters{resourceName.c_str(), (DataType)dataType, (DataValue)data, string_data.value_or(std::string()), binary_data, + static_cast<off64_t>(data_offset), + static_cast<size_t>(data_size), configuration.value_or(std::string())}); ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s," " binaryData = %d, configuration = %s", @@ -440,6 +449,12 @@ int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env) { gFabricatedOverlayInternalEntryOffsets.configuration = GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "configuration", "Ljava/lang/String;"); + gFabricatedOverlayInternalEntryOffsets.binaryDataOffset = + GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, + "binaryDataOffset", "J"); + gFabricatedOverlayInternalEntryOffsets.binaryDataSize = + GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, + "binaryDataSize", "J"); jclass parcelFileDescriptorClass = android::FindClassOrDie(env, "android/os/ParcelFileDescriptor"); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 52666ab8d1d5..fdb355192676 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1872,6 +1872,8 @@ struct FabricatedOverlayEntryParameters { DataValue data_value; std::string data_string_value; std::optional<android::base::borrowed_fd> data_binary_value; + off64_t binary_data_offset; + size_t binary_data_size; std::string configuration; }; |