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 <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