idmap2: remove the 'scan' command
The 'scan' command has been replaced by 'create-multiple'. Remove the unused code. Also remove unused functions and #includes from FileUtils, and the obsolete JNI plumbing. Test: atest idmap2_tests OverlayDeviceTests OverlayHostTests Change-Id: Iae073c13ce64b5db48f22f7e723bc8c0c5fcd2c9
This commit is contained in:
committed by
Ryan Mitchell
parent
dc91aaab2d
commit
3abb504a08
@@ -181,7 +181,6 @@ cc_binary {
|
||||
"idmap2/Dump.cpp",
|
||||
"idmap2/Lookup.cpp",
|
||||
"idmap2/Main.cpp",
|
||||
"idmap2/Scan.cpp",
|
||||
],
|
||||
target: {
|
||||
android: {
|
||||
|
||||
@@ -26,6 +26,5 @@ android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::str
|
||||
android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<std::string>& args);
|
||||
android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
|
||||
android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
|
||||
android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
|
||||
|
||||
#endif // IDMAP2_IDMAP2_COMMANDS_H_
|
||||
|
||||
@@ -53,8 +53,10 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
|
||||
int main(int argc, char** argv) {
|
||||
SYSTRACE << "main";
|
||||
const NameToFunctionMap commands = {
|
||||
{"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup},
|
||||
{"scan", Scan},
|
||||
{"create", Create},
|
||||
{"create-multiple", CreateMultiple},
|
||||
{"dump", Dump},
|
||||
{"lookup", Lookup},
|
||||
};
|
||||
if (argc <= 1) {
|
||||
PrintUsage(commands, std::cerr);
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Commands.h"
|
||||
#include "android-base/properties.h"
|
||||
#include "idmap2/CommandLineOptions.h"
|
||||
#include "idmap2/CommandUtils.h"
|
||||
#include "idmap2/FileUtils.h"
|
||||
#include "idmap2/Idmap.h"
|
||||
#include "idmap2/Policies.h"
|
||||
#include "idmap2/PolicyUtils.h"
|
||||
#include "idmap2/ResourceUtils.h"
|
||||
#include "idmap2/Result.h"
|
||||
#include "idmap2/SysTrace.h"
|
||||
#include "idmap2/XmlParser.h"
|
||||
|
||||
using android::idmap2::CommandLineOptions;
|
||||
using android::idmap2::Error;
|
||||
using android::idmap2::Idmap;
|
||||
using android::idmap2::Result;
|
||||
using android::idmap2::Unit;
|
||||
using android::idmap2::policy::kPolicyOdm;
|
||||
using android::idmap2::policy::kPolicyOem;
|
||||
using android::idmap2::policy::kPolicyProduct;
|
||||
using android::idmap2::policy::kPolicyPublic;
|
||||
using android::idmap2::policy::kPolicySystem;
|
||||
using android::idmap2::policy::kPolicyVendor;
|
||||
using android::idmap2::utils::ExtractOverlayManifestInfo;
|
||||
using android::idmap2::utils::FindFiles;
|
||||
using android::idmap2::utils::OverlayManifestInfo;
|
||||
using android::idmap2::utils::PoliciesToBitmaskResult;
|
||||
|
||||
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
|
||||
|
||||
namespace {
|
||||
|
||||
struct InputOverlay {
|
||||
bool operator<(InputOverlay const& rhs) const {
|
||||
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::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() {
|
||||
constexpr int kQSdkVersion = 29;
|
||||
constexpr int kBase = 10;
|
||||
std::string version_prop = android::base::GetProperty("ro.vndk.version", "29");
|
||||
int version = strtol(version_prop.data(), nullptr, kBase);
|
||||
|
||||
// If the string cannot be parsed, it is a development sdk codename.
|
||||
return version >= kQSdkVersion || version == 0;
|
||||
}
|
||||
|
||||
Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs,
|
||||
bool recursive) {
|
||||
SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
|
||||
const auto predicate = [](unsigned char type, const std::string& path) -> bool {
|
||||
static constexpr size_t kExtLen = 4; // strlen(".apk")
|
||||
return type == DT_REG && path.size() > kExtLen &&
|
||||
path.compare(path.size() - kExtLen, kExtLen, ".apk") == 0;
|
||||
};
|
||||
// pass apk paths through a set to filter out duplicates
|
||||
std::set<std::string> paths;
|
||||
for (const auto& dir : dirs) {
|
||||
const auto apk_paths = FindFiles(dir, recursive, predicate);
|
||||
if (!apk_paths) {
|
||||
return Error("failed to open directory %s", dir.c_str());
|
||||
}
|
||||
paths.insert(apk_paths->cbegin(), apk_paths->cend());
|
||||
}
|
||||
return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
|
||||
}
|
||||
|
||||
std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
|
||||
// clang-format off
|
||||
static const std::vector<std::pair<std::string, std::string>> values = {
|
||||
{"/odm/", kPolicyOdm},
|
||||
{"/oem/", kPolicyOem},
|
||||
{"/product/", kPolicyProduct},
|
||||
{"/system/", kPolicySystem},
|
||||
{"/system_ext/", kPolicySystem},
|
||||
{"/vendor/", kPolicyVendor},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
std::vector<std::string> fulfilled_policies = {kPolicyPublic};
|
||||
for (auto const& pair : values) {
|
||||
if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
|
||||
fulfilled_policies.emplace_back(pair.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fulfilled_policies;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result<Unit> Scan(const std::vector<std::string>& args) {
|
||||
SYSTRACE << "Scan " << args;
|
||||
std::vector<std::string> input_directories;
|
||||
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 =
|
||||
CommandLineOptions("idmap2 scan")
|
||||
.MandatoryOption("--input-directory", "directory containing overlay apks to scan",
|
||||
&input_directories)
|
||||
.OptionalFlag("--recursive", "also scan subfolders of overlay-directory", &recursive)
|
||||
.MandatoryOption("--target-package-name", "package name of target package",
|
||||
&target_package_name)
|
||||
.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)
|
||||
.OptionalOption(
|
||||
"--override-policy",
|
||||
"input: an overlayable policy this overlay fulfills "
|
||||
"(if none or supplied, the overlays will not have their policies overriden",
|
||||
&override_policies);
|
||||
const auto opts_ok = opts.Parse(args);
|
||||
if (!opts_ok) {
|
||||
return opts_ok.GetError();
|
||||
}
|
||||
|
||||
const auto apk_paths = FindApkFiles(input_directories, recursive);
|
||||
if (!apk_paths) {
|
||||
return Error(apk_paths.GetError(), "failed to find apk files");
|
||||
}
|
||||
|
||||
std::vector<InputOverlay> interesting_apks;
|
||||
for (const std::string& path : **apk_paths) {
|
||||
Result<OverlayManifestInfo> overlay_info =
|
||||
ExtractOverlayManifestInfo(path, /* assert_overlay */ false);
|
||||
if (!overlay_info) {
|
||||
return overlay_info.GetError();
|
||||
}
|
||||
|
||||
if (!overlay_info->is_static) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overlay_info->target_package.empty() ||
|
||||
overlay_info->target_package != target_package_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overlay_info->priority < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note that conditional property enablement/exclusion only applies if
|
||||
// the attribute is present. In its absence, all overlays are presumed enabled.
|
||||
if (!overlay_info->requiredSystemPropertyName.empty() &&
|
||||
!overlay_info->requiredSystemPropertyValue.empty()) {
|
||||
// if property set & equal to value, then include overlay - otherwise skip
|
||||
if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") !=
|
||||
overlay_info->requiredSystemPropertyValue) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> fulfilled_policies;
|
||||
if (!override_policies.empty()) {
|
||||
fulfilled_policies = override_policies;
|
||||
} else {
|
||||
fulfilled_policies = PoliciesForPath(path);
|
||||
}
|
||||
|
||||
bool ignore_overlayable = false;
|
||||
if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) !=
|
||||
fulfilled_policies.end() &&
|
||||
!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);
|
||||
|
||||
// Sort the static overlays in ascending priority order
|
||||
InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_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) {
|
||||
const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies);
|
||||
if (!policy_bitmask) {
|
||||
LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
|
||||
<< "\": " << policy_bitmask.GetErrorMessage();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask,
|
||||
!overlay.ignore_overlayable)) {
|
||||
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) {
|
||||
create_args.emplace_back("--policy");
|
||||
create_args.emplace_back(policy);
|
||||
}
|
||||
|
||||
const auto create_ok = Create(create_args);
|
||||
if (!create_ok) {
|
||||
LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
|
||||
<< "\": " << create_ok.GetError().GetMessage();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
stream << overlay.idmap_path << std::endl;
|
||||
}
|
||||
|
||||
std::cout << stream.str();
|
||||
|
||||
return Unit{};
|
||||
}
|
||||
@@ -17,27 +17,13 @@
|
||||
#ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
|
||||
#define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace android::idmap2::utils {
|
||||
|
||||
constexpr const char* kIdmapCacheDir = "/data/resource-cache";
|
||||
constexpr const mode_t kIdmapFilePermissionMask = 0133; // u=rw,g=r,o=r
|
||||
|
||||
typedef std::function<bool(unsigned char type /* DT_* from dirent.h */, const std::string& path)>
|
||||
FindFilesPredicate;
|
||||
std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse,
|
||||
const FindFilesPredicate& predicate);
|
||||
|
||||
std::unique_ptr<std::string> ReadFile(int fd);
|
||||
|
||||
std::unique_ptr<std::string> ReadFile(const std::string& path);
|
||||
|
||||
bool UidHasWriteAccessToPath(uid_t uid, const std::string& path);
|
||||
|
||||
} // namespace android::idmap2::utils
|
||||
|
||||
@@ -16,19 +16,7 @@
|
||||
|
||||
#include "idmap2/FileUtils.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "android-base/file.h"
|
||||
#include "android-base/macros.h"
|
||||
@@ -37,54 +25,6 @@
|
||||
|
||||
namespace android::idmap2::utils {
|
||||
|
||||
std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse,
|
||||
const FindFilesPredicate& predicate) {
|
||||
DIR* dir = opendir(root.c_str());
|
||||
if (dir == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<std::vector<std::string>> vector(new std::vector<std::string>());
|
||||
struct dirent* dirent;
|
||||
while ((dirent = readdir(dir)) != nullptr) {
|
||||
const std::string path = root + "/" + dirent->d_name;
|
||||
if (predicate(dirent->d_type, path)) {
|
||||
vector->push_back(path);
|
||||
}
|
||||
if (recurse && dirent->d_type == DT_DIR && strcmp(dirent->d_name, ".") != 0 &&
|
||||
strcmp(dirent->d_name, "..") != 0) {
|
||||
auto sub_vector = FindFiles(path, recurse, predicate);
|
||||
if (!sub_vector) {
|
||||
closedir(dir);
|
||||
return nullptr;
|
||||
}
|
||||
vector->insert(vector->end(), sub_vector->begin(), sub_vector->end());
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::string> ReadFile(const std::string& path) {
|
||||
std::unique_ptr<std::string> str(new std::string());
|
||||
std::ifstream fin(path);
|
||||
str->append({std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>()});
|
||||
fin.close();
|
||||
return str;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::string> ReadFile(int fd) {
|
||||
static constexpr const size_t kBufSize = 1024;
|
||||
|
||||
std::unique_ptr<std::string> str(new std::string());
|
||||
char buf[kBufSize];
|
||||
ssize_t r;
|
||||
while ((r = read(fd, buf, sizeof(buf))) > 0) {
|
||||
str->append(buf, r);
|
||||
}
|
||||
return r == 0 ? std::move(str) : nullptr;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) {
|
||||
// resolve symlinks and relative paths; the directories must exist
|
||||
|
||||
@@ -14,73 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "TestHelpers.h"
|
||||
#include "android-base/macros.h"
|
||||
#include "android-base/stringprintf.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "idmap2/FileUtils.h"
|
||||
#include "private/android_filesystem_config.h"
|
||||
|
||||
using ::testing::NotNull;
|
||||
|
||||
namespace android::idmap2::utils {
|
||||
|
||||
TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) {
|
||||
const auto& root = GetTestDataPath();
|
||||
auto v = utils::FindFiles(root, false,
|
||||
[](unsigned char type ATTRIBUTE_UNUSED,
|
||||
const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
|
||||
ASSERT_THAT(v, NotNull());
|
||||
ASSERT_EQ(v->size(), 7U);
|
||||
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({
|
||||
root + "/.",
|
||||
root + "/..",
|
||||
root + "/overlay",
|
||||
root + "/target",
|
||||
root + "/signature-overlay",
|
||||
root + "/system-overlay",
|
||||
root + "/system-overlay-invalid",
|
||||
}));
|
||||
}
|
||||
|
||||
TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
|
||||
const auto& root = GetTestDataPath();
|
||||
auto v = utils::FindFiles(root, true, [](unsigned char type, const std::string& path) -> bool {
|
||||
return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
|
||||
});
|
||||
ASSERT_THAT(v, NotNull());
|
||||
ASSERT_EQ(v->size(), 11U);
|
||||
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
|
||||
std::set<std::string>(
|
||||
{root + "/target/target.apk", root + "/target/target-no-overlayable.apk",
|
||||
root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk",
|
||||
root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-shared.apk",
|
||||
root + "/overlay/overlay-static-1.apk", root + "/overlay/overlay-static-2.apk",
|
||||
root + "/signature-overlay/signature-overlay.apk",
|
||||
root + "/system-overlay/system-overlay.apk",
|
||||
root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
|
||||
}
|
||||
|
||||
TEST(FileUtilsTests, ReadFile) {
|
||||
int pipefd[2];
|
||||
ASSERT_EQ(pipe2(pipefd, O_CLOEXEC), 0);
|
||||
|
||||
ASSERT_EQ(write(pipefd[1], "foobar", 6), 6);
|
||||
close(pipefd[1]);
|
||||
|
||||
auto data = ReadFile(pipefd[0]);
|
||||
ASSERT_THAT(data, NotNull());
|
||||
ASSERT_EQ(*data, "foobar");
|
||||
close(pipefd[0]);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
TEST(FileUtilsTests, UidHasWriteAccessToPath) {
|
||||
constexpr const char* tmp_path = "/data/local/tmp/test@idmap";
|
||||
|
||||
@@ -159,131 +159,6 @@ TEST_F(Idmap2BinaryTests, Dump) {
|
||||
unlink(GetIdmapPath().c_str());
|
||||
}
|
||||
|
||||
TEST_F(Idmap2BinaryTests, Scan) {
|
||||
SKIP_TEST_IF_CANT_EXEC_IDMAP2;
|
||||
|
||||
const std::string overlay_static_no_name_apk_path =
|
||||
GetTestDataPath() + "/overlay/overlay-no-name-static.apk";
|
||||
const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk";
|
||||
const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk";
|
||||
const std::string idmap_static_no_name_path =
|
||||
Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_no_name_apk_path);
|
||||
const std::string idmap_static_1_path =
|
||||
Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_1_apk_path);
|
||||
const std::string idmap_static_2_path =
|
||||
Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_2_apk_path);
|
||||
|
||||
// single input directory, recursive
|
||||
// clang-format off
|
||||
auto result = ExecuteBinary({"idmap2",
|
||||
"scan",
|
||||
"--input-directory", GetTestDataPath(),
|
||||
"--recursive",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
std::stringstream expected;
|
||||
expected << idmap_static_no_name_path << std::endl;
|
||||
expected << idmap_static_1_path << std::endl;
|
||||
expected << idmap_static_2_path << std::endl;
|
||||
ASSERT_EQ(result->stdout, expected.str());
|
||||
|
||||
auto idmap_static_no_name_raw_string = utils::ReadFile(idmap_static_no_name_path);
|
||||
auto idmap_static_no_name_raw_stream = std::istringstream(*idmap_static_no_name_raw_string);
|
||||
auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream);
|
||||
ASSERT_TRUE(idmap_static_no_name);
|
||||
ASSERT_IDMAP(**idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path);
|
||||
|
||||
auto idmap_static_1_raw_string = utils::ReadFile(idmap_static_1_path);
|
||||
auto idmap_static_1_raw_stream = std::istringstream(*idmap_static_1_raw_string);
|
||||
auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream);
|
||||
ASSERT_TRUE(idmap_static_1);
|
||||
ASSERT_IDMAP(**idmap_static_1, GetTargetApkPath(), overlay_static_1_apk_path);
|
||||
|
||||
auto idmap_static_2_raw_string = utils::ReadFile(idmap_static_2_path);
|
||||
auto idmap_static_2_raw_stream = std::istringstream(*idmap_static_2_raw_string);
|
||||
auto idmap_static_2 = Idmap::FromBinaryStream(idmap_static_2_raw_stream);
|
||||
ASSERT_TRUE(idmap_static_2);
|
||||
ASSERT_IDMAP(**idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path);
|
||||
|
||||
unlink(idmap_static_no_name_path.c_str());
|
||||
unlink(idmap_static_2_path.c_str());
|
||||
unlink(idmap_static_1_path.c_str());
|
||||
|
||||
// multiple input directories, non-recursive
|
||||
// clang-format off
|
||||
result = ExecuteBinary({"idmap2",
|
||||
"scan",
|
||||
"--input-directory", GetTestDataPath() + "/target",
|
||||
"--input-directory", GetTestDataPath() + "/overlay",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
ASSERT_EQ(result->stdout, expected.str());
|
||||
unlink(idmap_static_no_name_path.c_str());
|
||||
unlink(idmap_static_2_path.c_str());
|
||||
unlink(idmap_static_1_path.c_str());
|
||||
|
||||
// the same input directory given twice, but no duplicate entries
|
||||
// clang-format off
|
||||
result = ExecuteBinary({"idmap2",
|
||||
"scan",
|
||||
"--input-directory", GetTestDataPath(),
|
||||
"--input-directory", GetTestDataPath(),
|
||||
"--recursive",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
ASSERT_EQ(result->stdout, expected.str());
|
||||
unlink(idmap_static_no_name_path.c_str());
|
||||
unlink(idmap_static_2_path.c_str());
|
||||
unlink(idmap_static_1_path.c_str());
|
||||
|
||||
// no APKs in input-directory: ok, but no output
|
||||
// clang-format off
|
||||
result = ExecuteBinary({"idmap2",
|
||||
"scan",
|
||||
"--input-directory", GetTempDirPath(),
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
ASSERT_EQ(result->stdout, "");
|
||||
|
||||
// the signature idmap failing to generate should not cause scanning to fail
|
||||
// clang-format off
|
||||
result = ExecuteBinary({"idmap2",
|
||||
"scan",
|
||||
"--input-directory", GetTestDataPath(),
|
||||
"--recursive",
|
||||
"--target-package-name", "test.target",
|
||||
"--target-apk-path", GetTargetApkPath(),
|
||||
"--output-directory", GetTempDirPath(),
|
||||
"--override-policy", "public"});
|
||||
// clang-format on
|
||||
ASSERT_THAT(result, NotNull());
|
||||
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
|
||||
ASSERT_EQ(result->stdout, expected.str());
|
||||
unlink(idmap_static_no_name_path.c_str());
|
||||
unlink(idmap_static_2_path.c_str());
|
||||
unlink(idmap_static_1_path.c_str());
|
||||
}
|
||||
|
||||
TEST_F(Idmap2BinaryTests, Lookup) {
|
||||
SKIP_TEST_IF_CANT_EXEC_IDMAP2;
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ valgrind="valgrind --error-exitcode=1 -q --track-origins=yes --leak-check=full"
|
||||
_eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path"
|
||||
_eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path"
|
||||
_eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1"
|
||||
_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public"
|
||||
_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path"
|
||||
_eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests"
|
||||
exit $errors
|
||||
|
||||
@@ -1573,7 +1573,6 @@ public final class AssetManager implements AutoCloseable {
|
||||
private static native long nativeAssetGetLength(long assetPtr);
|
||||
private static native long nativeAssetGetRemainingLength(long assetPtr);
|
||||
|
||||
private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
|
||||
private static native @Nullable Map nativeGetOverlayableMap(long ptr,
|
||||
@NonNull String packageName);
|
||||
private static native @Nullable String nativeGetOverlayablesToString(long ptr,
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#include "androidfw/AssetManager2.h"
|
||||
#include "androidfw/AttributeResolution.h"
|
||||
#include "androidfw/MutexGuard.h"
|
||||
#include "androidfw/PosixUtils.h"
|
||||
#include "androidfw/ResourceTypes.h"
|
||||
#include "androidfw/ResourceUtils.h"
|
||||
|
||||
@@ -58,7 +57,6 @@ extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
|
||||
extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
|
||||
|
||||
using ::android::base::StringPrintf;
|
||||
using ::android::util::ExecuteBinary;
|
||||
|
||||
namespace android {
|
||||
|
||||
@@ -114,88 +112,6 @@ constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie)
|
||||
return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
|
||||
}
|
||||
|
||||
static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env,
|
||||
jclass /*clazz*/) {
|
||||
// --input-directory can be given multiple times, but idmap2 expects the directory to exist
|
||||
std::vector<std::string> input_dirs;
|
||||
struct stat st;
|
||||
if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
|
||||
input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR);
|
||||
}
|
||||
|
||||
if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
|
||||
input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
|
||||
}
|
||||
|
||||
if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) {
|
||||
input_dirs.push_back(AssetManager::SYSTEM_EXT_OVERLAY_DIR);
|
||||
}
|
||||
|
||||
if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
|
||||
input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR);
|
||||
}
|
||||
|
||||
if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) {
|
||||
input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR);
|
||||
}
|
||||
|
||||
if (input_dirs.empty()) {
|
||||
LOG(WARNING) << "no directories for idmap2 to scan";
|
||||
return env->NewObjectArray(0, g_stringClass, nullptr);
|
||||
}
|
||||
|
||||
if (access("/system/bin/idmap2", X_OK) == -1) {
|
||||
PLOG(WARNING) << "unable to execute idmap2";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> argv{"/system/bin/idmap2",
|
||||
"scan",
|
||||
"--recursive",
|
||||
"--target-package-name", "android",
|
||||
"--target-apk-path", "/system/framework/framework-res.apk",
|
||||
"--output-directory", "/data/resource-cache"};
|
||||
|
||||
for (const auto& dir : input_dirs) {
|
||||
argv.push_back("--input-directory");
|
||||
argv.push_back(dir);
|
||||
}
|
||||
|
||||
const auto result = ExecuteBinary(argv);
|
||||
|
||||
if (!result) {
|
||||
LOG(ERROR) << "failed to execute idmap2";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (result->status != 0) {
|
||||
LOG(ERROR) << "idmap2: " << result->stderr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> idmap_paths;
|
||||
std::istringstream input(result->stdout);
|
||||
std::string path;
|
||||
while (std::getline(input, path)) {
|
||||
idmap_paths.push_back(path);
|
||||
}
|
||||
|
||||
jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr);
|
||||
if (array == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < idmap_paths.size(); i++) {
|
||||
const std::string path = idmap_paths[i];
|
||||
jstring java_string = env->NewStringUTF(path.c_str());
|
||||
if (env->ExceptionCheck()) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetObjectArrayElement(array, i, java_string);
|
||||
env->DeleteLocalRef(java_string);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
|
||||
uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
|
||||
env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
|
||||
@@ -1563,8 +1479,6 @@ static const JNINativeMethod gAssetManagerMethods[] = {
|
||||
{"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
|
||||
|
||||
// System/idmap related methods.
|
||||
{"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
|
||||
(void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
|
||||
{"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
|
||||
(void*)NativeGetOverlayableMap},
|
||||
{"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
|
||||
|
||||
Reference in New Issue
Block a user