summaryrefslogtreecommitdiffstats
path: root/imgdiag/imgdiag_test.cc
blob: 1ac79304df7528a64d373c94e9e505c8d7941486 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>
#include <vector>
#include <sstream>

#include "common_runtime_test.h"

#include "runtime/os.h"
#include "runtime/arch/instruction_set.h"
#include "runtime/utils.h"
#include "runtime/gc/space/image_space.h"
#include "runtime/gc/heap.h"
#include "base/stringprintf.h"

#include <sys/types.h>
#include <unistd.h>

namespace art {

static const char* kImgDiagDiffPid = "--image-diff-pid";
static const char* kImgDiagBootImage = "--boot-image";
static const char* kImgDiagBinaryName = "imgdiag";

class ImgDiagTest : public CommonRuntimeTest {
 protected:
  virtual void SetUp() {
    CommonRuntimeTest::SetUp();

    // We loaded the runtime with an explicit image. Therefore the image space must exist.
    gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
    ASSERT_TRUE(image_space != nullptr);
    boot_image_location_ = image_space->GetImageLocation();
  }

  virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
    // Needs to live until CommonRuntimeTest::SetUp finishes, since we pass it a cstring.
    runtime_args_image_ = StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str());
    options->push_back(std::make_pair(runtime_args_image_, nullptr));
  }

  // Path to the imgdiag(d?)[32|64] binary.
  std::string GetImgDiagFilePath() {
    std::string root = GetTestAndroidRoot();

    root += "/bin/";
    root += kImgDiagBinaryName;

    if (kIsDebugBuild) {
      root += "d";
    }

    std::string root32 = root + "32";
    // If we have both a 32-bit and a 64-bit build, the 32-bit file will have a 32 suffix.
    if (OS::FileExists(root32.c_str()) && !Is64BitInstructionSet(kRuntimeISA)) {
      return root32;
    // Only a single build exists, so the filename never has an extra suffix.
    } else {
      return root;
    }
  }

  // Run imgdiag with a custom boot image location.
  bool Exec(pid_t image_diff_pid, const std::string& boot_image, std::string* error_msg) {
    // Invoke 'img_diag' against the current process.
    // This should succeed because we have a runtime and so it should
    // be able to map in the boot.art and do a diff for it.
    std::string file_path = GetImgDiagFilePath();
    EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";

    // Run imgdiag --image-diff-pid=$image_diff_pid and wait until it's done with a 0 exit code.
    std::string diff_pid_args;
    {
      std::stringstream diff_pid_args_ss;
      diff_pid_args_ss << kImgDiagDiffPid << "=" << image_diff_pid;
      diff_pid_args = diff_pid_args_ss.str();
    }
    std::string boot_image_args;
    {
      boot_image_args = boot_image_args + kImgDiagBootImage + "=" + boot_image;
    }

    std::vector<std::string> exec_argv = { file_path, diff_pid_args, boot_image_args };

    return ::art::Exec(exec_argv, error_msg);
  }

  // Run imgdiag with the default boot image location.
  bool ExecDefaultBootImage(pid_t image_diff_pid, std::string* error_msg) {
    return Exec(image_diff_pid, boot_image_location_, error_msg);
  }

 private:
  std::string runtime_args_image_;
  std::string boot_image_location_;
};

#if defined (ART_TARGET)
TEST_F(ImgDiagTest, ImageDiffPidSelf) {
#else
// Can't run this test on the host, it will fail when trying to open /proc/kpagestats
// because it's root read-only.
TEST_F(ImgDiagTest, DISABLED_ImageDiffPidSelf) {
#endif
  // Invoke 'img_diag' against the current process.
  // This should succeed because we have a runtime and so it should
  // be able to map in the boot.art and do a diff for it.

  // Run imgdiag --image-diff-pid=$(self pid) and wait until it's done with a 0 exit code.
  std::string error_msg;
  ASSERT_TRUE(ExecDefaultBootImage(getpid(), &error_msg)) << "Failed to execute -- because: "
                                                          << error_msg;
}

TEST_F(ImgDiagTest, ImageDiffBadPid) {
  // Invoke 'img_diag' against a non-existing process. This should fail.

  // Run imgdiag --image-diff-pid=some_bad_pid and wait until it's done with a 0 exit code.
  std::string error_msg;
  ASSERT_FALSE(ExecDefaultBootImage(-12345, &error_msg)) << "Incorrectly executed";
  UNUSED(error_msg);
}

}  // namespace art