Merge "Add enforcement of idmap policies"
This commit is contained in:
committed by
Android (Google) Code Review
commit
9853845074
@@ -39,6 +39,7 @@ cc_library {
|
||||
"libidmap2/CommandLineOptions.cpp",
|
||||
"libidmap2/FileUtils.cpp",
|
||||
"libidmap2/Idmap.cpp",
|
||||
"libidmap2/Policies.cpp",
|
||||
"libidmap2/PrettyPrintVisitor.cpp",
|
||||
"libidmap2/RawPrintVisitor.cpp",
|
||||
"libidmap2/ResourceUtils.cpp",
|
||||
@@ -88,6 +89,7 @@ cc_test {
|
||||
"tests/Idmap2BinaryTests.cpp",
|
||||
"tests/IdmapTests.cpp",
|
||||
"tests/Main.cpp",
|
||||
"tests/PoliciesTests.cpp",
|
||||
"tests/PrettyPrintVisitorTests.cpp",
|
||||
"tests/RawPrintVisitorTests.cpp",
|
||||
"tests/ResourceUtilsTests.cpp",
|
||||
|
||||
@@ -27,17 +27,25 @@
|
||||
#include "idmap2/CommandLineOptions.h"
|
||||
#include "idmap2/FileUtils.h"
|
||||
#include "idmap2/Idmap.h"
|
||||
#include "idmap2/Policies.h"
|
||||
#include "idmap2/Result.h"
|
||||
|
||||
using android::ApkAssets;
|
||||
using android::idmap2::BinaryStreamVisitor;
|
||||
using android::idmap2::CommandLineOptions;
|
||||
using android::idmap2::Idmap;
|
||||
using android::idmap2::PoliciesToBitmask;
|
||||
using android::idmap2::PolicyBitmask;
|
||||
using android::idmap2::PolicyFlags;
|
||||
using android::idmap2::Result;
|
||||
using android::idmap2::utils::kIdmapFilePermissionMask;
|
||||
|
||||
bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
std::string target_apk_path;
|
||||
std::string overlay_apk_path;
|
||||
std::string idmap_path;
|
||||
std::vector<std::string> policies;
|
||||
bool ignore_overlayable;
|
||||
|
||||
const CommandLineOptions opts =
|
||||
CommandLineOptions("idmap2 create")
|
||||
@@ -47,12 +55,28 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
.MandatoryOption("--overlay-apk-path",
|
||||
"input: path to apk which contains the new resource values",
|
||||
&overlay_apk_path)
|
||||
.MandatoryOption("--idmap-path", "output: path to where to write idmap file",
|
||||
&idmap_path);
|
||||
.MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
|
||||
.OptionalOption("--policy",
|
||||
"input: an overlayable policy this overlay fulfills "
|
||||
"(if none or supplied, the overlay policy will default to \"public\")",
|
||||
&policies)
|
||||
.OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
|
||||
&ignore_overlayable);
|
||||
if (!opts.Parse(args, out_error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PolicyBitmask fulfilled_policies = 0;
|
||||
if (auto result = PoliciesToBitmask(policies, out_error)) {
|
||||
fulfilled_policies |= *result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fulfilled_policies == 0) {
|
||||
fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
|
||||
}
|
||||
|
||||
const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
|
||||
if (!target_apk) {
|
||||
out_error << "error: failed to load apk " << target_apk_path << std::endl;
|
||||
@@ -66,7 +90,8 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
}
|
||||
|
||||
const std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
fulfilled_policies, !ignore_overlayable, out_error);
|
||||
if (!idmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,11 @@
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "android-base/properties.h"
|
||||
|
||||
#include "idmap2/CommandLineOptions.h"
|
||||
#include "idmap2/FileUtils.h"
|
||||
#include "idmap2/Idmap.h"
|
||||
@@ -34,6 +37,10 @@
|
||||
using android::idmap2::CommandLineOptions;
|
||||
using android::idmap2::Idmap;
|
||||
using android::idmap2::MemoryChunk;
|
||||
using android::idmap2::PoliciesToBitmask;
|
||||
using android::idmap2::PolicyBitmask;
|
||||
using android::idmap2::PolicyFlags;
|
||||
using android::idmap2::Result;
|
||||
using android::idmap2::Xml;
|
||||
using android::idmap2::ZipFile;
|
||||
using android::idmap2::utils::FindFiles;
|
||||
@@ -45,11 +52,19 @@ struct InputOverlay {
|
||||
return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
|
||||
}
|
||||
|
||||
std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
int priority; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
int priority; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
std::vector<std::string> policies; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
bool ignore_overlayable; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
};
|
||||
|
||||
bool VendorIsQOrLater() {
|
||||
// STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
|
||||
std::string version = android::base::GetProperty("ro.vndk.version", "Q");
|
||||
return version == "Q" || version == "q";
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
|
||||
bool recursive, std::ostream& out_error) {
|
||||
const auto predicate = [](unsigned char type, const std::string& path) -> bool {
|
||||
@@ -70,6 +85,22 @@ std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::st
|
||||
return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
|
||||
}
|
||||
|
||||
PolicyBitmask PolicyForPath(const std::string& apk_path) {
|
||||
static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
|
||||
{"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
|
||||
{"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
|
||||
{"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
|
||||
};
|
||||
|
||||
for (auto const& pair : values) {
|
||||
if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
|
||||
return pair.second | PolicyFlags::POLICY_PUBLIC;
|
||||
}
|
||||
}
|
||||
|
||||
return PolicyFlags::POLICY_PUBLIC;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
@@ -77,6 +108,7 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
std::string target_package_name;
|
||||
std::string target_apk_path;
|
||||
std::string output_directory;
|
||||
std::vector<std::string> override_policies;
|
||||
bool recursive = false;
|
||||
|
||||
const CommandLineOptions opts =
|
||||
@@ -89,7 +121,12 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
.MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
|
||||
.MandatoryOption("--output-directory",
|
||||
"directory in which to write artifacts (idmap files and overlays.list)",
|
||||
&output_directory);
|
||||
&output_directory)
|
||||
.OptionalOption(
|
||||
"--override-policy",
|
||||
"input: an overlayable policy this overlay fulfills "
|
||||
"(if none or supplied, the overlays will not have their policies overriden",
|
||||
&override_policies);
|
||||
if (!opts.Parse(args, out_error)) {
|
||||
return false;
|
||||
}
|
||||
@@ -144,29 +181,63 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sort the static overlays in ascending priority order
|
||||
PolicyBitmask fulfilled_policies;
|
||||
if (!override_policies.empty()) {
|
||||
if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) {
|
||||
fulfilled_policies = *result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
fulfilled_policies = PolicyForPath(path);
|
||||
}
|
||||
|
||||
bool ignore_overlayable = false;
|
||||
if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
|
||||
// If the overlay is on a pre-Q vendor partition, do not enforce overlayable
|
||||
// restrictions on this overlay because the pre-Q platform has no understanding of
|
||||
// overlayable.
|
||||
ignore_overlayable = true;
|
||||
}
|
||||
|
||||
std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
|
||||
InputOverlay input{path, idmap_path, priority};
|
||||
|
||||
// Sort the static overlays in ascending priority order
|
||||
InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable};
|
||||
interesting_apks.insert(
|
||||
std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
for (const auto& overlay : interesting_apks) {
|
||||
// Create the idmap for the overlay if it currently does not exist or if it is not up to date.
|
||||
std::stringstream dev_null;
|
||||
if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
|
||||
!Create(std::vector<std::string>({
|
||||
"--target-apk-path",
|
||||
target_apk_path,
|
||||
"--overlay-apk-path",
|
||||
overlay.apk_path,
|
||||
"--idmap-path",
|
||||
overlay.idmap_path,
|
||||
}),
|
||||
out_error)) {
|
||||
return false;
|
||||
|
||||
std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
|
||||
for (const std::string& policy : overlay.policies) {
|
||||
verify_args.emplace_back("--policy");
|
||||
verify_args.emplace_back(policy);
|
||||
}
|
||||
stream << overlay.idmap_path << std::endl;
|
||||
|
||||
if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
|
||||
std::vector<std::string> create_args = {"--target-apk-path", target_apk_path,
|
||||
"--overlay-apk-path", overlay.apk_path,
|
||||
"--idmap-path", overlay.idmap_path};
|
||||
if (overlay.ignore_overlayable) {
|
||||
create_args.emplace_back("--ignore-overlayable");
|
||||
}
|
||||
|
||||
for (const std::string& policy : overlay.policies) {
|
||||
verify_args.emplace_back("--policy");
|
||||
verify_args.emplace_back(policy);
|
||||
}
|
||||
|
||||
if (!Create(create_args, out_error)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stream << overlay.idmap_path << std::endl;
|
||||
}
|
||||
|
||||
std::cout << stream.str();
|
||||
|
||||
@@ -26,12 +26,15 @@
|
||||
#include <string>
|
||||
|
||||
#include "android-base/macros.h"
|
||||
#include "android-base/stringprintf.h"
|
||||
#include "utils/String8.h"
|
||||
#include "utils/Trace.h"
|
||||
|
||||
#include "idmap2/BinaryStreamVisitor.h"
|
||||
#include "idmap2/FileUtils.h"
|
||||
#include "idmap2/Idmap.h"
|
||||
#include "idmap2/Policies.h"
|
||||
#include "idmap2/Result.h"
|
||||
|
||||
#include "idmap2d/Idmap2Service.h"
|
||||
|
||||
@@ -39,6 +42,8 @@ using android::binder::Status;
|
||||
using android::idmap2::BinaryStreamVisitor;
|
||||
using android::idmap2::Idmap;
|
||||
using android::idmap2::IdmapHeader;
|
||||
using android::idmap2::PolicyBitmask;
|
||||
using android::idmap2::Result;
|
||||
using android::idmap2::utils::kIdmapFilePermissionMask;
|
||||
|
||||
namespace {
|
||||
@@ -54,6 +59,10 @@ Status error(const std::string& msg) {
|
||||
return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
|
||||
}
|
||||
|
||||
PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
|
||||
return static_cast<PolicyBitmask>(arg);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace android::os {
|
||||
@@ -78,6 +87,8 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
|
||||
}
|
||||
|
||||
Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
|
||||
int32_t fulfilled_policies ATTRIBUTE_UNUSED,
|
||||
bool enforce_overlayable ATTRIBUTE_UNUSED,
|
||||
int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
|
||||
assert(_aidl_return);
|
||||
const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
|
||||
@@ -86,11 +97,15 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
|
||||
fin.close();
|
||||
std::stringstream dev_null;
|
||||
*_aidl_return = header && header->IsUpToDate(dev_null);
|
||||
|
||||
// TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
|
||||
|
||||
return ok();
|
||||
}
|
||||
|
||||
Status Idmap2Service::createIdmap(const std::string& target_apk_path,
|
||||
const std::string& overlay_apk_path, int32_t user_id,
|
||||
const std::string& overlay_apk_path, int32_t fulfilled_policies,
|
||||
bool enforce_overlayable, int32_t user_id,
|
||||
std::unique_ptr<std::string>* _aidl_return) {
|
||||
assert(_aidl_return);
|
||||
std::stringstream trace;
|
||||
@@ -101,6 +116,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
|
||||
|
||||
_aidl_return->reset(nullptr);
|
||||
|
||||
const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
|
||||
|
||||
const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
|
||||
if (!target_apk) {
|
||||
return error("failed to load apk " + target_apk_path);
|
||||
@@ -113,7 +130,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
|
||||
|
||||
std::stringstream err;
|
||||
const std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
policy_bitmask, enforce_overlayable, err);
|
||||
if (!idmap) {
|
||||
return error(err.str());
|
||||
}
|
||||
|
||||
@@ -39,11 +39,12 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
|
||||
binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
|
||||
bool* _aidl_return);
|
||||
|
||||
binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id,
|
||||
bool* _aidl_return);
|
||||
binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
|
||||
bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
|
||||
|
||||
binder::Status createIdmap(const std::string& target_apk_path,
|
||||
const std::string& overlay_apk_path, int32_t user_id,
|
||||
const std::string& overlay_apk_path, int32_t fulfilled_policies,
|
||||
bool enforce_overlayable, int32_t user_id,
|
||||
std::unique_ptr<std::string>* _aidl_return);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,9 +20,18 @@ package android.os;
|
||||
* @hide
|
||||
*/
|
||||
interface IIdmap2 {
|
||||
const int POLICY_PUBLIC = 0x00000001;
|
||||
const int POLICY_SYSTEM_PARTITION = 0x00000002;
|
||||
const int POLICY_VENDOR_PARTITION = 0x00000004;
|
||||
const int POLICY_PRODUCT_PARTITION = 0x00000008;
|
||||
|
||||
@utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
|
||||
boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
|
||||
boolean verifyIdmap(@utf8InCpp String overlayApkPath, int userId);
|
||||
boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies,
|
||||
boolean enforceOverlayable, int userId);
|
||||
@nullable @utf8InCpp String createIdmap(@utf8InCpp String targetApkPath,
|
||||
@utf8InCpp String overlayApkPath, int userId);
|
||||
@utf8InCpp String overlayApkPath,
|
||||
int fulfilledPolicies,
|
||||
boolean enforceOverlayable,
|
||||
int userId);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ class CommandLineOptions {
|
||||
std::vector<std::string>* value);
|
||||
CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
|
||||
std::string* value);
|
||||
CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
|
||||
std::vector<std::string>* value);
|
||||
bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
|
||||
void Usage(std::ostream& out) const;
|
||||
|
||||
@@ -56,6 +58,7 @@ class CommandLineOptions {
|
||||
COUNT_OPTIONAL,
|
||||
COUNT_EXACTLY_ONCE,
|
||||
COUNT_ONCE_OR_MORE,
|
||||
COUNT_OPTIONAL_ONCE_OR_MORE,
|
||||
} count;
|
||||
bool argument;
|
||||
};
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
#include "androidfw/ResourceTypes.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "idmap2/Policies.h"
|
||||
|
||||
namespace android::idmap2 {
|
||||
|
||||
class Idmap;
|
||||
@@ -233,11 +235,10 @@ class Idmap {
|
||||
// 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 std::unique_ptr<const Idmap> FromApkAssets(const std::string& target_apk_path,
|
||||
const ApkAssets& target_apk_assets,
|
||||
const std::string& overlay_apk_path,
|
||||
const ApkAssets& overlay_apk_assets,
|
||||
std::ostream& out_error);
|
||||
static std::unique_ptr<const Idmap> FromApkAssets(
|
||||
const std::string& target_apk_path, const ApkAssets& target_apk_assets,
|
||||
const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
|
||||
const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error);
|
||||
|
||||
inline const std::unique_ptr<const IdmapHeader>& GetHeader() const {
|
||||
return header_;
|
||||
|
||||
41
cmds/idmap2/include/idmap2/Policies.h
Normal file
41
cmds/idmap2/include/idmap2/Policies.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "androidfw/ResourceTypes.h"
|
||||
#include "androidfw/StringPiece.h"
|
||||
|
||||
#include "Result.h"
|
||||
|
||||
#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
|
||||
#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
|
||||
|
||||
namespace android::idmap2 {
|
||||
|
||||
using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
|
||||
using PolicyBitmask = uint32_t;
|
||||
|
||||
// Parses a the string representation of a set of policies into a bitmask. The format of the string
|
||||
// is the same as for the <policy> element.
|
||||
Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
|
||||
std::ostream& err);
|
||||
|
||||
} // namespace android::idmap2
|
||||
|
||||
#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
|
||||
@@ -68,9 +68,18 @@ CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
|
||||
return *this;
|
||||
}
|
||||
|
||||
CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
|
||||
const std::string& description,
|
||||
std::vector<std::string>* value) {
|
||||
assert(value != nullptr);
|
||||
auto func = [value](const std::string& arg) -> void { value->push_back(arg); };
|
||||
options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL_ONCE_OR_MORE, true});
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
|
||||
const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
|
||||
return opt.count != Option::COUNT_OPTIONAL;
|
||||
return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
|
||||
});
|
||||
std::set<std::string> mandatory_opts;
|
||||
std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()),
|
||||
@@ -122,7 +131,8 @@ void CommandLineOptions::Usage(std::ostream& out) const {
|
||||
size_t maxLength = 0;
|
||||
out << "usage: " << name_;
|
||||
for (const Option& opt : options_) {
|
||||
const bool mandatory = opt.count != Option::COUNT_OPTIONAL;
|
||||
const bool mandatory =
|
||||
opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
|
||||
out << " ";
|
||||
if (!mandatory) {
|
||||
out << "[";
|
||||
@@ -134,9 +144,15 @@ void CommandLineOptions::Usage(std::ostream& out) const {
|
||||
out << opt.name;
|
||||
maxLength = std::max(maxLength, opt.name.size());
|
||||
}
|
||||
|
||||
if (opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
|
||||
out << " [..]";
|
||||
}
|
||||
|
||||
if (!mandatory) {
|
||||
out << "]";
|
||||
}
|
||||
|
||||
if (opt.count == Option::COUNT_ONCE_OR_MORE) {
|
||||
out << " [" << opt.name << " arg [..]]";
|
||||
}
|
||||
@@ -150,7 +166,8 @@ void CommandLineOptions::Usage(std::ostream& out) const {
|
||||
out << opt.name;
|
||||
}
|
||||
out << " " << opt.description;
|
||||
if (opt.count == Option::COUNT_ONCE_OR_MORE) {
|
||||
if (opt.count == Option::COUNT_ONCE_OR_MORE ||
|
||||
opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
|
||||
out << " (can be provided multiple times)";
|
||||
}
|
||||
out << std::endl;
|
||||
|
||||
@@ -274,11 +274,23 @@ std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream,
|
||||
return std::move(idmap);
|
||||
}
|
||||
|
||||
std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_path,
|
||||
const ApkAssets& target_apk_assets,
|
||||
const std::string& overlay_apk_path,
|
||||
const ApkAssets& overlay_apk_assets,
|
||||
std::ostream& out_error) {
|
||||
bool CheckOverlayable(const LoadedPackage& target_package, PolicyBitmask fulfilled_polices,
|
||||
ResourceId resid) {
|
||||
const OverlayableInfo* info = target_package.GetOverlayableInfo(resid);
|
||||
if (info == nullptr) {
|
||||
// If the resource does not have an overlayable definition, allow the resource to be overlaid.
|
||||
// Once overlayable enforcement is turned on, this check will return false.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enforce policy restrictions if the resource is declared as overlayable.
|
||||
return (info->policy_flags & fulfilled_polices) != 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<const Idmap> Idmap::FromApkAssets(
|
||||
const std::string& target_apk_path, const ApkAssets& target_apk_assets,
|
||||
const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
|
||||
const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
|
||||
AssetManager2 target_asset_manager;
|
||||
if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
|
||||
out_error << "error: failed to create target asset manager" << std::endl;
|
||||
@@ -380,6 +392,15 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_
|
||||
if (target_resid == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enforce_overlayable && !CheckOverlayable(*target_pkg, fulfilled_policies, target_resid)) {
|
||||
// The resources must be defined as overlayable and the overlay must fulfill at least one
|
||||
// policy enforced on the overlayable resource
|
||||
LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
|
||||
<< full_name << "\"" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
matching_resources.Add(target_resid, overlay_resid);
|
||||
}
|
||||
|
||||
|
||||
57
cmds/idmap2/libidmap2/Policies.cpp
Normal file
57
cmds/idmap2/libidmap2/Policies.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "androidfw/ResourceTypes.h"
|
||||
|
||||
#include "idmap2/Idmap.h"
|
||||
#include "idmap2/Policies.h"
|
||||
#include "idmap2/Result.h"
|
||||
|
||||
namespace android::idmap2 {
|
||||
|
||||
namespace {
|
||||
|
||||
const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
|
||||
{"public", PolicyFlags::POLICY_PUBLIC},
|
||||
{"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
|
||||
{"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
|
||||
{"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
|
||||
std::ostream& err) {
|
||||
PolicyBitmask bitmask = 0;
|
||||
for (const std::string& policy : policies) {
|
||||
const auto iter = kStringToFlag.find(policy);
|
||||
if (iter != kStringToFlag.end()) {
|
||||
bitmask |= iter->second;
|
||||
} else {
|
||||
err << "error: unknown policy \"" << policy << "\"";
|
||||
return kResultError;
|
||||
}
|
||||
}
|
||||
|
||||
return Result<PolicyBitmask>(bitmask);
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
@@ -78,7 +78,8 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) {
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
std::stringstream stream;
|
||||
@@ -101,25 +102,52 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) {
|
||||
header = loaded_idmap->GetEntryMapForType(0x02);
|
||||
ASSERT_THAT(header, NotNull());
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0002, &entry);
|
||||
success = LoadedIdmap::Lookup(header, 0x0000, &entry); // string/a
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0003, &entry);
|
||||
success = LoadedIdmap::Lookup(header, 0x0001, &entry); // string/b
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0002, &entry); // string/c
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0003, &entry); // string/not_overlayable
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0004, &entry); // string/policy_product
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0005, &entry); // string/policy_public
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0006, &entry); // string/policy_system
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0007, &entry); // string/policy_system_vendor
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0008, &entry); // string/str1
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(entry, 0x0000);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0004, &entry);
|
||||
success = LoadedIdmap::Lookup(header, 0x0009, &entry); // string/str2
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0005, &entry);
|
||||
success = LoadedIdmap::Lookup(header, 0x000a, &entry); // string/str3
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(entry, 0x0001);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0006, &entry);
|
||||
success = LoadedIdmap::Lookup(header, 0x000b, &entry); // string/str4
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(entry, 0x0002);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x0007, &entry);
|
||||
success = LoadedIdmap::Lookup(header, 0x000c, &entry); // string/x
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x000d, &entry); // string/y
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
success = LoadedIdmap::Lookup(header, 0x000e, &entry); // string/z
|
||||
ASSERT_FALSE(success);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,56 @@ TEST(CommandLineOptionsTests, OptionalOption) {
|
||||
ASSERT_FALSE(success);
|
||||
}
|
||||
|
||||
TEST(CommandLineOptionsTests, OptionalOptionList) {
|
||||
std::vector<std::string> foo;
|
||||
std::vector<std::string> bar;
|
||||
CommandLineOptions opts = CommandLineOptions("test")
|
||||
.OptionalOption("--foo", "", &foo)
|
||||
.OptionalOption("--bar", "", &bar);
|
||||
std::ostream fakeStdErr(nullptr);
|
||||
bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(foo.size(), 1U);
|
||||
ASSERT_EQ(foo[0], "FOO");
|
||||
ASSERT_EQ(bar.size(), 1U);
|
||||
ASSERT_EQ(bar[0], "BAR");
|
||||
|
||||
foo.clear();
|
||||
bar.clear();
|
||||
success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(foo.size(), 1U);
|
||||
ASSERT_EQ(foo[0], "BAZ");
|
||||
ASSERT_EQ(bar.size(), 0U);
|
||||
|
||||
foo.clear();
|
||||
bar.clear();
|
||||
success =
|
||||
opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_EQ(foo.size(), 2U);
|
||||
ASSERT_EQ(foo[0], "BAZ");
|
||||
ASSERT_EQ(foo[1], "BIZ");
|
||||
ASSERT_EQ(bar.size(), 2U);
|
||||
ASSERT_EQ(bar[0], "FIZ");
|
||||
ASSERT_EQ(bar[1], "FUZZ");
|
||||
|
||||
foo.clear();
|
||||
bar.clear();
|
||||
success = opts.Parse({"--foo"}, fakeStdErr);
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
foo.clear();
|
||||
bar.clear();
|
||||
success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
foo.clear();
|
||||
bar.clear();
|
||||
success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
|
||||
ASSERT_FALSE(success);
|
||||
}
|
||||
|
||||
TEST(CommandLineOptionsTests, CornerCases) {
|
||||
std::string foo;
|
||||
std::string bar;
|
||||
@@ -172,6 +222,7 @@ TEST(CommandLineOptionsTests, Usage) {
|
||||
bool arg5 = false;
|
||||
bool arg6 = false;
|
||||
std::vector<std::string> arg7;
|
||||
std::vector<std::string> arg8;
|
||||
CommandLineOptions opts = CommandLineOptions("test")
|
||||
.MandatoryOption("--aa", "description-aa", &arg1)
|
||||
.OptionalFlag("--bb", "description-bb", &arg5)
|
||||
@@ -179,12 +230,13 @@ TEST(CommandLineOptionsTests, Usage) {
|
||||
.OptionalOption("--dd", "description-dd", &arg3)
|
||||
.MandatoryOption("--ee", "description-ee", &arg4)
|
||||
.OptionalFlag("--ff", "description-ff", &arg6)
|
||||
.MandatoryOption("--gg", "description-gg", &arg7);
|
||||
.MandatoryOption("--gg", "description-gg", &arg7)
|
||||
.OptionalOption("--hh", "description-hh", &arg8);
|
||||
std::stringstream stream;
|
||||
opts.Usage(stream);
|
||||
const std::string s = stream.str();
|
||||
ASSERT_NE(s.find("usage: test --aa arg [--bb] [--cc arg] [--dd arg] --ee arg [--ff] --gg arg "
|
||||
"[--gg arg [..]]"),
|
||||
"[--gg arg [..]] [--hh arg [..]]"),
|
||||
std::string::npos);
|
||||
ASSERT_NE(s.find("--aa arg description-aa"), std::string::npos);
|
||||
ASSERT_NE(s.find("--ff description-ff"), std::string::npos);
|
||||
|
||||
@@ -37,10 +37,10 @@ TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) {
|
||||
[](unsigned char type ATTRIBUTE_UNUSED,
|
||||
const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
|
||||
ASSERT_THAT(v, NotNull());
|
||||
ASSERT_EQ(v->size(), 4U);
|
||||
ASSERT_EQ(
|
||||
std::set<std::string>(v->begin(), v->end()),
|
||||
std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target"}));
|
||||
ASSERT_EQ(v->size(), 6U);
|
||||
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
|
||||
std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target",
|
||||
root + "/system-overlay", root + "/system-overlay-invalid"}));
|
||||
}
|
||||
|
||||
TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
|
||||
@@ -49,11 +49,13 @@ TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
|
||||
return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
|
||||
});
|
||||
ASSERT_THAT(v, NotNull());
|
||||
ASSERT_EQ(v->size(), 4U);
|
||||
ASSERT_EQ(v->size(), 6U);
|
||||
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
|
||||
std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk",
|
||||
root + "/overlay/overlay-static-1.apk",
|
||||
root + "/overlay/overlay-static-2.apk"}));
|
||||
root + "/overlay/overlay-static-2.apk",
|
||||
root + "/system-overlay/system-overlay.apk",
|
||||
root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
|
||||
}
|
||||
|
||||
TEST(FileUtilsTests, ReadFile) {
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "androidfw/PosixUtils.h"
|
||||
|
||||
#include "idmap2/FileUtils.h"
|
||||
#include "idmap2/Idmap.h"
|
||||
|
||||
@@ -114,8 +115,9 @@ TEST_F(Idmap2BinaryTests, Dump) {
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
|
||||
ASSERT_NE(result->stdout.find("0x7f020003 -> 0x7f020000 string/str1"), std::string::npos);
|
||||
ASSERT_NE(result->stdout.find("0x7f020005 -> 0x7f020001 string/str3"), std::string::npos);
|
||||
ASSERT_NE(result->stdout.find("0x7f020008 -> 0x7f020000 string/str1"), std::string::npos);
|
||||
ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020001 string/str3"), std::string::npos);
|
||||
ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020002 string/str4"), std::string::npos);
|
||||
ASSERT_EQ(result->stdout.find("00000210: 007f target package id"), std::string::npos);
|
||||
|
||||
// clang-format off
|
||||
@@ -157,7 +159,8 @@ TEST_F(Idmap2BinaryTests, Scan) {
|
||||
"--recursive",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath()});
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
@@ -190,7 +193,8 @@ TEST_F(Idmap2BinaryTests, Scan) {
|
||||
"--input-directory", GetTestDataPath() + "/overlay",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath()});
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
@@ -207,7 +211,8 @@ TEST_F(Idmap2BinaryTests, Scan) {
|
||||
"--recursive",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath()});
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
@@ -222,7 +227,8 @@ TEST_F(Idmap2BinaryTests, Scan) {
|
||||
"--input-directory", GetTempDirPath(),
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath()});
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
@@ -245,7 +251,7 @@ TEST_F(Idmap2BinaryTests, Lookup) {
|
||||
"lookup",
|
||||
"--idmap-path", GetIdmapPath(),
|
||||
"--config", "",
|
||||
"--resid", "0x7f020003"}); // string/str1
|
||||
"--resid", "0x7f020008"}); // string/str1
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
@@ -310,6 +316,18 @@ TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_NE(result->status, EXIT_SUCCESS);
|
||||
|
||||
// unknown policy
|
||||
// clang-format off
|
||||
result = ExecuteBinary({"idmap2",
|
||||
"create",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--overlay-apk-path", GetOverlayApkPath(),
|
||||
"--idmap-path", GetIdmapPath(),
|
||||
"--policy", "this-does-not-exist"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_NE(result->status, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
|
||||
@@ -184,13 +184,14 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) {
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
ASSERT_THAT(idmap->GetHeader(), NotNull());
|
||||
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xf5ad1d1d);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xca2093da);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
|
||||
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
|
||||
@@ -216,13 +217,127 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) {
|
||||
ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
|
||||
ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
|
||||
ASSERT_EQ(types[1]->GetEntryCount(), 4U);
|
||||
ASSERT_EQ(types[1]->GetEntryOffset(), 3U);
|
||||
ASSERT_EQ(types[1]->GetEntryOffset(), 8U);
|
||||
ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
|
||||
ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
|
||||
ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
|
||||
ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
|
||||
}
|
||||
|
||||
TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
|
||||
const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
|
||||
std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
|
||||
ASSERT_THAT(target_apk, NotNull());
|
||||
|
||||
const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
|
||||
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
|
||||
ASSERT_THAT(overlay_apk, NotNull());
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
|
||||
/* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
|
||||
ASSERT_EQ(dataBlocks.size(), 1U);
|
||||
|
||||
const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
|
||||
|
||||
ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
|
||||
ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
|
||||
|
||||
const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
|
||||
ASSERT_EQ(types.size(), 1U);
|
||||
|
||||
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
|
||||
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
|
||||
ASSERT_EQ(types[0]->GetEntryCount(), 3U);
|
||||
ASSERT_EQ(types[0]->GetEntryOffset(), 5U);
|
||||
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_public
|
||||
ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_system
|
||||
ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_system_vendor
|
||||
}
|
||||
|
||||
TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
|
||||
const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
|
||||
std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
|
||||
ASSERT_THAT(target_apk, NotNull());
|
||||
|
||||
const std::string overlay_apk_path(GetTestDataPath() +
|
||||
"/system-overlay-invalid/system-overlay-invalid.apk");
|
||||
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
|
||||
ASSERT_THAT(overlay_apk, NotNull());
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
|
||||
/* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
|
||||
ASSERT_EQ(dataBlocks.size(), 1U);
|
||||
|
||||
const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
|
||||
|
||||
ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
|
||||
ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
|
||||
|
||||
const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
|
||||
ASSERT_EQ(types.size(), 1U);
|
||||
|
||||
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
|
||||
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
|
||||
ASSERT_EQ(types[0]->GetEntryCount(), 5U);
|
||||
ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
|
||||
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
|
||||
ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_product
|
||||
ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_public
|
||||
ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_system
|
||||
ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system_vendor
|
||||
}
|
||||
|
||||
TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
|
||||
const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
|
||||
std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
|
||||
ASSERT_THAT(target_apk, NotNull());
|
||||
|
||||
const std::string overlay_apk_path(GetTestDataPath() +
|
||||
"/system-overlay-invalid/system-overlay-invalid.apk");
|
||||
std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
|
||||
ASSERT_THAT(overlay_apk, NotNull());
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
|
||||
/* enforce_overlayable */ false, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
|
||||
ASSERT_EQ(dataBlocks.size(), 1U);
|
||||
|
||||
const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
|
||||
|
||||
ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
|
||||
ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
|
||||
|
||||
const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
|
||||
ASSERT_EQ(types.size(), 1U);
|
||||
|
||||
ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
|
||||
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
|
||||
ASSERT_EQ(types[0]->GetEntryCount(), 5U);
|
||||
ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
|
||||
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
|
||||
ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_product
|
||||
ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_public
|
||||
ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_system
|
||||
ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system_vendor
|
||||
}
|
||||
|
||||
TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
|
||||
std::string target_apk_path(GetTestDataPath());
|
||||
for (int i = 0; i < 32; i++) {
|
||||
@@ -239,7 +354,8 @@ TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, IsNull());
|
||||
}
|
||||
|
||||
@@ -255,8 +371,9 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
|
||||
ASSERT_THAT(overlay_apk, NotNull());
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
|
||||
std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(
|
||||
target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
|
||||
/* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
std::stringstream stream;
|
||||
|
||||
70
cmds/idmap2/tests/PoliciesTests.cpp
Normal file
70
cmds/idmap2/tests/PoliciesTests.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "TestHelpers.h"
|
||||
#include "idmap2/Policies.h"
|
||||
|
||||
using android::idmap2::PolicyBitmask;
|
||||
using android::idmap2::PolicyFlags;
|
||||
|
||||
namespace android::idmap2 {
|
||||
|
||||
TEST(PoliciesTests, PoliciesToBitmasks) {
|
||||
const Result<PolicyBitmask> bitmask1 = PoliciesToBitmask({"system"}, std::cerr);
|
||||
ASSERT_NE(bitmask1, kResultError);
|
||||
ASSERT_EQ(bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION);
|
||||
|
||||
const Result<PolicyBitmask> bitmask2 = PoliciesToBitmask({"system", "vendor"}, std::cerr);
|
||||
ASSERT_NE(bitmask2, kResultError);
|
||||
ASSERT_EQ(bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
|
||||
|
||||
const Result<PolicyBitmask> bitmask3 = PoliciesToBitmask({"vendor", "system"}, std::cerr);
|
||||
ASSERT_NE(bitmask3, kResultError);
|
||||
ASSERT_EQ(bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
|
||||
|
||||
const Result<PolicyBitmask> bitmask4 =
|
||||
PoliciesToBitmask({"public", "product", "system", "vendor"}, std::cerr);
|
||||
ASSERT_NE(bitmask4, kResultError);
|
||||
ASSERT_EQ(bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
|
||||
PolicyFlags::POLICY_SYSTEM_PARTITION |
|
||||
PolicyFlags::POLICY_VENDOR_PARTITION);
|
||||
|
||||
const Result<PolicyBitmask> bitmask5 =
|
||||
PoliciesToBitmask({"system", "system", "system"}, std::cerr);
|
||||
ASSERT_NE(bitmask5, kResultError);
|
||||
ASSERT_EQ(bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION);
|
||||
|
||||
const Result<PolicyBitmask> bitmask6 = PoliciesToBitmask({""}, std::cerr);
|
||||
ASSERT_EQ(bitmask6, kResultError);
|
||||
|
||||
const Result<PolicyBitmask> bitmask7 = PoliciesToBitmask({"foo"}, std::cerr);
|
||||
ASSERT_EQ(bitmask7, kResultError);
|
||||
|
||||
const Result<PolicyBitmask> bitmask8 = PoliciesToBitmask({"system", "foo"}, std::cerr);
|
||||
ASSERT_EQ(bitmask8, kResultError);
|
||||
|
||||
const Result<PolicyBitmask> bitmask9 = PoliciesToBitmask({"system", ""}, std::cerr);
|
||||
ASSERT_EQ(bitmask9, kResultError);
|
||||
|
||||
const Result<PolicyBitmask> bitmask10 = PoliciesToBitmask({"system "}, std::cerr);
|
||||
ASSERT_EQ(bitmask10, kResultError);
|
||||
}
|
||||
|
||||
} // namespace android::idmap2
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "androidfw/Idmap.h"
|
||||
|
||||
#include "idmap2/Idmap.h"
|
||||
#include "idmap2/Policies.h"
|
||||
#include "idmap2/PrettyPrintVisitor.h"
|
||||
|
||||
#include "TestHelpers.h"
|
||||
@@ -32,6 +33,7 @@
|
||||
using ::testing::NotNull;
|
||||
|
||||
using android::ApkAssets;
|
||||
using android::idmap2::PolicyBitmask;
|
||||
|
||||
namespace android::idmap2 {
|
||||
|
||||
@@ -46,7 +48,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
std::stringstream stream;
|
||||
|
||||
@@ -42,7 +42,8 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
|
||||
|
||||
std::stringstream error;
|
||||
std::unique_ptr<const Idmap> idmap =
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
|
||||
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
|
||||
PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
|
||||
ASSERT_THAT(idmap, NotNull());
|
||||
|
||||
std::stringstream stream;
|
||||
@@ -51,7 +52,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
|
||||
|
||||
ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("00000004: 00000001 version\n"), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("00000008: f5ad1d1d target crc\n"), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("00000008: ca2093da target crc\n"), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("0000000c: d470336b overlay crc\n"), std::string::npos);
|
||||
ASSERT_NE(stream.str().find("0000021c: 00000000 0x7f010000 -> 0x7f010000 integer/int1\n"),
|
||||
std::string::npos);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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.
|
||||
-->
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test.overlay.system.invalid">
|
||||
<overlay
|
||||
android:targetPackage="test.target" />
|
||||
</manifest>
|
||||
26
cmds/idmap2/tests/data/system-overlay-invalid/build
Normal file
26
cmds/idmap2/tests/data/system-overlay-invalid/build
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2019 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.
|
||||
|
||||
FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
|
||||
|
||||
aapt2 compile --dir res -o compiled.flata
|
||||
|
||||
aapt2 link \
|
||||
--no-resource-removal \
|
||||
-I "$FRAMEWORK_RES_APK" \
|
||||
--manifest AndroidManifest.xml \
|
||||
-o system-overlay-invalid.apk \
|
||||
compiled.flata
|
||||
|
||||
rm compiled.flata
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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.
|
||||
-->
|
||||
<resources>
|
||||
<!-- This overlay will fulfill the policies "public|system". This allows it overlay the
|
||||
following resources. -->
|
||||
<string name="policy_system">policy_system</string>
|
||||
<string name="policy_system_vendor">policy_system_vendor</string>
|
||||
<string name="policy_public">policy_public</string>
|
||||
|
||||
<!-- It also requests to overlay a resource that belongs to a policy the overlay does not
|
||||
fulfill.-->
|
||||
<string name="policy_product">policy_product</string>
|
||||
|
||||
<!-- It also requests to overlay a resource that is not declared as overlayable.-->
|
||||
<string name="not_overlayable">not_overlayable</string>
|
||||
</resources>
|
||||
Binary file not shown.
21
cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
Normal file
21
cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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.
|
||||
-->
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test.overlay.system">
|
||||
<overlay
|
||||
android:targetPackage="test.target" />
|
||||
</manifest>
|
||||
26
cmds/idmap2/tests/data/system-overlay/build
Normal file
26
cmds/idmap2/tests/data/system-overlay/build
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2019 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.
|
||||
|
||||
FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
|
||||
|
||||
aapt2 compile --dir res -o compiled.flata
|
||||
|
||||
aapt2 link \
|
||||
--no-resource-removal \
|
||||
-I "$FRAMEWORK_RES_APK" \
|
||||
--manifest AndroidManifest.xml \
|
||||
-o system-overlay.apk \
|
||||
compiled.flata
|
||||
|
||||
rm compiled.flata
|
||||
22
cmds/idmap2/tests/data/system-overlay/res/values/values.xml
Normal file
22
cmds/idmap2/tests/data/system-overlay/res/values/values.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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.
|
||||
-->
|
||||
<resources>
|
||||
<!-- This overlay will fulfill the policies "public|system". This allows it overlay the
|
||||
following resources. -->
|
||||
<string name="policy_system">policy_system</string>
|
||||
<string name="policy_system_vendor">policy_system_vendor</string>
|
||||
<string name="policy_public">policy_public</string>
|
||||
</resources>
|
||||
BIN
cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Normal file
BIN
cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Normal file
Binary file not shown.
48
cmds/idmap2/tests/data/target/res/values/overlayable.xml
Normal file
48
cmds/idmap2/tests/data/target/res/values/overlayable.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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.
|
||||
-->
|
||||
<resources>
|
||||
<overlayable name="TestResources">
|
||||
<!-- Publicly overlayable resources -->
|
||||
<item type="string" name="a" />
|
||||
<item type="string" name="b" />
|
||||
<item type="string" name="c" />
|
||||
<item type="string" name="str1" />
|
||||
<item type="string" name="str2" />
|
||||
<item type="string" name="str3" />
|
||||
<item type="string" name="str4" />
|
||||
<item type="string" name="x" />
|
||||
<item type="string" name="y" />
|
||||
<item type="string" name="z" />
|
||||
<item type="integer" name="int1" />
|
||||
|
||||
<!-- Resources with partition restrictins -->
|
||||
<policy type="system">
|
||||
<item type="string" name="policy_system" />
|
||||
</policy>
|
||||
|
||||
<policy type="system|vendor">
|
||||
<item type="string" name="policy_system_vendor" />
|
||||
</policy>
|
||||
|
||||
<policy type="product">
|
||||
<item type="string" name="policy_product" />
|
||||
</policy>
|
||||
|
||||
<policy type="public">
|
||||
<item type="string" name="policy_public" />
|
||||
</policy>
|
||||
</overlayable>
|
||||
</resources>
|
||||
@@ -25,4 +25,12 @@
|
||||
<string name="y">y</string>
|
||||
<string name="z">z</string>
|
||||
<integer name="int1">1</integer>
|
||||
|
||||
<!-- This resources is not marked as overlayable -->
|
||||
<string name="not_overlayable">not_overlayable</string>
|
||||
|
||||
<string name="policy_system">policy_system</string>
|
||||
<string name="policy_system_vendor">policy_system_vendor</string>
|
||||
<string name="policy_product">policy_product</string>
|
||||
<string name="policy_public">policy_public</string>
|
||||
</resources>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -24,11 +24,14 @@ import static com.android.server.om.OverlayManagerService.TAG;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.om.OverlayInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.IBinder;
|
||||
import android.os.IIdmap2;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -51,6 +54,13 @@ class IdmapManager {
|
||||
private final Installer mInstaller;
|
||||
private IIdmap2 mIdmap2Service;
|
||||
|
||||
private static final boolean VENDOR_IS_Q_OR_LATER;
|
||||
static {
|
||||
// STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
|
||||
final String value = SystemProperties.get("ro.vndk.version", "Q");
|
||||
VENDOR_IS_Q_OR_LATER = value.equals("Q") || value.equals("q");
|
||||
}
|
||||
|
||||
IdmapManager(final Installer installer) {
|
||||
mInstaller = installer;
|
||||
if (FEATURE_FLAG_IDMAP2) {
|
||||
@@ -69,10 +79,13 @@ class IdmapManager {
|
||||
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
|
||||
try {
|
||||
if (FEATURE_FLAG_IDMAP2) {
|
||||
if (mIdmap2Service.verifyIdmap(overlayPath, userId)) {
|
||||
int policies = determineFulfilledPolicies(overlayPackage);
|
||||
boolean enforce = enforceOverlayable(overlayPackage);
|
||||
if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
|
||||
return true;
|
||||
}
|
||||
return mIdmap2Service.createIdmap(targetPath, overlayPath, userId) != null;
|
||||
return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
|
||||
userId) != null;
|
||||
} else {
|
||||
mInstaller.idmap(targetPath, overlayPath, sharedGid);
|
||||
return true;
|
||||
@@ -156,4 +169,71 @@ class IdmapManager {
|
||||
}, SECOND_IN_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if overlayable and policies should be enforced on the specified overlay for backwards
|
||||
* compatibility with pre-Q overlays.
|
||||
*/
|
||||
private boolean enforceOverlayable(@NonNull final PackageInfo overlayPackage) {
|
||||
final ApplicationInfo ai = overlayPackage.applicationInfo;
|
||||
if (ai.targetSdkVersion >= VERSION_CODES.Q) {
|
||||
// Always enforce policies for overlays targeting Q+.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) {
|
||||
// If the overlay is on a pre-Q vendor partition, do not enforce overlayable
|
||||
// restrictions on this overlay because the pre-Q platform has no understanding of
|
||||
// overlayable.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not enforce overlayable restrictions on pre-Q overlays signed with the
|
||||
// platform signature.
|
||||
return !ai.isSignedWithPlatformKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills.
|
||||
* @throws SecurityException if the overlay is not allowed to overlay any resource
|
||||
*/
|
||||
private int determineFulfilledPolicies(@NonNull final PackageInfo overlayPackage)
|
||||
throws SecurityException {
|
||||
final ApplicationInfo ai = overlayPackage.applicationInfo;
|
||||
final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q;
|
||||
|
||||
int fulfilledPolicies = 0;
|
||||
|
||||
// TODO(b/119402606) : Add signature policy
|
||||
|
||||
// Vendor partition (/vendor)
|
||||
if (ai.isVendor()) {
|
||||
if (overlayIsQOrLater) {
|
||||
fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION;
|
||||
} else if (VENDOR_IS_Q_OR_LATER) {
|
||||
throw new SecurityException("Overlay must target Q sdk or higher");
|
||||
}
|
||||
}
|
||||
|
||||
// Product partition (/product)
|
||||
if (ai.isProduct()) {
|
||||
if (overlayIsQOrLater) {
|
||||
fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION;
|
||||
} else {
|
||||
throw new SecurityException("Overlay must target Q sdk or higher");
|
||||
}
|
||||
}
|
||||
|
||||
// System partition (/system)
|
||||
if (ai.isSystemApp()) {
|
||||
if (overlayIsQOrLater) {
|
||||
fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION;
|
||||
} else {
|
||||
throw new SecurityException("Overlay must target Q sdk or higher");
|
||||
}
|
||||
}
|
||||
|
||||
// All overlays can overlay resources with the public policy
|
||||
return fulfilledPolicies | IIdmap2.POLICY_PUBLIC;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user