Home | History | Annotate | Download | only in oatdump
      1 /*
      2  * Copyright (C) 2015 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 #ifndef ART_OATDUMP_OATDUMP_TEST_H_
     18 #define ART_OATDUMP_OATDUMP_TEST_H_
     19 
     20 #include <sstream>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include "android-base/strings.h"
     25 
     26 #include "arch/instruction_set.h"
     27 #include "base/file_utils.h"
     28 #include "base/os.h"
     29 #include "base/unix_file/fd_file.h"
     30 #include "base/utils.h"
     31 #include "common_runtime_test.h"
     32 #include "exec_utils.h"
     33 #include "gc/heap.h"
     34 #include "gc/space/image_space.h"
     35 
     36 #include <sys/types.h>
     37 #include <unistd.h>
     38 
     39 namespace art {
     40 
     41 class OatDumpTest : public CommonRuntimeTest {
     42  protected:
     43   virtual void SetUp() {
     44     CommonRuntimeTest::SetUp();
     45     core_art_location_ = GetCoreArtLocation();
     46     core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
     47     tmp_dir_ = GetScratchDir();
     48   }
     49 
     50   virtual void TearDown() {
     51     ClearDirectory(tmp_dir_.c_str(), /*recursive*/ false);
     52     ASSERT_EQ(rmdir(tmp_dir_.c_str()), 0);
     53     CommonRuntimeTest::TearDown();
     54   }
     55 
     56   std::string GetScratchDir() {
     57     // ANDROID_DATA needs to be set
     58     CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA"));
     59     std::string dir = getenv("ANDROID_DATA");
     60     dir += "/oatdump-tmp-dir-XXXXXX";
     61     if (mkdtemp(&dir[0]) == nullptr) {
     62       PLOG(FATAL) << "mkdtemp(\"" << &dir[0] << "\") failed";
     63     }
     64     return dir;
     65   }
     66 
     67   // Linking flavor.
     68   enum Flavor {
     69     kDynamic,  // oatdump(d), dex2oat(d)
     70     kStatic,   // oatdump(d)s, dex2oat(d)s
     71   };
     72 
     73   // Returns path to the oatdump/dex2oat/dexdump binary.
     74   std::string GetExecutableFilePath(const char* name, bool is_debug, bool is_static) {
     75     std::string root = GetTestAndroidRoot();
     76     root += "/bin/";
     77     root += name;
     78     if (is_debug) {
     79       root += "d";
     80     }
     81     if (is_static) {
     82       root += "s";
     83     }
     84     return root;
     85   }
     86 
     87   std::string GetExecutableFilePath(Flavor flavor, const char* name) {
     88     return GetExecutableFilePath(name, kIsDebugBuild, flavor == kStatic);
     89   }
     90 
     91   enum Mode {
     92     kModeOat,
     93     kModeOatWithBootImage,
     94     kModeArt,
     95     kModeSymbolize,
     96   };
     97 
     98   // Display style.
     99   enum Display {
    100     kListOnly,
    101     kListAndCode
    102   };
    103 
    104   std::string GetAppBaseName() {
    105     // Use ProfileTestMultiDex as it contains references to boot image strings
    106     // that shall use different code for PIC and non-PIC.
    107     return "ProfileTestMultiDex";
    108   }
    109 
    110   std::string GetAppOdexName() {
    111     return tmp_dir_ + "/" + GetAppBaseName() + ".odex";
    112   }
    113 
    114   bool GenerateAppOdexFile(Flavor flavor,
    115                            const std::vector<std::string>& args,
    116                            /*out*/ std::string* error_msg) {
    117     std::string dex2oat_path = GetExecutableFilePath(flavor, "dex2oat");
    118     std::vector<std::string> exec_argv = {
    119         dex2oat_path,
    120         "--runtime-arg",
    121         "-Xms64m",
    122         "--runtime-arg",
    123         "-Xmx512m",
    124         "--runtime-arg",
    125         "-Xnorelocate",
    126         "--boot-image=" + GetCoreArtLocation(),
    127         "--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)),
    128         "--dex-file=" + GetTestDexFileName(GetAppBaseName().c_str()),
    129         "--oat-file=" + GetAppOdexName(),
    130         "--compiler-filter=speed"
    131     };
    132     exec_argv.insert(exec_argv.end(), args.begin(), args.end());
    133 
    134     return ForkAndExecAndWait(exec_argv, error_msg);
    135   }
    136 
    137   // Run the test with custom arguments.
    138   bool Exec(Flavor flavor,
    139             Mode mode,
    140             const std::vector<std::string>& args,
    141             Display display,
    142             /*out*/ std::string* error_msg) {
    143     std::string file_path = GetExecutableFilePath(flavor, "oatdump");
    144 
    145     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
    146 
    147     // ScratchFile scratch;
    148     std::vector<std::string> exec_argv = { file_path };
    149     std::vector<std::string> expected_prefixes;
    150     if (mode == kModeSymbolize) {
    151       exec_argv.push_back("--symbolize=" + core_oat_location_);
    152       exec_argv.push_back("--output=" + core_oat_location_ + ".symbolize");
    153     } else {
    154       expected_prefixes.push_back("Dex file data for");
    155       expected_prefixes.push_back("Num string ids:");
    156       expected_prefixes.push_back("Num field ids:");
    157       expected_prefixes.push_back("Num method ids:");
    158       expected_prefixes.push_back("LOCATION:");
    159       expected_prefixes.push_back("MAGIC:");
    160       expected_prefixes.push_back("DEX FILE COUNT:");
    161       if (display == kListAndCode) {
    162         // Code and dex code do not show up if list only.
    163         expected_prefixes.push_back("DEX CODE:");
    164         expected_prefixes.push_back("CODE:");
    165         expected_prefixes.push_back("CodeInfoEncoding");
    166         expected_prefixes.push_back("CodeInfoInlineInfo");
    167       }
    168       if (mode == kModeArt) {
    169         exec_argv.push_back("--image=" + core_art_location_);
    170         exec_argv.push_back("--instruction-set=" + std::string(
    171             GetInstructionSetString(kRuntimeISA)));
    172         expected_prefixes.push_back("IMAGE LOCATION:");
    173         expected_prefixes.push_back("IMAGE BEGIN:");
    174         expected_prefixes.push_back("kDexCaches:");
    175       } else if (mode == kModeOatWithBootImage) {
    176         exec_argv.push_back("--boot-image=" + GetCoreArtLocation());
    177         exec_argv.push_back("--instruction-set=" + std::string(
    178             GetInstructionSetString(kRuntimeISA)));
    179         exec_argv.push_back("--oat-file=" + GetAppOdexName());
    180       } else {
    181         CHECK_EQ(static_cast<size_t>(mode), static_cast<size_t>(kModeOat));
    182         exec_argv.push_back("--oat-file=" + core_oat_location_);
    183       }
    184     }
    185     exec_argv.insert(exec_argv.end(), args.begin(), args.end());
    186 
    187     pid_t pid;
    188     int pipe_fd;
    189     bool result = ForkAndExec(exec_argv, &pid, &pipe_fd, error_msg);
    190     if (result) {
    191       static const size_t kLineMax = 256;
    192       char line[kLineMax] = {};
    193       size_t line_len = 0;
    194       size_t total = 0;
    195       std::vector<bool> found(expected_prefixes.size(), false);
    196       while (true) {
    197         while (true) {
    198           size_t spaces = 0;
    199           // Trim spaces at the start of the line.
    200           for (; spaces < line_len && isspace(line[spaces]); ++spaces) {}
    201           if (spaces > 0) {
    202             line_len -= spaces;
    203             memmove(&line[0], &line[spaces], line_len);
    204           }
    205           ssize_t bytes_read =
    206               TEMP_FAILURE_RETRY(read(pipe_fd, &line[line_len], kLineMax - line_len));
    207           if (bytes_read <= 0) {
    208             break;
    209           }
    210           line_len += bytes_read;
    211           total += bytes_read;
    212         }
    213         if (line_len == 0) {
    214           break;
    215         }
    216         // Check contents.
    217         for (size_t i = 0; i < expected_prefixes.size(); ++i) {
    218           const std::string& expected = expected_prefixes[i];
    219           if (!found[i] &&
    220               line_len >= expected.length() &&
    221               memcmp(line, expected.c_str(), expected.length()) == 0) {
    222             found[i] = true;
    223           }
    224         }
    225         // Skip to next line.
    226         size_t next_line = 0;
    227         for (; next_line + 1 < line_len && line[next_line] != '\n'; ++next_line) {}
    228         line_len -= next_line + 1;
    229         memmove(&line[0], &line[next_line + 1], line_len);
    230       }
    231       if (mode == kModeSymbolize) {
    232         EXPECT_EQ(total, 0u);
    233       } else {
    234         EXPECT_GT(total, 0u);
    235       }
    236       LOG(INFO) << "Processed bytes " << total;
    237       close(pipe_fd);
    238       int status = 0;
    239       if (waitpid(pid, &status, 0) != -1) {
    240         result = (status == 0);
    241       }
    242 
    243       for (size_t i = 0; i < expected_prefixes.size(); ++i) {
    244         if (!found[i]) {
    245           LOG(ERROR) << "Did not find prefix " << expected_prefixes[i];
    246           result = false;
    247         }
    248       }
    249     }
    250 
    251     return result;
    252   }
    253 
    254   bool ForkAndExec(const std::vector<std::string>& exec_argv,
    255                    /*out*/ pid_t* pid,
    256                    /*out*/ int* pipe_fd,
    257                    /*out*/ std::string* error_msg) {
    258     int link[2];
    259     if (pipe(link) == -1) {
    260       *error_msg = strerror(errno);
    261       return false;
    262     }
    263 
    264     *pid = fork();
    265     if (*pid == -1) {
    266       *error_msg = strerror(errno);
    267       close(link[0]);
    268       close(link[1]);
    269       return false;
    270     }
    271 
    272     if (*pid == 0) {
    273       dup2(link[1], STDOUT_FILENO);
    274       close(link[0]);
    275       close(link[1]);
    276       // change process groups, so we don't get reaped by ProcessManager
    277       setpgid(0, 0);
    278       // Use execv here rather than art::Exec to avoid blocking on waitpid here.
    279       std::vector<char*> argv;
    280       for (size_t i = 0; i < exec_argv.size(); ++i) {
    281         argv.push_back(const_cast<char*>(exec_argv[i].c_str()));
    282       }
    283       argv.push_back(nullptr);
    284       UNUSED(execv(argv[0], &argv[0]));
    285       const std::string command_line(android::base::Join(exec_argv, ' '));
    286       PLOG(ERROR) << "Failed to execv(" << command_line << ")";
    287       // _exit to avoid atexit handlers in child.
    288       _exit(1);
    289       UNREACHABLE();
    290     } else {
    291       close(link[1]);
    292       *pipe_fd = link[0];
    293       return true;
    294     }
    295   }
    296 
    297   bool ForkAndExecAndWait(const std::vector<std::string>& exec_argv,
    298                           /*out*/ std::string* error_msg) {
    299     pid_t pid;
    300     int pipe_fd;
    301     bool result = ForkAndExec(exec_argv, &pid, &pipe_fd, error_msg);
    302     if (result) {
    303       close(pipe_fd);
    304       int status = 0;
    305       if (waitpid(pid, &status, 0) != -1) {
    306         result = (status == 0);
    307       }
    308     }
    309     return result;
    310   }
    311 
    312   std::string tmp_dir_;
    313 
    314  private:
    315   std::string core_art_location_;
    316   std::string core_oat_location_;
    317 };
    318 
    319 }  // namespace art
    320 
    321 #endif  // ART_OATDUMP_OATDUMP_TEST_H_
    322