1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <string> 18 #include <vector> 19 #include <sstream> 20 21 #include "common_runtime_test.h" 22 23 #include "runtime/os.h" 24 #include "runtime/arch/instruction_set.h" 25 #include "runtime/utils.h" 26 #include "runtime/gc/space/image_space.h" 27 #include "runtime/gc/heap.h" 28 #include "base/stringprintf.h" 29 30 #include <sys/types.h> 31 #include <unistd.h> 32 33 namespace art { 34 35 static const char* kImgDiagDiffPid = "--image-diff-pid"; 36 static const char* kImgDiagBootImage = "--boot-image"; 37 static const char* kImgDiagBinaryName = "imgdiag"; 38 39 static const char* kImgDiagZygoteDiffPid = "--zygote-diff-pid"; 40 41 // from kernel <include/linux/threads.h> 42 #define PID_MAX_LIMIT (4*1024*1024) // Upper bound. Most kernel configs will have smaller max pid. 43 44 static const pid_t kImgDiagGuaranteedBadPid = (PID_MAX_LIMIT + 1); 45 46 class ImgDiagTest : public CommonRuntimeTest { 47 protected: 48 virtual void SetUp() { 49 CommonRuntimeTest::SetUp(); 50 51 // We loaded the runtime with an explicit image. Therefore the image space must exist. 52 std::vector<gc::space::ImageSpace*> image_spaces = 53 Runtime::Current()->GetHeap()->GetBootImageSpaces(); 54 ASSERT_TRUE(!image_spaces.empty()); 55 boot_image_location_ = image_spaces[0]->GetImageLocation(); 56 } 57 58 virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE { 59 // Needs to live until CommonRuntimeTest::SetUp finishes, since we pass it a cstring. 60 runtime_args_image_ = StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str()); 61 options->push_back(std::make_pair(runtime_args_image_, nullptr)); 62 } 63 64 // Path to the imgdiag(d?)[32|64] binary. 65 std::string GetImgDiagFilePath() { 66 std::string root = GetTestAndroidRoot(); 67 68 root += "/bin/"; 69 root += kImgDiagBinaryName; 70 71 if (kIsDebugBuild) { 72 root += "d"; 73 } 74 75 std::string root32 = root + "32"; 76 // If we have both a 32-bit and a 64-bit build, the 32-bit file will have a 32 suffix. 77 if (OS::FileExists(root32.c_str()) && !Is64BitInstructionSet(kRuntimeISA)) { 78 return root32; 79 // Only a single build exists, so the filename never has an extra suffix. 80 } else { 81 return root; 82 } 83 } 84 85 // Run imgdiag with a custom boot image location. 86 bool Exec(pid_t image_diff_pid, const std::string& boot_image, std::string* error_msg) { 87 // Invoke 'img_diag' against the current process. 88 // This should succeed because we have a runtime and so it should 89 // be able to map in the boot.art and do a diff for it. 90 std::string file_path = GetImgDiagFilePath(); 91 EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path"; 92 93 // Run imgdiag --image-diff-pid=$image_diff_pid and wait until it's done with a 0 exit code. 94 std::string diff_pid_args; 95 std::string zygote_diff_pid_args; 96 { 97 std::stringstream diff_pid_args_ss; 98 diff_pid_args_ss << kImgDiagDiffPid << "=" << image_diff_pid; 99 diff_pid_args = diff_pid_args_ss.str(); 100 } 101 { 102 std::stringstream zygote_pid_args_ss; 103 zygote_pid_args_ss << kImgDiagZygoteDiffPid << "=" << image_diff_pid; 104 zygote_diff_pid_args = zygote_pid_args_ss.str(); 105 } 106 std::string boot_image_args = std::string(kImgDiagBootImage) + "=" + boot_image; 107 108 std::vector<std::string> exec_argv = { 109 file_path, 110 diff_pid_args, 111 zygote_diff_pid_args, 112 boot_image_args 113 }; 114 115 return ::art::Exec(exec_argv, error_msg); 116 } 117 118 // Run imgdiag with the default boot image location. 119 bool ExecDefaultBootImage(pid_t image_diff_pid, std::string* error_msg) { 120 return Exec(image_diff_pid, boot_image_location_, error_msg); 121 } 122 123 private: 124 std::string runtime_args_image_; 125 std::string boot_image_location_; 126 }; 127 128 #if defined (ART_TARGET) && !defined(__mips__) 129 TEST_F(ImgDiagTest, ImageDiffPidSelf) { 130 #else 131 // Can't run this test on the host, it will fail when trying to open /proc/kpagestats 132 // because it's root read-only. 133 // Also test fails on mips. b/24596015. 134 TEST_F(ImgDiagTest, DISABLED_ImageDiffPidSelf) { 135 #endif 136 // Invoke 'img_diag' against the current process. 137 // This should succeed because we have a runtime and so it should 138 // be able to map in the boot.art and do a diff for it. 139 140 // Run imgdiag --image-diff-pid=$(self pid) and wait until it's done with a 0 exit code. 141 std::string error_msg; 142 ASSERT_TRUE(ExecDefaultBootImage(getpid(), &error_msg)) << "Failed to execute -- because: " 143 << error_msg; 144 } 145 146 TEST_F(ImgDiagTest, ImageDiffBadPid) { 147 // Invoke 'img_diag' against a non-existing process. This should fail. 148 149 // Run imgdiag --image-diff-pid=some_bad_pid and wait until it's done with a 0 exit code. 150 std::string error_msg; 151 ASSERT_FALSE(ExecDefaultBootImage(kImgDiagGuaranteedBadPid, 152 &error_msg)) << "Incorrectly executed"; 153 UNUSED(error_msg); 154 } 155 156 } // namespace art 157