summaryrefslogtreecommitdiff
path: root/patchoat/patchoat.cc
diff options
context:
space:
mode:
Diffstat (limited to 'patchoat/patchoat.cc')
-rw-r--r--patchoat/patchoat.cc159
1 files changed, 142 insertions, 17 deletions
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index b7ce02c50a..5240011901 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -31,6 +31,7 @@
#include "base/stringpiece.h"
#include "base/stringprintf.h"
#include "base/unix_file/fd_file.h"
+#include "base/unix_file/random_access_file_utils.h"
#include "elf_utils.h"
#include "elf_file.h"
#include "elf_file_impl.h"
@@ -151,6 +152,28 @@ static bool FinishFile(File* file, bool close) {
}
}
+static bool SymlinkFile(const std::string& input_filename, const std::string& output_filename) {
+ if (input_filename == output_filename) {
+ // Input and output are the same, nothing to do.
+ return true;
+ }
+
+ // Unlink the original filename, since we are overwriting it.
+ unlink(output_filename.c_str());
+
+ // Create a symlink from the source file to the target path.
+ if (symlink(input_filename.c_str(), output_filename.c_str()) < 0) {
+ PLOG(ERROR) << "Failed to create symlink " << output_filename << " -> " << input_filename;
+ return false;
+ }
+
+ if (kIsDebugBuild) {
+ LOG(INFO) << "Created symlink " << output_filename << " -> " << input_filename;
+ }
+
+ return true;
+}
+
bool PatchOat::Patch(const std::string& image_location,
off_t delta,
const std::string& output_directory,
@@ -230,9 +253,13 @@ bool PatchOat::Patch(const std::string& image_location,
space_to_memmap_map.emplace(space, std::move(image));
}
+ // Do a first pass over the image spaces. Symlink PIC oat and vdex files, and
+ // prepare PatchOat instances for the rest.
for (size_t i = 0; i < spaces.size(); ++i) {
gc::space::ImageSpace* space = spaces[i];
std::string input_image_filename = space->GetImageFilename();
+ std::string input_vdex_filename =
+ ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
std::string input_oat_filename =
ImageHeader::GetOatLocationFromImageLocation(input_image_filename);
std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str()));
@@ -261,13 +288,16 @@ bool PatchOat::Patch(const std::string& image_location,
std::string output_image_filename = output_directory +
(StartsWith(converted_image_filename, "/") ? "" : "/") +
converted_image_filename;
+ std::string output_vdex_filename =
+ ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
std::string output_oat_filename =
ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(),
output_oat_filename,
false,
- true)) {
+ true) ||
+ !SymlinkFile(input_vdex_filename, output_vdex_filename)) {
// Errors already logged by above call.
return false;
}
@@ -301,9 +331,13 @@ bool PatchOat::Patch(const std::string& image_location,
space_to_skip_patching_map.emplace(space, skip_patching_oat);
}
+ // Do a second pass over the image spaces. Patch image files, non-PIC oat files
+ // and symlink their corresponding vdex files.
for (size_t i = 0; i < spaces.size(); ++i) {
gc::space::ImageSpace* space = spaces[i];
std::string input_image_filename = space->GetImageFilename();
+ std::string input_vdex_filename =
+ ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
t.NewTiming("Writing files");
std::string converted_image_filename = space->GetImageLocation();
@@ -329,8 +363,11 @@ bool PatchOat::Patch(const std::string& image_location,
bool skip_patching_oat = space_to_skip_patching_map.find(space)->second;
if (!skip_patching_oat) {
+ std::string output_vdex_filename =
+ ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
std::string output_oat_filename =
ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
+
std::unique_ptr<File>
output_oat_file(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
if (output_oat_file.get() == nullptr) {
@@ -339,6 +376,9 @@ bool PatchOat::Patch(const std::string& image_location,
}
success = p.WriteElf(output_oat_file.get());
success = FinishFile(output_oat_file.get(), success);
+ if (success) {
+ success = SymlinkFile(input_vdex_filename, output_vdex_filename);
+ }
if (!success) {
return false;
}
@@ -921,6 +961,9 @@ NO_RETURN static void Usage(const char *fmt, ...) {
UsageError(" --input-oat-fd=<file-descriptor>: Specifies the file-descriptor of the oat file");
UsageError(" to be patched.");
UsageError("");
+ UsageError(" --input-vdex-fd=<file-descriptor>: Specifies the file-descriptor of the vdex file");
+ UsageError(" associated with the oat file.");
+ UsageError("");
UsageError(" --input-oat-location=<file.oat>: Specifies the 'location' to read the patched");
UsageError(" oat file from. If used one must also supply the --instruction-set");
UsageError("");
@@ -932,7 +975,10 @@ NO_RETURN static void Usage(const char *fmt, ...) {
UsageError(" file to.");
UsageError("");
UsageError(" --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the");
- UsageError(" the patched oat file to.");
+ UsageError(" patched oat file to.");
+ UsageError("");
+ UsageError(" --output-vdex-fd=<file-descriptor>: Specifies the file-descriptor to copy the");
+ UsageError(" the vdex file associated with the patch oat file to.");
UsageError("");
UsageError(" --output-image-file=<file.art>: Specifies the exact file to write the patched");
UsageError(" image file to.");
@@ -1029,10 +1075,12 @@ static int patchoat_oat(TimingLogger& timings,
off_t base_delta,
bool base_delta_set,
int input_oat_fd,
+ int input_vdex_fd,
const std::string& input_oat_location,
std::string input_oat_filename,
bool have_input_oat,
int output_oat_fd,
+ int output_vdex_fd,
std::string output_oat_filename,
bool have_output_oat,
bool lock_output,
@@ -1062,6 +1110,12 @@ static int patchoat_oat(TimingLogger& timings,
}
}
+ if ((input_oat_fd == -1) != (input_vdex_fd == -1)) {
+ Usage("Either both input oat and vdex have to be passed as file descriptors or none of them");
+ } else if ((output_oat_fd == -1) != (output_vdex_fd == -1)) {
+ Usage("Either both output oat and vdex have to be passed as file descriptors or none of them");
+ }
+
bool match_delta = false;
if (!patched_image_location.empty()) {
std::string system_filename;
@@ -1102,8 +1156,24 @@ static int patchoat_oat(TimingLogger& timings,
Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize);
}
+ // We can symlink VDEX only if we have both input and output specified as filenames.
+ // Store that piece of information before we possibly create bogus filenames for
+ // files passed as file descriptors.
+ bool symlink_vdex = !input_oat_filename.empty() && !output_oat_filename.empty();
+
+ // Infer names of VDEX files.
+ std::string input_vdex_filename;
+ std::string output_vdex_filename;
+ if (!input_oat_filename.empty()) {
+ input_vdex_filename = ReplaceFileExtension(input_oat_filename, "vdex");
+ }
+ if (!output_oat_filename.empty()) {
+ output_vdex_filename = ReplaceFileExtension(output_oat_filename, "vdex");
+ }
+
// Do we need to cleanup output files if we fail?
bool new_oat_out = false;
+ bool new_vdex_out = false;
std::unique_ptr<File> input_oat;
std::unique_ptr<File> output_oat;
@@ -1162,13 +1232,52 @@ static int patchoat_oat(TimingLogger& timings,
}
}
+ // Open VDEX files if we are not symlinking them.
+ std::unique_ptr<File> input_vdex;
+ std::unique_ptr<File> output_vdex;
+ if (symlink_vdex) {
+ new_vdex_out = !OS::FileExists(output_vdex_filename.c_str());
+ } else {
+ if (input_vdex_fd != -1) {
+ input_vdex.reset(new File(input_vdex_fd, input_vdex_filename, true));
+ if (input_vdex == nullptr) {
+ // Unlikely, but ensure exhaustive logging in non-0 exit code case
+ LOG(ERROR) << "Failed to open input vdex file by its FD" << input_vdex_fd;
+ }
+ } else {
+ input_vdex.reset(OS::OpenFileForReading(input_vdex_filename.c_str()));
+ if (input_vdex == nullptr) {
+ PLOG(ERROR) << "Failed to open input vdex file " << input_vdex_filename;
+ return EXIT_FAILURE;
+ }
+ }
+ if (output_vdex_fd != -1) {
+ output_vdex.reset(new File(output_vdex_fd, output_vdex_filename, true));
+ if (output_vdex == nullptr) {
+ // Unlikely, but ensure exhaustive logging in non-0 exit code case
+ LOG(ERROR) << "Failed to open output vdex file by its FD" << output_vdex_fd;
+ }
+ } else {
+ output_vdex.reset(CreateOrOpen(output_vdex_filename.c_str(), &new_vdex_out));
+ if (output_vdex == nullptr) {
+ PLOG(ERROR) << "Failed to open output vdex file " << output_vdex_filename;
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
// TODO: get rid of this.
- auto cleanup = [&output_oat_filename, &new_oat_out](bool success) {
+ auto cleanup = [&output_oat_filename, &output_vdex_filename, &new_oat_out, &new_vdex_out]
+ (bool success) {
if (!success) {
if (new_oat_out) {
CHECK(!output_oat_filename.empty());
unlink(output_oat_filename.c_str());
}
+ if (new_vdex_out) {
+ CHECK(!output_vdex_filename.empty());
+ unlink(output_vdex_filename.c_str());
+ }
}
if (kIsDebugBuild) {
@@ -1220,6 +1329,14 @@ static int patchoat_oat(TimingLogger& timings,
new_oat_out);
ret = FinishFile(output_oat.get(), ret);
+ if (ret) {
+ if (symlink_vdex) {
+ ret = SymlinkFile(input_vdex_filename, output_vdex_filename);
+ } else {
+ ret = unix_file::CopyFile(*input_vdex.get(), output_vdex.get());
+ }
+ }
+
if (kIsDebugBuild) {
LOG(INFO) << "Exiting with return ... " << ret;
}
@@ -1227,6 +1344,18 @@ static int patchoat_oat(TimingLogger& timings,
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}
+static int ParseFd(const StringPiece& option, const char* cmdline_arg) {
+ int fd;
+ const char* fd_str = option.substr(strlen(cmdline_arg)).data();
+ if (!ParseInt(fd_str, &fd)) {
+ Usage("Failed to parse %d argument '%s' as an integer", cmdline_arg, fd_str);
+ }
+ if (fd < 0) {
+ Usage("%s pass a negative value %d", cmdline_arg, fd);
+ }
+ return fd;
+}
+
static int patchoat(int argc, char **argv) {
InitLogging(argv);
MemMap::Init();
@@ -1253,10 +1382,12 @@ static int patchoat(int argc, char **argv) {
std::string input_oat_filename;
std::string input_oat_location;
int input_oat_fd = -1;
+ int input_vdex_fd = -1;
bool have_input_oat = false;
std::string input_image_location;
std::string output_oat_filename;
int output_oat_fd = -1;
+ int output_vdex_fd = -1;
bool have_output_oat = false;
std::string output_image_filename;
off_t base_delta = 0;
@@ -1296,13 +1427,9 @@ static int patchoat(int argc, char **argv) {
Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
}
have_input_oat = true;
- const char* oat_fd_str = option.substr(strlen("--input-oat-fd=")).data();
- if (!ParseInt(oat_fd_str, &input_oat_fd)) {
- Usage("Failed to parse --input-oat-fd argument '%s' as an integer", oat_fd_str);
- }
- if (input_oat_fd < 0) {
- Usage("--input-oat-fd pass a negative value %d", input_oat_fd);
- }
+ input_oat_fd = ParseFd(option, "--input-oat-fd=");
+ } else if (option.starts_with("--input-vdex-fd=")) {
+ input_vdex_fd = ParseFd(option, "--input-vdex-fd=");
} else if (option.starts_with("--input-image-location=")) {
input_image_location = option.substr(strlen("--input-image-location=")).data();
} else if (option.starts_with("--output-oat-file=")) {
@@ -1316,13 +1443,9 @@ static int patchoat(int argc, char **argv) {
Usage("Only one of --output-oat-file, --output-oat-fd may be used.");
}
have_output_oat = true;
- const char* oat_fd_str = option.substr(strlen("--output-oat-fd=")).data();
- if (!ParseInt(oat_fd_str, &output_oat_fd)) {
- Usage("Failed to parse --output-oat-fd argument '%s' as an integer", oat_fd_str);
- }
- if (output_oat_fd < 0) {
- Usage("--output-oat-fd pass a negative value %d", output_oat_fd);
- }
+ output_oat_fd = ParseFd(option, "--output-oat-fd=");
+ } else if (option.starts_with("--output-vdex-fd=")) {
+ output_vdex_fd = ParseFd(option, "--output-vdex-fd=");
} else if (option.starts_with("--output-image-file=")) {
output_image_filename = option.substr(strlen("--output-image-file=")).data();
} else if (option.starts_with("--base-offset-delta=")) {
@@ -1367,10 +1490,12 @@ static int patchoat(int argc, char **argv) {
base_delta,
base_delta_set,
input_oat_fd,
+ input_vdex_fd,
input_oat_location,
input_oat_filename,
have_input_oat,
output_oat_fd,
+ output_vdex_fd,
output_oat_filename,
have_output_oat,
lock_output,