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

Commit 2fedba9a authored by Ryan Mitchell's avatar Ryan Mitchell
Browse files

Add <staging-public-group-final> to aapt2

To allow apps that compiled against a pre-release SDK to continue
working for a period of time after API finalization, a new tag,
<staging-public-group-final>, has been added to aapt2.

When finalizing the framework resource API, converting
<staging-public-group> tags to <staging-public-group-final> will
cause aapt2 to generate the resource table so that there is a resource
entry for the old non-finalized (staged) resource ID and another entry
for the finalized resource ID of newly finalized resources. This allows
an application that compiled against the pre-release SDK to continue
resolving resources using pre-release resource IDs.

All references to pre-release resource IDs will be rewritten to their
finalized resource IDs through the information stored in the new staged
alias chunk. This allows applications compiled against
<staging-public-group> resources to use the newly finalized
resource ID without re-compilation.

When an application is re-compiled against the SDK with
<staging-public-group-final> tags, the application will use the
finalized resource IDs.

This change limits the use of the alias chunk to the framework for S.

Bug: 183411356
Test: aapt2_test
Change-Id: Iba1c3033c3c2f32de8e4a19b58d3921c971092c4
parent 969f4ec6
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -221,6 +221,16 @@ void AssetManager2::BuildDynamicRefTable() {
    for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
      iter2->dynamic_ref_table->addMapping(String16(package_name.c_str(), package_name.size()),
                                           iter->dynamic_ref_table->mAssignedPackageId);

      // Add the alias resources to the dynamic reference table of every package group. Since
      // staging aliases can only be defined by the framework package (which is not a shared
      // library), the compile-time package id of the framework is the same across all packages
      // that compile against the framework.
      for (const auto& package : iter2->packages_) {
        for (const auto& entry : package.loaded_package_->GetAliasResourceIdMap()) {
          iter->dynamic_ref_table->addAlias(entry.first, entry.second);
        }
      }
    }
  }
}
+37 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ using android::base::StringPrintf;

namespace android {

constexpr const static int kFrameworkPackageId = 0x01;
constexpr const static int kAppPackageId = 0x7f;

namespace {
@@ -675,6 +676,42 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
        }
      } break;

      case RES_TABLE_STAGED_ALIAS_TYPE: {
        if (loaded_package->package_id_ != kFrameworkPackageId) {
          LOG(WARNING) << "Alias chunk ignored for non-framework package '"
                       << loaded_package->package_name_ << "'";
          break;
        }

        std::unordered_set<uint32_t> finalized_ids;
        const auto lib_alias = child_chunk.header<ResTable_staged_alias_header>();
        if (!lib_alias) {
          return {};
        }
        const auto entry_begin = child_chunk.data_ptr().convert<ResTable_staged_alias_entry>();
        const auto entry_end = entry_begin + dtohl(lib_alias->count);
        for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
          if (!entry_iter) {
            return {};
          }
          auto finalized_id = dtohl(entry_iter->finalizedResId);
          if (!finalized_ids.insert(finalized_id).second) {
            LOG(ERROR) << StringPrintf("Repeated finalized resource id '%08x' in staged aliases.",
                                       finalized_id);
            return {};
          }

          auto staged_id = dtohl(entry_iter->stagedResId);
          auto [_, success] = loaded_package->alias_id_map_.insert(std::make_pair(staged_id,
                                                                                  finalized_id));
          if (!success) {
            LOG(ERROR) << StringPrintf("Repeated staged resource id '%08x' in staged aliases.",
                                       staged_id);
            return {};
          }
        }
      } break;

      default:
        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
        break;
+14 −2
Original line number Diff line number Diff line
@@ -7079,6 +7079,10 @@ void DynamicRefTable::addMapping(uint8_t buildPackageId, uint8_t runtimePackageI
    mLookupTable[buildPackageId] = runtimePackageId;
}

void DynamicRefTable::addAlias(uint32_t stagedId, uint32_t finalizedId) {
  mAliasId[stagedId] = finalizedId;
}

status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
    uint32_t res = *resId;
    size_t packageId = Res_GETPACKAGE(res) + 1;
@@ -7088,8 +7092,16 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
        return NO_ERROR;
    }

    if (packageId == APP_PACKAGE_ID && !mAppAsLib) {
        // No lookup needs to be done, app package IDs are absolute.
    auto alias_id = mAliasId.find(res);
    if (alias_id != mAliasId.end()) {
      // Rewrite the resource id to its alias resource id. Since the alias resource id is a
      // compile-time id, it still needs to be resolved further.
      res = alias_id->second;
    }

    if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) {
        // No lookup needs to be done, app and framework package IDs are absolute.
        *resId = res;
        return NO_ERROR;
    }

+16 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef LOADEDARSC_H_
#define LOADEDARSC_H_

#include <map>
#include <memory>
#include <set>
#include <vector>
@@ -171,51 +172,51 @@ class LoadedPackage {
      incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset);

  // Returns the string pool where type names are stored.
  inline const ResStringPool* GetTypeStringPool() const {
  const ResStringPool* GetTypeStringPool() const {
    return &type_string_pool_;
  }

  // Returns the string pool where the names of resource entries are stored.
  inline const ResStringPool* GetKeyStringPool() const {
  const ResStringPool* GetKeyStringPool() const {
    return &key_string_pool_;
  }

  inline const std::string& GetPackageName() const {
  const std::string& GetPackageName() const {
    return package_name_;
  }

  inline int GetPackageId() const {
  int GetPackageId() const {
    return package_id_;
  }

  // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
  inline bool IsDynamic() const {
  bool IsDynamic() const {
    return (property_flags_ & PROPERTY_DYNAMIC) != 0;
  }

  // Returns true if this package is a Runtime Resource Overlay.
  inline bool IsOverlay() const {
  bool IsOverlay() const {
    return (property_flags_ & PROPERTY_OVERLAY) != 0;
  }

  // Returns true if this package originates from a system provided resource.
  inline bool IsSystem() const {
  bool IsSystem() const {
    return (property_flags_ & PROPERTY_SYSTEM) != 0;
  }

  // Returns true if this package is a custom loader and should behave like an overlay.
  inline bool IsCustomLoader() const {
  bool IsCustomLoader() const {
    return (property_flags_ & PROPERTY_LOADER) != 0;
  }

  inline package_property_t GetPropertyFlags() const {
  package_property_t GetPropertyFlags() const {
    return property_flags_;
  }

  // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
  // package could have been assigned a different package ID than what this LoadedPackage was
  // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
  inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
  const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
    return dynamic_package_map_;
  }

@@ -270,6 +271,10 @@ class LoadedPackage {
    return overlayable_map_;
  }

  const std::map<uint32_t, uint32_t>& GetAliasResourceIdMap() const {
    return alias_id_map_;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(LoadedPackage);

@@ -287,6 +292,7 @@ class LoadedPackage {
  ByteBucketArray<uint32_t> resource_ids_;
  std::vector<DynamicPackageEntry> dynamic_package_map_;
  std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
  std::map<uint32_t, uint32_t> alias_id_map_;

  // A map of overlayable name to actor
  std::unordered_map<std::string, std::string> overlayable_map_;
+45 −17
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <android/configuration.h>

#include <array>
#include <map>
#include <memory>

namespace android {
@@ -253,6 +254,7 @@ enum {
    RES_TABLE_LIBRARY_TYPE            = 0x0203,
    RES_TABLE_OVERLAYABLE_TYPE        = 0x0204,
    RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205,
    RES_TABLE_STAGED_ALIAS_TYPE       = 0x0206,
};

/**
@@ -1638,6 +1640,29 @@ struct ResTable_lib_entry
    uint16_t packageName[128];
};

/**
 * A map that allows rewriting staged (non-finalized) resource ids to their finalized counterparts.
 */
struct ResTable_staged_alias_header
{
    struct ResChunk_header header;

    // The number of ResTable_staged_alias_entry that follow this header.
    uint32_t count;
};

/**
 * Maps the staged (non-finalized) resource id to its finalized resource id.
 */
struct ResTable_staged_alias_entry
{
  // The compile-time staged resource id to rewrite.
  uint32_t stagedResId;

  // The compile-time finalized resource id to which the staged resource id should be rewritten.
  uint32_t finalizedResId;
};

/**
 * Specifies the set of resources that are explicitly allowed to be overlaid by RROs.
 */
@@ -1751,6 +1776,8 @@ public:

    void addMapping(uint8_t buildPackageId, uint8_t runtimePackageId);

    void addAlias(uint32_t stagedId, uint32_t finalizedId);

    // Returns whether or not the value must be looked up.
    bool requiresLookup(const Res_value* value) const;

@@ -1768,6 +1795,7 @@ private:
    uint8_t                         mLookupTable[256];
    KeyedVector<String16, uint8_t>  mEntries;
    bool                            mAppAsLib;
    std::map<uint32_t, uint32_t>    mAliasId;
};

bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
Loading