blob: ecc1ce65d124a5849bac719729f335435fcbf3a8 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IDMAP_H_
#define IDMAP_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <variant>
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
#include "androidfw/ResourceTypes.h"
#include "utils/ByteOrder.h"
namespace android {
class LoadedIdmap;
class IdmapResMap;
// A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
// table and additionally allows for loading strings from the idmap string pool. The idmap string
// pool strings are offset after the end of the overlay resource table string pool entries so
// queries for strings defined inline in the idmap do not conflict with queries for overlay
// resource table strings.
class OverlayStringPool : public ResStringPool {
public:
virtual ~OverlayStringPool();
const char16_t* stringAt(size_t idx, size_t* outLen) const override;
const char* string8At(size_t idx, size_t* outLen) const override;
size_t size() const override;
explicit OverlayStringPool(const LoadedIdmap* loaded_idmap);
private:
const Idmap_data_header* data_header_;
const ResStringPool* idmap_string_pool_;
};
// A dynamic reference table for loaded overlay packages that rewrites the resource id of overlay
// resources to the resource id of corresponding target resources.
class OverlayDynamicRefTable : public DynamicRefTable {
public:
~OverlayDynamicRefTable() override = default;
status_t lookupResourceId(uint32_t* resId) const override;
private:
explicit OverlayDynamicRefTable(const Idmap_data_header* data_header,
const Idmap_overlay_entry* entries,
uint8_t target_assigned_package_id);
// Rewrites a compile-time overlay resource id to the runtime resource id of corresponding target
// resource.
virtual status_t lookupResourceIdNoRewrite(uint32_t* resId) const;
const Idmap_data_header* data_header_;
const Idmap_overlay_entry* entries_;
const int8_t target_assigned_package_id_;
friend LoadedIdmap;
friend IdmapResMap;
};
// A mapping of target resource ids to a values or resource ids that should overlay the target.
class IdmapResMap {
public:
// Represents the result of a idmap lookup. The result can be one of three possibillities:
// 1) The result is a resource id which represents the overlay resource that should act as an
// alias of the target resource.
// 2) The result is a table entry which overlays the type and value of the target resource.
// 3) The result is neither and the target resource is not overlaid.
class Result {
public:
Result() : data_(nullptr) {};
explicit Result(uint32_t value) : data_(value) {};
explicit Result(ResTable_entry_handle&& value) : data_(value) { };
// Returns `true` if the resource is overlaid.
inline explicit operator bool() const {
return !std::get_if<nullptr_t>(&data_);
}
inline bool IsResourceId() const {
return std::get_if<uint32_t>(&data_);
}
inline uint32_t GetResourceId() const {
return *std::get_if<uint32_t>(&data_);
}
inline bool IsTableEntry() const {
return std::get_if<ResTable_entry_handle>(&data_);
}
inline const ResTable_entry_handle& GetTableEntry() const {
return *std::get_if<ResTable_entry_handle>(&data_);
}
private:
std::variant<uint32_t, nullptr_t, ResTable_entry_handle> data_;
};
// Looks up the value that overlays the target resource id.
Result Lookup(uint32_t target_res_id) const;
inline const OverlayDynamicRefTable* GetOverlayDynamicRefTable() const {
return overlay_ref_table_;
}
private:
explicit IdmapResMap(const Idmap_data_header* data_header,
const Idmap_target_entry* entries,
uint8_t target_assigned_package_id,
const OverlayDynamicRefTable* overlay_ref_table);
const Idmap_data_header* data_header_;
const Idmap_target_entry* entries_;
const uint8_t target_assigned_package_id_;
const OverlayDynamicRefTable* overlay_ref_table_;
friend LoadedIdmap;
};
// Represents a loaded/parsed IDMAP for a Runtime Resource Overlay (RRO).
// An RRO and its target APK have different resource IDs assigned to their resources.
// An IDMAP is a generated mapping between the resource IDs of the RRO and the target APK.
// A LoadedIdmap can be set alongside the overlay's LoadedArsc to allow the overlay ApkAssets to
// masquerade as the target ApkAssets resources.
class LoadedIdmap {
public:
// Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_path,
const StringPiece& idmap_data);
// Returns the path to the IDMAP.
inline const std::string& IdmapPath() const {
return idmap_path_;
}
// Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
inline const std::string& OverlayApkPath() const {
return overlay_apk_path_;
}
// Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
inline const std::string& TargetApkPath() const {
return target_apk_path_;
}
// Returns a mapping from target resource ids to overlay values.
inline const IdmapResMap GetTargetResourcesMap(
uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const {
return IdmapResMap(data_header_, target_entries_, target_assigned_package_id,
overlay_ref_table);
}
// Returns a dynamic reference table for a loaded overlay package.
inline const OverlayDynamicRefTable GetOverlayDynamicRefTable(
uint8_t target_assigned_package_id) const {
return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
}
// Returns whether the idmap file on disk has not been modified since the construction of this
// LoadedIdmap.
bool IsUpToDate() const;
protected:
// Exposed as protected so that tests can subclass and mock this class out.
LoadedIdmap() = default;
const Idmap_header* header_;
const Idmap_data_header* data_header_;
const Idmap_target_entry* target_entries_;
const Idmap_overlay_entry* overlay_entries_;
const std::unique_ptr<ResStringPool> string_pool_;
const std::string idmap_path_;
std::string overlay_apk_path_;
std::string target_apk_path_;
const time_t idmap_last_mod_time_;
private:
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
explicit LoadedIdmap(std::string&& idmap_path,
time_t last_mod_time,
const Idmap_header* header,
const Idmap_data_header* data_header,
const Idmap_target_entry* target_entries,
const Idmap_overlay_entry* overlay_entries,
ResStringPool* string_pool);
friend OverlayStringPool;
};
} // namespace android
#endif // IDMAP_H_