Merge "Add enforcement of idmap policies"
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 423bbd2..803f83c 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -39,6 +39,7 @@
"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 @@
"tests/Idmap2BinaryTests.cpp",
"tests/IdmapTests.cpp",
"tests/Main.cpp",
+ "tests/PoliciesTests.cpp",
"tests/PrettyPrintVisitorTests.cpp",
"tests/RawPrintVisitorTests.cpp",
"tests/ResourceUtilsTests.cpp",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index b075673..c455ac0 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.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 @@
.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 @@
}
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;
}
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4f88127..a269ee9 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -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 @@
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 @@
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 @@
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 @@
.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 @@
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();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d2e46e1..a3c7527 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -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::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 @@
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::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 @@
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 @@
_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 @@
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());
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index e0bc22e..1aab059 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -39,11 +39,12 @@
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);
};
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index d475417..ea7274f 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -20,9 +20,18 @@
* @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);
}
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index b93e716..6db6bf9 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -44,6 +44,8 @@
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 @@
COUNT_OPTIONAL,
COUNT_EXACTLY_ONCE,
COUNT_ONCE_OR_MORE,
+ COUNT_OPTIONAL_ONCE_OR_MORE,
} count;
bool argument;
};
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index b989e4c..1666dc8 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -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 @@
// 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_;
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
new file mode 100644
index 0000000..eecee25
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -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_
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index cabc8f3..a49a607 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -68,9 +68,18 @@
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 @@
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 @@
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 @@
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;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 37d6af8..2890ae1 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -274,11 +274,23 @@
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 @@
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);
}
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
new file mode 100644
index 0000000..0f87ef0
--- /dev/null
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -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
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 2698ac0..35ec1ff 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -78,7 +78,8 @@
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 @@
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);
}
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index c27d27a..39f18d3 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -121,6 +121,56 @@
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 @@
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 @@
.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);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 4bf832a..d9d9a7f 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -37,10 +37,10 @@
[](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 @@
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) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 22f48e9..0c8f164 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
#include "gtest/gtest.h"
#include "androidfw/PosixUtils.h"
+
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
@@ -114,8 +115,9 @@
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 @@
"--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 @@
"--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 @@
"--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 @@
"--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 @@
"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 @@
// 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
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 963f22e..c6eb71c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -184,13 +184,14 @@
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 @@
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 @@
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 @@
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;
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
new file mode 100644
index 0000000..ab567ad
--- /dev/null
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -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
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 7736bc0..eaa47cd 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -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 @@
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;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 0318cd2..b58c61a 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -42,7 +42,8 @@
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 @@
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);
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
new file mode 100644
index 0000000..977cd97
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -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>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build
new file mode 100644
index 0000000..920e1f8
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/build
@@ -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
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
new file mode 100644
index 0000000..5127707
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -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>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
new file mode 100644
index 0000000..c367f82
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
new file mode 100644
index 0000000..8af9064
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -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>
diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build
new file mode 100644
index 0000000..be0d239
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/build
@@ -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
diff --git a/cmds/idmap2/tests/data/system-overlay/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
new file mode 100644
index 0000000..6aaa0b0
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
@@ -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>
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
new file mode 100644
index 0000000..90f30eb
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
new file mode 100644
index 0000000..de19e6f
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -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>
\ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 56bf0d6..ef9012e 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -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>
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 18ecc27..9a6220d 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 8634747..2049123 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 16143d3..74fbea1 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -24,11 +24,14 @@
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 @@
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 @@
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 @@
}, 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;
+ }
}