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 class ImgDiagTest : public CommonRuntimeTest { 40 protected: 41 virtual void SetUp() { 42 CommonRuntimeTest::SetUp(); 43 44 // We loaded the runtime with an explicit image. Therefore the image space must exist. 45 gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace(); 46 ASSERT_TRUE(image_space != nullptr); 47 boot_image_location_ = image_space->GetImageLocation(); 48 } 49 50 virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE { 51 // Needs to live until CommonRuntimeTest::SetUp finishes, since we pass it a cstring. 52 runtime_args_image_ = StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str()); 53 options->push_back(std::make_pair(runtime_args_image_, nullptr)); 54 } 55 56 // Path to the imgdiag(d?)[32|64] binary. 57 std::string GetImgDiagFilePath() { 58 std::string root = GetTestAndroidRoot(); 59 60 root += "/bin/"; 61 root += kImgDiagBinaryName; 62 63 if (kIsDebugBuild) { 64 root += "d"; 65 } 66 67 std::string root32 = root + "32"; 68 // If we have both a 32-bit and a 64-bit build, the 32-bit file will have a 32 suffix. 69 if (OS::FileExists(root32.c_str()) && !Is64BitInstructionSet(kRuntimeISA)) { 70 return root32; 71 // Only a single build exists, so the filename never has an extra suffix. 72 } else { 73 return root; 74 } 75 } 76 77 // Run imgdiag with a custom boot image location. 78 bool Exec(pid_t image_diff_pid, const std::string& boot_image, std::string* error_msg) { 79 // Invoke 'img_diag' against the current process. 80 // This should succeed because we have a runtime and so it should 81 // be able to map in the boot.art and do a diff for it. 82 std::string file_path = GetImgDiagFilePath(); 83 EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path"; 84 85 // Run imgdiag --image-diff-pid=$image_diff_pid and wait until it's done with a 0 exit code. 86 std::string diff_pid_args; 87 { 88 std::stringstream diff_pid_args_ss; 89 diff_pid_args_ss << kImgDiagDiffPid << "=" << image_diff_pid; 90 diff_pid_args = diff_pid_args_ss.str(); 91 } 92 std::string boot_image_args; 93 { 94 boot_image_args = boot_image_args + kImgDiagBootImage + "=" + boot_image; 95 } 96 97 std::vector<std::string> exec_argv = { file_path, diff_pid_args, boot_image_args }; 98 99 return ::art::Exec(exec_argv, error_msg); 100 } 101 102 // Run imgdiag with the default boot image location. 103 bool ExecDefaultBootImage(pid_t image_diff_pid, std::string* error_msg) { 104 return Exec(image_diff_pid, boot_image_location_, error_msg); 105 } 106 107 private: 108 std::string runtime_args_image_; 109 std::string boot_image_location_; 110 }; 111 112 #if defined (ART_TARGET) 113 TEST_F(ImgDiagTest, ImageDiffPidSelf) { 114 #else 115 // Can't run this test on the host, it will fail when trying to open /proc/kpagestats 116 // because it's root read-only. 117 TEST_F(ImgDiagTest, DISABLED_ImageDiffPidSelf) { 118 #endif 119 // Invoke 'img_diag' against the current process. 120 // This should succeed because we have a runtime and so it should 121 // be able to map in the boot.art and do a diff for it. 122 123 // Run imgdiag --image-diff-pid=$(self pid) and wait until it's done with a 0 exit code. 124 std::string error_msg; 125 ASSERT_TRUE(ExecDefaultBootImage(getpid(), &error_msg)) << "Failed to execute -- because: " 126 << error_msg; 127 } 128 129 TEST_F(ImgDiagTest, ImageDiffBadPid) { 130 // Invoke 'img_diag' against a non-existing process. This should fail. 131 132 // Run imgdiag --image-diff-pid=some_bad_pid and wait until it's done with a 0 exit code. 133 std::string error_msg; 134 ASSERT_FALSE(ExecDefaultBootImage(-12345, &error_msg)) << "Incorrectly executed"; 135 UNUSED(error_msg); 136 } 137 138 } // namespace art 139