0002-Use-ASharedMemory-functions-when-possible.patch 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. diff --git a/third_party/ashmem/ashmem-dev.c b/third_party/ashmem/ashmem-dev.c
  2. index 52b3f47eeae0..25a33cdcd0c8 100644
  3. --- a/third_party/ashmem/ashmem-dev.c
  4. +++ b/third_party/ashmem/ashmem-dev.c
  5. @@ -14,23 +14,115 @@
  6. * limitations under the License.
  7. */
  8. -/*
  9. - * Implementation of the user-space ashmem API for devices, which have our
  10. - * ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
  11. - * used by the simulator.
  12. - */
  13. +#include "ashmem.h"
  14. +#include <dlfcn.h>
  15. +#include <errno.h>
  16. #include <unistd.h>
  17. +#include <stdlib.h>
  18. #include <string.h>
  19. +#include <sys/mman.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <sys/ioctl.h>
  23. +#include <sys/stat.h> /* for fdstat() */
  24. #include <fcntl.h>
  25. #include <linux/ashmem.h>
  26. -#include "ashmem.h"
  27. +#include <sys/system_properties.h>
  28. -#define ASHMEM_DEVICE "/dev/ashmem"
  29. +#define ASHMEM_DEVICE "/dev/ashmem"
  30. +
  31. +/* Technical note regarding reading system properties.
  32. + *
  33. + * Try to use the new __system_property_read_callback API that appeared in
  34. + * Android O / API level 26 when available. Otherwise use the deprecated
  35. + * __system_property_get function.
  36. + *
  37. + * For more technical details from an NDK maintainer, see:
  38. + * https://bugs.chromium.org/p/chromium/issues/detail?id=392191#c17
  39. + */
  40. +
  41. +/* Weak symbol import */
  42. +void __system_property_read_callback(
  43. + const prop_info* info,
  44. + void (*callback)(
  45. + void* cookie, const char* name, const char* value, uint32_t serial),
  46. + void* cookie) __attribute__((weak));
  47. +
  48. +/* Callback used with __system_property_read_callback. */
  49. +static void prop_read_int(void* cookie,
  50. + const char* name,
  51. + const char* value,
  52. + uint32_t serial) {
  53. + *(int *)cookie = atoi(value);
  54. + (void)name;
  55. + (void)serial;
  56. +}
  57. +
  58. +static int system_property_get_int(const char* name) {
  59. + int result = 0;
  60. + if (__system_property_read_callback) {
  61. + const prop_info* info = __system_property_find(name);
  62. + if (info)
  63. + __system_property_read_callback(info, &prop_read_int, &result);
  64. + } else {
  65. + char value[PROP_VALUE_MAX] = {};
  66. + if (__system_property_get(name, value) >= 1)
  67. + result = atoi(value);
  68. + }
  69. + return result;
  70. +}
  71. +
  72. +static int device_api_level() {
  73. + static int s_api_level = -1;
  74. + if (s_api_level < 0)
  75. + s_api_level = system_property_get_int("ro.build.version.sdk");
  76. + return s_api_level;
  77. +}
  78. +
  79. +typedef enum {
  80. + ASHMEM_STATUS_INIT,
  81. + ASHMEM_STATUS_NOT_SUPPORTED,
  82. + ASHMEM_STATUS_SUPPORTED,
  83. +} AshmemStatus;
  84. +
  85. +static AshmemStatus s_ashmem_status = ASHMEM_STATUS_INIT;
  86. +static dev_t s_ashmem_dev;
  87. +
  88. +/* Return the dev_t of a given file path, or 0 if not available, */
  89. +static dev_t ashmem_find_dev(const char* path) {
  90. + struct stat st;
  91. + dev_t result = 0;
  92. + if (stat(path, &st) == 0 && S_ISCHR(st.st_mode))
  93. + result = st.st_dev;
  94. + return result;
  95. +}
  96. +
  97. +static AshmemStatus ashmem_get_status(void) {
  98. + /* NOTE: No need to make this thread-safe, assuming that
  99. + * all threads will find the same value. */
  100. + if (s_ashmem_status != ASHMEM_STATUS_INIT)
  101. + return s_ashmem_status;
  102. +
  103. + s_ashmem_dev = ashmem_find_dev(ASHMEM_DEVICE);
  104. + s_ashmem_status = (s_ashmem_dev == 0) ? ASHMEM_STATUS_NOT_SUPPORTED
  105. + : ASHMEM_STATUS_SUPPORTED;
  106. + return s_ashmem_status;
  107. +}
  108. +
  109. +/* Returns true iff the ashmem device ioctl should be used for a given fd.
  110. + * NOTE: Try not to use fstat() when possible to avoid performance issues. */
  111. +static int ashmem_dev_fd_check(int fd) {
  112. + if (device_api_level() <= __ANDROID_API_O_MR1__)
  113. + return 1;
  114. + if (ashmem_get_status() == ASHMEM_STATUS_SUPPORTED) {
  115. + struct stat st;
  116. + return (fstat(fd, &st) == 0 && S_ISCHR(st.st_mode) &&
  117. + st.st_dev != 0 && st.st_dev == s_ashmem_dev);
  118. + }
  119. + return 0;
  120. +}
  121. /*
  122. * ashmem_create_region - creates a new ashmem region and returns the file
  123. @@ -39,67 +131,133 @@
  124. * `name' is an optional label to give the region (visible in /proc/pid/maps)
  125. * `size' is the size of the region, in page-aligned bytes
  126. */
  127. -int ashmem_create_region(const char *name, size_t size)
  128. -{
  129. - int fd, ret;
  130. +static int ashmem_dev_create_region(const char *name, size_t size) {
  131. + int fd = open(ASHMEM_DEVICE, O_RDWR);
  132. + if (fd < 0)
  133. + return fd;
  134. - fd = open(ASHMEM_DEVICE, O_RDWR);
  135. - if (fd < 0)
  136. - return fd;
  137. + int ret;
  138. + if (name) {
  139. + char buf[ASHMEM_NAME_LEN];
  140. + strlcpy(buf, name, sizeof(buf));
  141. + ret = ioctl(fd, ASHMEM_SET_NAME, buf);
  142. + if (ret < 0)
  143. + goto error;
  144. + }
  145. + ret = ioctl(fd, ASHMEM_SET_SIZE, size);
  146. + if (ret < 0)
  147. + goto error;
  148. - if (name) {
  149. - char buf[ASHMEM_NAME_LEN];
  150. + return fd;
  151. - strlcpy(buf, name, sizeof(buf));
  152. - ret = ioctl(fd, ASHMEM_SET_NAME, buf);
  153. - if (ret < 0)
  154. - goto error;
  155. - }
  156. +error:
  157. + close(fd);
  158. + return ret;
  159. +}
  160. - ret = ioctl(fd, ASHMEM_SET_SIZE, size);
  161. - if (ret < 0)
  162. - goto error;
  163. +static int ashmem_dev_set_prot_region(int fd, int prot) {
  164. + return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
  165. +}
  166. - return fd;
  167. +static int ashmem_dev_get_prot_region(int fd) {
  168. + return ioctl(fd, ASHMEM_GET_PROT_MASK);
  169. +}
  170. -error:
  171. - close(fd);
  172. - return ret;
  173. +static int ashmem_dev_pin_region(int fd, size_t offset, size_t len) {
  174. + struct ashmem_pin pin = { offset, len };
  175. + return ioctl(fd, ASHMEM_PIN, &pin);
  176. }
  177. -int ashmem_set_prot_region(int fd, int prot)
  178. -{
  179. - return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
  180. +static int ashmem_dev_unpin_region(int fd, size_t offset, size_t len) {
  181. + struct ashmem_pin pin = { offset, len };
  182. + return ioctl(fd, ASHMEM_UNPIN, &pin);
  183. }
  184. -int ashmem_get_prot_region(int fd)
  185. -{
  186. - return ioctl(fd, ASHMEM_GET_PROT_MASK);
  187. +static size_t ashmem_dev_get_size_region(int fd) {
  188. + return ioctl(fd, ASHMEM_GET_SIZE, NULL);
  189. }
  190. -int ashmem_pin_region(int fd, size_t offset, size_t len)
  191. -{
  192. - struct ashmem_pin pin = { offset, len };
  193. - return ioctl(fd, ASHMEM_PIN, &pin);
  194. +// Starting with API level 26, the following functions from
  195. +// libandroid.so should be used to create shared memory regions.
  196. +typedef int(*ASharedMemory_createFunc)(const char*, size_t);
  197. +typedef size_t(*ASharedMemory_getSizeFunc)(int fd);
  198. +typedef int(*ASharedMemory_setProtFunc)(int fd, int prot);
  199. +
  200. +// Function pointers to shared memory functions.
  201. +typedef struct {
  202. + ASharedMemory_createFunc create;
  203. + ASharedMemory_getSizeFunc getSize;
  204. + ASharedMemory_setProtFunc setProt;
  205. +} ASharedMemoryFuncs;
  206. +
  207. +const ASharedMemoryFuncs* ashmem_get_funcs() {
  208. + static ASharedMemoryFuncs s_ashmem_funcs = {};
  209. + ASharedMemoryFuncs* funcs = &s_ashmem_funcs;
  210. + if (funcs->create == NULL) {
  211. + if (device_api_level() >= __ANDROID_API_O__) {
  212. + /* Leaked intentionally! */
  213. + void* lib = dlopen("libandroid.so", RTLD_NOW);
  214. + funcs->create = (ASharedMemory_createFunc)
  215. + dlsym(lib, "ASharedMemory_create");
  216. + funcs->getSize = (ASharedMemory_getSizeFunc)
  217. + dlsym(lib, "ASharedMemory_getSize");
  218. + funcs->setProt = (ASharedMemory_setProtFunc)
  219. + dlsym(lib, "ASharedMemory_setProt");
  220. + } else {
  221. + funcs->create = &ashmem_dev_create_region;
  222. + funcs->getSize = &ashmem_dev_get_size_region;
  223. + funcs->setProt = &ashmem_dev_set_prot_region;
  224. + }
  225. + }
  226. + return funcs;
  227. }
  228. -int ashmem_unpin_region(int fd, size_t offset, size_t len)
  229. -{
  230. - struct ashmem_pin pin = { offset, len };
  231. - return ioctl(fd, ASHMEM_UNPIN, &pin);
  232. +int ashmem_create_region(const char* name, size_t size) {
  233. + return ashmem_get_funcs()->create(name, size);
  234. }
  235. -int ashmem_get_size_region(int fd)
  236. -{
  237. - return ioctl(fd, ASHMEM_GET_SIZE, NULL);
  238. +int ashmem_set_prot_region(int fd, int prot) {
  239. + return ashmem_get_funcs()->setProt(fd, prot);
  240. }
  241. -int ashmem_purge_all(void)
  242. -{
  243. - const int fd = open(ASHMEM_DEVICE, O_RDWR);
  244. - if (fd < 0)
  245. - return fd;
  246. - const int ret = ioctl(fd, ASHMEM_PURGE_ALL_CACHES, 0);
  247. - close(fd);
  248. - return ret;
  249. +int ashmem_get_prot_region(int fd) {
  250. + if (ashmem_dev_fd_check(fd))
  251. + return ashmem_dev_get_prot_region(fd);
  252. + /* There are only two practical values to return here: either
  253. + * PROT_READ|PROT_WRITE or just PROT_READ, so try to determine
  254. + * the flags by trying to mmap() the region read-write first.
  255. + */
  256. + int result = PROT_READ;
  257. + const size_t page_size = (size_t)sysconf(_SC_PAGESIZE);
  258. + void* m = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
  259. + MAP_PRIVATE, fd, 0);
  260. + if (m != MAP_FAILED) {
  261. + munmap(m, page_size);
  262. + result = PROT_READ|PROT_WRITE;
  263. + }
  264. + return result;
  265. +}
  266. +
  267. +int ashmem_pin_region(int fd, size_t offset, size_t len) {
  268. + if (ashmem_dev_fd_check(fd))
  269. + return ashmem_dev_pin_region(fd, offset, len);
  270. + return ASHMEM_NOT_PURGED;
  271. +}
  272. +
  273. +int ashmem_unpin_region(int fd, size_t offset, size_t len) {
  274. + if (ashmem_dev_fd_check(fd))
  275. + return ashmem_dev_unpin_region(fd, offset, len);
  276. + /* NOTE: It is not possible to use madvise() here because it requires a
  277. + * memory address. This could be done in the caller though, instead of
  278. + * this function. */
  279. + return 0;
  280. +}
  281. +
  282. +int ashmem_get_size_region(int fd) {
  283. + /* NOTE: Original API returns an int. Avoid breaking it. */
  284. + return (int)ashmem_get_funcs()->getSize(fd);
  285. +}
  286. +
  287. +int ashmem_device_is_supported(void) {
  288. + return ashmem_get_status() == ASHMEM_STATUS_SUPPORTED;
  289. }
  290. diff --git a/third_party/ashmem/ashmem.h b/third_party/ashmem/ashmem.h
  291. index d8afccbd2a6e..f3675c98b19a 100644
  292. --- a/third_party/ashmem/ashmem.h
  293. +++ b/third_party/ashmem/ashmem.h
  294. @@ -16,13 +16,20 @@
  295. extern "C" {
  296. #endif
  297. +/* Returns true if the ashmem device is supported on this device.
  298. + * Not that even if the device is not supported,
  299. + * ashmem_{create,set_prot,get_prot,get_size}_region() will still work
  300. + * because they will use the ASharedMemory functions from libandroid.so
  301. + * instead. But ashmem_{pin,unpin}_region() will be no-ops.
  302. + */
  303. +int ashmem_device_is_supported(void);
  304. +
  305. int ashmem_create_region(const char *name, size_t size);
  306. int ashmem_set_prot_region(int fd, int prot);
  307. int ashmem_get_prot_region(int fd);
  308. int ashmem_pin_region(int fd, size_t offset, size_t len);
  309. int ashmem_unpin_region(int fd, size_t offset, size_t len);
  310. int ashmem_get_size_region(int fd);
  311. -int ashmem_purge_all(void);
  312. #ifdef __cplusplus
  313. }