Refactor ApkAsset loading APIs

To add the partner requested ResourcesProvider#loadFromDir APIs, this
change adds format type integer that allows us to reduce the number of
ApkAssets loading overrides.

This change also adds hidden offset and length based ResourcesProvider
APIs that could not make R.

Bug: 142716192
Test: atest FrameworksResourceLoaderTests
Change-Id: I926fde257cae701901dcd4ca408024feae8c90a6
Merged-In: I926fde257cae701901dcd4ca408024feae8c90a6
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index b2b0ec2..946fcc0 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -41,28 +41,85 @@
 static const std::string kResourcesArsc("resources.arsc");
 
 ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle,
-                     const std::string& path,
+                     std::string path,
                      time_t last_mod_time,
                      package_property_t property_flags)
-    : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time),
+    : zip_handle_(unmanaged_handle, ::CloseArchive),
+      path_(std::move(path)),
+      last_mod_time_(last_mod_time),
       property_flags_(property_flags) {
 }
 
-std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system,
-                                                 bool for_loader) {
-  package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) |
-                             (for_loader ? PROPERTY_LOADER : 0U);
-  return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags);
+std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path,
+                                                 const package_property_t flags) {
+  ::ZipArchiveHandle unmanaged_handle;
+  const int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+  if (result != 0) {
+    LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
+    ::CloseArchive(unmanaged_handle);
+    return {};
+  }
+
+  return LoadImpl(unmanaged_handle,  path, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
+                  flags);
 }
 
-std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
-                                                                bool system) {
-  package_property_t flags = PROPERTY_DYNAMIC | (system ? PROPERTY_SYSTEM : 0U);
-  return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags);
+std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
+                                                       const std::string& friendly_name,
+                                                       const package_property_t flags,
+                                                       const off64_t offset,
+                                                       const off64_t length) {
+  CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
+  CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
+                                                 << kUnknownLength;
+
+  ::ZipArchiveHandle unmanaged_handle;
+  const int32_t result = (length == kUnknownLength)
+      ? ::OpenArchiveFd(fd.release(), friendly_name.c_str(), &unmanaged_handle)
+      : ::OpenArchiveFdRange(fd.release(), friendly_name.c_str(), &unmanaged_handle, length,
+                             offset);
+
+  if (result != 0) {
+    LOG(ERROR) << "Failed to open APK '" << friendly_name << "' through FD with offset " << offset
+               << " and length " << length << ": " << ::ErrorCodeString(result);
+    ::CloseArchive(unmanaged_handle);
+    return {};
+  }
+
+  return LoadImpl(unmanaged_handle, friendly_name, nullptr /*idmap_asset*/,
+                  nullptr /*loaded_idmap*/, flags);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadTable(const std::string& path,
+                                                      const package_property_t flags) {
+  auto resources_asset = CreateAssetFromFile(path);
+  if (!resources_asset) {
+    LOG(ERROR) << "Failed to open ARSC '" << path;
+    return {};
+  }
+
+  return LoadTableImpl(std::move(resources_asset), path, flags);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadTableFromFd(unique_fd fd,
+                                                            const std::string& friendly_name,
+                                                            const package_property_t flags,
+                                                            const off64_t offset,
+                                                            const off64_t length) {
+  auto resources_asset = CreateAssetFromFd(std::move(fd), nullptr /* path */, offset, length);
+  if (!resources_asset) {
+    LOG(ERROR) << "Failed to open ARSC '" << friendly_name << "' through FD with offset " << offset
+               << " and length " << length;
+    return {};
+  }
+
+  return LoadTableImpl(std::move(resources_asset), friendly_name, flags);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
-                                                        bool system) {
+                                                        const package_property_t flags) {
+  CHECK((flags & PROPERTY_LOADER) == 0U) << "Cannot load RROs through loaders";
+
   std::unique_ptr<Asset> idmap_asset = CreateAssetFromFile(idmap_path);
   if (idmap_asset == nullptr) {
     return {};
@@ -77,75 +134,74 @@
     return {};
   }
 
-  auto apkPath = loaded_idmap->OverlayApkPath();
-  return LoadImpl({} /*fd*/, apkPath,
-                  std::move(idmap_asset),
-                  std::move(loaded_idmap),
-                  PROPERTY_OVERLAY | (system ? PROPERTY_SYSTEM : 0U));
-}
 
-std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
-                                                       const std::string& friendly_name,
-                                                       bool system, bool force_shared_lib,
-                                                       bool for_loader) {
-  package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) |
-                             (force_shared_lib ? PROPERTY_DYNAMIC : 0U) |
-                             (for_loader ? PROPERTY_LOADER : 0U);
-  return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
-                  flags);
-}
-
-std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(const std::string& path,
-                                                     bool for_loader) {
-  return LoadArscImpl({} /*fd*/, path, for_loader ? PROPERTY_LOADER : 0U);
-}
-
-std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(unique_fd fd,
-                                                     const std::string& friendly_name,
-                                                     bool for_loader) {
-  return LoadArscImpl(std::move(fd), friendly_name, for_loader ? PROPERTY_LOADER : 0U);
-}
-
-std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
-  unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
-  if (fd == -1) {
-    LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
-    return {};
-  }
-
-  const off64_t file_len = lseek64(fd, 0, SEEK_END);
-  if (file_len < 0) {
-    LOG(ERROR) << "Failed to get size of file '" << path << "': " << SystemErrorCodeToString(errno);
-    return {};
-  }
-
-  std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
-  if (!file_map->create(path.c_str(), fd, 0, static_cast<size_t>(file_len), true /*readOnly*/)) {
-    LOG(ERROR) << "Failed to mmap file '" << path << "': " << SystemErrorCodeToString(errno);
-    return {};
-  }
-  return Asset::createFromUncompressedMap(std::move(file_map), Asset::AccessMode::ACCESS_RANDOM);
-}
-
-std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
-    unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset,
-    std::unique_ptr<const LoadedIdmap> loaded_idmap, package_property_t property_flags) {
   ::ZipArchiveHandle unmanaged_handle;
-  int32_t result;
-  if (fd >= 0) {
-    result =
-        ::OpenArchiveFd(fd.release(), path.c_str(), &unmanaged_handle, true /*assume_ownership*/);
-  } else {
-    result = ::OpenArchive(path.c_str(), &unmanaged_handle);
-  }
-
+  auto overlay_path = loaded_idmap->OverlayApkPath();
+  const int32_t result = ::OpenArchive(overlay_path.c_str(), &unmanaged_handle);
   if (result != 0) {
-    LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
+    LOG(ERROR) << "Failed to open overlay APK '" << overlay_path << "' "
+               << ::ErrorCodeString(result);
     ::CloseArchive(unmanaged_handle);
     return {};
   }
 
-  time_t last_mod_time = getFileModDate(path.c_str());
+  return LoadImpl(unmanaged_handle, overlay_path, std::move(idmap_asset), std::move(loaded_idmap),
+                  flags | PROPERTY_OVERLAY);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(const package_property_t flags) {
+  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "empty", -1, flags));
+  loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
+  // Need to force a move for mingw32.
+  return std::move(loaded_apk);
+}
+
+std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
+  unique_fd fd(base::utf8::open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
+  if (!fd.ok()) {
+    LOG(ERROR) << "Failed to open file '" << path << "': " << SystemErrorCodeToString(errno);
+    return {};
+  }
+
+  return CreateAssetFromFd(std::move(fd), path.c_str());
+}
+
+std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd,
+                                                    const char* path,
+                                                    off64_t offset,
+                                                    off64_t length) {
+  CHECK(length >= kUnknownLength) << "length must be greater than or equal to " << kUnknownLength;
+  CHECK(length != kUnknownLength || offset == 0) << "offset must be 0 if length is "
+                                                 << kUnknownLength;
+  if (length == kUnknownLength) {
+    length = lseek64(fd, 0, SEEK_END);
+    if (length < 0) {
+      LOG(ERROR) << "Failed to get size of file '" << ((path) ? path : "anon") << "': "
+                 << SystemErrorCodeToString(errno);
+      return {};
+    }
+  }
+
+  std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
+  if (!file_map->create(path, fd, offset, static_cast<size_t>(length), true /*readOnly*/)) {
+    LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': "
+               << SystemErrorCodeToString(errno);
+    return {};
+  }
+
+  // If `path` is set, do not pass ownership of the `fd` to the new Asset since
+  // Asset::openFileDescriptor can use `path` to create new file descriptors.
+  return Asset::createFromUncompressedMap(std::move(file_map),
+                                          (path) ? base::unique_fd(-1) : std::move(fd),
+                                          Asset::AccessMode::ACCESS_RANDOM);
+}
+
+std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(ZipArchiveHandle unmanaged_handle,
+                                                     const std::string& path,
+                                                     std::unique_ptr<Asset> idmap_asset,
+                                                     std::unique_ptr<const LoadedIdmap> idmap,
+                                                     package_property_t property_flags) {
+  const time_t last_mod_time = getFileModDate(path.c_str());
 
   // Wrap the handle in a unique_ptr so it gets automatically closed.
   std::unique_ptr<ApkAssets>
@@ -153,7 +209,7 @@
 
   // Find the resource table.
   ::ZipEntry entry;
-  result = ::FindEntry(loaded_apk->zip_handle_.get(), kResourcesArsc, &entry);
+  int32_t result = ::FindEntry(loaded_apk->zip_handle_.get(), kResourcesArsc, &entry);
   if (result != 0) {
     // There is no resources.arsc, so create an empty LoadedArsc and return.
     loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
@@ -173,7 +229,7 @@
 
   // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid.
   loaded_apk->idmap_asset_ = std::move(idmap_asset);
-  loaded_apk->loaded_idmap_ = std::move(loaded_idmap);
+  loaded_apk->loaded_idmap_ = std::move(idmap);
 
   const StringPiece data(
       reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
@@ -189,24 +245,10 @@
   return std::move(loaded_apk);
 }
 
-std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd,
-                                                         const std::string& path,
-                                                         package_property_t property_flags) {
-  std::unique_ptr<Asset> resources_asset;
-
-  if (fd >= 0) {
-    resources_asset = std::unique_ptr<Asset>(Asset::createFromFd(fd.release(), nullptr,
-        Asset::AccessMode::ACCESS_BUFFER));
-  } else {
-    resources_asset = CreateAssetFromFile(path);
-  }
-
-  if (resources_asset == nullptr) {
-    LOG(ERROR) << "Failed to open ARSC '" << path;
-    return {};
-  }
-
-  time_t last_mod_time = getFileModDate(path.c_str());
+std::unique_ptr<const ApkAssets> ApkAssets::LoadTableImpl(std::unique_ptr<Asset> resources_asset,
+                                                          const std::string& path,
+                                                          package_property_t property_flags) {
+  const time_t last_mod_time = getFileModDate(path.c_str());
 
   std::unique_ptr<ApkAssets> loaded_apk(
       new ApkAssets(nullptr, path, last_mod_time, property_flags));
@@ -225,13 +267,6 @@
   return std::move(loaded_apk);
 }
 
-std::unique_ptr<const ApkAssets> ApkAssets::LoadEmpty(bool for_loader) {
-  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, "", -1, for_loader));
-  loaded_apk->loaded_arsc_ = LoadedArsc::CreateEmpty();
-  // Need to force a move for mingw32.
-  return std::move(loaded_apk);
-}
-
 std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode mode) const {
   // If this is a resource loader from an .arsc, there will be no zip handle
   if (zip_handle_ == nullptr) {
@@ -244,10 +279,12 @@
     return {};
   }
 
+  const int fd = ::GetFileDescriptor(zip_handle_.get());
+  const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
   if (entry.method == kCompressDeflated) {
     std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
-    if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset,
-                     entry.compressed_length, true /*readOnly*/)) {
+    if (!map->create(path_.c_str(), fd, fd_offset + entry.offset, entry.compressed_length,
+                     true /*readOnly*/)) {
       LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
       return {};
     }
@@ -261,13 +298,18 @@
     return asset;
   } else {
     std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
-    if (!map->create(path_.c_str(), ::GetFileDescriptor(zip_handle_.get()), entry.offset,
-                     entry.uncompressed_length, true /*readOnly*/)) {
+    if (!map->create(path_.c_str(), fd, fd_offset + entry.offset, entry.uncompressed_length,
+                     true /*readOnly*/)) {
       LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
       return {};
     }
 
-    std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map), mode);
+    // TODO: apks created from file descriptors residing in RAM currently cannot open file
+    //  descriptors to the assets they contain. This is because the Asset::openFileDeescriptor uses
+    //  the zip path on disk to create a new file descriptor. This is fixed in a future change
+    //  in the change topic.
+    std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map),
+        unique_fd(-1) /* fd*/, mode);
     if (asset == nullptr) {
       LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << path_ << "'";
       return {};
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index c132f34..cd30c18 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -298,14 +298,13 @@
 /*
  * Create a new Asset from a memory mapping.
  */
-/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap,
-    AccessMode mode)
+/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap, AccessMode mode)
 {
     _FileAsset* pAsset;
     status_t result;
 
     pAsset = new _FileAsset;
-    result = pAsset->openChunk(dataMap);
+    result = pAsset->openChunk(dataMap, base::unique_fd(-1));
     if (result != NO_ERROR) {
         delete pAsset;
         return NULL;
@@ -316,11 +315,11 @@
 }
 
 /*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
-    AccessMode mode)
+    base::unique_fd fd, AccessMode mode)
 {
     std::unique_ptr<_FileAsset> pAsset = util::make_unique<_FileAsset>();
 
-    status_t result = pAsset->openChunk(dataMap.get());
+    status_t result = pAsset->openChunk(dataMap.get(), std::move(fd));
     if (result != NO_ERROR) {
         return NULL;
     }
@@ -415,7 +414,7 @@
  * Constructor.
  */
 _FileAsset::_FileAsset(void)
-    : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
+    : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mMap(NULL), mBuf(NULL)
 {
     // Register the Asset with the global list here after it is fully constructed and its
     // vtable pointer points to this concrete type. b/31113965
@@ -485,7 +484,7 @@
 /*
  * Create the chunk from the map.
  */
-status_t _FileAsset::openChunk(FileMap* dataMap)
+status_t _FileAsset::openChunk(FileMap* dataMap, base::unique_fd fd)
 {
     assert(mFp == NULL);    // no reopen
     assert(mMap == NULL);
@@ -494,6 +493,7 @@
     mMap = dataMap;
     mStart = -1;            // not used
     mLength = dataMap->getDataLength();
+    mFd = std::move(fd);
     assert(mOffset == 0);
 
     return NO_ERROR;
@@ -692,6 +692,17 @@
 int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
 {
     if (mMap != NULL) {
+        if (mFd.ok()) {
+          *outStart = mMap->getDataOffset();
+          *outLength = mMap->getDataLength();
+          const int fd = dup(mFd);
+          if (fd < 0) {
+            ALOGE("Unable to dup fd (%d).", mFd.get());
+            return -1;
+          }
+          lseek64(fd, 0, SEEK_SET);
+          return fd;
+        }
         const char* fname = mMap->getFileName();
         if (fname == NULL) {
             fname = mFileName;
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index e35c024..70bb441 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -749,7 +749,7 @@
 
 std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
                                                    const LoadedIdmap* loaded_idmap,
-                                                   package_property_t property_flags) {
+                                                   const package_property_t property_flags) {
   ATRACE_NAME("LoadedArsc::Load");
 
   // Not using make_unique because the constructor is private.
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index af802b0..643dc5c 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -37,49 +37,46 @@
 
 // Holds an APK.
 class ApkAssets {
+  // This means the data extends to the end of the file.
+  static constexpr off64_t kUnknownLength = -1;
+
  public:
-  // Creates an ApkAssets.
-  // If `system` is true, the package is marked as a system package, and allows some functions to
-  // filter out this package when computing what configurations/resources are available.
-  static std::unique_ptr<const ApkAssets> Load(const std::string& path, bool system = false,
-                                               bool for_loader = false);
-
-  // Creates an ApkAssets, but forces any package with ID 0x7f to be loaded as a shared library.
-  // If `system` is true, the package is marked as a system package, and allows some functions to
-  // filter out this package when computing what configurations/resources are available.
-  static std::unique_ptr<const ApkAssets> LoadAsSharedLibrary(const std::string& path,
-                                                              bool system = false);
-
-  // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay
-  // data.
-  // If `system` is true, the package is marked as a system package, and allows some functions to
-  // filter out this package when computing what configurations/resources are available.
-  static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path,
-                                                      bool system = false);
+  // Creates an ApkAssets from the zip path.
+  static std::unique_ptr<const ApkAssets> Load(const std::string& path,
+                                               package_property_t flags = 0U);
 
   // Creates an ApkAssets from the given file descriptor, and takes ownership of the file
   // descriptor. The `friendly_name` is some name that will be used to identify the source of
   // this ApkAssets in log messages and other debug scenarios.
-  // If `system` is true, the package is marked as a system package, and allows some functions to
-  // filter out this package when computing what configurations/resources are available.
-  // If `force_shared_lib` is true, any package with ID 0x7f is loaded as a shared library.
+  // If `length` equals kUnknownLength, offset must equal 0; otherwise, the apk data will be read
+  // using the `offset` into the file descriptor and will be `length` bytes long.
   static std::unique_ptr<const ApkAssets> LoadFromFd(base::unique_fd fd,
-                                                     const std::string& friendly_name, bool system,
-                                                     bool force_shared_lib,
-                                                     bool for_loader = false);
+                                                     const std::string& friendly_name,
+                                                     package_property_t flags = 0U,
+                                                     off64_t offset = 0,
+                                                     off64_t length = kUnknownLength);
 
-  // Creates an empty wrapper ApkAssets from the given path which points to an .arsc.
-  static std::unique_ptr<const ApkAssets> LoadArsc(const std::string& path,
-                                                   bool for_loader = false);
+  // Creates an ApkAssets from the given path which points to a resources.arsc.
+  static std::unique_ptr<const ApkAssets> LoadTable(const std::string& path,
+                                                    package_property_t flags = 0U);
 
-  // Creates an empty wrapper ApkAssets from the given file descriptor which points to an .arsc,
-  // Takes ownership of the file descriptor.
-  static std::unique_ptr<const ApkAssets> LoadArsc(base::unique_fd fd,
-                                                   const std::string& friendly_name,
-                                                   bool for_loader = false);
+  // Creates an ApkAssets from the given file descriptor which points to an resources.arsc, and
+  // takes ownership of the file descriptor.
+  // If `length` equals kUnknownLength, offset must equal 0; otherwise, the .arsc data will be read
+  // using the `offset` into the file descriptor and will be `length` bytes long.
+  static std::unique_ptr<const ApkAssets> LoadTableFromFd(base::unique_fd fd,
+                                                          const std::string& friendly_name,
+                                                          package_property_t flags = 0U,
+                                                          off64_t offset = 0,
+                                                          off64_t length = kUnknownLength);
+
+  // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay
+  // data.
+  static std::unique_ptr<const ApkAssets> LoadOverlay(const std::string& idmap_path,
+                                                      package_property_t flags = 0U);
 
   // Creates a totally empty ApkAssets with no resources table and no file entries.
-  static std::unique_ptr<const ApkAssets> LoadEmpty(bool for_loader = false);
+  static std::unique_ptr<const ApkAssets> LoadEmpty(package_property_t flags = 0U);
 
   std::unique_ptr<Asset> Open(const std::string& path,
                               Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
@@ -105,28 +102,38 @@
   }
 
   inline bool IsOverlay() const {
-    return (property_flags_ & PROPERTY_OVERLAY) != 0;
+    return loaded_idmap_ != nullptr;
   }
 
   bool IsUpToDate() const;
 
-  // Creates an Asset from any file on the file system.
+  // Creates an Asset from a file on disk.
   static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
 
+  // Creates an Asset from a file descriptor.
+  //
+  // The asset takes ownership of the file descriptor. If `length` equals kUnknownLength, offset
+  // must equal 0; otherwise, the asset data will be read using the `offset` into the file
+  // descriptor and will be `length` bytes long.
+  static std::unique_ptr<Asset> CreateAssetFromFd(base::unique_fd fd,
+                                                  const char* path,
+                                                  off64_t offset = 0,
+                                                  off64_t length = kUnknownLength);
  private:
   DISALLOW_COPY_AND_ASSIGN(ApkAssets);
 
-  static std::unique_ptr<const ApkAssets> LoadImpl(base::unique_fd fd, const std::string& path,
+  static std::unique_ptr<const ApkAssets> LoadImpl(ZipArchiveHandle unmanaged_handle,
+                                                   const std::string& path,
                                                    std::unique_ptr<Asset> idmap_asset,
-                                                   std::unique_ptr<const LoadedIdmap> loaded_idmap,
+                                                   std::unique_ptr<const LoadedIdmap> idmap,
                                                    package_property_t property_flags);
 
-  static std::unique_ptr<const ApkAssets> LoadArscImpl(base::unique_fd fd,
-                                                       const std::string& path,
-                                                       package_property_t property_flags);
+  static std::unique_ptr<const ApkAssets> LoadTableImpl(std::unique_ptr<Asset> resources_asset,
+                                                        const std::string& path,
+                                                        package_property_t property_flags);
 
   ApkAssets(ZipArchiveHandle unmanaged_handle,
-            const std::string& path,
+            std::string path,
             time_t last_mod_time,
             package_property_t property_flags);
 
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
index 053dbb7..7576174 100644
--- a/libs/androidfw/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -26,6 +26,7 @@
 
 #include <memory>
 
+#include <android-base/unique_fd.h>
 #include <utils/Compat.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
@@ -202,8 +203,14 @@
      */
     static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
 
+    /*
+     * Create the asset from a memory-mapped file segment.
+     *
+     * The asset takes ownership of the FileMap and the file descriptor "fd". The file descriptor is
+     * used to request new file descriptors using "openFileDescriptor".
+     */
     static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
-        AccessMode mode);
+        base::unique_fd fd, AccessMode mode);
 
     /*
      * Create the asset from a memory-mapped file segment with compressed
@@ -256,9 +263,9 @@
     /*
      * Use a memory-mapped region.
      *
-     * On success, the object takes ownership of "dataMap".
+     * On success, the object takes ownership of "dataMap" and "fd".
      */
-    status_t openChunk(FileMap* dataMap);
+    status_t openChunk(FileMap* dataMap, base::unique_fd fd);
 
     /*
      * Standard Asset interfaces.
@@ -273,11 +280,12 @@
     virtual bool isAllocated(void) const { return mBuf != NULL; }
 
 private:
-    off64_t     mStart;         // absolute file offset of start of chunk
-    off64_t     mLength;        // length of the chunk
-    off64_t     mOffset;        // current local offset, 0 == mStart
-    FILE*       mFp;            // for read/seek
-    char*       mFileName;      // for opening
+    off64_t         mStart;         // absolute file offset of start of chunk
+    off64_t         mLength;        // length of the chunk
+    off64_t         mOffset;        // current local offset, 0 == mStart
+    FILE*           mFp;            // for read/seek
+    char*           mFileName;      // for opening
+    base::unique_fd mFd;            // for opening file descriptors
 
     /*
      * To support getBuffer() we either need to read the entire thing into
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index b5d3a1f..89ff9f5 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -69,12 +69,24 @@
   }
 };
 
+// Flags that change the behavior of loaded packages.
+// Keep in sync with f/b/android/content/res/ApkAssets.java
 using package_property_t = uint32_t;
 enum : package_property_t {
-  PROPERTY_DYNAMIC = 1,
-  PROPERTY_LOADER = 2,
-  PROPERTY_OVERLAY = 4,
-  PROPERTY_SYSTEM = 8,
+  // The package contains framework resource values specified by the system.
+  // This allows some functions to filter out this package when computing
+  // what configurations/resources are available.
+  PROPERTY_SYSTEM = 1U << 0U,
+
+  // The package is a shared library or has a package id of 7f and is loaded as a shared library by
+  // force.
+  PROPERTY_DYNAMIC = 1U << 1U,
+
+  // The package has been loaded dynamically using a ResourcesProvider.
+  PROPERTY_LOADER = 1U << 2U,
+
+  // The package is a RRO.
+  PROPERTY_OVERLAY = 1U << 3U,
 };
 
 // TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index 0f2ee6f..26bf5ff 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -70,7 +70,7 @@
   ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
   EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic());
 
-  loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
+  loaded_apk = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk", PROPERTY_DYNAMIC);
   ASSERT_THAT(loaded_apk, NotNull());
 
   loaded_arsc = loaded_apk->GetLoadedArsc();
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 35fea7a..ac32699 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -63,10 +63,12 @@
     libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
     ASSERT_NE(nullptr, libclient_assets_);
 
-    appaslib_assets_ = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
+    appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk",
+                                       PROPERTY_DYNAMIC);
     ASSERT_NE(nullptr, appaslib_assets_);
 
-    system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
+    system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk",
+                                     PROPERTY_SYSTEM);
     ASSERT_NE(nullptr, system_assets_);
 
     app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index c8dbe20..24361b5 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -67,7 +67,7 @@
 
 TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
   AssetManager2 assetmanager;
-  auto apk_assets = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/styles/styles.apk");
+  auto apk_assets = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk", PROPERTY_DYNAMIC);
   ASSERT_NE(nullptr, apk_assets);
   assetmanager.SetApkAssets({apk_assets.get()});
 
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index b679672..41ba637 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -221,8 +221,8 @@
 
 TEST_F(IdmapTest, OverlayLoaderInterop) {
   std::string contents;
-  auto loader_assets = ApkAssets::LoadArsc(GetTestDataPath() + "/loader/resources.arsc",
-                                           /* for_loader */ true);
+  auto loader_assets = ApkAssets::LoadTable(GetTestDataPath() + "/loader/resources.arsc",
+                                            PROPERTY_LOADER);
 
   AssetManager2 asset_manager;
   asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),