Home | History | Annotate | Download | only in imgdiag
      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