Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62b4ddd5 authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "libandroidfw: Add SparseEntry support for LoadedArsc"

parents bdf30c84 73f6f9da
Loading
Loading
Loading
Loading
+66 −20
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "androidfw/LoadedArsc.h"

#include <algorithm>
#include <cstddef>
#include <limits>

@@ -244,31 +245,63 @@ bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_i

  for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
    const Type* type = &type_spec_ptr->types[i];
    const ResTable_type* type_chunk = type->type;

    if (type->configuration.match(config) &&
        (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
      // The configuration matches and is better than the previous selection.
      // Find the entry value if it exists for this configuration.
      const size_t entry_count = dtohl(type->type->entryCount);
      const size_t offsets_offset = dtohs(type->type->header.headerSize);
      if (entry_idx < entry_count) {
      const size_t entry_count = dtohl(type_chunk->entryCount);
      const size_t offsets_offset = dtohs(type_chunk->header.headerSize);

      // If the package hasn't been verified, do bounds checking.
      if (!Verified) {
          if (!VerifyResTableType(type->type)) {
        if (!VerifyResTableType(type_chunk)) {
          continue;
        }
      }

      // Check if there is the desired entry in this type.

      if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
        // This is encoded as a sparse map, so perform a binary search.
        const ResTable_sparseTypeEntry* sparse_indices =
            reinterpret_cast<const ResTable_sparseTypeEntry*>(
                reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
        const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
        const ResTable_sparseTypeEntry* result =
            std::lower_bound(sparse_indices, sparse_indices_end, entry_idx,
                             [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
                               return dtohs(entry.idx) < entry_idx;
                             });

        if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) {
          // No entry found.
          continue;
        }

        // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
        // the real offset divided by 4.
        best_offset = dtohs(result->offset) * 4u;
      } else {
        if (entry_idx >= entry_count) {
          // This entry cannot be here.
          continue;
        }

        const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
            reinterpret_cast<const uint8_t*>(type->type) + offsets_offset);
            reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
        const uint32_t offset = dtohl(entry_offsets[entry_idx]);
        if (offset != ResTable_type::NO_ENTRY) {
        if (offset == ResTable_type::NO_ENTRY) {
          continue;
        }

        // There is an entry for this resource, record it.
          best_config = &type->configuration;
          best_type = type->type;
        best_offset = offset;
      }
      }

      best_config = &type->configuration;
      best_type = type_chunk;
    }
  }

@@ -335,9 +368,21 @@ static bool VerifyType(const Chunk& chunk) {
  const size_t entry_count = dtohl(header->entryCount);
  const size_t offsets_offset = chunk.header_size();

  if (header->flags & ResTable_type::FLAG_SPARSE) {
    // This is encoded as a sparse map, so perform a binary search.
    const ResTable_sparseTypeEntry* sparse_indices =
        reinterpret_cast<const ResTable_sparseTypeEntry*>(reinterpret_cast<const uint8_t*>(header) +
                                                          offsets_offset);
    for (size_t i = 0; i < entry_count; i++) {
      const uint32_t offset = uint32_t{dtohs(sparse_indices[i].offset)} * 4u;
      if (!VerifyResTableEntry(header, offset, i)) {
        return false;
      }
    }
  } else {
    // Check each entry offset.
  const uint32_t* offsets =
      reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset);
    const uint32_t* offsets = reinterpret_cast<const uint32_t*>(
        reinterpret_cast<const uint8_t*>(header) + offsets_offset);
    for (size_t i = 0; i < entry_count; i++) {
      uint32_t offset = dtohl(offsets[i]);
      if (offset != ResTable_type::NO_ENTRY) {
@@ -346,6 +391,7 @@ static bool VerifyType(const Chunk& chunk) {
        }
      }
    }
  }
  return true;
}

+0 −31
Original line number Diff line number Diff line
@@ -83,37 +83,6 @@ static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) {
}
BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);

static void GetResourceBenchmark(const std::vector<std::string>& paths,
                                 const ResTable_config* config, uint32_t resid,
                                 benchmark::State& state) {
  std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
  std::vector<const ApkAssets*> apk_assets_ptrs;
  for (const std::string& path : paths) {
    std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
    if (apk == nullptr) {
      state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
      return;
    }
    apk_assets_ptrs.push_back(apk.get());
    apk_assets.push_back(std::move(apk));
  }

  AssetManager2 assetmanager;
  assetmanager.SetApkAssets(apk_assets_ptrs);
  if (config != nullptr) {
    assetmanager.SetConfiguration(*config);
  }

  Res_value value;
  ResTable_config selected_config;
  uint32_t flags;

  while (state.KeepRunning()) {
    assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
                             &selected_config, &flags);
  }
}

static void BM_AssetManagerGetResource(benchmark::State& state) {
  GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
                       basic::R::integer::number1, state);
+31 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "android-base/stringprintf.h"
#include "androidfw/AssetManager.h"
#include "androidfw/AssetManager2.h"

namespace android {

@@ -48,4 +49,34 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab
  }
}

void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config,
                          uint32_t resid, benchmark::State& state) {
  std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
  std::vector<const ApkAssets*> apk_assets_ptrs;
  for (const std::string& path : paths) {
    std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path);
    if (apk == nullptr) {
      state.SkipWithError(base::StringPrintf("Failed to load assets %s", path.c_str()).c_str());
      return;
    }
    apk_assets_ptrs.push_back(apk.get());
    apk_assets.push_back(std::move(apk));
  }

  AssetManager2 assetmanager;
  assetmanager.SetApkAssets(apk_assets_ptrs);
  if (config != nullptr) {
    assetmanager.SetConfiguration(*config);
  }

  Res_value value;
  ResTable_config selected_config;
  uint32_t flags;

  while (state.KeepRunning()) {
    assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
                             &selected_config, &flags);
  }
}

}  // namespace android
+3 −0
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ namespace android {
void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTable_config* config,
                             uint32_t resid, ::benchmark::State& state);

void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_config* config,
                          uint32_t resid, benchmark::State& state);

}  // namespace android

#endif  // ANDROIDFW_TESTS_BENCHMARKHELPERS_H
+19 −0
Original line number Diff line number Diff line
@@ -19,11 +19,13 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
#include "data/libclient/R.h"
#include "data/sparse/R.h"
#include "data/styles/R.h"

namespace app = com::android::app;
namespace basic = com::android::basic;
namespace libclient = com::android::libclient;
namespace sparse = com::android::sparse;

namespace android {

@@ -68,6 +70,23 @@ TEST(LoadedArscTest, FindDefaultEntry) {
  ASSERT_NE(nullptr, entry.entry);
}

TEST(LoadedArscTest, LoadSparseEntryApp) {
  std::string contents;
  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
                                      &contents));

  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
  ASSERT_NE(nullptr, loaded_arsc);

  ResTable_config config;
  memset(&config, 0, sizeof(config));
  config.sdkVersion = 26;

  FindEntryResult entry;
  ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry));
  ASSERT_NE(nullptr, entry.entry);
}

TEST(LoadedArscTest, LoadSharedLibrary) {
  std::string contents;
  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
Loading