blob: e86f81485a41824a1e4c2cfd6164017f902b6bba [file] [log] [blame]
/*
* Copyright (C) 2018 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.
*/
/*
* # idmap file format (current version)
*
* idmap := header data*
* header := magic version target_crc overlay_crc fulfilled_policies
* enforce_overlayable target_path overlay_path overlay_name
* debug_info
* data := data_header target_entry* target_inline_entry*
target_inline_entry_value* config* overlay_entry* string_pool
* data_header := target_entry_count target_inline_entry_count
target_inline_entry_value_count config_count overlay_entry_count
* string_pool_index
* target_entry := target_id overlay_id
* target_inline_entry := target_id start_value_index value_count
* target_inline_entry_value := config_index Res_value::size padding(1) Res_value::type
* Res_value::value
* config := target_id Res_value::size padding(1) Res_value::type
* Res_value::value
* overlay_entry := overlay_id target_id
*
* debug_info := string
* enforce_overlayable := <uint32_t>
* fulfilled_policies := <uint32_t>
* magic := <uint32_t>
* overlay_crc := <uint32_t>
* overlay_entry_count := <uint32_t>
* overlay_id := <uint32_t>
* overlay_package_id := <uint8_t>
* overlay_name := string
* overlay_path := string
* padding(n) := <uint8_t>[n]
* Res_value::size := <uint16_t>
* Res_value::type := <uint8_t>
* Res_value::value := <uint32_t>
* string := <uint32_t> <uint8_t>+ padding(n)
* string_pool := string
* string_pool_index := <uint32_t>
* string_pool_length := <uint32_t>
* target_crc := <uint32_t>
* target_entry_count := <uint32_t>
* target_inline_entry_count := <uint32_t>
* target_inline_entry_value_count := <uint32_t>
* config_count := <uint32_t>
* config_index := <uint32_t>
* start_value_index := <uint32_t>
* value_count := <uint32_t>
* target_id := <uint32_t>
* target_package_id := <uint8_t>
* target_path := string
* value_type := <uint8_t>
* value_data := <uint32_t>
* version := <uint32_t>
*/
#ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
#define IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
#include <istream>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
#include "androidfw/ConfigDescription.h"
#include "idmap2/ResourceContainer.h"
#include "idmap2/ResourceMapping.h"
namespace android::idmap2 {
class Idmap;
class Visitor;
// magic number: all idmap files start with this
static constexpr const uint32_t kIdmapMagic = android::kIdmapMagic;
// current version of the idmap binary format; must be incremented when the format is changed
static constexpr const uint32_t kIdmapCurrentVersion = android::kIdmapCurrentVersion;
class IdmapHeader {
public:
static std::unique_ptr<const IdmapHeader> FromBinaryStream(std::istream& stream);
inline uint32_t GetMagic() const {
return magic_;
}
inline uint32_t GetVersion() const {
return version_;
}
inline uint32_t GetTargetCrc() const {
return target_crc_;
}
inline uint32_t GetOverlayCrc() const {
return overlay_crc_;
}
inline uint32_t GetFulfilledPolicies() const {
return fulfilled_policies_;
}
bool GetEnforceOverlayable() const {
return enforce_overlayable_;
}
const std::string& GetTargetPath() const {
return target_path_;
}
const std::string& GetOverlayPath() const {
return overlay_path_;
}
const std::string& GetOverlayName() const {
return overlay_name_;
}
const std::string& GetDebugInfo() const {
return debug_info_;
}
// Invariant: anytime the idmap data encoding is changed, the idmap version
// field *must* be incremented. Because of this, we know that if the idmap
// header is up-to-date the entire file is up-to-date.
Result<Unit> IsUpToDate(const TargetResourceContainer& target,
const OverlayResourceContainer& overlay, const std::string& overlay_name,
PolicyBitmask fulfilled_policies, bool enforce_overlayable) const;
Result<Unit> IsUpToDate(const std::string& target_path, const std::string& overlay_path,
const std::string& overlay_name, uint32_t target_crc,
uint32_t overlay_crc, PolicyBitmask fulfilled_policies,
bool enforce_overlayable) const;
void accept(Visitor* v) const;
private:
IdmapHeader() = default;
uint32_t magic_;
uint32_t version_;
uint32_t target_crc_;
uint32_t overlay_crc_;
uint32_t fulfilled_policies_;
bool enforce_overlayable_;
std::string target_path_;
std::string overlay_path_;
std::string overlay_name_;
std::string debug_info_;
friend Idmap;
DISALLOW_COPY_AND_ASSIGN(IdmapHeader);
};
class IdmapData {
public:
class Header {
public:
static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream);
[[nodiscard]] inline uint32_t GetTargetEntryCount() const {
return target_entry_count;
}
[[nodiscard]] inline uint32_t GetTargetInlineEntryCount() const {
return target_entry_inline_count;
}
[[nodiscard]] inline uint32_t GetTargetInlineEntryValueCount() const {
return target_entry_inline_value_count;
}
[[nodiscard]] inline uint32_t GetConfigCount() const {
return config_count;
}
[[nodiscard]] inline uint32_t GetOverlayEntryCount() const {
return overlay_entry_count;
}
[[nodiscard]] inline uint32_t GetStringPoolIndexOffset() const {
return string_pool_index_offset;
}
void accept(Visitor* v) const;
private:
uint32_t target_entry_count;
uint32_t target_entry_inline_count;
uint32_t target_entry_inline_value_count;
uint32_t config_count;
uint32_t overlay_entry_count;
uint32_t string_pool_index_offset;
Header() = default;
friend Idmap;
friend IdmapData;
DISALLOW_COPY_AND_ASSIGN(Header);
};
struct TargetEntry {
ResourceId target_id;
ResourceId overlay_id;
};
struct TargetInlineEntry {
ResourceId target_id;
std::map<ConfigDescription, TargetValue> values;
};
struct OverlayEntry {
ResourceId overlay_id;
ResourceId target_id;
};
static std::unique_ptr<const IdmapData> FromBinaryStream(std::istream& stream);
static Result<std::unique_ptr<const IdmapData>> FromResourceMapping(
const ResourceMapping& resource_mapping);
const std::unique_ptr<const Header>& GetHeader() const {
return header_;
}
const std::vector<TargetEntry>& GetTargetEntries() const {
return target_entries_;
}
const std::vector<TargetInlineEntry>& GetTargetInlineEntries() const {
return target_inline_entries_;
}
[[nodiscard]] const std::vector<OverlayEntry>& GetOverlayEntries() const {
return overlay_entries_;
}
[[nodiscard]] const std::string& GetStringPoolData() const {
return string_pool_data_;
}
void accept(Visitor* v) const;
private:
IdmapData() = default;
std::unique_ptr<const Header> header_;
std::vector<TargetEntry> target_entries_;
std::vector<TargetInlineEntry> target_inline_entries_;
std::vector<OverlayEntry> overlay_entries_;
std::string string_pool_data_;
friend Idmap;
DISALLOW_COPY_AND_ASSIGN(IdmapData);
};
class Idmap {
public:
static std::string CanonicalIdmapPathFor(std::string_view absolute_dir,
std::string_view absolute_apk_path);
static Result<std::unique_ptr<const Idmap>> FromBinaryStream(std::istream& stream);
// In the current version of idmap, the first package in each resources.arsc
// file is used; change this in the next version of idmap to use a named
// package instead; also update FromApkAssets to take additional parameters:
// the target and overlay package names
static Result<std::unique_ptr<const Idmap>> FromContainers(
const TargetResourceContainer& target, const OverlayResourceContainer& overlay,
const std::string& overlay_name, const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable);
const std::unique_ptr<const IdmapHeader>& GetHeader() const {
return header_;
}
const std::vector<std::unique_ptr<const IdmapData>>& GetData() const {
return data_;
}
void accept(Visitor* v) const;
private:
Idmap() = default;
std::unique_ptr<const IdmapHeader> header_;
std::vector<std::unique_ptr<const IdmapData>> data_;
DISALLOW_COPY_AND_ASSIGN(Idmap);
};
class Visitor {
public:
virtual ~Visitor() = default;
virtual void visit(const Idmap& idmap) = 0;
virtual void visit(const IdmapHeader& header) = 0;
virtual void visit(const IdmapData& data) = 0;
virtual void visit(const IdmapData::Header& header) = 0;
};
inline size_t CalculatePadding(size_t data_length) {
return (4 - (data_length % 4)) % 4;
}
} // namespace android::idmap2
#endif // IDMAP2_INCLUDE_IDMAP2_IDMAP_H_