diff options
| -rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 174 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/ResourceTypes.h | 10 |
2 files changed, 61 insertions, 123 deletions
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 5e8a623d4205..46fbe7c4d981 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -1020,6 +1020,40 @@ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool: return base::unexpected(std::nullopt); } +template <typename TChar, typename SP> +base::expected<size_t, NullOrIOError> ResStringPool::stringIndex( + SP sp, std::unordered_map<SP, size_t>& map) const +{ + AutoMutex lock(mStringIndexLock); + + if (map.empty()) { + // build string index on the first call + for (size_t i = 0; i < mHeader->stringCount; i++) { + base::expected<SP, NullOrIOError> s; + if constexpr(std::is_same_v<TChar, char16_t>) { + s = stringAt(i); + } else { + s = string8At(i); + } + if (s.has_value()) { + const auto r = map.insert({*s, i}); + if (!r.second) { + ALOGE("failed to build string index, string id=%zu\n", i); + } + } else { + return base::unexpected(s.error()); + } + } + } + + if (!map.empty()) { + const auto result = map.find(sp); + if (result != map.end()) + return result->second; + } + return base::unexpected(std::nullopt); +} + base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str, size_t strLen) const { @@ -1027,134 +1061,28 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_ return base::unexpected(std::nullopt); } - if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { - if (kDebugStringPoolNoisy) { - ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string()); - } - - // The string pool contains UTF 8 strings; we don't want to cause - // temporary UTF-16 strings to be created as we search. - if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { - // Do a binary search for the string... this is a little tricky, - // because the strings are sorted with strzcmp16(). So to match - // the ordering, we need to convert strings in the pool to UTF-16. - // But we don't want to hit the cache, so instead we will have a - // local temporary allocation for the conversions. - size_t convBufferLen = strLen + 4; - std::vector<char16_t> convBuffer(convBufferLen); - ssize_t l = 0; - ssize_t h = mHeader->stringCount-1; - - ssize_t mid; - while (l <= h) { - mid = l + (h - l)/2; - int c = -1; - const base::expected<StringPiece, NullOrIOError> s = string8At(mid); - if (UNLIKELY(IsIOError(s))) { - return base::unexpected(s.error()); - } - if (s.has_value()) { - char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()), - s->size(), convBuffer.data(), convBufferLen); - c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen); - } - if (kDebugStringPoolNoisy) { - ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", - s->data(), c, (int)l, (int)mid, (int)h); - } - if (c == 0) { - if (kDebugStringPoolNoisy) { - ALOGI("MATCH!"); - } - return mid; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - } else { - // It is unusual to get the ID from an unsorted string block... - // most often this happens because we want to get IDs for style - // span tags; since those always appear at the end of the string - // block, start searching at the back. - String8 str8(str, strLen); - const size_t str8Len = str8.size(); - for (int i=mHeader->stringCount-1; i>=0; i--) { - const base::expected<StringPiece, NullOrIOError> s = string8At(i); - if (UNLIKELY(IsIOError(s))) { - return base::unexpected(s.error()); - } - if (s.has_value()) { - if (kDebugStringPoolNoisy) { - ALOGI("Looking at %s, i=%d\n", s->data(), i); - } - if (str8Len == s->size() - && memcmp(s->data(), str8.string(), str8Len) == 0) { - if (kDebugStringPoolNoisy) { - ALOGI("MATCH!"); - } - return i; - } - } - } - } + if (kDebugStringPoolNoisy) { + ALOGI("indexOfString (%s): %s", isUTF8() ? "UTF-8" : "UTF-16", + String8(str, strLen).string()); + } + base::expected<size_t, NullOrIOError> idx; + if (isUTF8()) { + auto str8 = String8(str, strLen); + idx = stringIndex<char>(StringPiece(str8.c_str(), str8.size()), mStringIndex8); } else { - if (kDebugStringPoolNoisy) { - ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()); - } + idx = stringIndex<char16_t>(StringPiece16(str, strLen), mStringIndex16); + } - if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { - // Do a binary search for the string... - ssize_t l = 0; - ssize_t h = mHeader->stringCount-1; + if (UNLIKELY(!idx.has_value())) { + return base::unexpected(idx.error()); + } - ssize_t mid; - while (l <= h) { - mid = l + (h - l)/2; - const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid); - if (UNLIKELY(IsIOError(s))) { - return base::unexpected(s.error()); - } - int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1; - if (kDebugStringPoolNoisy) { - ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", - String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h); - } - if (c == 0) { - if (kDebugStringPoolNoisy) { - ALOGI("MATCH!"); - } - return mid; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - } else { - // It is unusual to get the ID from an unsorted string block... - // most often this happens because we want to get IDs for style - // span tags; since those always appear at the end of the string - // block, start searching at the back. - for (int i=mHeader->stringCount-1; i>=0; i--) { - const base::expected<StringPiece16, NullOrIOError> s = stringAt(i); - if (UNLIKELY(IsIOError(s))) { - return base::unexpected(s.error()); - } - if (kDebugStringPoolNoisy) { - ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i); - } - if (s.has_value() && strLen == s->size() && - strzcmp16(s->data(), s->size(), str, strLen) == 0) { - if (kDebugStringPoolNoisy) { - ALOGI("MATCH!"); - } - return i; - } - } + if (*idx < mHeader->stringCount) { + if (kDebugStringPoolNoisy) { + ALOGI("MATCH! (idx=%zu)", *idx); } + return *idx; } return base::unexpected(std::nullopt); } diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 8c614bcf7145..77765efcd223 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -41,6 +41,7 @@ #include <array> #include <map> #include <memory> +#include <unordered_map> namespace android { @@ -562,8 +563,17 @@ private: incfs::map_ptr<uint32_t> mStyles; uint32_t mStylePoolSize; // number of uint32_t + // mStringIndex is used to quickly map a string to its ID + mutable Mutex mStringIndexLock; + mutable std::unordered_map<StringPiece, size_t> mStringIndex8; + mutable std::unordered_map<StringPiece16, size_t> mStringIndex16; + base::expected<StringPiece, NullOrIOError> stringDecodeAt( size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const; + + template <typename TChar, typename SP=BasicStringPiece<TChar>> + base::expected<size_t, NullOrIOError> stringIndex( + SP str, std::unordered_map<SP, size_t>& map) const; }; /** |