blob: ca6cff426838b6db9fba659e2597f7a091b56011 [file] [log] [blame]
bigbiff6411e082020-09-14 20:13:12 -04001#include "twrpApex.hpp"
bigbiff0e97f7e2021-02-25 10:16:59 -05002#include "twrp-functions.hpp"
bigbiff79924302021-05-02 20:06:09 -04003#include "common.h"
bigbiff6411e082020-09-14 20:13:12 -04004
5namespace fs = std::filesystem;
6
7bool twrpApex::loadApexImages() {
8 std::vector<std::string> apexFiles;
bigbiff79924302021-05-02 20:06:09 -04009 std::vector<std::string> checkApexFlatFiles;
10#ifdef TW_ADDITIONAL_APEX_FILES
11 char* additionalFiles = strdup(EXPAND(TW_ADDITIONAL_APEX_FILES));
12 char* additionalApexFiles = std::strtok(additionalFiles, " ");
13#endif
14
15 apexFiles.push_back(APEX_DIR "/com.android.apex.cts.shim.apex");
16 apexFiles.push_back(APEX_DIR "/com.google.android.tzdata2.apex");
17 apexFiles.push_back(APEX_DIR "/com.android.tzdata.apex");
18 apexFiles.push_back(APEX_DIR "/com.android.art.release.apex");
19 apexFiles.push_back(APEX_DIR "/com.google.android.media.swcodec.apex");
20 apexFiles.push_back(APEX_DIR "/com.android.media.swcodec.apex");
21
22#ifdef TW_ADDITIONAL_APEX_FILES
23 while(additionalApexFiles) {
24 std::stringstream apexFile;
25 apexFile << APEX_DIR << "/" << additionalApexFiles;
26 apexFiles.push_back(apexFile.str());
27 additionalApexFiles = std::strtok(nullptr, " ");
28 }
29#endif
30
bigbiff6411e082020-09-14 20:13:12 -040031 if (access(APEX_DIR, F_OK) != 0) {
32 LOGERR("Unable to open %s\n", APEX_DIR);
33 return false;
34 }
35 for (const auto& entry : fs::directory_iterator(APEX_DIR)) {
36 if (entry.is_regular_file()) {
bigbiff79924302021-05-02 20:06:09 -040037 checkApexFlatFiles.push_back(entry.path().string());
bigbiff6411e082020-09-14 20:13:12 -040038 }
39 }
40
bigbiff79924302021-05-02 20:06:09 -040041 if (checkApexFlatFiles.size() == 0) {
bigbiff6411e082020-09-14 20:13:12 -040042 // flattened apex directory
43 LOGINFO("Bind mounting flattened apex directory\n");
44 if (mount(APEX_DIR, APEX_BASE, "", MS_BIND, NULL) < 0) {
45 LOGERR("Unable to bind mount flattened apex directory\n");
46 return false;
47 }
bigbiffab036612021-06-24 21:31:40 -040048 android::base::SetProperty("twrp.apex.flattened", "true");
bigbiff6411e082020-09-14 20:13:12 -040049 return true;
50 }
bigbiff0e97f7e2021-02-25 10:16:59 -050051 if (!mountApexOnLoopbackDevices(apexFiles)) {
bigbiff6411e082020-09-14 20:13:12 -040052 LOGERR("Unable to create loop devices to mount apex files\n");
53 return false;
54 }
55
bigbiff6411e082020-09-14 20:13:12 -040056 return true;
57}
58
59std::string twrpApex::unzipImage(std::string file) {
60 ZipArchiveHandle handle;
61 int32_t ret = OpenArchive(file.c_str(), &handle);
62 if (ret != 0) {
bigbiff79924302021-05-02 20:06:09 -040063 LOGINFO("unable to open zip archive %s. Reason: %s\n", file.c_str(), strerror(errno));
64 return std::string();
bigbiff6411e082020-09-14 20:13:12 -040065 }
66
67 ZipEntry entry;
bigbiff673c7ae2020-12-02 19:44:56 -050068 std::string zip_string(APEX_PAYLOAD);
bigbiff6411e082020-09-14 20:13:12 -040069 ret = FindEntry(handle, zip_string, &entry);
70 if (ret != 0) {
71 LOGERR("unable to find %s in zip\n", APEX_PAYLOAD);
72 CloseArchive(handle);
bigbiff79924302021-05-02 20:06:09 -040073 return std::string();
bigbiff6411e082020-09-14 20:13:12 -040074 }
75
76 std::string baseFile = basename(file.c_str());
77 std::string path("/tmp/");
78 path = path + baseFile;
79 int fd = open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
80 ret = ExtractEntryToFile(handle, &entry, fd);
81 if (ret != 0) {
82 LOGERR("unable to extract %s\n", path.c_str());
83 close(fd);
84 CloseArchive(handle);
bigbiff79924302021-05-02 20:06:09 -040085 return std::string();
bigbiff6411e082020-09-14 20:13:12 -040086 }
87
bigbiff6411e082020-09-14 20:13:12 -040088 CloseArchive(handle);
bigbiff0e97f7e2021-02-25 10:16:59 -050089 close(fd);
bigbiff6411e082020-09-14 20:13:12 -040090 return path;
91}
92
bigbiff0e97f7e2021-02-25 10:16:59 -050093bool twrpApex::mountApexOnLoopbackDevices(std::vector<std::string> apexFiles) {
94 int fd = open(LOOP_CONTROL, O_RDWR | O_CLOEXEC);
95 if (fd < 0) {
96 LOGERR("Unable to open %s device. Reason: %s\n", LOOP_CONTROL, strerror(errno));
97 return false;
bigbiff6411e082020-09-14 20:13:12 -040098 }
99
bigbiff0e97f7e2021-02-25 10:16:59 -0500100 size_t device_no = 0;
101 for (auto&& apexFile:apexFiles) {
102 int num = ioctl(fd, LOOP_CTL_GET_FREE);
103 std::string loop_device = LOOP_BLOCK_DEVICE_DIR;
104 loop_device = loop_device + "loop" + std::to_string(num);
105 if (!TWFunc::Path_Exists(loop_device)) {
106 int ret = mknod(loop_device.c_str(), S_IFBLK | S_IRUSR | S_IWUSR , makedev(7, device_no));
bigbiff6411e082020-09-14 20:13:12 -0400107 if (ret != 0) {
bigbiff0e97f7e2021-02-25 10:16:59 -0500108 LOGERR("Unable to create loop device: %s\n", loop_device.c_str());
bigbiff6411e082020-09-14 20:13:12 -0400109 return false;
110 }
111 }
bigbiff0e97f7e2021-02-25 10:16:59 -0500112 std::string fileToMount = unzipImage(apexFile);
bigbiff79924302021-05-02 20:06:09 -0400113 if (fileToMount.empty()) {
114 LOGINFO("Skipping non-existent apex file: %s\n", apexFile.c_str());
115 continue;
116 }
bigbiff0e97f7e2021-02-25 10:16:59 -0500117 bool load_result = loadApexImage(fileToMount, device_no);
118 if (!load_result) {
119 return false;
120 }
121 device_no++;
bigbiff6411e082020-09-14 20:13:12 -0400122 }
123 return true;
124}
125
126bool twrpApex::loadApexImage(std::string fileToMount, size_t loop_device_number) {
127 struct loop_info64 info;
128
bigbiff0e97f7e2021-02-25 10:16:59 -0500129 int fd = open(fileToMount.c_str(), O_RDONLY | O_CLOEXEC);
bigbiff6411e082020-09-14 20:13:12 -0400130 if (fd < 0) {
bigbiff0e97f7e2021-02-25 10:16:59 -0500131 LOGERR("unable to open apex file: %s. Reason: %s\n", fileToMount.c_str(), strerror(errno));
bigbiff6411e082020-09-14 20:13:12 -0400132 return false;
133 }
134
135 std::string loop_device = "/dev/block/loop" + std::to_string(loop_device_number);
136 int loop_fd = open(loop_device.c_str(), O_RDONLY);
137 if (loop_fd < 0) {
138 LOGERR("unable to open loop device: %s\n", loop_device.c_str());
139 close(fd);
140 return false;
141 }
142
143 if (ioctl(loop_fd, LOOP_SET_FD, fd) < 0) {
bigbiff79924302021-05-02 20:06:09 -0400144 LOGERR("failed to mount %s to loop device %s. Reason: %s\n", fileToMount.c_str(), loop_device.c_str(),
145 strerror(errno));
bigbiff6411e082020-09-14 20:13:12 -0400146 close(fd);
147 close(loop_fd);
148 return false;
149 }
150
151 close(fd);
152
153 memset(&info, 0, sizeof(struct loop_info64));
bigbiff0e97f7e2021-02-25 10:16:59 -0500154 strlcpy((char*)info.lo_crypt_name, "twrpApex", LO_NAME_SIZE);
155 off_t apex_size = lseek(fd, 0, SEEK_END);
156 info.lo_sizelimit = apex_size;
bigbiff6411e082020-09-14 20:13:12 -0400157 if (ioctl(loop_fd, LOOP_SET_STATUS64, &info)) {
158 LOGERR("failed to mount loop: %s: %s\n", fileToMount.c_str(), strerror(errno));
159 close(loop_fd);
160 return false;
161 }
bigbiff0e97f7e2021-02-25 10:16:59 -0500162 if (ioctl(loop_fd, BLKFLSBUF, 0) == -1) {
163 LOGERR("Unable to flush loop device buffers\n");
164 return false;
165 }
166 if (ioctl(loop_fd, LOOP_SET_BLOCK_SIZE, 4096) == -1) {
167 LOGINFO("Failed to set DIRECT_IO buffer size\n");
168 }
bigbiff6411e082020-09-14 20:13:12 -0400169 close(loop_fd);
bigbiff0e97f7e2021-02-25 10:16:59 -0500170
bigbiff6411e082020-09-14 20:13:12 -0400171 std::string bind_mount(APEX_BASE);
172 bind_mount = bind_mount + basename(fileToMount.c_str());
bigbiff0e97f7e2021-02-25 10:16:59 -0500173
bigbiff6411e082020-09-14 20:13:12 -0400174 int ret = mkdir(bind_mount.c_str(), 0666);
175 if (ret != 0) {
bigbiff0e97f7e2021-02-25 10:16:59 -0500176 LOGERR("Unable to create bind mount directory: %s\n", bind_mount.c_str());
bigbiff6411e082020-09-14 20:13:12 -0400177 return false;
178 }
179
180 ret = mount(loop_device.c_str(), bind_mount.c_str(), "ext4", MS_RDONLY, nullptr);
181 if (ret != 0) {
bigbiff0e97f7e2021-02-25 10:16:59 -0500182 LOGERR("unable to mount loop device %s to %s. Reason: %s\n", loop_device.c_str(), bind_mount.c_str(), strerror(errno));
bigbiff6411e082020-09-14 20:13:12 -0400183 return false;
184 }
185
186 return true;
187}
bigbiffcfa875c2021-06-20 16:20:27 -0400188
189bool twrpApex::Unmount() {
190 return (umount2(APEX_BASE, MNT_DETACH) == 0);
191}