create.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #include "idmap.h"
  2. #include <memory>
  3. #include <androidfw/AssetManager.h>
  4. #include <androidfw/ResourceTypes.h>
  5. #include <androidfw/ZipFileRO.h>
  6. #include <utils/String8.h>
  7. #include <fcntl.h>
  8. #include <sys/file.h>
  9. #include <sys/stat.h>
  10. using namespace android;
  11. namespace {
  12. int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc)
  13. {
  14. std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(zip_path));
  15. if (zip.get() == NULL) {
  16. return -1;
  17. }
  18. ZipEntryRO entry = zip->findEntryByName(entry_name);
  19. if (entry == NULL) {
  20. return -1;
  21. }
  22. if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) {
  23. return -1;
  24. }
  25. zip->releaseEntry(entry);
  26. return 0;
  27. }
  28. int open_idmap(const char *path)
  29. {
  30. int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
  31. if (fd == -1) {
  32. ALOGD("error: open %s: %s\n", path, strerror(errno));
  33. goto fail;
  34. }
  35. if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
  36. ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
  37. goto fail;
  38. }
  39. if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) {
  40. ALOGD("error: flock %s: %s\n", path, strerror(errno));
  41. goto fail;
  42. }
  43. return fd;
  44. fail:
  45. if (fd != -1) {
  46. close(fd);
  47. unlink(path);
  48. }
  49. return -1;
  50. }
  51. int write_idmap(int fd, const uint32_t *data, size_t size)
  52. {
  53. if (lseek(fd, 0, SEEK_SET) < 0) {
  54. return -1;
  55. }
  56. size_t bytesLeft = size;
  57. while (bytesLeft > 0) {
  58. ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft));
  59. if (w < 0) {
  60. fprintf(stderr, "error: write: %s\n", strerror(errno));
  61. return -1;
  62. }
  63. bytesLeft -= static_cast<size_t>(w);
  64. }
  65. return 0;
  66. }
  67. bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd)
  68. {
  69. static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES;
  70. struct stat st;
  71. if (fstat(idmap_fd, &st) == -1) {
  72. return true;
  73. }
  74. if (st.st_size < static_cast<off_t>(N)) {
  75. // file is empty or corrupt
  76. return true;
  77. }
  78. char buf[N];
  79. size_t bytesLeft = N;
  80. if (lseek(idmap_fd, 0, SEEK_SET) < 0) {
  81. return true;
  82. }
  83. for (;;) {
  84. ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft));
  85. if (r < 0) {
  86. return true;
  87. }
  88. bytesLeft -= static_cast<size_t>(r);
  89. if (bytesLeft == 0) {
  90. break;
  91. }
  92. if (r == 0) {
  93. // "shouldn't happen"
  94. return true;
  95. }
  96. }
  97. uint32_t version, cached_target_crc, cached_overlay_crc;
  98. String8 cached_target_path, cached_overlay_path;
  99. if (!ResTable::getIdmapInfo(buf, N, &version, &cached_target_crc, &cached_overlay_crc,
  100. &cached_target_path, &cached_overlay_path)) {
  101. return true;
  102. }
  103. if (version != ResTable::IDMAP_CURRENT_VERSION) {
  104. return true;
  105. }
  106. if (cached_target_path != target_apk_path) {
  107. return true;
  108. }
  109. if (cached_overlay_path != overlay_apk_path) {
  110. return true;
  111. }
  112. uint32_t actual_target_crc, actual_overlay_crc;
  113. if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
  114. &actual_target_crc) == -1) {
  115. return true;
  116. }
  117. if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
  118. &actual_overlay_crc) == -1) {
  119. return true;
  120. }
  121. return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc;
  122. }
  123. bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path,
  124. const char *idmap_path)
  125. {
  126. struct stat st;
  127. if (stat(idmap_path, &st) == -1) {
  128. // non-existing idmap is always stale; on other errors, abort idmap generation
  129. return errno == ENOENT;
  130. }
  131. int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY));
  132. if (idmap_fd == -1) {
  133. return false;
  134. }
  135. bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd);
  136. close(idmap_fd);
  137. return is_stale;
  138. }
  139. int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
  140. uint32_t **data, size_t *size)
  141. {
  142. uint32_t target_crc, overlay_crc;
  143. if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
  144. &target_crc) == -1) {
  145. return -1;
  146. }
  147. if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
  148. &overlay_crc) == -1) {
  149. return -1;
  150. }
  151. AssetManager am;
  152. bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
  153. data, size);
  154. return b ? 0 : -1;
  155. }
  156. int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
  157. int fd, bool check_if_stale)
  158. {
  159. if (check_if_stale) {
  160. if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
  161. // already up to date -- nothing to do
  162. return 0;
  163. }
  164. }
  165. uint32_t *data = NULL;
  166. size_t size;
  167. if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
  168. return -1;
  169. }
  170. if (write_idmap(fd, data, size) == -1) {
  171. free(data);
  172. return -1;
  173. }
  174. free(data);
  175. return 0;
  176. }
  177. }
  178. int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
  179. const char *idmap_path)
  180. {
  181. if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
  182. // already up to date -- nothing to do
  183. return EXIT_SUCCESS;
  184. }
  185. int fd = open_idmap(idmap_path);
  186. if (fd == -1) {
  187. return EXIT_FAILURE;
  188. }
  189. int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
  190. close(fd);
  191. if (r != 0) {
  192. unlink(idmap_path);
  193. }
  194. return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
  195. }
  196. int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
  197. {
  198. return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
  199. EXIT_SUCCESS : EXIT_FAILURE;
  200. }
  201. int idmap_verify_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
  202. {
  203. return !is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd) ?
  204. EXIT_SUCCESS : EXIT_FAILURE;
  205. }