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