| /* | |
| * 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. | |
| */ | |
| /* | |
| * The tests in this file operate on a higher level than the tests in the other | |
| * files. Here, all tests execute the idmap2 binary and only depend on | |
| * libidmap2 to verify the output of idmap2. | |
| */ | |
| #include <fcntl.h> | |
| #include <sys/stat.h> | |
| #include <sys/types.h> | |
| #include <sys/wait.h> | |
| #include <unistd.h> | |
| #include <cerrno> | |
| #include <cstdlib> | |
| #include <cstring> // strerror | |
| #include <fstream> | |
| #include <memory> | |
| #include <sstream> | |
| #include <string> | |
| #include <vector> | |
| #include "R.h" | |
| #include "TestConstants.h" | |
| #include "TestHelpers.h" | |
| #include "androidfw/PosixUtils.h" | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| #include "idmap2/FileUtils.h" | |
| #include "idmap2/Idmap.h" | |
| #include "private/android_filesystem_config.h" | |
| using ::android::base::StringPrintf; | |
| using ::android::util::ExecuteBinary; | |
| namespace android::idmap2 { | |
| class Idmap2BinaryTests : public Idmap2Tests {}; | |
| namespace { | |
| void AssertIdmap(const Idmap& idmap, const std::string& target_apk_path, | |
| const std::string& overlay_apk_path) { | |
| // check that the idmap file looks reasonable (IdmapTests is responsible for | |
| // more in-depth verification) | |
| ASSERT_EQ(idmap.GetHeader()->GetMagic(), kIdmapMagic); | |
| ASSERT_EQ(idmap.GetHeader()->GetVersion(), kIdmapCurrentVersion); | |
| ASSERT_EQ(idmap.GetHeader()->GetTargetPath(), target_apk_path); | |
| ASSERT_EQ(idmap.GetHeader()->GetOverlayPath(), overlay_apk_path); | |
| ASSERT_EQ(idmap.GetData().size(), 1U); | |
| } | |
| #define ASSERT_IDMAP(idmap_ref, target_apk_path, overlay_apk_path) \ | |
| do { \ | |
| ASSERT_NO_FATAL_FAILURE(AssertIdmap(idmap_ref, target_apk_path, overlay_apk_path)); \ | |
| } while (0) | |
| #ifdef __ANDROID__ | |
| #define SKIP_TEST_IF_CANT_EXEC_IDMAP2 \ | |
| do { \ | |
| const uid_t uid = getuid(); \ | |
| if (uid != AID_ROOT && uid != AID_SYSTEM) { \ | |
| GTEST_SKIP(); \ | |
| } \ | |
| } while (0) | |
| #else | |
| #define SKIP_TEST_IF_CANT_EXEC_IDMAP2 | |
| #endif | |
| } // namespace | |
| TEST_F(Idmap2BinaryTests, Create) { | |
| SKIP_TEST_IF_CANT_EXEC_IDMAP2; | |
| // clang-format off | |
| auto result = ExecuteBinary({"idmap2", | |
| "create", | |
| "--target-apk-path", GetTargetApkPath(), | |
| "--overlay-apk-path", GetOverlayApkPath(), | |
| "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT, | |
| "--idmap-path", GetIdmapPath()}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| struct stat st; | |
| ASSERT_EQ(stat(GetIdmapPath().c_str(), &st), 0); | |
| std::ifstream fin(GetIdmapPath()); | |
| const auto idmap = Idmap::FromBinaryStream(fin); | |
| fin.close(); | |
| ASSERT_TRUE(idmap); | |
| ASSERT_EQ((*idmap)->GetConstraints()->constraints.size(), 0); | |
| ASSERT_IDMAP(**idmap, GetTargetApkPath(), GetOverlayApkPath()); | |
| unlink(GetIdmapPath().c_str()); | |
| } | |
| TEST_F(Idmap2BinaryTests, Dump) { | |
| SKIP_TEST_IF_CANT_EXEC_IDMAP2; | |
| // clang-format off | |
| auto result = ExecuteBinary({"idmap2", | |
| "create", | |
| "--target-apk-path", GetTargetApkPath(), | |
| "--overlay-apk-path", GetOverlayApkPath(), | |
| "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT, | |
| "--idmap-path", GetIdmapPath()}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "dump", | |
| "--idmap-path", GetIdmapPath()}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1, | |
| R::overlay::integer::int1)), | |
| std::string::npos) | |
| << result.stdout_str; | |
| ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1, | |
| R::overlay::string::str1)), | |
| std::string::npos) | |
| << result.stdout_str; | |
| ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3, | |
| R::overlay::string::str3)), | |
| std::string::npos) | |
| << result.stdout_str; | |
| ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4, | |
| R::overlay::string::str4)), | |
| std::string::npos) | |
| << result.stdout_str; | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "dump", | |
| "--verbose", | |
| "--idmap-path", GetIdmapPath()}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| ASSERT_NE(result.stdout_str.find("00000000: 504d4449 magic"), std::string::npos); | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "dump", | |
| "--verbose", | |
| "--idmap-path", GetTestDataPath() + "/DOES-NOT-EXIST"}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_NE(result.status, EXIT_SUCCESS); | |
| unlink(GetIdmapPath().c_str()); | |
| } | |
| TEST_F(Idmap2BinaryTests, Lookup) { | |
| SKIP_TEST_IF_CANT_EXEC_IDMAP2; | |
| // clang-format off | |
| auto result = ExecuteBinary({"idmap2", | |
| "create", | |
| "--target-apk-path", GetTargetApkPath(), | |
| "--overlay-apk-path", GetOverlayApkPath(), | |
| "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT, | |
| "--idmap-path", GetIdmapPath()}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "lookup", | |
| "--idmap-path", GetIdmapPath(), | |
| "--config", "", | |
| "--resid", StringPrintf("0x%08x", R::target::string::str1)}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| ASSERT_NE(result.stdout_str.find("overlay-1"), std::string::npos); | |
| ASSERT_EQ(result.stdout_str.find("overlay-1-sv"), std::string::npos); | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "lookup", | |
| "--idmap-path", GetIdmapPath(), | |
| "--config", "", | |
| "--resid", "test.target:string/str1"}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| ASSERT_NE(result.stdout_str.find("overlay-1"), std::string::npos); | |
| ASSERT_EQ(result.stdout_str.find("overlay-1-sv"), std::string::npos); | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "lookup", | |
| "--idmap-path", GetIdmapPath(), | |
| "--config", "sv", | |
| "--resid", "test.target:string/str1"}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str; | |
| ASSERT_NE(result.stdout_str.find("overlay-1-sv"), std::string::npos); | |
| unlink(GetIdmapPath().c_str()); | |
| } | |
| TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) { | |
| SKIP_TEST_IF_CANT_EXEC_IDMAP2; | |
| const std::string invalid_target_apk_path = GetTestDataPath() + "/DOES-NOT-EXIST"; | |
| // missing mandatory options | |
| // clang-format off | |
| auto result = ExecuteBinary({"idmap2", | |
| "create"}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_NE(result.status, EXIT_SUCCESS); | |
| // missing argument to option | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "create", | |
| "--target-apk-path", GetTargetApkPath(), | |
| "--overlay-apk-path", GetOverlayApkPath(), | |
| "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT, | |
| "--idmap-path"}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_NE(result.status, EXIT_SUCCESS); | |
| // invalid target apk path | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "create", | |
| "--target-apk-path", invalid_target_apk_path, | |
| "--overlay-apk-path", GetOverlayApkPath(), | |
| "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT, | |
| "--idmap-path", GetIdmapPath()}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_NE(result.status, EXIT_SUCCESS); | |
| // unknown policy | |
| // clang-format off | |
| result = ExecuteBinary({"idmap2", | |
| "create", | |
| "--target-apk-path", GetTargetApkPath(), | |
| "--overlay-apk-path", GetOverlayApkPath(), | |
| "--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT, | |
| "--idmap-path", GetIdmapPath(), | |
| "--policy", "this-does-not-exist"}); | |
| // clang-format on | |
| ASSERT_TRUE((bool)result); | |
| ASSERT_NE(result.status, EXIT_SUCCESS); | |
| } | |
| } // namespace android::idmap2 |