| /* |
| * 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_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 |