summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author MÃ¥rten Kongstad <marten.kongstad@sony.com> 2019-01-07 17:26:25 -0800
committer Ryan Mitchell <rtmitchell@google.com> 2019-01-16 11:47:24 -0800
commitd10d06d0b01151d6fcdf7ac70b5382e08858e233 (patch)
tree40d35254623f0ca31593e020a15c8f79b64f7f28
parentf9d106211850390c6ff162ccd1467e6c3ffce219 (diff)
Add enforcement of idmap policies
Teaches idmap2 to recognize policy restrictions put on overlayable resources. If overlayable enforcement is turned on for an overlay, then any resources defined within the overlayable api of the target will have policy restrictions imposed on them. All resources without overlayable definitions will continue to be overlayable without policy restrictions. Bug: 119390857 Test: atest idmap2 and booting Co-authored-by: Ryan Mitchell <rtmitchell@google.com> Change-Id: I7e435648eb6e4a87b0b90a7b2a0c3f33c1516ea6
-rw-r--r--cmds/idmap2/Android.bp2
-rw-r--r--cmds/idmap2/idmap2/Create.cpp31
-rw-r--r--cmds/idmap2/idmap2/Scan.cpp107
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp22
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.h7
-rw-r--r--cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl13
-rw-r--r--cmds/idmap2/include/idmap2/CommandLineOptions.h3
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h11
-rw-r--r--cmds/idmap2/include/idmap2/Policies.h41
-rw-r--r--cmds/idmap2/libidmap2/CommandLineOptions.cpp23
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp31
-rw-r--r--cmds/idmap2/libidmap2/Policies.cpp57
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp42
-rw-r--r--cmds/idmap2/tests/CommandLineOptionsTests.cpp56
-rw-r--r--cmds/idmap2/tests/FileUtilsTests.cpp14
-rw-r--r--cmds/idmap2/tests/Idmap2BinaryTests.cpp32
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp129
-rw-r--r--cmds/idmap2/tests/PoliciesTests.cpp70
-rw-r--r--cmds/idmap2/tests/PrettyPrintVisitorTests.cpp5
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp5
-rw-r--r--cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml21
-rw-r--r--cmds/idmap2/tests/data/system-overlay-invalid/build26
-rw-r--r--cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml29
-rw-r--r--cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apkbin0 -> 1427 bytes
-rw-r--r--cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml21
-rw-r--r--cmds/idmap2/tests/data/system-overlay/build26
-rw-r--r--cmds/idmap2/tests/data/system-overlay/res/values/values.xml22
-rw-r--r--cmds/idmap2/tests/data/system-overlay/system-overlay.apkbin0 -> 1283 bytes
-rw-r--r--cmds/idmap2/tests/data/target/res/values/overlayable.xml48
-rw-r--r--cmds/idmap2/tests/data/target/res/values/values.xml8
-rw-r--r--cmds/idmap2/tests/data/target/target.apkbin2173 -> 3669 bytes
-rw-r--r--libs/androidfw/tests/data/overlayable/overlayable.apkbin5523 -> 3443 bytes
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java84
33 files changed, 912 insertions, 74 deletions
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index abe18ba8a415..e9cfe63e0d03 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -38,6 +38,7 @@ cc_library {
"libidmap2/CommandLineOptions.cpp",
"libidmap2/FileUtils.cpp",
"libidmap2/Idmap.cpp",
+ "libidmap2/Policies.cpp",
"libidmap2/PrettyPrintVisitor.cpp",
"libidmap2/RawPrintVisitor.cpp",
"libidmap2/ResourceUtils.cpp",
@@ -87,6 +88,7 @@ cc_test {
"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 b07567331e85..c455ac0f83af 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 @@ 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;
}
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4f88127f8af1..a269ee958497 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 @@ 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();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d2e46e15fc59..a3c752718ee2 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::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());
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index e0bc22e9e9e6..1aab0598449b 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -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);
};
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index d475417a0935..ea7274f3ea58 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -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);
}
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index b93e71631d08..6db6bf9ea8ad 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -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;
};
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index b989e4c3f9d1..1666dc8a3bbd 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 @@ 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_;
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
new file mode 100644
index 000000000000..eecee25445e2
--- /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 cabc8f398c46..a49a607091a4 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -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;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 37d6af8fa477..2890ae11b0af 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -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);
}
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
new file mode 100644
index 000000000000..0f87ef0c4ea9
--- /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 2698ac0a734d..35ec1ff1dbb5 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -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);
}
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index c27d27a16b94..39f18d3336af 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -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);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 4bf832a34691..d9d9a7f829cf 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -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) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 22f48e9a396f..0c8f164bf096 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 @@ 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
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 963f22ec8d72..c6eb71cbeb72 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -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;
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
new file mode 100644
index 000000000000..ab567adc6f19
--- /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 7736bc063131..eaa47cd79533 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 @@ 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;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 0318cd20a9bb..b58c61a0c284 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -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);
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 000000000000..977cd97f21c3
--- /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 000000000000..920e1f8ad6f3
--- /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 000000000000..512770722a4b
--- /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 000000000000..c367f82e21e6
--- /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 000000000000..8af9064ba64f
--- /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 000000000000..be0d2390f535
--- /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 000000000000..6aaa0b02639e
--- /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 000000000000..90f30eb68c15
--- /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 000000000000..de19e6fcd022
--- /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 56bf0d60021a..ef9012e49300 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 18ecc276caae..9a6220dbe3ca 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 863474794d00..2049123e9cb2 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 16143d3ae9e0..74fbea1544bd 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 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;
+ }
}