diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp index 6b1c7e83c826f6d90f0f082c39fbf4e092174661..15109d99a6fd752c8b09a283e8f40125ec8e8672 100644 --- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp +++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp @@ -144,7 +144,7 @@ TEST(FabricatedOverlayTests, SerializeAndDeserialize) { "com.example.target:string/string1", Res_value::TYPE_STRING, "foobar", "") .Build(); ASSERT_TRUE(overlay); - TemporaryFile tf; + TempFrroFile tf; std::ofstream out(tf.path); ASSERT_TRUE((*overlay).ToBinaryStream(out)); out.close(); diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index a384305da43db45063a3f4e3dc1c044bfa130e61..c85619c1e4bfb265e92da14af7f82a58ed6883c1 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -274,7 +274,7 @@ TEST(IdmapTests, FabricatedOverlay) { .Build(); ASSERT_TRUE(frro); - TemporaryFile tf; + TempFrroFile tf; std::ofstream out(tf.path); ASSERT_TRUE((*frro).ToBinaryStream(out)); out.close(); @@ -467,9 +467,9 @@ TEST(IdmapTests, CreateIdmapDataInlineResources) { TEST(IdmapTests, IdmapHeaderIsUpToDate) { fclose(stderr); // silence expected warnings from libandroidfw - const std::string target_apk_path = kIdmapRawTargetPath; - const std::string overlay_apk_path = kIdmapRawOverlayPath; - const std::string overlay_name = kIdmapRawOverlayName; + const std::string target_apk_path {kIdmapRawTargetPath}; + const std::string overlay_apk_path {kIdmapRawOverlayPath}; + const std::string overlay_name {kIdmapRawOverlayName}; const PolicyBitmask policies = kIdmapRawDataPolicies; const uint32_t target_crc = kIdmapRawDataTargetCrc; const uint32_t overlay_crc = kIdmapRawOverlayCrc; diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index db44c23a41f9b113bfe390f422c38b430b57c27c..1d2255378018cbfb8f16c8c18557044e326b3080 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -217,7 +217,7 @@ TEST(ResourceMappingTests, FabricatedOverlay) { .Build(); ASSERT_TRUE(frro); - TemporaryFile tf; + TempFrroFile tf; std::ofstream out(tf.path); ASSERT_TRUE((*frro).ToBinaryStream(out)); out.close(); diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index cdc0b8fbb87e6d1b47bb2ed76e1fdbf5a35b918b..bf01c32c4c86ad8aaf82089f43cf8c2c4cbb491e 100644 --- a/cmds/idmap2/tests/TestHelpers.h +++ b/cmds/idmap2/tests/TestHelpers.h @@ -17,11 +17,15 @@ #ifndef IDMAP2_TESTS_TESTHELPERS_H_ #define IDMAP2_TESTS_TESTHELPERS_H_ +#include <stdio.h> #include <string> +#include <string_view> #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "android-base/file.h" + namespace android::idmap2 { const unsigned char kIdmapRawData[] = { @@ -197,12 +201,23 @@ const unsigned int kIdmapRawDataOffset = 0x54; const unsigned int kIdmapRawDataTargetCrc = 0x1234; const unsigned int kIdmapRawOverlayCrc = 0x5678; const unsigned int kIdmapRawDataPolicies = 0x11; -inline const std::string kIdmapRawTargetPath = "targetX.apk"; -inline const std::string kIdmapRawOverlayPath = "overlayX.apk"; -inline const std::string kIdmapRawOverlayName = "OverlayName"; +inline const std::string_view kIdmapRawTargetPath = "targetX.apk"; +inline const std::string_view kIdmapRawOverlayPath = "overlayX.apk"; +inline const std::string_view kIdmapRawOverlayName = "OverlayName"; std::string GetTestDataPath(); +class TempFrroFile : public TemporaryFile { +public: + TempFrroFile() { + std::string new_path = path; + new_path += ".frro"; + ::rename(path, new_path.c_str()); + const auto new_len = new_path.copy(path, sizeof(path) - 1); + path[new_len] = '\0'; + } +}; + class Idmap2Tests : public testing::Test { protected: void SetUp() override { diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index f0c639574a9ff8e99043fcd73bfd0174a82f5fdc..49254d1c6f6ea00445ad95d1428173a6ec1e4d61 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -81,7 +81,7 @@ ApkAssetsPtr ApkAssets::LoadOverlay(const std::string& idmap_path, package_prope std::string overlay_path(loaded_idmap->OverlayApkPath()); auto fd = unique_fd(base::utf8::open(overlay_path.c_str(), O_RDONLY | O_CLOEXEC)); std::unique_ptr<AssetsProvider> overlay_assets; - if (IsFabricatedOverlay(fd)) { + if (IsFabricatedOverlayName(overlay_path) && IsFabricatedOverlay(fd)) { // Fabricated overlays do not contain resource definitions. All of the overlay resource values // are defined inline in the idmap. overlay_assets = EmptyAssetsProvider::Create(std::move(overlay_path)); @@ -137,8 +137,7 @@ ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_asset, return {}; } loaded_arsc = LoadedArsc::Load(data, length, loaded_idmap.get(), property_flags); - } else if (loaded_idmap != nullptr && - IsFabricatedOverlay(std::string(loaded_idmap->OverlayApkPath()))) { + } else if (loaded_idmap != nullptr && IsFabricatedOverlay(loaded_idmap->OverlayApkPath())) { loaded_arsc = LoadedArsc::Load(loaded_idmap.get()); } else { loaded_arsc = LoadedArsc::CreateEmpty(); diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp index 5f98b8f8db43e8107ec8ea1cfff8400fa69686b4..982419059ead0d671b4800ededdee7ca1a91a3fb 100644 --- a/libs/androidfw/Idmap.cpp +++ b/libs/androidfw/Idmap.cpp @@ -18,8 +18,10 @@ #include "androidfw/Idmap.h" +#include "android-base/file.h" #include "android-base/logging.h" #include "android-base/stringprintf.h" +#include "android-base/utf8.h" #include "androidfw/misc.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" @@ -250,7 +252,12 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size } } // namespace -LoadedIdmap::LoadedIdmap(std::string&& idmap_path, const Idmap_header* header, +// O_PATH is a lightweight way of creating an FD, only exists on Linux +#ifndef O_PATH +#define O_PATH (0) +#endif + +LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header, const Idmap_data_header* data_header, const Idmap_target_entry* target_entries, const Idmap_target_entry_inline* target_inline_entries, @@ -267,10 +274,10 @@ LoadedIdmap::LoadedIdmap(std::string&& idmap_path, const Idmap_header* header, configurations_(configs), overlay_entries_(overlay_entries), string_pool_(std::move(string_pool)), - idmap_path_(std::move(idmap_path)), + idmap_fd_(android::base::utf8::open(idmap_path.c_str(), O_RDONLY|O_CLOEXEC|O_BINARY|O_PATH)), overlay_apk_path_(overlay_apk_path), target_apk_path_(target_apk_path), - idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {} + idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) {} std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) { ATRACE_CALL(); @@ -368,7 +375,7 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie } bool LoadedIdmap::IsUpToDate() const { - return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str()); + return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get()); } } // namespace android diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 2c99f1aa3675e40a21a036c6c83b43f155f82690..a3dd9833219ea34da29371fce9e134ccd682eaee 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -54,6 +54,8 @@ #define INT32_MAX ((int32_t)(2147483647)) #endif +using namespace std::literals; + namespace android { #if defined(_WIN32) @@ -237,12 +239,24 @@ void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData)); } -bool IsFabricatedOverlay(const std::string& path) { - return IsFabricatedOverlay(path.c_str()); +bool IsFabricatedOverlayName(std::string_view path) { + static constexpr auto suffixFrro = ".frro"sv; + static constexpr auto suffixIdmap = ".frro@idmap"sv; + + return (path.size() > suffixFrro.size() && path.ends_with(suffixFrro)) + || (path.size() > suffixIdmap.size() && path.ends_with(suffixIdmap)); } -bool IsFabricatedOverlay(const char* path) { - auto fd = base::unique_fd(base::utf8::open(path, O_RDONLY|O_CLOEXEC)); +bool IsFabricatedOverlay(std::string_view path) { + if (!IsFabricatedOverlayName(path)) { + return false; + } + std::string path_copy; + if (path[path.size()] != '\0') { + path_copy.assign(path); + path = path_copy; + } + auto fd = base::unique_fd(base::utf8::open(path.data(), O_RDONLY|O_CLOEXEC|O_BINARY)); if (fd < 0) { return false; } @@ -7319,9 +7333,6 @@ class IdmapTypeMapping { public: void add(uint32_t targetResId, uint32_t overlayResId) { uint8_t targetTypeId = Res_GETTYPE(targetResId); - if (mData.find(targetTypeId) == mData.end()) { - mData.emplace(targetTypeId, std::set<std::pair<uint32_t, uint32_t>>()); - } auto& entries = mData[targetTypeId]; entries.insert(std::make_pair(targetResId, overlayResId)); } diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index d9f7c2a1ac195184ac58a1ec53b080cbf997025d..c32a38ee9ec27bda776da690a5fe0c764e149b8f 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -23,6 +23,7 @@ #include <variant> #include "android-base/macros.h" +#include "android-base/unique_fd.h" #include "androidfw/ConfigDescription.h" #include "androidfw/StringPiece.h" #include "androidfw/ResourceTypes.h" @@ -159,11 +160,6 @@ class LoadedIdmap { // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed. static std::unique_ptr<LoadedIdmap> Load(StringPiece idmap_path, StringPiece idmap_data); - // Returns the path to the IDMAP. - std::string_view IdmapPath() const { - return idmap_path_; - } - // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. std::string_view OverlayApkPath() const { return overlay_apk_path_; @@ -203,7 +199,7 @@ class LoadedIdmap { const Idmap_overlay_entry* overlay_entries_; const std::unique_ptr<ResStringPool> string_pool_; - std::string idmap_path_; + android::base::unique_fd idmap_fd_; std::string_view overlay_apk_path_; std::string_view target_apk_path_; time_t idmap_last_mod_time_; @@ -211,7 +207,7 @@ class LoadedIdmap { private: DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); - explicit LoadedIdmap(std::string&& idmap_path, + explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header, const Idmap_data_header* data_header, const Idmap_target_entry* target_entries, diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 3d1403d0e039f4f4d54f3e20967c9a45442e49df..c2648909386ca3722c8a3bff98708505ab4f27a2 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -59,8 +59,8 @@ constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endi constexpr const uint32_t kFabricatedOverlayCurrentVersion = 3; // Returns whether or not the path represents a fabricated overlay. -bool IsFabricatedOverlay(const std::string& path); -bool IsFabricatedOverlay(const char* path); +bool IsFabricatedOverlayName(std::string_view path); +bool IsFabricatedOverlay(std::string_view path); bool IsFabricatedOverlay(android::base::borrowed_fd fd); /** diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h index d40d24ede769eb1240ee3fdf01157d378385223b..077609d20d551e924df897a64eab3c0ba3007b8c 100644 --- a/libs/androidfw/include/androidfw/misc.h +++ b/libs/androidfw/include/androidfw/misc.h @@ -43,6 +43,8 @@ typedef enum FileType { FileType getFileType(const char* fileName); /* get the file's modification date; returns -1 w/errno set on failure */ time_t getFileModDate(const char* fileName); +/* same, but also returns -1 if the file has already been deleted */ +time_t getFileModDate(int fd); // Check if |path| or |fd| resides on a readonly filesystem. bool isReadonlyFilesystem(const char* path); diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp index d3949e9cf69ff972d9653f48690b36b607afa561..93dcaf549a907c594a079ba6a1901455b8a982ef 100644 --- a/libs/androidfw/misc.cpp +++ b/libs/androidfw/misc.cpp @@ -76,13 +76,23 @@ FileType getFileType(const char* fileName) /* * Get a file's modification date. */ -time_t getFileModDate(const char* fileName) -{ +time_t getFileModDate(const char* fileName) { struct stat sb; + if (stat(fileName, &sb) < 0) { + return (time_t)-1; + } + return sb.st_mtime; +} - if (stat(fileName, &sb) < 0) - return (time_t) -1; - +time_t getFileModDate(int fd) { + struct stat sb; + if (fstat(fd, &sb) < 0) { + return (time_t)-1; + } + if (sb.st_nlink <= 0) { + errno = ENOENT; + return (time_t)-1; + } return sb.st_mtime; }