Merge "[res] Use fstat() for idmap::IsUpToDate()" into main
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index 6b1c7e8..15109d9 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -144,7 +144,7 @@
"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 a384305..c85619c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -274,7 +274,7 @@
.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, 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 db44c23..1d22553 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -217,7 +217,7 @@
.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 cdc0b8f..bf01c32 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 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 f0c6395..49254d1 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -81,7 +81,7 @@
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 @@
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 5f98b8f..9824190 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 @@
}
} // 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 @@
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 @@
}
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 2c99f1a..a3dd983 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 @@
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 @@
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 d9f7c2a..c32a38e 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 @@
// 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 @@
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 @@
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 3d1403d..c264890 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -59,8 +59,8 @@
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 d40d24e..077609d 100644
--- a/libs/androidfw/include/androidfw/misc.h
+++ b/libs/androidfw/include/androidfw/misc.h
@@ -43,6 +43,8 @@
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 d3949e9..93dcaf5 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -76,13 +76,23 @@
/*
* 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;
}