diff options
20 files changed, 267 insertions, 52 deletions
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 55ec7dae16b1..6e51f009f76c 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -86,6 +86,7 @@ cc_library { static_libs: [ "libidmap2_policies", "libidmap2_protos", + "libpng", ], shared_libs: [ "libandroidfw", @@ -107,6 +108,7 @@ cc_library { "libcutils", "libidmap2_policies", "libidmap2_protos", + "libpng", "libprotobuf-cpp-lite", "libutils", "libz", @@ -185,6 +187,7 @@ cc_test { static_libs: [ "libgmock", "libidmap2_protos", + "libpng", ], target: { android: { @@ -258,6 +261,7 @@ cc_binary { "libbase", "libcutils", "libidmap2", + "libpng", "libprotobuf-cpp-lite", "libutils", "libz", @@ -275,6 +279,7 @@ cc_binary { "libidmap2", "libidmap2_policies", "liblog", + "libpng", "libprotobuf-cpp-lite", "libutils", "libziparchive", diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index d76ca5bdce42..f264125cfde5 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -266,7 +266,8 @@ Status Idmap2Service::createFabricatedOverlay( } else if (res.binaryData.has_value()) { builder.SetResourceValue(res.resourceName, res.binaryData->get(), res.binaryDataOffset, res.binaryDataSize, - res.configuration.value_or(std::string())); + res.configuration.value_or(std::string()), + res.isNinePatch); } 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 8ebd454705f0..bca2ff3c86f1 100644 --- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl +++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl @@ -28,4 +28,5 @@ parcelable FabricatedOverlayInternalEntry { @nullable @utf8InCpp String configuration; long binaryDataOffset; long binaryDataSize; + boolean isNinePatch; }
\ No newline at end of file diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h index 1e7d4c28f45c..bfcd4b9f5941 100644 --- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h +++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h @@ -19,6 +19,8 @@ #include <libidmap2/proto/fabricated_v1.pb.h> +#include "androidfw/Streams.h" + #include <istream> #include <map> #include <memory> @@ -51,7 +53,8 @@ struct FabricatedOverlay { std::optional<android::base::borrowed_fd>&& binary_value, off64_t data_binary_offset, size_t data_binary_size, - const std::string& configuration); + const std::string& configuration, + bool nine_patch); inline Builder& setFrroPath(std::string frro_path) { frro_path_ = std::move(frro_path); @@ -70,6 +73,7 @@ struct FabricatedOverlay { off64_t data_binary_offset; size_t data_binary_size; std::string configuration; + bool nine_patch; }; std::string package_name_; @@ -81,7 +85,7 @@ struct FabricatedOverlay { }; struct BinaryData { - android::base::borrowed_fd file_descriptor; + std::unique_ptr<android::InputStream> input_stream; off64_t offset; size_t size; }; diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index d4490ef47b25..9e463c9a9fca 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -45,6 +45,7 @@ struct TargetValue { std::optional<android::base::borrowed_fd> data_binary_value; off64_t data_binary_offset; size_t data_binary_size; + bool nine_patch; }; struct TargetValueWithConfig { diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp index 47daf23c6381..16bb896e939c 100644 --- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp +++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp @@ -20,8 +20,16 @@ #include <sys/types.h> // umask #include <android-base/file.h> +#include <android-base/strings.h> +#include <androidfw/BigBuffer.h> +#include <androidfw/BigBufferStream.h> +#include <androidfw/FileStream.h> +#include <androidfw/Image.h> +#include <androidfw/Png.h> #include <androidfw/ResourceUtils.h> +#include <androidfw/StringPiece.h> #include <androidfw/StringPool.h> +#include <androidfw/Streams.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <utils/ByteOrder.h> @@ -32,9 +40,9 @@ #include <memory> #include <string> #include <utility> +#include <sys/utsname.h> namespace android::idmap2 { - constexpr auto kBufferSize = 1024; namespace { @@ -81,7 +89,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, 0, 0, configuration}); + Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration, false}); return *this; } @@ -89,18 +97,90 @@ 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, 0, 0, configuration}); + Entry{resource_name, + data_type, + 0, + data_string_value, + std::nullopt, + 0, + 0, + configuration, + false}); return *this; } FabricatedOverlay::Builder& 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) { + off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration, + bool nine_patch) { entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value, - data_binary_offset, data_binary_size, configuration}); + data_binary_offset, data_binary_size, configuration, nine_patch}); return *this; } +static Result<FabricatedOverlay::BinaryData> buildBinaryData( + pb::ResourceValue* pb_value, const TargetValue &value) { + pb_value->set_data_type(Res_value::TYPE_STRING); + size_t binary_size; + off64_t binary_offset; + std::unique_ptr<android::InputStream> binary_stream; + + if (value.nine_patch) { + std::string file_contents; + file_contents.resize(value.data_binary_size); + if (!base::ReadFullyAtOffset(value.data_binary_value->get(), file_contents.data(), + value.data_binary_size, value.data_binary_offset)) { + return Error("Failed to read binary file data."); + } + const StringPiece content(file_contents.c_str(), file_contents.size()); + android::PngChunkFilter png_chunk_filter(content); + android::AndroidLogDiagnostics diag; + auto png = android::ReadPng(&png_chunk_filter, &diag); + if (!png) { + return Error("Error opening file as png"); + } + + std::string err; + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(png->rows.get(), + png->width, png->height, + &err); + if (!nine_patch) { + return Error("%s", err.c_str()); + } + + png->width -= 2; + png->height -= 2; + memmove(png->rows.get(), png->rows.get() + 1, png->height * sizeof(uint8_t**)); + for (int32_t h = 0; h < png->height; h++) { + memmove(png->rows[h], png->rows[h] + 4, png->width * 4); + } + + android::BigBuffer buffer(value.data_binary_size); + android::BigBufferOutputStream buffer_output_stream(&buffer); + if (!android::WritePng(png.get(), nine_patch.get(), &buffer_output_stream, {}, + &diag, false)) { + return Error("Error writing frro png"); + } + + binary_size = buffer.size(); + binary_offset = 0; + android::BigBufferInputStream *buffer_input_stream + = new android::BigBufferInputStream(std::move(buffer)); + binary_stream.reset(buffer_input_stream); + } else { + binary_size = value.data_binary_size; + binary_offset = value.data_binary_offset; + android::FileInputStream *fis + = new android::FileInputStream(value.data_binary_value.value()); + binary_stream.reset(fis); + } + + return FabricatedOverlay::BinaryData{ + std::move(binary_stream), + binary_offset, + binary_size}; +} + Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() { using ConfigMap = std::map<std::string, TargetValue, std::less<>>; using EntryMap = std::map<std::string, ConfigMap, std::less<>>; @@ -150,7 +230,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_binary_offset, res_entry.data_binary_size}; + res_entry.data_binary_offset, res_entry.data_binary_size, + res_entry.nine_patch}; } pb::FabricatedOverlay overlay_pb; @@ -183,18 +264,20 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() { auto ref = string_pool.MakeRef(value.second.data_string_value); 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); - 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> (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()); + auto binary_data = buildBinaryData(pb_value, value.second); + if (!binary_data) { + return binary_data.GetError(); + } + pb_value->set_data_type(Res_value::TYPE_STRING); + + 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> (binary_data->size)); + total_binary_bytes += binary_data->size; + binary_files.emplace_back(std::move(*binary_data)); + auto ref = string_pool.MakeRef(std::move(uri)); + pb_value->set_data_value(ref.index()); } else { pb_value->set_data_value(value.second.data_value); } @@ -311,9 +394,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 FabricatedOverlay::BinaryData fd : binary_files_) { - file_contents.resize(fd.size); - if (!ReadFullyAtOffset(fd.file_descriptor, file_contents.data(), fd.size, fd.offset)) { + for (const FabricatedOverlay::BinaryData& bd : binary_files_) { + file_contents.resize(bd.size); + if (!bd.input_stream->ReadFullyAtOffset(file_contents.data(), bd.size, bd.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 c7f5cf3632c5..7f9c4686c55a 100644 --- a/cmds/idmap2/self_targeting/SelfTargeting.cpp +++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp @@ -53,7 +53,7 @@ CreateFrroFile(std::string& out_err_result, const std::string& packageName, 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); + entry_params.configuration, entry_params.nine_patch); } else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) { builder.SetResourceValue(entry_params.resource_name, dataType, entry_params.data_value, entry_params.configuration); diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp index b460bb33f559..6b1c7e83c826 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, 0, 8341, "port-xxhdpi-v7") + .SetResourceValue("com.example.target:drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7", false) .setFrroPath("/foo/bar/biz.frro") .Build(); ASSERT_TRUE(overlay); diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index a3448fda60d9..a384305da43d 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, 0, 8341, "port-xxhdpi-v7") + .SetResourceValue("drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7", false) .setFrroPath("/foo/bar/biz.frro") .Build(); diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 40f98c2f351b..db44c23a41f9 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, 0, 8341, "") + .SetResourceValue("drawable/dr1", fd, 0, 8341, "", false) .setFrroPath("/foo/bar/biz.frro") .Build(); diff --git a/core/api/current.txt b/core/api/current.txt index f01563a90fb3..3e229bb66fa2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11787,6 +11787,7 @@ package android.content.om { public class FabricatedOverlay { ctor public FabricatedOverlay(@NonNull String, @NonNull String); method @NonNull public android.content.om.OverlayIdentifier getIdentifier(); + method @FlaggedApi("android.content.res.nine_patch_frro") @NonNull public void setNinePatchResourceValue(@NonNull String, @NonNull android.os.ParcelFileDescriptor, @Nullable String); 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); diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java index df2d7e70880f..40ffb0ff5c80 100644 --- a/core/java/android/content/om/FabricatedOverlay.java +++ b/core/java/android/content/om/FabricatedOverlay.java @@ -281,8 +281,8 @@ public class FabricatedOverlay { @NonNull ParcelFileDescriptor value, @Nullable String configuration) { ensureValidResourceName(resourceName); - mEntries.add( - generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); + mEntries.add(generateFabricatedOverlayInternalEntry( + resourceName, value, configuration, false)); return this; } @@ -361,6 +361,16 @@ public class FabricatedOverlay { } /** + * Set the package that owns the overlay + * + * @param owningPackage the package that should own the overlay. + * @hide + */ + public void setOwningPackage(@NonNull String owningPackage) { + mOverlay.packageName = owningPackage; + } + + /** * Set the target overlayable name of the overlay * * The target package defines may define several overlayables. The {@link FabricatedOverlay} @@ -442,13 +452,14 @@ public class FabricatedOverlay { @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @NonNull ParcelFileDescriptor parcelFileDescriptor, - @Nullable String configuration) { + @Nullable String configuration, boolean isNinePatch) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.binaryData = Objects.requireNonNull(parcelFileDescriptor); entry.configuration = configuration; entry.binaryDataOffset = 0; entry.binaryDataSize = parcelFileDescriptor.getStatSize(); + entry.isNinePatch = isNinePatch; return entry; } @@ -534,7 +545,26 @@ public class FabricatedOverlay { @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add( - generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); + generateFabricatedOverlayInternalEntry(resourceName, value, configuration, false)); + } + + /** + * Sets the resource value in the fabricated overlay from a nine patch. + * + * @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 + @FlaggedApi(android.content.res.Flags.FLAG_NINE_PATCH_FRRO) + public void setNinePatchResourceValue( + @NonNull String resourceName, + @NonNull ParcelFileDescriptor value, + @Nullable String configuration) { + ensureValidResourceName(resourceName); + mOverlay.entries.add( + generateFabricatedOverlayInternalEntry(resourceName, value, configuration, true)); } /** diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig index 40592a151fa7..3a00d91bfb9f 100644 --- a/core/java/android/content/res/flags.aconfig +++ b/core/java/android/content/res/flags.aconfig @@ -24,3 +24,10 @@ flag { # This flag is read in PackageParser at boot time, and in aapt2 which is a build tool. is_fixed_read_only: true } + +flag { + name: "nine_patch_frro" + namespace: "resource_manager" + description: "Feature flag for creating an frro from a 9-patch" + bug: "309232726" +} diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp index 0c39a6928391..358531a81979 100644 --- a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp +++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp @@ -46,6 +46,7 @@ static struct fabricated_overlay_internal_entry_offsets_t { jfieldID configuration; jfieldID binaryDataOffset; jfieldID binaryDataSize; + jfieldID isNinePatch; } gFabricatedOverlayInternalEntryOffsets; static struct parcel_file_descriptor_offsets_t { @@ -288,13 +289,16 @@ static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataOffset); const auto data_size = env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataSize); + const auto nine_patch = + env->GetBooleanField(entry, gFabricatedOverlayInternalEntryOffsets.isNinePatch); 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())}); + configuration.value_or(std::string()), + static_cast<bool>(nine_patch)}); ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s," " binaryData = %d, configuration = %s", resourceName.c_str(), dataType, data, string_data.value_or(std::string()).c_str(), @@ -455,6 +459,9 @@ int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env) { gFabricatedOverlayInternalEntryOffsets.binaryDataSize = GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "binaryDataSize", "J"); + gFabricatedOverlayInternalEntryOffsets.isNinePatch = + GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "isNinePatch", + "Z"); jclass parcelFileDescriptorClass = android::FindClassOrDie(env, "android/os/ParcelFileDescriptor"); diff --git a/libs/androidfw/FileStream.cpp b/libs/androidfw/FileStream.cpp index b86c9cb729d4..e8989490fe2c 100644 --- a/libs/androidfw/FileStream.cpp +++ b/libs/androidfw/FileStream.cpp @@ -22,6 +22,7 @@ #include "android-base/errors.h" #include "android-base/file.h" // for O_BINARY +#include "android-base/logging.h" #include "android-base/macros.h" #include "android-base/utf8.h" @@ -37,9 +38,9 @@ using ::android::base::unique_fd; namespace android { FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity) - : buffer_capacity_(buffer_capacity) { + : should_close_(true), buffer_capacity_(buffer_capacity) { int mode = O_RDONLY | O_CLOEXEC | O_BINARY; - fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode))); + fd_ = TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode)); if (fd_ == -1) { error_ = SystemErrorCodeToString(errno); } else { @@ -48,7 +49,17 @@ FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity } FileInputStream::FileInputStream(int fd, size_t buffer_capacity) - : fd_(fd), buffer_capacity_(buffer_capacity) { + : fd_(fd), should_close_(true), buffer_capacity_(buffer_capacity) { + if (fd_ < 0) { + error_ = "Bad File Descriptor"; + } else { + buffer_.reset(new uint8_t[buffer_capacity_]); + } +} + +FileInputStream::FileInputStream(android::base::borrowed_fd fd, size_t buffer_capacity) + : fd_(fd.get()), should_close_(false), buffer_capacity_(buffer_capacity) { + if (fd_ < 0) { error_ = "Bad File Descriptor"; } else { @@ -56,6 +67,7 @@ FileInputStream::FileInputStream(int fd, size_t buffer_capacity) } } + bool FileInputStream::Next(const void** data, size_t* size) { if (HadError()) { return false; @@ -73,7 +85,12 @@ bool FileInputStream::Next(const void** data, size_t* size) { ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_)); if (n < 0) { error_ = SystemErrorCodeToString(errno); - fd_.reset(); + if (fd_ != -1) { + if (should_close_) { + close(fd_); + } + fd_ = -1; + } buffer_.reset(); return false; } diff --git a/libs/androidfw/include/androidfw/BigBufferStream.h b/libs/androidfw/include/androidfw/BigBufferStream.h index e55fe0d653cc..c23194bae423 100644 --- a/libs/androidfw/include/androidfw/BigBufferStream.h +++ b/libs/androidfw/include/androidfw/BigBufferStream.h @@ -24,8 +24,13 @@ namespace android { class BigBufferInputStream : public KnownSizeInputStream { public: inline explicit BigBufferInputStream(const BigBuffer* buffer) - : buffer_(buffer), iter_(buffer->begin()) { + : owning_buffer_(0), buffer_(buffer), iter_(buffer->begin()) { } + + inline explicit BigBufferInputStream(android::BigBuffer&& buffer) + : owning_buffer_(std::move(buffer)), buffer_(&owning_buffer_), iter_(buffer_->begin()) { + } + virtual ~BigBufferInputStream() = default; bool Next(const void** data, size_t* size) override; @@ -47,6 +52,7 @@ class BigBufferInputStream : public KnownSizeInputStream { private: DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream); + android::BigBuffer owning_buffer_; const BigBuffer* buffer_; BigBuffer::const_iterator iter_; size_t offset_ = 0; diff --git a/libs/androidfw/include/androidfw/FileStream.h b/libs/androidfw/include/androidfw/FileStream.h index fb84a91a00de..87c42d12f825 100644 --- a/libs/androidfw/include/androidfw/FileStream.h +++ b/libs/androidfw/include/androidfw/FileStream.h @@ -18,6 +18,7 @@ #include <memory> #include <string> +#include <unistd.h> #include "Streams.h" #include "android-base/macros.h" @@ -35,6 +36,16 @@ class FileInputStream : public InputStream { // Take ownership of `fd`. explicit FileInputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity); + // Take ownership of `fd`. + explicit FileInputStream(android::base::borrowed_fd fd, + size_t buffer_capacity = kDefaultBufferCapacity); + + ~FileInputStream() { + if (should_close_ && (fd_ != -1)) { + close(fd_); + } + } + bool Next(const void** data, size_t* size) override; void BackUp(size_t count) override; @@ -50,8 +61,9 @@ class FileInputStream : public InputStream { private: DISALLOW_COPY_AND_ASSIGN(FileInputStream); - android::base::unique_fd fd_; + int fd_ = -1; std::string error_; + bool should_close_; std::unique_ptr<uint8_t[]> buffer_; size_t buffer_capacity_ = 0u; size_t buffer_offset_ = 0u; diff --git a/libs/androidfw/include/androidfw/IDiagnostics.h b/libs/androidfw/include/androidfw/IDiagnostics.h index 865a298f8389..d1dda818d97c 100644 --- a/libs/androidfw/include/androidfw/IDiagnostics.h +++ b/libs/androidfw/include/androidfw/IDiagnostics.h @@ -17,10 +17,15 @@ #ifndef _ANDROID_DIAGNOSTICS_H #define _ANDROID_DIAGNOSTICS_H +// on some systems ERROR is defined as 0 so android::base::ERROR becomes android::base::0 +// which doesn't compile. We undef it here to avoid that and because we don't ever need that def. +#undef ERROR + #include <sstream> #include <string> #include "Source.h" +#include "android-base/logging.h" #include "android-base/macros.h" #include "androidfw/StringPiece.h" @@ -144,6 +149,36 @@ class NoOpDiagnostics : public IDiagnostics { DISALLOW_COPY_AND_ASSIGN(NoOpDiagnostics); }; +class AndroidLogDiagnostics : public IDiagnostics { + public: + AndroidLogDiagnostics() = default; + + void Log(Level level, DiagMessageActual& actual_msg) override { + android::base::LogSeverity severity; + switch (level) { + case Level::Error: + severity = android::base::ERROR; + break; + + case Level::Warn: + severity = android::base::WARNING; + break; + + case Level::Note: + severity = android::base::INFO; + break; + } + if (!actual_msg.source.path.empty()) { + LOG(severity) << actual_msg.source << ": " + actual_msg.message; + } else { + LOG(severity) << actual_msg.message; + } + } + + DISALLOW_COPY_AND_ASSIGN(AndroidLogDiagnostics); +}; + + } // namespace android #endif /* _ANDROID_DIAGNOSTICS_H */ diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index fdb355192676..c0514fdff469 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1875,6 +1875,7 @@ struct FabricatedOverlayEntryParameters { off64_t binary_data_offset; size_t binary_data_size; std::string configuration; + bool nine_patch; }; class AssetManager2; diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java index f77d789891f7..d9c8ec6e5ed1 100644 --- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java +++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java @@ -317,11 +317,11 @@ final class OverlayManagerShellCommand extends ShellCommand { return 1; } final String overlayPackageName = "com.android.shell"; - FabricatedOverlay.Builder overlayBuilder = new FabricatedOverlay.Builder( - overlayPackageName, name, targetPackage) - .setTargetOverlayable(targetOverlayable); + FabricatedOverlay overlay = new FabricatedOverlay(name, targetPackage); + overlay.setTargetOverlayable(targetOverlayable); + overlay.setOwningPackage(overlayPackageName); if (filename != null) { - int result = addOverlayValuesFromXml(overlayBuilder, targetPackage, filename); + int result = addOverlayValuesFromXml(overlay, targetPackage, filename); if (result != 0) { return result; } @@ -329,18 +329,18 @@ final class OverlayManagerShellCommand extends ShellCommand { final String resourceName = getNextArgRequired(); final String typeStr = getNextArgRequired(); final String strData = String.join(" ", peekRemainingArgs()); - if (addOverlayValue(overlayBuilder, resourceName, typeStr, strData, config) != 0) { + if (addOverlayValue(overlay, resourceName, typeStr, strData, config) != 0) { return 1; } } mInterface.commit(new OverlayManagerTransaction.Builder() - .registerFabricatedOverlay(overlayBuilder.build()).build()); + .registerFabricatedOverlay(overlay).build()); return 0; } private int addOverlayValuesFromXml( - FabricatedOverlay.Builder overlayBuilder, String targetPackage, String filename) { + FabricatedOverlay overlay, String targetPackage, String filename) { final PrintWriter err = getErrPrintWriter(); File file = new File(filename); if (!file.exists()) { @@ -388,7 +388,7 @@ final class OverlayManagerShellCommand extends ShellCommand { return 1; } String config = parser.getAttributeValue(null, "config"); - if (addOverlayValue(overlayBuilder, targetPackage + ':' + target, + if (addOverlayValue(overlay, targetPackage + ':' + target, overlayType, value, config) != 0) { return 1; } @@ -405,8 +405,8 @@ final class OverlayManagerShellCommand extends ShellCommand { return 0; } - private int addOverlayValue(FabricatedOverlay.Builder overlayBuilder, - String resourceName, String typeString, String valueString, String configuration) { + private int addOverlayValue(FabricatedOverlay overlay, String resourceName, String typeString, + String valueString, String configuration) { final int type; typeString = typeString.toLowerCase(Locale.getDefault()); if (TYPE_MAP.containsKey(typeString)) { @@ -419,10 +419,14 @@ final class OverlayManagerShellCommand extends ShellCommand { } } if (type == TypedValue.TYPE_STRING) { - overlayBuilder.setResourceValue(resourceName, type, valueString, configuration); + overlay.setResourceValue(resourceName, type, valueString, configuration); } else if (type < 0) { ParcelFileDescriptor pfd = openFileForSystem(valueString, "r"); - overlayBuilder.setResourceValue(resourceName, pfd, configuration); + if (valueString.endsWith(".9.png")) { + overlay.setNinePatchResourceValue(resourceName, pfd, configuration); + } else { + overlay.setResourceValue(resourceName, pfd, configuration); + } } else { final int intData; if (valueString.startsWith("0x")) { @@ -430,7 +434,7 @@ final class OverlayManagerShellCommand extends ShellCommand { } else { intData = Integer.parseUnsignedInt(valueString); } - overlayBuilder.setResourceValue(resourceName, type, intData, configuration); + overlay.setResourceValue(resourceName, type, intData, configuration); } return 0; } |