mirror of https://github.com/NekoX-Dev/NekoX.git
Compare commits
1006 Commits
v7.3.1-rc1
...
main
Author | SHA1 | Date |
---|---|---|
luvletter2333 | e72c1741bf | |
luvletter2333 | 6a5b90ed4b | |
luvletter2333 | f469c7fef9 | |
luvletter2333 | eb8eb1474d | |
luvletter2333 | c0fdbb58c0 | |
luvletter2333 | e63f66f505 | |
luvletter2333 | 71b3bb5e01 | |
luvletter2333 | 13d2187bdb | |
luvletter2333 | 92e5043254 | |
luvletter2333 | 4799b030b4 | |
Luv Letter | e392d0db9b | |
luvletter2333 | 4933c7107b | |
xaxtix | bab9943ee0 | |
xaxtix | 5e5b7659cb | |
xaxtix | c06f56dcad | |
luvletter2333 | 6d0964f995 | |
luvletter2333 | cf7001b2fc | |
luvletter2333 | 733feb011e | |
luvletter2333 | 1e59e4e335 | |
luvletter2333 | da6d0bea22 | |
luvletter2333 | 1063f56a25 | |
luvletter2333 | c068a74dd8 | |
xaxtix | 07a2c9a330 | |
xaxtix | 1dcd153fe2 | |
xaxtix | 1a48adbec4 | |
xaxtix | d374d4875d | |
luvletter2333 | 021af48ee3 | |
luvletter2333 | ed4fdf2fe3 | |
luvletter2333 | 14e962d30a | |
luvletter2333 | cedce6813e | |
luvletter2333 | afe1f215c8 | |
luvletter2333 | 0ee46c7b1c | |
luvletter2333 | 1497c7ddd3 | |
luvletter2333 | d0bf3ef05b | |
luvletter2333 | 7fe115e83c | |
luvletter2333 | 7f43e7f173 | |
xaxtix | 1ac56c671e | |
xaxtix | 8bb3438f62 | |
xaxtix | 7554c9b726 | |
xaxtix | 116092e32d | |
xaxtix | 810bc4ae67 | |
xaxtix | 51e9947527 | |
xaxtix | c48aa4f3c9 | |
xaxtix | fb2d9f90bc | |
xaxtix | 135e3cc766 | |
xaxtix | 2628a58147 | |
xaxtix | 17283cea01 | |
xaxtix | f7f9363423 | |
luvletter2333 | 5890d96dda | |
luvletter2333 | c71626f80e | |
luvletter2333 | adcafbfc6d | |
luvletter2333 | 12bbf436a1 | |
luvletter2333 | 7ef3a53a2f | |
luvletter2333 | 5aa483a795 | |
James Clef | 8f4e6d9428 | |
luvletter2333 | 69c6fce26b | |
luvletter2333 | 27ced58f8c | |
luvletter2333 | f11f97bd2e | |
luvletter2333 | 2eb50eca97 | |
luvletter2333 | 2e15f20707 | |
luvletter2333 | 92d0a8e072 | |
luvletter2333 | 8673b032af | |
luvletter2333 | 85688e84af | |
luvletter2333 | 355df746a1 | |
xaxtix | 1c03d75ea8 | |
xaxtix | 5a31f93ec2 | |
xaxtix | 3ccf875b1b | |
xaxtix | 2c71f6c92b | |
xaxtix | 03e899e4ec | |
xaxtix | b73fc8de38 | |
luvletter2333 | 2077f74a85 | |
luvletter2333 | 89dee06649 | |
luvletter2333 | 17546df4bb | |
luvletter2333 | 9d4ce33277 | |
luvletter2333 | 07b9af621d | |
luvletter2333 | 2984ee4ef3 | |
luvletter2333 | f56b39d56d | |
luvletter2333 | 8c043db2ce | |
luvletter2333 | 85ff913c2b | |
luvletter2333 | 9ed10404e5 | |
luvletter2333 | b95fa5971d | |
luvletter2333 | 6b59317fa6 | |
xaxtix | 0e17caa7a6 | |
xaxtix | 97ab6c63c8 | |
xaxtix | 9bd017a72a | |
xaxtix | 4951061dde | |
luvletter2333 | 25a1933416 | |
xaxtix | 23118a4a6c | |
xaxtix | a2981ddd29 | |
xaxtix | 342e681114 | |
xaxtix | 67b1fd17e6 | |
luvletter2333 | 079b3bb355 | |
luvletter2333 | 46f7f843b1 | |
luvletter2333 | 0b68460d21 | |
luvletter2333 | 50f2b934c5 | |
luvletter2333 | a5393e9e9d | |
luvletter2333 | 68708c8ff3 | |
luvletter2333 | de75de1f2a | |
luvletter2333 | a4aa5f8099 | |
luvletter2333 | 9af95477cc | |
luvletter2333 | 5e4e11dbcd | |
luvletter2333 | 905cf0a7b3 | |
luvletter2333 | 4c8b0b14fa | |
xaxtix | e9a35cea54 | |
xaxtix | 11edd5ee0d | |
xaxtix | abb896635f | |
rhuba8324 | 086b1a6b1c | |
Hykilpikonna | 2340eea7e9 | |
Furkan Karcıoğlu | e653a90ebd | |
luvletter2333 | 2b9cdaab4f | |
luvletter2333 | ed3ba3dcb5 | |
luvletter2333 | 0aaaa283cf | |
luvletter2333 | e59512fa7c | |
luvletter2333 | 6bf77388d7 | |
luvletter2333 | 92f75541ec | |
luvletter2333 | 4f17a21015 | |
luvletter2333 | 70bb838901 | |
luvletter2333 | a7c7030271 | |
luvletter2333 | 4ca3b95c0c | |
luvletter2333 | 7d2d1d12aa | |
luvletter2333 | bd9483a80f | |
luvletter2333 | 575fd5a684 | |
luvletter2333 | 7d1f137c21 | |
luvletter2333 | db06bb66f4 | |
luvletter2333 | 8b2dca3ea7 | |
luvletter2333 | 6c5fae9fae | |
xaxtix | 43fe75b46b | |
xaxtix | 172335d189 | |
xaxtix | b1aa2020e5 | |
luvletter2333 | 41a4743870 | |
luvletter2333 | bfb3168c36 | |
luvletter2333 | dcff475b34 | |
luvletter2333 | 68ae4ede1f | |
luvletter2333 | 6f1f65d1ac | |
luvletter2333 | bca854c8af | |
luvletter2333 | 0a5c733149 | |
luvletter2333 | 0462fe9875 | |
luvletter2333 | e70805c398 | |
luvletter2333 | e879e46f09 | |
luvletter2333 | 8f18d21c78 | |
luvletter2333 | 4151c906a2 | |
Next Alone | bcec381654 | |
luvletter2333 | 6ccb87a96e | |
Next Alone | fd452a03ac | |
luvletter2333 | b87cd3624d | |
luvletter2333 | 93a286ba44 | |
luvletter2333 | 383be2281f | |
luvletter2333 | 271b0dc136 | |
luvletter2333 | 66eb744fc7 | |
luvletter2333 | 3c1d1bf7cd | |
luvletter2333 | 27cb3dc403 | |
luvletter2333 | db86538019 | |
luvletter2333 | ef9e0aa3d5 | |
luvletter2333 | 36ce0178f6 | |
luvletter2333 | c00cac6b28 | |
luvletter2333 | de6d5e01f3 | |
luvletter2333 | 946f24c45b | |
luvletter2333 | 31abbbbddd | |
luvletter2333 | 8f4741f8ab | |
luvletter2333 | e8accc449d | |
luvletter2333 | c71f3240a3 | |
luvletter2333 | b2a57d7c02 | |
luvletter2333 | ec0caec469 | |
luvletter2333 | f8a72d335e | |
luvletter2333 | 11f055d23f | |
luvletter2333 | de2d16705a | |
xtaodada | a3e489c2f9 | |
xtaodada | 7595ba071e | |
luvletter2333 | 7dcb3abadc | |
luvletter2333 | f002ddc261 | |
luvletter2333 | d7e8ce80e3 | |
luvletter2333 | 6e17a698e0 | |
luvletter2333 | ac8950ad0f | |
luvletter2333 | 8e25de7902 | |
luvletter2333 | c15d817e81 | |
Next Alone | 8f3d631d4f | |
Next Alone | 5f9c66e5be | |
Next Alone | eab8088cae | |
luvletter2333 | d0e1ebd029 | |
luvletter2333 | 77d0e82cb0 | |
luvletter2333 | a0f3ad497d | |
luvletter2333 | 4f85d02518 | |
luvletter2333 | 531f4f9ba9 | |
xaxtix | 6cb1cdf898 | |
luvletter2333 | 0a05e0476b | |
luvletter2333 | 73cb11f883 | |
xaxtix | 43401a515c | |
xaxtix | 0a3abc5158 | |
luvletter2333 | 2a317b62ac | |
luvletter2333 | 8057580313 | |
luvletter2333 | 018c93db24 | |
luvletter2333 | 1c3495c92e | |
luvletter2333 | 780dc4d5b6 | |
luvletter2333 | 00f2a0271c | |
xaxtix | 4a95c2fc1f | |
luvletter2333 | 47ba651ce1 | |
luvletter2333 | 58d91d99aa | |
luvletter2333 | e44072e04b | |
luvletter2333 | 013a7aaa89 | |
luvletter2333 | 1cf9174b75 | |
luvletter2333 | 23952a1dd5 | |
xaxtix | 96dce2c9aa | |
luvletter2333 | e3fcc75eca | |
luvletter2333 | 21563770fc | |
luvletter2333 | 067deb365d | |
luvletter2333 | 06df7442ef | |
hhn1611245010 | 6aa94cff52 | |
luvletter2333 | 37c2793e69 | |
luvletter2333 | fa99e892bc | |
xaxtix | 32aef72421 | |
xaxtix | 136c9582a8 | |
xaxtix | 8283c12364 | |
xaxtix | 8309ac8d7c | |
luvletter2333 | 10016b3e49 | |
xaxtix | 1e50785b90 | |
luvletter2333 | b16a3bb372 | |
Weblate (bot) | 0b83d38bba | |
luvletter2333 | a11fc83509 | |
luvletter2333 | 9115bb9569 | |
ChristinaLee | 51a3dad697 | |
luvletter2333 | 9023f54a10 | |
luvletter2333 | 8d5ef289a2 | |
luvletter2333 | 324c39dded | |
gao_cai_sheng | b709d28bff | |
NatsumeMio | 88ef26f33a | |
NatsumeMio | 9e7fd90610 | |
NatsumeMio | 8f54fb267d | |
NatsumeMio | 1c123dedc6 | |
luvletter2333 | 55024ce8bb | |
Legend | 0aabf18b0c | |
luvletter2333 | 9969037be2 | |
luvletter2333 | ff45bdac1e | |
luvletter2333 | 79c6d00fbb | |
luvletter2333 | 538e82ff01 | |
luvletter2333 | 0ed8ff1ed3 | |
luvletter2333 | 00f7b2c892 | |
luvletter2333 | 2f86e87899 | |
luvletter2333 | a6c39637da | |
xaxtix | 0abe4541dd | |
luvletter2333 | 1b78fc6cf1 | |
luvletter2333 | 8cf8776235 | |
luvletter2333 | 4b010e3b11 | |
luvletter2333 | c1a21028e4 | |
luvletter2333 | de17e63f2a | |
luvletter2333 | 7a29fe9d2d | |
luvletter2333 | 8de1a84dc0 | |
luvletter2333 | c26b65bee9 | |
luvletter2333 | 8311829a9b | |
luvletter2333 | fa5b44b51e | |
luvletter2333 | 3b8cf4fde4 | |
xaxtix | 5d5527525f | |
xaxtix | d30f796d8c | |
luvletter2333 | 86c7a6d0be | |
luvletter2333 | 7e03bca531 | |
luvletter2333 | 4a1e66b96b | |
luvletter2333 | d3511e568b | |
luvletter2333 | 6d4e8a06c8 | |
luvletter2333 | be3ff350fb | |
luvletter2333 | 1c57ed952e | |
luvletter2333 | 9fd741ffa0 | |
luvletter2333 | 959f9dfc26 | |
luvletter2333 | 8a999c6aaf | |
luvletter2333 | b10b2e0f7c | |
luvletter2333 | 34d78450c7 | |
luvletter2333 | f406f07718 | |
luvletter2333 | 1bece71050 | |
luvletter2333 | c19229663f | |
luvletter2333 | ab0c0ed4d8 | |
luvletter2333 | 6512972f30 | |
luvletter2333 | f438230f13 | |
luvletter2333 | 32066ecf1f | |
xaxtix | 3708e9847a | |
xaxtix | b5694a1ca6 | |
luvletter2333 | 0379caa36f | |
luvletter2333 | 92bb673a32 | |
xaxtix | 3b4919a542 | |
luvletter2333 | 8a3dc467d3 | |
luvletter2333 | 016bdc4a7d | |
luvletter2333 | d01678de23 | |
luvletter2333 | 47724d4d61 | |
luvletter2333 | ba9f84efee | |
luvletter2333 | 62c7c8b5cf | |
luvletter2333 | c811f7d06b | |
luvletter2333 | 6ca737b4e1 | |
luvletter2333 | 672c7e8688 | |
luvletter2333 | 8d07f4d1ad | |
luvletter2333 | c706d2c2c5 | |
luvletter2333 | be79f8f6de | |
luvletter2333 | c60fd69b04 | |
xaxtix | 146cea26cd | |
luvletter2333 | db1ba95ae5 | |
luvletter2333 | b1d798c8d3 | |
luvletter2333 | 83e8a1b61a | |
luvletter2333 | d4e8d513c4 | |
luvletter2333 | cdc56f97e7 | |
luvletter2333 | d54dd02b59 | |
luvletter2333 | e36c89be5a | |
gao_cai_sheng | fd0ea5b158 | |
luvletter2333 | 00ae420abf | |
luvletter2333 | 20f3658279 | |
luvletter2333 | 2a19e63c62 | |
xaxtix | a1817ea7d3 | |
xaxtix | ee217d739f | |
xaxtix | ad05eea682 | |
luvletter2333 | 040500f1d9 | |
luvletter2333 | 3eaa650947 | |
luvletter2333 | ac308681c6 | |
luvletter2333 | fef56f8a49 | |
luvletter2333 | d041495b30 | |
luvletter2333 | 2c4fdbc001 | |
luvletter2333 | 91857d5a37 | |
luvletter2333 | a6457cac77 | |
luvletter2333 | 7aab8fad6d | |
luvletter2333 | d3ff18c668 | |
luvletter2333 | d67c5c27b9 | |
luvletter2333 | 76ef6ac602 | |
luvletter2333 | 7a63017f54 | |
luvletter2333 | 1d3011ea58 | |
luvletter2333 | b848e5e666 | |
luvletter2333 | 9861e319f4 | |
luvletter2333 | 8618ac484b | |
luvletter2333 | e8e446f586 | |
luvletter2333 | 632b36170c | |
luvletter2333 | cf712d9641 | |
luvletter2333 | 200a359dd7 | |
luvletter2333 | f64c20581d | |
luvletter2333 | b1dce3510f | |
luvletter2333 | e1c74d2aaf | |
luvletter2333 | 2456ab21f1 | |
luvletter2333 | c4afcbf6f2 | |
luvletter2333 | 6a69aa0e9c | |
luvletter2333 | e46ea1135e | |
6666666 | 91a4b200dd | |
xaxtix | f0f858ad3f | |
luvletter2333 | 56a79e2f35 | |
Radshasak Paitoonlerd | 3f410a2017 | |
luvletter2333 | 2de5fba21f | |
Radshasak Paitoonlerd | 66ce1f0fb7 | |
luvletter2333 | 2a6708a4cc | |
luvletter2333 | 2237ece95d | |
luvletter2333 | 130230f081 | |
luvletter2333 | f4d4851672 | |
luvletter2333 | 47d3372766 | |
luvletter2333 | 2288606583 | |
luvletter2333 | f973694b41 | |
luvletter2333 | 6249aba960 | |
luvletter2333 | e78748b6b8 | |
Denys Nykula | 865bf40424 | |
Denys Nykula | 270143347d | |
Denys Nykula | a0f23bad7d | |
Denys Nykula | a21fbf2dc6 | |
FW | 0e7240ed97 | |
araccaine | 0aeec8b717 | |
FW | d7c7e5d63c | |
bruh | ff11feb1a6 | |
qqqq1 | 896904b499 | |
qqqq1 | 4cb2b02b4d | |
qqqq1 | e44ac90834 | |
xaxtix | ad6629f6fc | |
Sam | 86dd5c2a6e | |
Traditional Chinese | a3ab5bfa3c | |
Traditional Chinese | 9df9a377bf | |
Traditional Chinese | befd389536 | |
ssantos | 26f90bdb61 | |
Reza Esmaeili | a8914934c7 | |
Reza Esmaeili | c36ac8299e | |
luvletter2333 | a413352c45 | |
luvletter2333 | b472662a3f | |
luvletter2333 | 097acd41c7 | |
luvletter2333 | 50ed8cfb8b | |
luvletter2333 | 305c7fe18d | |
luvletter2333 | c39ab4ce95 | |
luvletter2333 | 785a883f4e | |
luvletter2333 | 0c53f2b9ed | |
luvletter2333 | 9870b8e343 | |
luvletter2333 | 7474cd9718 | |
xaxtix | c1c2ebaf46 | |
xaxtix | 9e740dfd4d | |
Luv Letter | 1b5efe7178 | |
luvletter2333 | d0bf834786 | |
luvletter2333 | 2584e307a6 | |
luvletter2333 | fdb6ee227a | |
luvletter2333 | 4c8c6de621 | |
luvletter2333 | 21e8c8432e | |
Luv Letter | 3cf4eb12f7 | |
Luv Letter | 4e7e596959 | |
luvletter2333 | e4924c245a | |
luvletter2333 | ecb6ec1c8e | |
luvletter2333 | 65f7479c7c | |
thermatk | ef1107f2f5 | |
thermatk | 0bed4a37d0 | |
luvletter2333 | 6f01267133 | |
luvletter2333 | be93f69a31 | |
luvletter2333 | 67703b1717 | |
luvletter2333 | 5f41f3f0cb | |
luvletter2333 | cde8d42dc7 | |
luvletter2333 | bb2acb6a29 | |
luvletter2333 | 6e60b3ab64 | |
luvletter2333 | 6666c0d566 | |
luvletter2333 | 99d38cb371 | |
luvletter2333 | 72cb3361e1 | |
luvletter2333 | eacd2894ca | |
luvletter2333 | 1d46cd930f | |
luvletter2333 | 23f7d3f443 | |
luvletter2333 | 7c5a12e340 | |
luvletter2333 | 663dc36f12 | |
luvletter2333 | bc309b2104 | |
Алексей Муратов | c25a49894b | |
Алексей Муратов | d9c968cbf4 | |
xaxtix | 4a43f809b3 | |
luvletter2333 | dac6bc4003 | |
luvletter2333 | 159ced5544 | |
luvletter2333 | 0aa89c87be | |
luvletter2333 | b8e0cee4cb | |
luvletter2333 | e8484a26a1 | |
luvletter2333 | 14d60206f5 | |
luvletter2333 | b16412e075 | |
luvletter2333 | 534d30325e | |
luvletter2333 | 5d800050de | |
luvletter2333 | 246e4823ad | |
arm64v8a | e7d45120ba | |
NekoInverter | e7b9b95371 | |
NekoInverter | 9424f76de0 | |
NekoInverter | 4e91347163 | |
xaxtix | dee3203dfa | |
arm64v8a | 3533f7b61e | |
luvletter2333 | d938d7ff9b | |
xaxtix | 3477d72367 | |
xaxtix | dcf1c6d4c3 | |
xaxtix | 64c32ace43 | |
arm64v8a | 6d4984b864 | |
luvletter2333 | 2432283df7 | |
luvletter2333 | 7e6e1498ec | |
luvletter2333 | 5dcfafeca4 | |
luvletter2333 | 334294d683 | |
luvletter2333 | 1e31c91623 | |
luvletter2333 | 2354bc0989 | |
luvletter2333 | 0c3a27f20b | |
luvletter2333 | a6f4408cd7 | |
luvletter2333 | 245eca618b | |
luvletter2333 | 3522b51b18 | |
luvletter2333 | acd5961324 | |
Алексей Муратов | 07ec4d40d5 | |
arm64v8a | 1ec3c9de1a | |
arm64v8a | 04e62a0c0a | |
arm64v8a | 762a7b43be | |
arm64v8a | 657f4bd66c | |
arm64v8a | a5c29444a7 | |
arm64v8a | 1014cfd48d | |
arm64v8a | f4c5e5d919 | |
arm64v8a | 34cc2b6e91 | |
luvletter2333 | 3c8ea5d10b | |
luvletter2333 | fb3a2b88fd | |
luvletter2333 | a8b667084e | |
aarch64 | 9e2f8c6754 | |
luvletter2333 | 59a5b6d633 | |
luvletter2333 | 1c60992a42 | |
arm64v8a | f13d267d32 | |
arm64v8a | d09b2201e5 | |
aarch64 | f7c18a91a4 | |
arm64v8a | 3ff59f4a7d | |
arm64v8a | 158fc41032 | |
proletarius101 | 1081f036c3 | |
proletarius101 | 302e658b0e | |
luvletter2333 | 99c7ba1302 | |
luvletter2333 | fb0a01b4d1 | |
luvletter2333 | 6cb7ce9432 | |
luvletter2333 | 7ae80a380c | |
luvletter2333 | a932196248 | |
luvletter2333 | 087154ed02 | |
arm64v8a | 87e5cb5211 | |
luvletter2333 | 1a384e7819 | |
luvletter2333 | d2e681675d | |
luvletter2333 | 078720aeeb | |
arm64v8a | edd2b3f224 | |
luvletter2333 | 3af0d658e4 | |
luvletter2333 | 6aa2a01b76 | |
luvletter2333 | c245244b29 | |
luvletter2333 | b68bb4932c | |
xaxtix | 23b70a3882 | |
arm64v8a | cb22a70c96 | |
arm64v8a | ca671a7c01 | |
arm64v8a | 4a12bad17c | |
arm64v8a | dd007a01e7 | |
arm64v8a | ddf8e8b7ae | |
arm64v8a | 783aa55c5a | |
arm64v8a | 55edb6bde4 | |
arm64v8a | ac47e574e0 | |
arm64v8a | 3c8781c7de | |
arm64v8a | 4eacbcf38f | |
luvletter2333 | 9dee7ae6d2 | |
luvletter2333 | a097f87677 | |
luvletter2333 | c139e60d06 | |
arm64v8a | 575dc800c2 | |
arm64v8a | a08f0973a4 | |
arm64v8a | dea17045af | |
arm64v8a | 23e1b288b7 | |
xaxtix | 3b971647e2 | |
xaxtix | 44be21dd0f | |
arm64v8a | 28b2b53012 | |
arm64v8a | f3510d25cd | |
arm64v8a | 0637f83540 | |
arm64v8a | 9828ce5de6 | |
arm64v8a | 5696cc55ab | |
arm64v8a | d0bb8abd61 | |
aarch64 | 2ae3c318ef | |
arm64v8a | 771a87b40e | |
arm64v8a | 4471aa430a | |
arm64v8a | ecac2aaa96 | |
arm64v8a | 7a9c83d2b8 | |
arm64v8a | e1098169b6 | |
arm64v8a | 74a2518785 | |
xaxtix | 1d379b9a7b | |
luvletter2333 | 6400ef3a86 | |
luvletter2333 | 6233580e24 | |
arm64v8a | a5ce6c5b91 | |
arm64v8a | 3f4ff5c9ff | |
arm64v8a | c972890ddd | |
Luv Letter | ef0f3cd542 | |
arm64v8a | 099ecfbae1 | |
arm64v8a | bcfbe63b3d | |
arm64v8a | 907f0032ca | |
N | de604298a3 | |
luvletter2333 | 48f9ef024a | |
luvletter2333 | 6aeb6f679e | |
arm64v8a | 837a6543e0 | |
arm64v8a | 11ebf4e639 | |
arm64v8a | 9f288f8999 | |
arm64v8a | eaffdc28ad | |
luvletter2333 | 34c63b4991 | |
luvletter2333 | ef9a38a104 | |
luvletter2333 | af9c719d69 | |
luvletter2333 | 054494a475 | |
arm64v8a | dbc331947f | |
arm64v8a | cf5115cafa | |
arm64v8a | c2bc81ac5a | |
arm64v8a | de5573c5ad | |
aarch64 | 9f686460c2 | |
arm64v8a | 2e9f810e4d | |
arm64v8a | 4ff6df9f9a | |
arm64v8a | c37dfa2831 | |
arm64v8a | 44d546c170 | |
arm64v8a | f4c919d593 | |
arm64v8a | da8d2942f0 | |
arm64v8a | 26f3498957 | |
arm64v8a | d62d686e6c | |
arm64v8a | a60e43c704 | |
arm64v8a | b62eed4c9c | |
arm64v8a | edb9fc5501 | |
arm64v8a | 81c43686ca | |
qwq233 | 9577c1e319 | |
luvletter2333 | d8105a7223 | |
luvletter2333 | d491dd5331 | |
luvletter2333 | 9c31adf0db | |
luvletter2333 | c85b411a3e | |
luvletter2333 | 78a8692a67 | |
luvletter2333 | 77e081f98c | |
luvletter2333 | e4559ae03e | |
luvletter2333 | 97d13b90a4 | |
xaxtix | 09f95ec069 | |
luvletter2333 | 02a95a3ce9 | |
luvletter2333 | a7c1f6958a | |
luvletter2333 | bb58092263 | |
luvletter2333 | 36ed1295c9 | |
luvletter2333 | 99858655f1 | |
luvletter2333 | 6ccaf3ff78 | |
xaxtix | 7e91c949bc | |
xaxtix | 58aded63e9 | |
世界 | a36a9c5980 | |
世界 | 8c0def7556 | |
luvletter2333 | 7cc94fa9ea | |
luvletter2333 | 87a6a5b5e9 | |
luvletter2333 | 219549f0fd | |
luvletter2333 | 5c57c63af0 | |
luvletter2333 | cead4be034 | |
luvletter2333 | d5188d73f9 | |
luvletter2333 | 03db127ae1 | |
luvletter2333 | 972d5b0430 | |
luvletter2333 | b3e16dca87 | |
luvletter2333 | 5ca6f284e4 | |
luvletter2333 | b6c695022e | |
luvletter2333 | 1d25b61d10 | |
luvletter2333 | c063ee58b5 | |
luvletter2333 | 2b1309bb69 | |
luvletter2333 | 0656bd2ef8 | |
luvletter2333 | bcff1d141e | |
luvletter2333 | 2292c48ea1 | |
luvletter2333 | f6d1807fbe | |
luvletter2333 | 65548549fd | |
xaxtix | 42feed0f42 | |
luvletter2333 | 43001f700a | |
xaxtix | 418f478a62 | |
luvletter2333 | af3b235626 | |
luvletter2333 | 8a080aa535 | |
luvletter2333 | 72d85b8a80 | |
luvletter2333 | c62714af5a | |
luvletter2333 | be1c61363e | |
luvletter2333 | 007b632c51 | |
luvletter2333 | 9125d6e0f3 | |
luvletter2333 | 54295812ec | |
luvletter2333 | bb2dff85cd | |
luvletter2333 | 2e99b4e41d | |
luvletter2333 | 986762f504 | |
DrKLO | 368822d20f | |
luvletter2333 | 087c7b850e | |
luvletter2333 | 181fba47ae | |
luvletter2333 | 3cb50b03be | |
luvletter2333 | 87eab8f0df | |
luvletter2333 | 891a10e69c | |
luvletter2333 | 94a130346c | |
luvletter2333 | 50ee1ecd98 | |
luvletter2333 | 31a35ce721 | |
luvletter2333 | f0761cb93c | |
luvletter2333 | df23ecad49 | |
luvletter2333 | ad62860829 | |
luvletter2333 | 5b8479f679 | |
luvletter2333 | cd6cbd8afe | |
luvletter2333 | f527e84247 | |
luvletter2333 | e8179cd090 | |
luvletter2333 | 3822b50f4b | |
luvletter2333 | b30dcf0479 | |
luvletter2333 | 332bd58746 | |
luvletter2333 | f2780a2acc | |
luvletter2333 | f4453c1377 | |
luvletter2333 | d87666c9c1 | |
DrKLO | ab221dafad | |
DrKLO | fc12550efb | |
Riko Sakurauchi | 255bb50555 | |
luvletter2333 | c5989d43ca | |
luvletter2333 | feac2daf64 | |
luvletter2333 | f64b8055e5 | |
luvletter2333 | 256445c91f | |
luvletter2333 | 32097cc6e0 | |
luvletter2333 | 0fd1f7ba12 | |
luvletter2333 | 160d644695 | |
luvletter2333 | 1cc03ad060 | |
DrKLO | 24c6968b8a | |
DrKLO | 3e5d2ba92b | |
luvletter2333 | 5d1583e35b | |
luvletter2333 | e6619a7a0e | |
luvletter2333 | 0f6b02ac5f | |
luvletter2333 | 13e630d832 | |
luvletter2333 | 432ecbe331 | |
luvletter2333 | 717581e722 | |
luvletter2333 | 01aedba9a8 | |
DrKLO | 7a60f948ae | |
luvletter2333 | b0f64e4eb1 | |
luvletter2333 | 17dd08d9ba | |
DrKLO | 3ac3c37dd2 | |
luvletter2333 | 90e8b77849 | |
luvletter2333 | bc6525c56e | |
luvletter2333 | e97bc91323 | |
luvletter2333 | ec29db5acf | |
luvletter2333 | ee12252e5b | |
luvletter2333 | b3f25718b1 | |
luvletter2333 | 4e6ae450c8 | |
luvletter2333 | 6efcbb7bfa | |
luvletter2333 | 76b408ab98 | |
luvletter2333 | a7380ee9f2 | |
luvletter2333 | 37382da6d4 | |
世界 | 865248a9e7 | |
luvletter2333 | 067fe3c18a | |
luvletter2333 | 7814c6514f | |
世界 | cd036ed2ca | |
DrKLO | dd2b001b95 | |
DrKLO | e8d88e56e4 | |
世界 | 8d33950e7d | |
luvletter2333 | 1dbe1e1014 | |
luvletter2333 | 731de1efec | |
luvletter2333 | 28b9fc4fc2 | |
世界 | 47c813ba92 | |
世界 | c20e334ab9 | |
世界 | 0669407f1f | |
世界 | eff7e5e352 | |
世界 | 1c1ebf4c75 | |
世界 | c8b67f359c | |
世界 | 1f553870bf | |
luvletter2333 | f56f434b23 | |
luvletter2333 | e8ff4351be | |
luvletter2333 | 02395f334e | |
Weblate (bot) | 651c396410 | |
luvletter2333 | e213444f35 | |
世界 | 0287857e76 | |
世界 | 5280b740f5 | |
luvletter2333 | 38d78341da | |
世界 | 238e3afb37 | |
世界 | 721e39aa9b | |
世界 | 0b53321c2d | |
世界 | fbe71f4e69 | |
世界 | 28e80df48b | |
世界 | 1b7a765115 | |
luvletter2333 | 33e83cae6b | |
luvletter2333 | 1c6a86b164 | |
luvletter2333 | b47d649861 | |
luvletter2333 | 74fe32e2f8 | |
luvletter2333 | 8154cf501b | |
luvletter2333 | 793fd0d51f | |
luvletter2333 | 85aba5f968 | |
luvletter2333 | 854b68a3c1 | |
luvletter2333 | fa796e34d6 | |
世界 | 71289f6c78 | |
世界 | 06e78c6d1d | |
世界 | 31e606c3a2 | |
世界 | 1c87a98d8a | |
luvletter2333 | 9b727252d1 | |
luvletter2333 | f82978c683 | |
folfdev | e38ef93fad | |
luvletter2333 | 4e07c7f573 | |
luvletter2333 | e0f548e3e0 | |
luvletter2333 | 6cec982eee | |
luvletter2333 | 4da82b928c | |
世界 | 988eb00623 | |
世界 | 614eb41d65 | |
世界 | d1b90f29e6 | |
世界 | 4546cdaaa1 | |
世界 | 22d8712fb0 | |
世界 | 379bac4fef | |
luvletter2333 | e2a5097979 | |
luvletter2333 | 64b9d411cb | |
世界 | e45913c40b | |
世界 | f093096b39 | |
世界 | ec6ae15448 | |
luvletter2333 | 6e80a66573 | |
luvletter2333 | 3d4ab4fb89 | |
DrKLO | a5939ccb34 | |
世界 | c0d06c0065 | |
世界 | ee84a235c8 | |
dependabot-preview[bot] | f60aded53b | |
世界 | 023e6639c4 | |
DrKLO | c4ada53b0d | |
世界 | 024578a13a | |
世界 | f36e97a63a | |
世界 | 044a1bd8b0 | |
世界 | 4fdb6eb283 | |
世界 | e84cae9de1 | |
世界 | aa21a87a10 | |
DrKLO | 8bf056e27b | |
世界 | 9b15e641e5 | |
世界 | 1ba8675f64 | |
世界 | c18c9ac4dc | |
世界 | 91db8f4bd7 | |
世界 | 735fdcf2b8 | |
Weblate (bot) | 2596ecf6ac | |
世界 | 015b1f9086 | |
世界 | 2441154750 | |
世界 | a0bce539d3 | |
世界 | 865e4b9b9a | |
世界 | 3168b0d38f | |
世界 | abb3f31b38 | |
世界 | 7b3f82ac3d | |
世界 | ea31d82c6e | |
世界 | 2c28b02448 | |
世界 | 487b6877dc | |
世界 | 58942794e3 | |
世界 | 5d88b7c83e | |
世界 | ae7023e9d4 | |
世界 | a9a6b72a42 | |
世界 | 1ecfe3a9b0 | |
世界 | 579e722873 | |
世界 | 50d7d66373 | |
世界 | 3562aad367 | |
世界 | 1bdf9da53a | |
世界 | ba6a717ae5 | |
世界 | 543e479b22 | |
dependabot-preview[bot] | 86b3043291 | |
秋のかえで | e84e03224c | |
秋のかえで | 2b27049a51 | |
世界 | 2b1f7bfe81 | |
世界 | 72ec881744 | |
世界 | fcbf91cb4a | |
世界 | f7dbc0df85 | |
世界 | 10decf6b77 | |
世界 | 09aa41e6d3 | |
世界 | 95c574f012 | |
DrKLO | 7ba9838a2d | |
世界 | 1623657bba | |
世界 | e177be18c4 | |
世界 | 0a14723068 | |
世界 | 488723b4a3 | |
世界 | 1c10953868 | |
世界 | 99f45be0d4 | |
世界 | 1b37387043 | |
freetux | 5d67144209 | |
世界 | 165d6ceeff | |
世界 | 567c0e7be5 | |
dependabot-preview[bot] | 60c815ae2a | |
freetux | e3e97e9e0d | |
世界 | 95f268ed02 | |
世界 | d6e45e0e0d | |
herotux | a320bfe14b | |
世界 | c6ce1a5988 | |
世界 | ede59575b4 | |
世界 | b3fb6381b7 | |
herotux | 53bc1b0bbe | |
世界 | 3b39eed879 | |
世界 | 8b0a6ba576 | |
世界 | 2db9ec8767 | |
luvletter2333 | b47167982a | |
luvletter2333 | 61243e461b | |
luvletter2333 | 9ad38d5956 | |
Weblate (bot) | 36f3f6038d | |
世界 | a418baea30 | |
世界 | 204364d787 | |
luvletter2333 | 770715234c | |
世界 | 8967508df4 | |
世界 | 5d7c4e7d01 | |
luvletter2333 | 7e876b20e3 | |
世界 | cadc7b5758 | |
Weblate (bot) | d5a13f87e0 | |
世界 | e6f1b563ef | |
dependabot-preview[bot] | d2e17bb656 | |
dependabot-preview[bot] | 4cb7ae0a49 | |
世界 | 68a7e5a51b | |
世界 | f15f5f10de | |
世界 | 1ebdde0cb4 | |
世界 | 462edddba6 | |
世界 | d5e3001135 | |
dependabot-preview[bot] | 7d41995d13 | |
luvletter2333 | 870fab1a9a | |
luvletter2333 | d5143cd276 | |
luvletter2333 | 9560a1f58d | |
tehcneko | df00b507b3 | |
luvletter2333 | a9a93732c3 | |
Weblate (bot) | 65732dcea4 | |
世界 | 8d60277298 | |
世界 | 352eafcb9e | |
世界 | d56dc04314 | |
世界 | 06873276ec | |
世界 | 1cf953005b | |
luvletter2333 | cf6fd70fac | |
世界 | 0f070914df | |
世界 | e62ba018b6 | |
世界 | 9f9bb21d62 | |
世界 | 0a96b0c061 | |
世界 | 8e583128e4 | |
世界 | 6770e0fe3f | |
世界 | 1baae62f97 | |
luvletter2333 | 3b673baacf | |
世界 | 6da2d1167f | |
世界 | 75f5a5e43e | |
世界 | 28301ad426 | |
Weblate (bot) | cd182b1b07 | |
世界 | 973b11ee60 | |
世界 | 18fc50b9eb | |
世界 | c483b0f616 | |
世界 | b21d0c7280 | |
世界 | cd8073f605 | |
Weblate (bot) | a12215d6aa | |
世界 | 0d8e32f95f | |
世界 | be7a415a03 | |
DrKLO | ca13bc972d | |
世界 | 2cec79e12e | |
世界 | 81d0af640f | |
世界 | 6513842f1c | |
世界 | 4a9856da36 | |
世界 | 8363772ce5 | |
世界 | b053ce66d8 | |
世界 | 6798c1a2c2 | |
世界 | 5978900bec | |
世界 | 9ac96c40a5 | |
世界 | 576ccf6c19 | |
luvletter2333 | 77c8d8ed37 | |
世界 | 6acd0f6ebe | |
世界 | 748ac2252d | |
世界 | 850f3f7d2c | |
世界 | 7fff3339ca | |
世界 | 8007d57bec | |
世界 | 3baedb37f2 | |
世界 | 4ef352adfd | |
luvletter2333 | 02a25e368c | |
世界 | c8a61434fa | |
Weblate (bot) | c765012eb3 | |
世界 | 2fc53585d9 | |
世界 | 9c10d75bdf | |
世界 | b30bc1ed80 | |
世界 | aadfcb7e96 | |
世界 | 7f8ca21868 | |
世界 | f6ba45836a | |
世界 | f31999e653 | |
世界 | 83278a4d76 | |
世界 | b17d97b8e4 | |
世界 | d367b863f1 | |
世界 | 629593bf19 | |
世界 | a0efbf7776 | |
Weblate (bot) | 25e1c271fa | |
世界 | b4b67aa8f3 | |
世界 | 307f701bd3 | |
Luv Letter | 5be149a76e | |
世界 | 232a7dc812 | |
世界 | c9b3656089 | |
Weblate (bot) | 1c2405fd8c | |
世界 | b89be7f504 | |
世界 | 11de01f3ae | |
世界 | 9b2f136ac0 | |
世界 | 55b094742f | |
Weblate (bot) | 6f59540ec3 | |
世界 | 6ebcd5dd3d | |
世界 | a6c0bca680 | |
世界 | e01fe0d361 | |
世界 | a2fb6ad09a | |
世界 | 211e521e85 | |
世界 | 56c45fc5c1 | |
tehcneko | 368ab7ab8b | |
23rd | 2dd69697cb | |
世界 | 2b7a6229fc | |
世界 | 2d1e4b2013 | |
世界 | a63c76fa8b | |
世界 | ec1bf51f21 | |
世界 | ac3cd25765 | |
世界 | bda178a833 | |
世界 | cee746ad11 | |
世界 | b8728ea742 | |
世界 | c1eba3ecfe | |
世界 | 8be6130ffe | |
世界 | 82b789b78b | |
世界 | b3ede707b5 | |
世界 | 5a2184d411 | |
世界 | 5a5e602bc7 | |
世界 | f0e45007d1 | |
世界 | b033b6d704 | |
世界 | e20cc7426a | |
世界 | 210b1e2aae | |
世界 | 1fc5975e76 | |
世界 | 510b8d05d9 | |
世界 | 69a40d7258 | |
DrKLO | e1c101c334 | |
世界 | cc6d2d278c | |
世界 | 535f946239 | |
世界 | bca990b9e7 | |
世界 | b700ee2967 | |
世界 | 2ce54d1bac | |
世界 | 8f08d090c5 | |
世界 | 5efb0b1ad9 | |
DrKLO | c44841a55b | |
世界 | 7a0ddf096b | |
世界 | 99783dd511 | |
世界 | 64f9152f8a | |
世界 | 5c75f74b1d | |
世界 | 2b8b83f506 | |
DrKLO | 31b580133f | |
DrKLO | 92cfded3fc | |
世界 | 5ff717d494 | |
世界 | 9ae71d521a | |
世界 | 68a544914d | |
世界 | a9c96bca07 | |
世界 | dcf7b7854f | |
世界 | 96533f6c2a | |
世界 | c15c13ecc2 | |
世界 | 62f4b4a037 | |
世界 | 2df1f59d7a | |
世界 | 01e8c8c64c | |
世界 | be2516ccd7 | |
世界 | b128aca4cb | |
世界 | 7fbadfe09a | |
世界 | 4611743ef3 | |
世界 | 06df6a63dd | |
世界 | bc2261efd9 | |
世界 | 8f9ef0ba91 | |
世界 | 2952673a25 | |
世界 | 94d985c679 | |
世界 | e954b7fd2e | |
世界 | 52fc46a0d5 | |
世界 | 7394c6df07 | |
世界 | 9814510f8e | |
世界 | fcc1d76006 | |
世界 | 62bc6c4aea | |
世界 | e432b75ff6 | |
世界 | 04f8f5cf29 | |
世界 | abdcfc28d8 | |
世界 | 5a2b2430a4 | |
世界 | f46e76399b | |
世界 | 5162f72215 | |
世界 | 9229bf7b91 | |
世界 | 3587c48fec | |
世界 | 7eac5f48ef | |
世界 | e7bf596501 | |
世界 | b9624d14c6 | |
世界 | 3146a49afd | |
世界 | 1a2569bad4 | |
世界 | e85a773906 | |
世界 | 2debb39e74 | |
世界 | 34a97553dd | |
世界 | 56c53abcc4 | |
世界 | ada851e69b | |
世界 | 75eff5aa7f | |
世界 | b54a41dc6c | |
世界 | 3b9f39167f | |
世界 | e3d67c0f7e | |
世界 | 163b422db1 | |
世界 | 20606ea25e | |
世界 | bb0a1720a7 | |
DrKLO | 3480f19272 | |
世界 | db70486fae | |
DrKLO | eb2bbd32c1 | |
NekoInverter | c7211b912d | |
NekoInverter | 09f6eff406 | |
世界 | bb0e10e3dc | |
世界 | bbc106c2fe | |
DrKLO | fed0c139e7 | |
世界 | c7f786a112 | |
DrKLO | eb94e31b4c | |
DrKLO | 77bbe5baec | |
世界 | b3cf9f3cbb | |
世界 | 1144b9e24e | |
世界 | 92c74bbc21 | |
世界 | fba981b99f |
|
@ -1 +1,2 @@
|
|||
patreon: NekoXDev
|
||||
open_collective: nekox
|
||||
liberapay: nekohasekai
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
name: Language builtin request
|
||||
about: Request to amend the built-in translation
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Language (please complete the following information):**
|
||||
- Language: [e.g. en_US]
|
||||
- Pack Link: [e.g. https://translations.telegram.org/en/]
|
||||
|
||||
**If the language has already been built in, please describe the reason for the replacement:**
|
||||
e.g. The language pack is no longer maintained / The original meaning is modified
|
Binary file not shown.
After Width: | Height: | Size: 178 KiB |
|
@ -0,0 +1,164 @@
|
|||
import requests
|
||||
import sys
|
||||
import os
|
||||
|
||||
def read_env(key):
|
||||
if key in os.environ:
|
||||
return os.environ[key]
|
||||
else:
|
||||
print(f"failed to read env {key}")
|
||||
return ""
|
||||
|
||||
APK_FOLDER = "apks"
|
||||
API_PREFIX = "http://127.0.0.1:38118/bot" + os.environ["BOT_TOKEN"] + "/"
|
||||
|
||||
BOT_TARGET = read_env("BOT_TARGET")
|
||||
ADMIN_USERID = BOT_TARGET.replace("-100","")
|
||||
|
||||
VERSION_NAME = read_env("VERSION_NAME")
|
||||
VERSION_CODE = read_env("VERSION_CODE")
|
||||
COMMIT_HASH = read_env("GITHUB_SHA")
|
||||
COMMIT_MESSAGE = read_env("COMMIT_MESSAGE")
|
||||
|
||||
APK_CHANNEL_ID = "@NekoXApks"
|
||||
UPDATE_CHANNEL_ID = "@NekogramX"
|
||||
UPDATE_METADATA_CHANNEL_ID = "@nekox_update_metadata"
|
||||
CI_CHANNEL_ID = "@NekoX_CI"
|
||||
|
||||
|
||||
def addEntity(entities, origin_str, en_type, content, url = None) -> str:
|
||||
origin_len = len(origin_str)
|
||||
entity = {
|
||||
"type": en_type,
|
||||
"offset": origin_len,
|
||||
"length": len(content)
|
||||
}
|
||||
if url:
|
||||
entity["url"] = url
|
||||
entities.append(entity)
|
||||
return content
|
||||
|
||||
|
||||
def waitReply(mid):
|
||||
last_update = 0
|
||||
while True:
|
||||
print(f"Waiting reply for {mid} offset {last_update}...")
|
||||
resp = requests.post(API_PREFIX + "getUpdates", json={"allowed_updates":["message"], "timeout": 20, "offset": last_update + 1})
|
||||
resp = resp.json()
|
||||
if not resp["ok"]:
|
||||
continue
|
||||
resp = resp["result"]
|
||||
for update in resp:
|
||||
if 'message' in update:
|
||||
msg = update["message"]
|
||||
if 'from' in msg and str(msg['from']["id"]) == ADMIN_USERID:
|
||||
if 'reply_to_message' in msg and str(msg["reply_to_message"]["message_id"]) == str(mid):
|
||||
return msg
|
||||
for update in resp:
|
||||
last_update = max(last_update, update["update_id"])
|
||||
|
||||
|
||||
def sendMessage(message, user_id = BOT_TARGET, entities = None) -> int:
|
||||
data = {
|
||||
"chat_id" : user_id,
|
||||
"text": message,
|
||||
"entities": entities
|
||||
}
|
||||
print(message)
|
||||
print(entities)
|
||||
resp = requests.post(API_PREFIX + "sendMessage", json=data).json()
|
||||
print(resp)
|
||||
return int(resp["result"]["message_id"])
|
||||
|
||||
|
||||
def sendDocument(user_id, path, message = "", entities = None):
|
||||
files = {'document': open(path, 'rb')}
|
||||
data = {'chat_id': user_id,
|
||||
'caption': message,
|
||||
'parse_mode': 'Markdown',
|
||||
'caption_entities': entities}
|
||||
response = requests.post(API_PREFIX + "sendDocument", files=files, data=data)
|
||||
print(response.json())
|
||||
|
||||
|
||||
def sendRelease():
|
||||
apks = os.listdir(APK_FOLDER)
|
||||
apks.sort()
|
||||
print(apks)
|
||||
|
||||
# read message from admin
|
||||
mid = sendMessage(f"Please reply the release message for the version {VERSION_NAME},{VERSION_CODE}:", user_id=BOT_TARGET)
|
||||
admin_resp = waitReply(mid)
|
||||
|
||||
# send message and apks to APK channel
|
||||
message = f"=== {VERSION_NAME} ==="
|
||||
apk_channel_first_id = sendMessage(message, user_id=APK_CHANNEL_ID)
|
||||
|
||||
for apk in apks:
|
||||
path = os.path.join(APK_FOLDER, apk)
|
||||
sendDocument(user_id=APK_CHANNEL_ID, path=path)
|
||||
|
||||
# generate release message and send to update channel
|
||||
entities = []
|
||||
text = ""
|
||||
text += addEntity(entities, text, "hashtag", f"#{'PRE_RELEASE' if 'preview' in VERSION_NAME else 'RELEASE'}")
|
||||
text += " "
|
||||
text += addEntity(entities, text, "text_link", " ", f'https://t.me/{APK_CHANNEL_ID.replace("@","")}/{apk_channel_first_id + 1}')
|
||||
text += " "
|
||||
text += addEntity(entities, text, "bold", VERSION_NAME)
|
||||
text += "\n\n"
|
||||
if "entities" not in admin_resp:
|
||||
admin_resp["entities"] = list()
|
||||
resp_entities = admin_resp["entities"]
|
||||
for en in resp_entities:
|
||||
copy = en.copy()
|
||||
copy["offset"] += len(text)
|
||||
entities.append(copy)
|
||||
text += admin_resp["text"]
|
||||
text += "\n\n"
|
||||
text += addEntity(entities, text, "text_link", "GitHub Release", f"https://github.com/NekoX-Dev/NekoX/releases/{VERSION_NAME}")
|
||||
text += " | "
|
||||
text += addEntity(entities, text, "text_link", "Apks", f'https://t.me/{APK_CHANNEL_ID.replace("@","")}/{apk_channel_first_id}')
|
||||
text += " | "
|
||||
text += addEntity(entities, text, "text_link", "Check Update", "tg://update/")
|
||||
|
||||
sendMessage(text, user_id=UPDATE_CHANNEL_ID, entities=entities)
|
||||
|
||||
# send release message to metadata channel
|
||||
mid = sendMessage(admin_resp["text"], user_id=UPDATE_METADATA_CHANNEL_ID, entities=admin_resp["entities"])
|
||||
meta_msg = f"{VERSION_NAME},{VERSION_CODE},{apk_channel_first_id},{mid}"
|
||||
sendMessage(meta_msg, user_id=UPDATE_METADATA_CHANNEL_ID)
|
||||
|
||||
|
||||
def sendCIRelease():
|
||||
apks = os.listdir(APK_FOLDER)
|
||||
apks.sort()
|
||||
apk = os.path.join(APK_FOLDER, apks[0])
|
||||
entities = []
|
||||
message = f"CI Build\n\n{COMMIT_MESSAGE}\n\n"
|
||||
message += addEntity(entities, message, "text_link", COMMIT_HASH[0:8], f"https://github.com/NekoX-Dev/NekoX/commit/{COMMIT_HASH}")
|
||||
sendDocument(user_id=CI_CHANNEL_ID, path = apk, message=message, )
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(sys.argv)
|
||||
if len(sys.argv) != 2:
|
||||
print("Run Type: release, ci, debug")
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
exit(1)
|
||||
mode = sys.argv[1]
|
||||
if mode == "release":
|
||||
sendRelease()
|
||||
elif mode == "ci":
|
||||
if COMMIT_MESSAGE.startswith("ci"):
|
||||
CI_CHANNEL_ID = BOT_TARGET
|
||||
sendCIRelease()
|
||||
elif mode == "debug":
|
||||
APK_CHANNEL_ID = "@test_channel_nekox"
|
||||
UPDATE_CHANNEL_ID = "@test_channel_nekox"
|
||||
UPDATE_METADATA_CHANNEL_ID = "@test_channel_nekox"
|
||||
sendRelease()
|
||||
else:
|
||||
print("unknown mode")
|
||||
|
|
@ -0,0 +1,533 @@
|
|||
name: Debug build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/debug.yml'
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
artifacts:
|
||||
description: 'y, if need artifacts'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
ffmpeg:
|
||||
name: Native Build (FFmpeg)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/libvpx > libvpx_status
|
||||
- name: FFmpeg Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/ffmpeg/build
|
||||
TMessagesProj/jni/libvpx/build
|
||||
key: ${{ hashFiles('ffmpeg_status', 'libvpx_status', 'TMessagesProj/jni/*ffmpeg*.sh', 'TMessagesProj/jni/*libvpx*.sh', 'TMessagesProj/jni/patches/ffmpeg/*') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get install yasm -y
|
||||
./run init libs libvpx
|
||||
./run init libs ffmpeg
|
||||
boringssl:
|
||||
name: Native Build (BoringSSL)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
- name: BoringSSL Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/boringssl/build
|
||||
key: ${{ hashFiles('boringssl_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
./run init action boringssl
|
||||
./run init libs boringssl
|
||||
native:
|
||||
name: Native Build (Telegram)
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- ffmpeg
|
||||
- boringssl
|
||||
strategy:
|
||||
matrix:
|
||||
flavor:
|
||||
- armeabi-v7a
|
||||
- arm64-v8a
|
||||
- x86
|
||||
- x86_64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/libvpx > libvpx_status
|
||||
git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
- name: Native Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-${{ matrix.flavor }}
|
||||
- name: Checkout Library
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git submodule update --init 'TMessagesProj/jni/*'
|
||||
- name: FFmpeg Cache
|
||||
uses: actions/cache@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/ffmpeg/build
|
||||
TMessagesProj/jni/libvpx/build
|
||||
key: ${{ hashFiles('ffmpeg_status', 'libvpx_status', 'TMessagesProj/jni/*ffmpeg*.sh', 'TMessagesProj/jni/*libvpx*.sh', 'TMessagesProj/jni/patches/ffmpeg/*') }}
|
||||
- name: BoringSSL Cache
|
||||
uses: actions/cache@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/boringssl/build
|
||||
key: ${{ hashFiles('boringssl_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Fix BoringSSL
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd TMessagesProj/jni
|
||||
./patch_boringssl.sh
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
export NATIVE_TARGET="${{ matrix.flavor }}"
|
||||
./run libs native
|
||||
v2ray:
|
||||
name: Native Build (V2ray)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status v2ray > v2ray_status
|
||||
- name: V2ray Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/libv2ray.aar
|
||||
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Install Golang
|
||||
uses: actions/setup-go@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
go-version: 1.16
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run libs v2ray
|
||||
shadowsocks:
|
||||
name: Native Build (Shadowsocks)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
|
||||
- name: Shadowsocks Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ss-rust-release.aar
|
||||
key: ${{ hashFiles('shadowsocks_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Install Rust
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run init action shadowsocks
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run libs shadowsocks
|
||||
shadowsocksr:
|
||||
name: Native Build (ShadowsocksR)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status 'ssr-libev/*' > shadowsocksr_status
|
||||
- name: ShadowsocksR Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ssr-libev-release.aar
|
||||
key: ${{ hashFiles('shadowsocksr_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run libs ssr
|
||||
build:
|
||||
name: Gradle Build
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- native
|
||||
- v2ray
|
||||
- shadowsocks
|
||||
- shadowsocksr
|
||||
strategy:
|
||||
matrix:
|
||||
flavor:
|
||||
- MiniRelease
|
||||
- MiniReleaseNoGcm
|
||||
- FullRelease
|
||||
- FullReleaseNoGcm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Install NDK
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
|
||||
git submodule status 'ssr-libev/*' > shadowsocksr_status
|
||||
git submodule status v2ray > v2ray_status
|
||||
- name: Native Cache (armeabi-v7a)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-armeabi-v7a
|
||||
- name: Native Cache (arm64-v8a)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-arm64-v8a
|
||||
- name: Native Cache (x86)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86
|
||||
- name: Native Cache (x86_64)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86_64
|
||||
- name: V2ray Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/libv2ray.aar
|
||||
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
|
||||
- name: Shadowsocks Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ss-rust-release.aar
|
||||
key: ${{ hashFiles('shadowsocks_status') }}
|
||||
- name: ShadowsocksR Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ssr-libev-release.aar
|
||||
key: ${{ hashFiles('shadowsocksr_status') }}
|
||||
- name: Configure Gradle
|
||||
run: |
|
||||
sed -i -e "s/16384/6144/g" gradle.properties
|
||||
echo "sdk.dir=${ANDROID_HOME}" >> local.properties
|
||||
# echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" >> local.properties
|
||||
- name: Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle
|
||||
key: gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Debug Build
|
||||
run: |
|
||||
export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}"
|
||||
export DEBUG_BUILD=true
|
||||
./gradlew TMessagesProj:assemble${{ matrix.flavor }}
|
||||
|
||||
echo "APK_FILE=$(find TMessagesProj/build/outputs/apk -name '*arm64-v8a*.apk')" >> $GITHUB_ENV
|
||||
echo "APK_FILE_ARMV7=$(find TMessagesProj/build/outputs/apk -name '*armeabi*.apk')" >> $GITHUB_ENV
|
||||
echo "APK_FILE_X86=$(find TMessagesProj/build/outputs/apk -name '*x86-*.apk')" >> $GITHUB_ENV
|
||||
echo "APK_FILE_X64=$(find TMessagesProj/build/outputs/apk -name '*x86_64*.apk')" >> $GITHUB_ENV
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: github.event.inputs.artifacts == 'y'
|
||||
name: Upload apk (arm64-v8a)
|
||||
with:
|
||||
name: NekoX-${{ matrix.flavor }}-arm64-v8a
|
||||
path: ${{ env.APK_FILE }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: github.event.inputs.artifacts == 'y'
|
||||
name: Upload apk (armeabi-v7a)
|
||||
with:
|
||||
name: NekoX-${{ matrix.flavor }}-armeabi-v7a
|
||||
path: ${{ env.APK_FILE_ARMV7 }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: github.event.inputs.artifacts == 'y'
|
||||
name: Upload apk (x86_64)
|
||||
with:
|
||||
name: NekoX-${{ matrix.flavor }}-x86_64
|
||||
path: ${{ env.APK_FILE_X64 }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: github.event.inputs.artifacts == 'y'
|
||||
name: Upload apk (x86)
|
||||
with:
|
||||
name: NekoX-${{ matrix.flavor }}-x86
|
||||
path: ${{ env.APK_FILE_X86 }}
|
||||
|
||||
build-dev:
|
||||
name: Gradle Build
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' && success() }}
|
||||
needs:
|
||||
- native
|
||||
- v2ray
|
||||
- telegram-bot-api
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Install NDK
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
|
||||
git submodule status 'ssr-libev/*' > shadowsocksr_status
|
||||
git submodule status v2ray > v2ray_status
|
||||
- name: Native Cache (armeabi-v7a)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-armeabi-v7a
|
||||
- name: Native Cache (arm64-v8a)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-arm64-v8a
|
||||
- name: Native Cache (x86)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86
|
||||
- name: Native Cache (x86_64)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86_64
|
||||
- name: V2ray Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/libv2ray.aar
|
||||
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
|
||||
- name: Build Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/build
|
||||
TMessagesProj/.cxx
|
||||
ss-rust/build
|
||||
ssr-rust/build
|
||||
openpgp-api/build
|
||||
key: build-cache
|
||||
- name: Configure Gradle
|
||||
run: |
|
||||
sed -i -e "s/16384/6144/g" gradle.properties
|
||||
echo "sdk.dir=${ANDROID_HOME}" >> local.properties
|
||||
# echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" >> local.properties
|
||||
- name: Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle
|
||||
key: gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Download Telegram Bot API Binary
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: telegram-bot-api-binary
|
||||
path: .
|
||||
- name: CI Build
|
||||
run: |
|
||||
export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}"
|
||||
export DEBUG_BUILD=true
|
||||
export NATIVE_TARGET=universal
|
||||
./gradlew TMessagesProj:assembleMiniRelease
|
||||
|
||||
APK=$(find TMessagesProj/build/outputs/apk/mini/release -name 'NekoX*.apk')
|
||||
echo "APK=$APK" >> $GITHUB_ENV
|
||||
VERSION_CODE=$(grep -E "def verCode = ([0-9]+)" TMessagesProj/build.gradle | sed "s/def verCode = //")
|
||||
VERSION_NAME=$(grep -E "def verName = " TMessagesProj/build.gradle | sed "s/def verName = //" | sed "s/\"//g")
|
||||
echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
|
||||
echo "VERSION_NAME=VERSION_NAME" >> $GITHUB_ENV
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ci-apk
|
||||
path: ${{ env.APK }}
|
||||
upload:
|
||||
name: Upload Apks to Telegram
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build-dev
|
||||
- telegram-bot-api
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: ci-apk
|
||||
path: apks
|
||||
- name: Download Telegram Bot API Binary
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: telegram-bot-api-binary
|
||||
path: .
|
||||
- name: Install Python Environment
|
||||
run: |
|
||||
sudo apt install python3 python3-pip -y
|
||||
pip3 install requests
|
||||
- name: Prepare Upload
|
||||
run: |
|
||||
chmod +x telegram-bot-api-binary
|
||||
function start() {
|
||||
./telegram-bot-api-binary --api-id=21724 --api-hash=3e0cb5efcd52300aec5994fdfc5bdc16 -p 38118 --local 2>&1 > /dev/null &
|
||||
sleep 5
|
||||
}
|
||||
start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
- name: Upload
|
||||
run: |
|
||||
curl https://raw.githubusercontent.com/NekoX-Dev/NekoX/dev/.github/scripts/upload.py -o upload.py
|
||||
|
||||
export BOT_TOKEN="${{ secrets.HELPER_BOT_TOKEN }}"
|
||||
export BOT_TARGET="${{ secrets.HELPER_BOT_TARGET }}"
|
||||
export COMMIT_MESSAGE="${{ github.event.head_commit.message }}"
|
||||
|
||||
python3 upload.py ci
|
||||
|
||||
pkill telegram-bot
|
||||
|
||||
telegram-bot-api:
|
||||
name: Telegram Bot API
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Clone Telegram Bot API
|
||||
run: |
|
||||
git clone --recursive https://github.com/tdlib/telegram-bot-api.git
|
||||
git status telegram-bot-api >> telegram-bot-api-status
|
||||
- name: Cache Bot API Binary
|
||||
id: cache-bot-api
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: telegram-bot-api-binary
|
||||
key: CI-telegram-bot-api-${{ hashFiles('telegram-bot-api-status') }}
|
||||
- name: Compile Telegram Bot API
|
||||
if: steps.cache-bot-api.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install make git zlib1g-dev libssl-dev gperf cmake g++
|
||||
cd telegram-bot-api
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=.. ..
|
||||
cmake --build . --target install -j$(nproc)
|
||||
cd ../..
|
||||
ls -l telegram-bot-api/bin/telegram-bot-api*
|
||||
cp telegram-bot-api/bin/telegram-bot-api telegram-bot-api-binary
|
||||
- name: Upload Binary
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: telegram-bot-api-binary
|
||||
path: telegram-bot-api-binary
|
|
@ -0,0 +1,445 @@
|
|||
name: Release Build
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release Tag'
|
||||
required: true
|
||||
play:
|
||||
description: 'Play: If want ignore'
|
||||
required: false
|
||||
upload:
|
||||
description: 'Upload: If want ignore'
|
||||
required: false
|
||||
publish:
|
||||
description: 'Publish: If want ignore'
|
||||
required: false
|
||||
jobs:
|
||||
check:
|
||||
name: Check Access
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Check access"
|
||||
uses: "lannonbr/repo-permission-check-action@2.0.0"
|
||||
with:
|
||||
permission: "write"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ffmpeg:
|
||||
name: Native Build (FFmpeg)
|
||||
runs-on: ubuntu-latest
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/libvpx > libvpx_status
|
||||
- name: FFmpeg Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/ffmpeg/build
|
||||
TMessagesProj/jni/libvpx/build
|
||||
key: ${{ hashFiles('ffmpeg_status', 'libvpx_status', 'TMessagesProj/jni/*ffmpeg*.sh', 'TMessagesProj/jni/*libvpx*.sh', 'TMessagesProj/jni/patches/ffmpeg/*') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get install yasm -y
|
||||
./run init libs libvpx
|
||||
./run init libs ffmpeg
|
||||
boringssl:
|
||||
name: Native Build (BoringSSL)
|
||||
runs-on: ubuntu-latest
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
- name: BoringSSL Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/boringssl/build
|
||||
key: ${{ hashFiles('boringssl_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
./run init action boringssl
|
||||
./run init libs boringssl
|
||||
native:
|
||||
name: Native Build (Telegram)
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- ffmpeg
|
||||
- boringssl
|
||||
strategy:
|
||||
matrix:
|
||||
flavor:
|
||||
- armeabi-v7a
|
||||
- arm64-v8a
|
||||
- x86
|
||||
- x86_64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/libvpx > libvpx_status
|
||||
git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
- name: Native Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-${{ matrix.flavor }}
|
||||
- name: Checkout Library
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git submodule update --init 'TMessagesProj/jni/*'
|
||||
- name: FFmpeg Cache
|
||||
uses: actions/cache@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/ffmpeg/build
|
||||
TMessagesProj/jni/libvpx/build
|
||||
key: ${{ hashFiles('ffmpeg_status', 'libvpx_status', 'TMessagesProj/jni/*ffmpeg*.sh', 'TMessagesProj/jni/*libvpx*.sh', 'TMessagesProj/jni/patches/ffmpeg/*') }}
|
||||
- name: BoringSSL Cache
|
||||
uses: actions/cache@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/jni/boringssl/build
|
||||
key: ${{ hashFiles('boringssl_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Fix BoringSSL
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd TMessagesProj/jni
|
||||
./patch_boringssl.sh
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
export NATIVE_TARGET="${{ matrix.flavor }}"
|
||||
./run libs native
|
||||
v2ray:
|
||||
name: Native Build (V2ray)
|
||||
runs-on: ubuntu-latest
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status v2ray > v2ray_status
|
||||
- name: V2ray Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/libv2ray.aar
|
||||
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Install Golang
|
||||
uses: actions/setup-go@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
go-version: 1.16
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run libs v2ray
|
||||
shadowsocks:
|
||||
name: Native Build (Shadowsocks)
|
||||
runs-on: ubuntu-latest
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
|
||||
- name: Shadowsocks Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ss-rust-release.aar
|
||||
key: ${{ hashFiles('shadowsocks_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Install Rust
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run init action shadowsocks
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run libs shadowsocks
|
||||
shadowsocksr:
|
||||
name: Native Build (ShadowsocksR)
|
||||
runs-on: ubuntu-latest
|
||||
needs: check
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Fetch Status
|
||||
run: git submodule status 'ssr-libev/*' > shadowsocksr_status
|
||||
- name: ShadowsocksR Cache
|
||||
id: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ssr-libev-release.aar
|
||||
key: ${{ hashFiles('shadowsocksr_status') }}
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
- name: Install NDK
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Native Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: ./run libs ssr
|
||||
build:
|
||||
name: Gradle Build
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- native
|
||||
- v2ray
|
||||
- shadowsocks
|
||||
- shadowsocksr
|
||||
strategy:
|
||||
matrix:
|
||||
flavor:
|
||||
- FullRelease
|
||||
- FullReleaseNoGcm
|
||||
- MiniRelease
|
||||
- MiniReleaseNoGcm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Android SDK Tools
|
||||
uses: android-actions/setup-android@v2
|
||||
- name: Install NDK
|
||||
run: |
|
||||
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
|
||||
echo "sdk.dir=${ANDROID_HOME}" > local.properties
|
||||
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
|
||||
- name: Fetch Status
|
||||
run: |
|
||||
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
|
||||
git submodule status TMessagesProj/jni/boringssl > boringssl_status
|
||||
git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
|
||||
git submodule status 'ssr-libev/*' > shadowsocksr_status
|
||||
git submodule status v2ray > v2ray_status
|
||||
- name: Native Cache (armeabi-v7a)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-armeabi-v7a
|
||||
- name: Native Cache (arm64-v8a)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-arm64-v8a
|
||||
- name: Native Cache (x86)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86
|
||||
- name: Native Cache (x86_64)
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/src/main/libs
|
||||
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86_64
|
||||
- name: V2ray Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/libv2ray.aar
|
||||
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
|
||||
- name: Shadowsocks Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ss-rust-release.aar
|
||||
key: ${{ hashFiles('shadowsocks_status') }}
|
||||
- name: ShadowsocksR Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
TMessagesProj/libs/ssr-libev-release.aar
|
||||
key: ${{ hashFiles('shadowsocksr_status') }}
|
||||
- name: Fix Gradle Memoery
|
||||
run: |
|
||||
sed -i -e "s/16384/6144/g" gradle.properties
|
||||
# echo "ndk.dir=${ANDROID_HOME}/ndk-bundle" > local.properties
|
||||
- name: Gradle cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle
|
||||
key: gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Release Build
|
||||
run: |
|
||||
export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}"
|
||||
./gradlew TMessagesProj:assemble${{ matrix.flavor }}
|
||||
|
||||
APK=$(find TMessagesProj/build/outputs/apk -name '*arm64-v8a*.apk')
|
||||
APK=$(dirname $APK)
|
||||
echo "APK=$APK" >> $GITHUB_ENV
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.flavor }}
|
||||
path: ${{ env.APK }}
|
||||
publish:
|
||||
name: Publish Release
|
||||
if: github.event.inputs.publish != 'y'
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Donwload Artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
run: |
|
||||
wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz
|
||||
tar -xvf ghr.tar.gz
|
||||
mv ghr*linux_amd64/ghr .
|
||||
mkdir apks
|
||||
find artifacts -name "*.apk" -exec cp {} apks \;
|
||||
./ghr -delete -t "${{ github.token }}" -n "${{ github.event.inputs.tag }}" "${{ github.event.inputs.tag }}" apks
|
||||
upload:
|
||||
name: Upload Release
|
||||
if: github.event.inputs.upload != 'y'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
- telegram-bot-api
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Download Telegram Bot API Binary
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: telegram-bot-api-binary
|
||||
path: .
|
||||
- name: Prepare Upload
|
||||
run: |
|
||||
chmod +x telegram-bot-api-binary
|
||||
function start() {
|
||||
./telegram-bot-api-binary -p 38118 --api-id=21724 --api-hash=3e0cb5efcd52300aec5994fdfc5bdc16 --local 2>&1 > /dev/null &
|
||||
sleep 5
|
||||
}
|
||||
start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
curl http://127.0.0.1:38118/ || start
|
||||
- name: Upload
|
||||
run: |
|
||||
mkdir apks
|
||||
find artifacts -name "*.apk" -exec cp {} apks \;
|
||||
curl https://raw.githubusercontent.com/NekoX-Dev/NekoX/dev/.github/scripts/upload.py -o upload.py
|
||||
export BOT_TOKEN="${{ secrets.HELPER_BOT_TOKEN }}"
|
||||
export BOT_TARGET="${{ secrets.HELPER_BOT_TARGET }}"
|
||||
export VERSION_CODE="$(grep -E "def verCode = ([0-9]+)" TMessagesProj/build.gradle | sed "s/def verCode = //")"
|
||||
export VERSION_NAME="$(grep -E "def verName = " TMessagesProj/build.gradle | sed "s/def verName = //" | sed "s/\"//g")"
|
||||
python3 upload.py release
|
||||
pkill telegram-bot
|
||||
- name: Setup upterm session
|
||||
uses: lhotari/action-upterm@v1
|
||||
with:
|
||||
limit-access-to-users: luvletter2333
|
||||
|
||||
telegram-bot-api:
|
||||
name: Telegram Bot API
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Clone Telegram Bot API
|
||||
run: |
|
||||
git clone --recursive https://github.com/tdlib/telegram-bot-api.git
|
||||
git status telegram-bot-api >> telegram-bot-api-status
|
||||
- name: Cache Bot API Binary
|
||||
id: cache-bot-api
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: telegram-bot-api-binary
|
||||
key: CI-telegram-bot-api-${{ hashFiles('telegram-bot-api-status') }}
|
||||
- name: Compile Telegram Bot API
|
||||
if: steps.cache-bot-api.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install make git zlib1g-dev libssl-dev gperf cmake g++
|
||||
cd telegram-bot-api
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=.. ..
|
||||
cmake --build . --target install -j$(nproc)
|
||||
cd ../..
|
||||
ls -l telegram-bot-api/bin/telegram-bot-api*
|
||||
cp telegram-bot-api/bin/telegram-bot-api telegram-bot-api-binary
|
||||
- name: Upload Binary
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: telegram-bot-api-binary
|
||||
path: telegram-bot-api-binary
|
|
@ -9,6 +9,10 @@
|
|||
path = TMessagesProj/jni/boringssl
|
||||
url = https://github.com/google/boringssl
|
||||
ignore = dirty
|
||||
[submodule "TMessagesProj/jni/libvpx"]
|
||||
path = TMessagesProj/jni/libvpx
|
||||
url = https://github.com/webmproject/libvpx
|
||||
ignore = dirty
|
||||
|
||||
[submodule "ss-rust/src/main/rust/shadowsocks-rust"]
|
||||
path = ss-rust/src/main/rust/shadowsocks-rust
|
||||
|
@ -32,4 +36,7 @@
|
|||
branch = stable
|
||||
[submodule "ssr-libev/src/main/jni/re2"]
|
||||
path = ssr-libev/src/main/jni/re2
|
||||
url = https://github.com/google/re2.git
|
||||
url = https://github.com/google/re2.git
|
||||
[submodule "v2ray"]
|
||||
path = v2ray
|
||||
url = https://github.com/nekohasekai/AndroidLibV2rayLite
|
||||
|
|
27
Dockerfile
27
Dockerfile
|
@ -1,27 +0,0 @@
|
|||
FROM gradle:6.5.0-jdk8
|
||||
|
||||
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
|
||||
ENV ANDROID_API_LEVEL android-30
|
||||
ENV ANDROID_BUILD_TOOLS_VERSION 30.0.3
|
||||
ENV ANDROID_HOME /usr/local/android-sdk-linux
|
||||
ENV ANDROID_NDK_VERSION 21.1.6352462
|
||||
ENV ANDROID_VERSION 30
|
||||
ENV ANDROID_NDK_HOME ${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/
|
||||
ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
|
||||
|
||||
RUN mkdir "$ANDROID_HOME" .android && \
|
||||
cd "$ANDROID_HOME" && \
|
||||
curl -o sdk.zip $ANDROID_SDK_URL && \
|
||||
unzip sdk.zip && \
|
||||
rm sdk.zip
|
||||
|
||||
RUN yes | ${ANDROID_HOME}/tools/bin/sdkmanager --licenses
|
||||
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
|
||||
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" \
|
||||
"platforms;android-${ANDROID_VERSION}" \
|
||||
"platform-tools" \
|
||||
"ndk;$ANDROID_NDK_VERSION"
|
||||
ENV PATH ${ANDROID_NDK_HOME}:$PATH
|
||||
ENV PATH ${ANDROID_NDK_HOME}/prebuilt/linux-x86_64/bin/:$PATH
|
||||
|
||||
CMD mkdir -p /home/source/TMessagesProj/build/outputs/apk && mkdir -p /home/source/TMessagesProj/build/outputs/native-debug-symbols && cp -R /home/source/. /home/gradle && cd /home/gradle && gradle assembleRelease && cp -R /home/gradle/TMessagesProj/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && cp -R /home/gradle/TMessagesProj/build/outputs/native-debug-symbols/. /home/source/TMessagesProj/build/outputs/native-debug-symbols
|
193
README.md
193
README.md
|
@ -1,56 +1,90 @@
|
|||
# NekoX
|
||||
|
||||
NekoX is an **open source** third-party Telegram client, based on Telegram-FOSS with features added.
|
||||
NekoX is an **free and open source** third-party Telegram client, based on Telegram-FOSS with features added.
|
||||
|
||||
[中文FAQ](https://github.com/NekoX-Dev/NekoX/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
|
||||
|
||||
[![Get it on F-Droid](https://i.imgur.com/HDicnzz.png)](https://f-droid.org/packages/nekox.messenger) Fdroid releases can not upgrade to other releases.
|
||||
|
||||
- [Google Play Store](https://play.google.com/store/apps/details?id=nekox.messenger)
|
||||
- [Update News Telegram](https://t.me/NekogramX)
|
||||
- [GitHub Feedback](https://github.com/NekoX-Dev/NekoX/issues)
|
||||
- [Group Chat (English / Chinese)](https://t.me/NekoXChat)
|
||||
- [Group Chat (Persian)](https://t.me/NekogramX_Persian)
|
||||
|
||||
The play store version is outdated [due to](https://developer.android.com/distribute/best-practices/develop/target-sdk) the target api level 29 is not supported yet. Otherwise, the play version won't be able to read photos and files (like other 3rd apps do).
|
||||
- [Group Chat (Indonesia)](https://t.me/NekoxID)
|
||||
- [Group Chat (Russian)](https://t.me/NekoXRussia)
|
||||
- [Group Chat (Hindi)](https://t.me/NekoXHindi)
|
||||
- [Group Chat (Turkish)](https://t.me/NekoXTurkish)
|
||||
|
||||
## NekoX Changes
|
||||
|
||||
- Most of Nekogram's features
|
||||
- OpenCC Chinese Convert
|
||||
- Built-in Vmess, Shadowsocks, SSR proxies support
|
||||
- Built-in public proxy list / Proxy subscription support.
|
||||
- Proxies import and export, remarks, speed measurement, sorting, delete unusable nodes, etc.
|
||||
- Scan the qrcode (any link, can add a proxy).
|
||||
- The ( vemss / vmess1 / ss / ssr / rb ) proxy link in the message can be clicked.
|
||||
- Allow auto disable proxy when VPN is enabled
|
||||
- Proxy automatic switcher
|
||||
- Add stickers without sticker pack
|
||||
- Allow disable vibration
|
||||
- Sticker set list backup / restore / share
|
||||
- Full InstantView translation support
|
||||
- Translation support for selected text on input and in messages
|
||||
- Delete all messages in group
|
||||
- Dialog sorting is optional "Unread and can be prioritized for reminding" etc.
|
||||
- Allow to skip "regret within five seconds"
|
||||
- Unblock all users support
|
||||
- Login via QR code
|
||||
- Scan and confirm the login QR code directly
|
||||
- Allow clear application data
|
||||
- Option to not send comment first when forwarding
|
||||
- 0ption to use nekox chat input menu: replace record button with a menu which contains an switch to control link preview (enabled by default)
|
||||
- Option to disable link preview by default: to prevent the server from knowing that the link is shared through Telegram.
|
||||
- Option to ignore Android-only content restrictions (except for the Play Store version).
|
||||
- OpenKaychain client ( sign / verify / decrypt / import )
|
||||
- Google Cloud Translate / Yandex.Translate support
|
||||
- Custom cache directory (supports external storage)
|
||||
- Custom AppId and Hash (optional NekoX / Andorid / Android X or Manual input)
|
||||
- Custom server (official, test DC or Manual input)
|
||||
- Keep the original file name when downloading files
|
||||
- View the data center you belong to when you don't have an avatar
|
||||
- Proxies, groups, channels, sticker packs are able to shared as QRCodes.
|
||||
- Force English emoji keywords to be loaded
|
||||
- Add "@Name" when long press @ user option
|
||||
- Enhanced notification service, optional version without Google Services.
|
||||
- Don't alert "Proxy unavailable" for non-current account
|
||||
- Tgx style message unpin menu
|
||||
- Built-in Material Design themes / Telegram X style icons
|
||||
- Unlimited login accounts
|
||||
- **Proxy**
|
||||
- Built-in VMess, Shadowsocks, SSR, Trojan-GFW proxies support (No longer maintained)
|
||||
- Built-in public proxy (WebSocket relay via Cloudflare CDN), [documentation and for PC](https://github.com/arm64v8a/NekoXProxy)
|
||||
- Proxy subscription support
|
||||
- Ipv6 MTProxy support
|
||||
- Able to parse all proxy subscription format: SIP008, ssr, v2rayN, vmess1, shit ios app formats, clash config and more
|
||||
- Proxies import and export, remarks, speed measurement, sorting, delete unusable nodes, etc
|
||||
- Scan the QR code (any link, can add a proxy)
|
||||
- The ( vmess / vmess1 / ss / ssr / trojan ) proxy link in the message can be clicked
|
||||
- Allow auto-disabling proxy when VPN is enabled
|
||||
- Proxy automatic switcher
|
||||
- Don't alert "Proxy unavailable" for non-current account
|
||||
- **Stickers**
|
||||
- Custom [Emoji packs](https://github.com/NekoX-Dev/NekoX/wiki/emoji)
|
||||
- Add stickers without sticker pack
|
||||
- Sticker set list backup / restore / share
|
||||
- **Internationalization**
|
||||
- OpenCC Chinese Convert
|
||||
- Full InstantView translation support
|
||||
- Translation support for selected text on input and in messages
|
||||
- Google Cloud Translate / Yandex.Translate support
|
||||
- Force English emoji keywords to be loaded
|
||||
- Persian calendar support
|
||||
- **Additional Options**
|
||||
- Option to disable vibration
|
||||
- Dialog sorting is optional "Unread and can be prioritized for reminding" etc
|
||||
- Option to skip "regret within five seconds"
|
||||
- Option to not send comment first when forwarding
|
||||
- Option to use nekox chat input menu: replace record button with a menu which contains an switch to control link preview (enabled by default)
|
||||
- Option to disable link preview by default: to prevent the server from knowing that the link is shared through Telegram.
|
||||
- Option to ignore Android-only content restrictions (except for the Play Store version).
|
||||
- Custom cache directory (supports external storage)
|
||||
- Custom server (official, test DC)
|
||||
- Option to block others from starting a secret chat with you
|
||||
- Option to disable trending
|
||||
- **Additional Actions**
|
||||
- Allow clicking on links in self profile
|
||||
- Delete all messages in group
|
||||
- Unblock all users support
|
||||
- Login via QR code
|
||||
- Scan and confirm the login QR code directly
|
||||
- Allow clearing app data
|
||||
- Proxies, groups, channels, sticker packs are able to be shared as QR codes
|
||||
- Add "@Name" when long-pressing @user option
|
||||
- Allow creating a group without inviting anyone
|
||||
- Allow upgrading a group to a supergroup
|
||||
- Mark dialogs as read using tab menu
|
||||
- Enabled set auto delete timer option for private chats and private groups
|
||||
- Support saving multiple selected messages to Saved Messages
|
||||
- Support unpinning multiple selected messages
|
||||
- View stats option for messages
|
||||
- **Optimization**
|
||||
- Keep the original file name when downloading files
|
||||
- View the data center you belong to when you don't have an avatar
|
||||
- Enhanced notification service, optional version without Google Services
|
||||
- Improved session dialog
|
||||
- Improved link long click menu
|
||||
- Improved hide messages from blocked users feature
|
||||
- Don't process cleanup draft events after opening chat
|
||||
- **Others**
|
||||
- OpenKeychain client (sign / verify / decrypt / import)
|
||||
- Text replacer
|
||||
- **UI**
|
||||
- Telegram X style menu for unpinning messages
|
||||
- Built-in Material Design themes / Telegram X style icons
|
||||
- And more :)
|
||||
|
||||
## Compilation Guide
|
||||
|
||||
|
@ -59,17 +93,21 @@ Consider using a Linux VM or dual booting.**
|
|||
|
||||
**Important:**
|
||||
|
||||
1. Install Android Sdk and NDK ( default location is $HOME/Android/Sdk, otherwise you need to specify $ANDROID_HOME for it )
|
||||
|
||||
It is recommended to use [AndroidStudio](https://developer.android.com/studio) to install. [here is how to install AndroidStudio](https://developer.android.com/studio/install).
|
||||
|
||||
2. Install golang ( >= 1.15.5 ).
|
||||
|
||||
```shell
|
||||
apt install -y golang
|
||||
0. Checkout all submodules
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
3. Install rust and its stdlib for android abis, add environment variables for it.
|
||||
1. Install Android SDK and NDK (default location is $HOME/Android/SDK, otherwise you need to specify $ANDROID_HOME for it)
|
||||
|
||||
It is recommended to use [AndroidStudio](https://developer.android.com/studio) to install.
|
||||
|
||||
2. Install golang and yasm
|
||||
```shell
|
||||
apt install -y golang-1.16 yasm
|
||||
```
|
||||
|
||||
3. Install Rust and its stdlib for Android ABIs, and add environment variables for it.
|
||||
|
||||
It is recommended to use the official script, otherwise you may not find rustup.
|
||||
|
||||
|
@ -77,7 +115,8 @@ It is recommended to use the official script, otherwise you may not find rustup.
|
|||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none -y
|
||||
echo "source \$HOME/.cargo/env" >> $HOME/.bashrc && source $HOME/.cargo/env
|
||||
|
||||
cd ss-rust/src/main/rust/shadowsocks-rust
|
||||
rustup install $(cat ss-rust/src/main/rust/shadowsocks-rust/rust-toolchain)
|
||||
rustup default $(cat ss-rust/src/main/rust/shadowsocks-rust/rust-toolchain)
|
||||
rustup target install armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
|
||||
```
|
||||
|
||||
|
@ -85,27 +124,59 @@ rustup target install armv7-linux-androideabi aarch64-linux-android i686-linux-a
|
|||
5. Build external libraries and native code: `./run libs update`
|
||||
6. Fill out `TELEGRAM_APP_ID` and `TELEGRAM_APP_HASH` in `local.properties`
|
||||
7. Replace TMessagesProj/google-services.json if you want fcm to work.
|
||||
8. Replace release.keystore with yours and fill out `ALIAS_NAME`, `KEYSTORE_PASS` and `ALIAS_PASS` in `local.properties` if you want a non-debug build.
|
||||
8. Replace release.keystore with yours and fill out `ALIAS_NAME`, `KEYSTORE_PASS` and `ALIAS_PASS` in `local.properties` if you want a custom sign key.
|
||||
|
||||
`./gradlew assemble<Full/Mini><Debug/Release/ReleaseNoGcm>`
|
||||
|
||||
## FAQ
|
||||
|
||||
#### What is the relationship between NekoX and Nekogram?
|
||||
#### What is the differences between NekoX and Nekogram?
|
||||
|
||||
More features, **without** [additional trackers](https://gitlab.com/search?utf8=%E2%9C%93&snippets=false&scope=&repository_ref=master&search=AnalyticsHelper&group_id=10273976&project_id=22804922).
|
||||
Developed by different developers, read the feature list above to understand the differences.
|
||||
|
||||
#### What is the difference between Full and Mini version?
|
||||
#### What is the difference between the Full and Mini version?
|
||||
|
||||
The full version comes with built-in proxy support for v2ray, shadowsocks, and shadowsocksr, which is usually provided to advanced users to help friends who have no computer knowledge in mainland China to bypass censorship. Don't complain about imperfect functions or ask to add other rare proxy types, you can use their clients directly.
|
||||
The full version comes with built-in proxy support for v2ray, shadowsocks, shadowsocksr, and trojan, which is usually provided to advanced users to help friends who have no computer knowledge in mainland China to bypass censorship. Don't complain about imperfect functions or ask to add other rare proxy types, you can use their clients directly.
|
||||
|
||||
#### What if I don't need a proxy?
|
||||
|
||||
Then it is recommended to use the `Mini` version.
|
||||
|
||||
#### How can I help with Localization?
|
||||
#### What is the noGcm version?
|
||||
|
||||
Join the project at https://nekox.crowdin.com/nekox.
|
||||
Google Cloud Messaging, also known as gcm / fcm, message push service by google used by original Telegram android app, it requires your device to have Google Service Framework (non-free) installed.
|
||||
|
||||
#### I've encountered a bug!
|
||||
|
||||
First, make sure you have the latest version installed (check the channel, Play store versions usually have a delay).
|
||||
|
||||
Then, if the issue appears in the official Telegram client too, please submit it to the officials, (be careful not to show NekoX in the description and screenshots, the official developers doesn't like us!).
|
||||
|
||||
Then, please *detail* your issue, create an issue or submit it to our [group](https://t.me/NekoXChat) with #bug.
|
||||
|
||||
If you experience a *crash*, you also need to click on the version number at the bottom of the settings and select "Enable Log" and send it to us.
|
||||
|
||||
## Localization
|
||||
|
||||
Is NekoX not in your language, or the translation is incorrect or incomplete? Get involved in the translations on our [Weblate](https://hosted.weblate.org/engage/nekox/).
|
||||
|
||||
[![Translation status](https://hosted.weblate.org/widgets/nekox/-/horizontal-auto.svg)](https://hosted.weblate.org/engage/nekox/)
|
||||
|
||||
### Adding a new language
|
||||
|
||||
First and foremost, Android must already support the specific language and locale you want to add. We cannot work with languages that Android and the SDK do not support, the tools simply break down. Next, if you are considering adding a country-specific variant of a language (e.g. de-AT), first make sure that the main language is well maintained (e.g. de). Your contribution might be useful to more people if you contribute to the existing version of your language rather than the country-specific variant.
|
||||
|
||||
Anyone can create a new language via Weblate.
|
||||
|
||||
### Adding unofficial translations for Telegram
|
||||
|
||||
Current built-in language packs:
|
||||
|
||||
* 简体中文: [moecn](https://translations.telegram.org/moecn)
|
||||
* 正體中文: [taiwan](https://translations.telegram.org/taiwan)
|
||||
* 日本語: [ja_raw](https://translations.telegram.org/ja_raw)
|
||||
|
||||
You can [open an issue to](https://github.com/NekoX-Dev/NekoX/issues/new?&template=language_request.md) request to amend the built-in translation.
|
||||
|
||||
## Credits
|
||||
|
||||
|
@ -119,4 +190,8 @@ Join the project at https://nekox.crowdin.com/nekox.
|
|||
<li>HanLP: <a href="https://github.com/hankcs/HanLP/blob/1.x/LICENSE">Apache License 2.0</a></li>
|
||||
<li>OpenCC: <a href="https://github.com/BYVoid/OpenCC/blob/master/LICENSE">Apache License 2.0</a></li>
|
||||
<li>opencc-data: <a href="https://github.com/nk2028/opencc-data">Apache License 2.0</a></li>
|
||||
<li>android-device-list: <a href="https://github.com/pbakondy/android-device-list/blob/master/LICENSE">MIT</a> </li>
|
||||
<li>JetBrains: for allocating free open-source licences for IDEs</li>
|
||||
</ul>
|
||||
|
||||
[<img src=".github/jetbrains-variant-3.png" width="200"/>](https://jb.gg/OpenSource)
|
||||
|
|
|
@ -1,129 +1,54 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
import cn.hutool.core.util.RuntimeUtil
|
||||
|
||||
def verName = "7.3.1-rc17"
|
||||
def verCode = 164
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: "kotlin-android"
|
||||
|
||||
def verName = "9.5.6-preview01"
|
||||
def verCode = 725
|
||||
|
||||
if (System.getenv("DEBUG_BUILD") == "true") {
|
||||
verName += "-" + RuntimeUtil.execForStr("git log --pretty=format:'%h' -n 1").trim().replace('\'','')
|
||||
}
|
||||
|
||||
def officialVer = "9.5.6"
|
||||
def officialCode = 3237
|
||||
|
||||
def serviceAccountCredentialsFile = rootProject.file("service_account_credentials.json")
|
||||
|
||||
def beta = verName.contains("preview")
|
||||
|
||||
if (serviceAccountCredentialsFile.isFile()) {
|
||||
|
||||
setupPlay(beta)
|
||||
|
||||
play.serviceAccountCredentials = serviceAccountCredentialsFile
|
||||
|
||||
} else if (System.getenv().containsKey("ANDROID_PUBLISHER_CREDENTIALS")) {
|
||||
|
||||
setupPlay(beta)
|
||||
|
||||
}
|
||||
|
||||
void setupPlay(boolean beta) {
|
||||
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
|
||||
apply plugin: "com.github.triplet.play"
|
||||
play {
|
||||
|
||||
track = beta ? "beta" : "production"
|
||||
defaultToAppBundles = true
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
configurations {
|
||||
compile.exclude module: 'support-v4'
|
||||
}
|
||||
|
||||
def okHttpVersion = '4.9.0'
|
||||
def fcmVersion = '21.0.1'
|
||||
def crashlyticsVersion = '17.3.0'
|
||||
def playCoreVersion = '1.9.0'
|
||||
|
||||
repositories {
|
||||
|
||||
jcenter()
|
||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation "androidx.browser:browser:1.3.0"
|
||||
implementation 'androidx.core:core-ktx:1.5.0-beta01'
|
||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||
implementation 'androidx.viewpager:viewpager:1.0.0'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.2'
|
||||
implementation "androidx.interpolator:interpolator:1.0.0"
|
||||
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.sharetarget:sharetarget:1.1.0'
|
||||
|
||||
// replace zxing with latest
|
||||
// TODO: fix problem with android L
|
||||
implementation 'com.google.zxing:core:3.4.1'
|
||||
|
||||
compileOnly 'org.checkerframework:checker-qual:3.9.1'
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:2.5.5'
|
||||
|
||||
// don't change this :)
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.googlecode.mp4parser:isoparser:1.0.6'
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'org.osmdroid:osmdroid-android:6.1.8'
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.21-2'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
|
||||
implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okHttpVersion"
|
||||
implementation 'dnsjava:dnsjava:3.3.1'
|
||||
implementation 'org.dizitart:nitrite:3.4.3'
|
||||
|
||||
implementation 'cn.hutool:hutool-core:5.5.7'
|
||||
implementation 'cn.hutool:hutool-crypto:5.5.7'
|
||||
implementation 'cn.hutool:hutool-http:5.5.7'
|
||||
|
||||
implementation 'com.jakewharton:process-phoenix:2.0.0'
|
||||
|
||||
implementation project(":openpgp-api")
|
||||
|
||||
compileOnly files('libs/libv2ray.aar')
|
||||
compileOnly "com.google.firebase:firebase-messaging:$fcmVersion"
|
||||
compileOnly "com.google.firebase:firebase-crashlytics:$crashlyticsVersion"
|
||||
compileOnly "com.google.android.play:core:$playCoreVersion"
|
||||
|
||||
debugImplementation "com.google.firebase:firebase-messaging:$fcmVersion"
|
||||
debugImplementation "com.google.firebase:firebase-crashlytics:$crashlyticsVersion"
|
||||
debugImplementation "com.google.android.play:core:$playCoreVersion"
|
||||
releaseImplementation "com.google.firebase:firebase-messaging:$fcmVersion"
|
||||
releaseImplementation "com.google.firebase:firebase-crashlytics:$crashlyticsVersion"
|
||||
releaseImplementation "com.google.android.play:core:$playCoreVersion"
|
||||
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
testImplementation 'androidx.test:core:1.3.0'
|
||||
testImplementation "org.robolectric:robolectric:4.4"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
||||
|
||||
compile.exclude module: "support-v4"
|
||||
}
|
||||
|
||||
def keystorePwd = null
|
||||
def alias = null
|
||||
def pwd = null
|
||||
Properties properties
|
||||
def disableCMakeRelWithDebInfo = System.getenv("COMPILE_NATIVE") == null
|
||||
|
||||
if (project.rootProject.file('local.properties').exists()) {
|
||||
Properties properties
|
||||
def base64 = System.getenv("LOCAL_PROPERTIES")
|
||||
if (base64 != null && !base64.isBlank()) {
|
||||
properties = new Properties()
|
||||
properties.load(project.rootProject.file('local.properties').newDataInputStream())
|
||||
} else {
|
||||
def base64 = System.getenv("LOCAL_PROPERTIES")
|
||||
if (base64 != null && !base64.isBlank()) {
|
||||
properties = new Properties()
|
||||
properties.load(new ByteArrayInputStream(Base64.decoder.decode(base64)))
|
||||
}
|
||||
properties.load(new ByteArrayInputStream(Base64.decoder.decode(base64)))
|
||||
} else if (project.rootProject.file("local.properties").exists()) {
|
||||
properties = new Properties()
|
||||
properties.load(project.rootProject.file("local.properties").newDataInputStream())
|
||||
}
|
||||
|
||||
if (properties != null) {
|
||||
|
@ -136,17 +61,51 @@ keystorePwd = keystorePwd ?: System.getenv("KEYSTORE_PASS")
|
|||
alias = alias ?: System.getenv("ALIAS_NAME")
|
||||
pwd = pwd ?: System.getenv("ALIAS_PASS")
|
||||
|
||||
def targetTask = ""
|
||||
if (!gradle.startParameter.taskNames.isEmpty()) {
|
||||
if (gradle.startParameter.taskNames.size == 1) {
|
||||
targetTask = gradle.startParameter.taskNames[0].toLowerCase()
|
||||
}
|
||||
}
|
||||
|
||||
def nativeTarget = System.getenv("NATIVE_TARGET")
|
||||
if (nativeTarget == null) nativeTarget = ""
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '30.0.3'
|
||||
compileSdkVersion 33
|
||||
buildToolsVersion "33.0.0"
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
defaultConfig.applicationId = "nekox.messenger"
|
||||
|
||||
splits {
|
||||
|
||||
abi {
|
||||
if (targetTask.contains("fdroid")) {
|
||||
enable false
|
||||
universalApk true
|
||||
} else {
|
||||
if (nativeTarget.toLowerCase().equals("universal")) {
|
||||
enable false
|
||||
universalApk true
|
||||
} else if (!nativeTarget.isBlank()) {
|
||||
enable true
|
||||
universalApk false
|
||||
reset()
|
||||
include nativeTarget
|
||||
} else {
|
||||
enable true
|
||||
universalApk false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
minSdkVersion 19
|
||||
//noinspection ExpiredTargetSdkVersion,OldTargetApi
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 32
|
||||
|
||||
versionName verName
|
||||
versionCode verCode
|
||||
|
@ -161,13 +120,16 @@ android {
|
|||
appHash = properties.getProperty("TELEGRAM_APP_HASH") ?: System.getenv("TELEGRAM_APP_HASH") ?: appHash
|
||||
}
|
||||
|
||||
buildConfigField 'int', 'APP_ID', appId
|
||||
buildConfigField 'String', 'APP_HASH', "\"" + appHash + "\""
|
||||
|
||||
buildConfigField "String", "OFFICIAL_VERSION", "\"" + officialVer + "\""
|
||||
buildConfigField "int", "OFFICIAL_VERSION_CODE", officialCode + ""
|
||||
buildConfigField "int", "APP_ID", appId
|
||||
buildConfigField "String", "APP_HASH", "\"" + appHash + "\""
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
version '3.10.2'
|
||||
arguments '-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-16', "-j=16"
|
||||
version "3.10.2"
|
||||
arguments "-DANDROID_STL=c++_static", "-DANDROID_PLATFORM=android-16"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,39 +143,24 @@ android {
|
|||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'jni/CMakeLists.txt'
|
||||
path "jni/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
disable 'ExtraTranslation'
|
||||
disable 'BlockedPrivateApi'
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
|
||||
exclude '/fabric/**'
|
||||
exclude '/META-INF/*.version'
|
||||
exclude '/META-INF/*.kotlin_module'
|
||||
exclude '/builddef.lst'
|
||||
exclude '/*.txt'
|
||||
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
jumboMode = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
|
||||
coreLibraryDesugaringEnabled true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
|
||||
testOptions {
|
||||
|
@ -222,7 +169,7 @@ android {
|
|||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile project.file('release.keystore')
|
||||
storeFile project.file("release.keystore")
|
||||
storePassword keystorePwd
|
||||
keyAlias alias
|
||||
keyPassword pwd
|
||||
|
@ -233,10 +180,11 @@ android {
|
|||
debug {
|
||||
isDefault true
|
||||
debuggable true
|
||||
jniDebuggable false
|
||||
jniDebuggable true
|
||||
multiDexEnabled true
|
||||
zipAlignEnabled true
|
||||
zipAlignEnabled true;
|
||||
signingConfig keystorePwd == null ? signingConfigs.debug : signingConfigs.release
|
||||
ndk.debugSymbolLevel = "FULL"
|
||||
}
|
||||
|
||||
releaseNoGcm {
|
||||
|
@ -246,9 +194,9 @@ android {
|
|||
shrinkResources true
|
||||
multiDexEnabled true
|
||||
zipAlignEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
matchingFallbacks = ['debug']
|
||||
signingConfig signingConfigs.release
|
||||
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
matchingFallbacks = ["release", "debug"]
|
||||
signingConfig keystorePwd == null ? signingConfigs.debug : signingConfigs.release
|
||||
}
|
||||
|
||||
release {
|
||||
|
@ -258,9 +206,9 @@ android {
|
|||
shrinkResources true
|
||||
multiDexEnabled true
|
||||
zipAlignEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
matchingFallbacks = ['debug']
|
||||
signingConfig signingConfigs.release
|
||||
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
matchingFallbacks = ["release", "debug"]
|
||||
signingConfig keystorePwd == null ? signingConfigs.debug : signingConfigs.release
|
||||
}
|
||||
|
||||
foss {
|
||||
|
@ -270,8 +218,13 @@ android {
|
|||
shrinkResources true
|
||||
multiDexEnabled true
|
||||
zipAlignEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
matchingFallbacks = ['debug']
|
||||
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
matchingFallbacks = ["release", "debug"]
|
||||
}
|
||||
|
||||
fdroidRelease {
|
||||
initWith foss
|
||||
matchingFallbacks = ["release", "debug"]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,32 +232,51 @@ android {
|
|||
|
||||
main {
|
||||
jni.srcDirs = []
|
||||
assets.srcDirs = ["src/main/assets", "src/emojis/twitter"]
|
||||
}
|
||||
|
||||
debug {
|
||||
jniLibs.srcDir 'src/main/libs'
|
||||
manifest.srcFile 'src/gservcies/AndroidManifest.xml'
|
||||
java {
|
||||
srcDirs "src/main/java", "src/gservcies/java"
|
||||
}
|
||||
jni.srcDirs = ["./jni/"]
|
||||
manifest {
|
||||
srcFile "src/gservcies/AndroidManifest.xml"
|
||||
}
|
||||
}
|
||||
|
||||
releaseNoGcm {
|
||||
jniLibs.srcDir 'src/main/libs'
|
||||
jni.srcDirs = []
|
||||
jniLibs {
|
||||
srcDir "src/main/libs"
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
jniLibs.srcDir 'src/main/libs'
|
||||
manifest.srcFile 'src/gservcies/AndroidManifest.xml'
|
||||
java {
|
||||
srcDirs "src/main/java", "src/gservcies/java"
|
||||
}
|
||||
jni.srcDirs = []
|
||||
jniLibs {
|
||||
srcDir "src/main/libs"
|
||||
}
|
||||
manifest {
|
||||
srcFile "src/gservcies/AndroidManifest.xml"
|
||||
}
|
||||
}
|
||||
|
||||
foss {
|
||||
jni.srcDirs = ['./jni/']
|
||||
jni {
|
||||
srcDirs = ["./jni/"]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
splits.abi {
|
||||
|
||||
enable true
|
||||
universalApk false
|
||||
fdroidRelease {
|
||||
jni {
|
||||
srcDirs = ["./jni/"]
|
||||
}
|
||||
jniLibs.srcDirs = []
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -312,68 +284,143 @@ android {
|
|||
|
||||
productFlavors {
|
||||
mini {
|
||||
versionNameSuffix '-mini'
|
||||
}
|
||||
miniAppleEmoji {
|
||||
versionNameSuffix '-mini'
|
||||
isDefault true
|
||||
manifestPlaceholders = [is_full_version: "false"]
|
||||
}
|
||||
full {
|
||||
isDefault true
|
||||
manifestPlaceholders = [is_full_version: "true"]
|
||||
}
|
||||
fullAppleEmoji {
|
||||
versionNameSuffix '-full-apple-emoji'
|
||||
}
|
||||
fullPlay {
|
||||
versionNameSuffix '-play'
|
||||
versionCode verCode - 1
|
||||
miniPlay {
|
||||
versionNameSuffix "-play"
|
||||
versionCode verCode - 2
|
||||
manifestPlaceholders = [is_full_version: "false"]
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets.all { set ->
|
||||
if (set.name.startsWith("full")) {
|
||||
set.dependencies {
|
||||
implementation files('libs/libv2ray.aar', 'libs/ss-rust-release.aar', 'libs/ssr-libev-release.aar')
|
||||
}
|
||||
}
|
||||
if (set.name.matches("(mini|full).*")) {
|
||||
if (set.name.contains("Apple")) {
|
||||
set.assets.srcDirs = ["src/main/assets", "src/emojis/apple"]
|
||||
/*} else if (set.name.contains("Twitter")) {
|
||||
set.assets.srcDirs = ["src/main/assets", "src/emojis/twitter"]*/
|
||||
} else {
|
||||
set.assets.srcDirs = ["src/main/assets", "src/emojis/twitter"]
|
||||
implementation fileTree("libs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.all { task ->
|
||||
if (((task.name.endsWith('Ndk') || task.name.startsWith('generateJsonModel') || task.name.startsWith('externalNativeBuild'))) && !task.name.contains("Foss")) {
|
||||
if (((task.name.endsWith("Ndk") || task.name.startsWith("generateJsonModel") || task.name.startsWith("externalNativeBuild"))) && !(task.name.contains("Debug") || task.name.contains("Foss") || task.name.contains("Fdroid"))) {
|
||||
task.enabled = false
|
||||
}
|
||||
if (task.name.contains("uploadCrashlyticsMappingFile")) {
|
||||
enabled = false
|
||||
}
|
||||
if (disableCMakeRelWithDebInfo && task.name.contains("CMakeRelWithDebInfo") && !targetTask.contains("fdroid")) {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all { output ->
|
||||
outputFileName = outputFileName.replace("TMessagesProj", "NekoX")
|
||||
outputFileName = outputFileName.replace("TMessagesProj", "NekoX-v" + versionName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
def fcmVersion = "23.0.7"
|
||||
def crashlyticsVersion = "18.2.12"
|
||||
def playCoreVersion = "1.10.3"
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation "androidx.browser:browser:1.5.0"
|
||||
implementation "androidx.core:core-ktx:1.9.0"
|
||||
implementation "androidx.palette:palette-ktx:1.0.0"
|
||||
implementation "androidx.viewpager:viewpager:1.0.0"
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.6"
|
||||
implementation "androidx.interpolator:interpolator:1.0.0"
|
||||
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
implementation "androidx.sharetarget:sharetarget:1.2.0"
|
||||
|
||||
// just follow official
|
||||
compileOnly 'org.checkerframework:checker-qual:2.5.2'
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
|
||||
|
||||
// don"t change this :)
|
||||
//noinspection GradleDependency
|
||||
implementation "com.googlecode.mp4parser:isoparser:1.0.6"
|
||||
|
||||
implementation "com.google.code.gson:gson:2.8.9"
|
||||
implementation "org.osmdroid:osmdroid-android:6.1.10"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.10"
|
||||
implementation 'com.neovisionaries:nv-websocket-client:2.14'
|
||||
implementation 'dnsjava:dnsjava:3.4.1'
|
||||
implementation "org.dizitart:nitrite:3.4.3"
|
||||
|
||||
implementation "cn.hutool:hutool-core:5.7.13"
|
||||
implementation "cn.hutool:hutool-crypto:5.7.13"
|
||||
implementation 'cn.hutool:hutool-http:5.7.5'
|
||||
implementation "com.jakewharton:process-phoenix:2.1.2"
|
||||
implementation 'com.google.guava:guava:31.1-android'
|
||||
|
||||
compileOnly 'org.yaml:snakeyaml:1.29'
|
||||
fullImplementation 'org.yaml:snakeyaml:1.29'
|
||||
|
||||
implementation project(":openpgp-api")
|
||||
|
||||
compileOnly fileTree("libs")
|
||||
|
||||
compileOnly "com.google.firebase:firebase-messaging:$fcmVersion"
|
||||
compileOnly "com.google.firebase:firebase-crashlytics:$crashlyticsVersion"
|
||||
compileOnly "com.google.android.play:core:$playCoreVersion"
|
||||
|
||||
debugImplementation 'com.google.android.gms:play-services-maps:18.1.0'
|
||||
debugImplementation 'com.google.android.gms:play-services-location:20.0.0'
|
||||
releaseImplementation 'com.google.android.gms:play-services-maps:18.1.0'
|
||||
releaseImplementation 'com.google.android.gms:play-services-location:20.0.0'
|
||||
|
||||
debugImplementation "com.google.firebase:firebase-messaging:$fcmVersion"
|
||||
debugImplementation "com.google.firebase:firebase-crashlytics:$crashlyticsVersion"
|
||||
debugImplementation "com.google.android.play:core:$playCoreVersion"
|
||||
releaseImplementation "com.google.firebase:firebase-messaging:$fcmVersion"
|
||||
releaseImplementation "com.google.firebase:firebase-crashlytics:$crashlyticsVersion"
|
||||
releaseImplementation "com.google.android.play:core:$playCoreVersion"
|
||||
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
testImplementation "androidx.test:core:1.5.0"
|
||||
testImplementation "org.robolectric:robolectric:4.5.1"
|
||||
|
||||
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.2.0"
|
||||
|
||||
}
|
||||
|
||||
apply plugin: "com.google.gms.google-services"
|
||||
apply plugin: "com.google.firebase.crashlytics"
|
||||
|
||||
android {
|
||||
|
||||
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
excludes += ['/fabric/**', '/META-INF/native-image/**']
|
||||
}
|
||||
resources {
|
||||
excludes += ['/fabric/**', '/META-INF/*.version', '/META-INF/*.kotlin_module', '/META-INF/native-image/**', '/builddef.lst', '/*.txt', '/DebugProbesKt.bin', '/okhttp3/internal/publicsuffix/NOTICE']
|
||||
}
|
||||
}
|
||||
namespace "org.telegram.messenger"
|
||||
lint {
|
||||
disable 'MissingTranslation', 'ExtraTranslation', 'BlockedPrivateApi'
|
||||
}
|
||||
|
||||
tasks.all { task ->
|
||||
if (task.name.startsWith('uploadCrashlyticsMappingFile')) {
|
||||
if (task.name.startsWith("uploadCrashlyticsMappingFile")) {
|
||||
task.enabled = false
|
||||
} else if (task.name.contains('Crashlytics') && task.name.contains("NoGcm")) {
|
||||
} else if (task.name.contains("Crashlytics") && task.name.contains("NoGcm")) {
|
||||
task.enabled = false
|
||||
} else if (task.name.endsWith('GoogleServices') && task.name.contains("NoGcm")) {
|
||||
} else if (task.name.endsWith("GoogleServices") && task.name.contains("NoGcm")) {
|
||||
task.enabled = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,20 +5,31 @@ set(CMAKE_C_FLAGS "-w -std=c11 -DANDROID -D_LARGEFILE_SOURCE=1")
|
|||
set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--exclude-libs,libtgvoip.a,libtgcalls.a,libtgcalls_tp.a,libtgnet.a,liblz4.a,libwebp.a,libflac.a,librlottie.a,libsqlite.a,
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libtgvoip.a,libtgcalls.a,libtgcalls_tp.a,libtgnet.a,liblz4.a,libwebp.a,libflac.a,librlottie.a,libsqlite.a,
|
||||
${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libswscale.a,
|
||||
${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libavformat.a,
|
||||
${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libavcodec.a,
|
||||
${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libavresample.a,
|
||||
${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libavutil.a,
|
||||
${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libswresample.a,
|
||||
${CMAKE_HOME_DIRECTORY}/libvpx/build/${ANDROID_ABI}/lib/libvpx.a,
|
||||
${CMAKE_HOME_DIRECTORY}/boringssl/build/${ANDROID_ABI}/ssl/libssl.a,
|
||||
${CMAKE_HOME_DIRECTORY}/boringssl/build/${ANDROID_ABI}/crypto/libcrypto.a")
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Os -DNDEBUG")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Os -DNDEBUG")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-exclude-libs,ALL -Wl,--gc-sections -Wl,--strip-all")
|
||||
endif()
|
||||
|
||||
if (${ANDROID_ABI} STREQUAL "armeabi-v7a" OR ${ANDROID_ABI} STREQUAL "arm64-v8a")
|
||||
enable_language(ASM)
|
||||
else ()
|
||||
else()
|
||||
enable_language(ASM_NASM)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
add_library(avutil STATIC IMPORTED)
|
||||
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libavutil.a)
|
||||
|
@ -32,6 +43,9 @@ set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTOR
|
|||
add_library(avresample STATIC IMPORTED)
|
||||
set_target_properties(avresample PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libavresample.a)
|
||||
|
||||
add_library(swresample STATIC IMPORTED)
|
||||
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libswresample.a)
|
||||
|
||||
add_library(swscale STATIC IMPORTED)
|
||||
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/ffmpeg/build/${ANDROID_ABI}/lib/libswscale.a)
|
||||
|
||||
|
@ -41,6 +55,10 @@ set_target_properties(crypto PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY
|
|||
add_library(ssl STATIC IMPORTED)
|
||||
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/boringssl/build/${ANDROID_ABI}/ssl/libssl.a)
|
||||
|
||||
add_library(libvpx STATIC IMPORTED)
|
||||
set_target_properties(libvpx PROPERTIES IMPORTED_LOCATION ${CMAKE_HOME_DIRECTORY}/libvpx/build/${ANDROID_ABI}/lib/libvpx.a)
|
||||
|
||||
|
||||
#tgnet
|
||||
add_library(mozjpeg STATIC
|
||||
mozjpeg/cjpeg.c mozjpeg/cdjpeg.c mozjpeg/rdgif.c mozjpeg/rdppm.c mozjpeg/rdjpeg.c mozjpeg/rdswitch.c mozjpeg/rdbmp.c
|
||||
|
@ -441,10 +459,41 @@ set_target_properties(sqlite PROPERTIES
|
|||
target_compile_definitions(sqlite PUBLIC
|
||||
NULL=0 SOCKLEN_T=socklen_t LOCALE_NOT_USED ANDROID_NDK DISABLE_IMPORTGL AVOID_TABLES ANDROID_TILE_BASED_DECODE HAVE_STRCHRNUL=0 ANDROID_ARMV6_IDCT)
|
||||
|
||||
#breakpad
|
||||
add_library(breakpad STATIC
|
||||
third_party/breakpad/src/client/linux/crash_generation/crash_generation_client.cc
|
||||
third_party/breakpad/src/client/linux/handler/exception_handler.cc
|
||||
third_party/breakpad/src/client/linux/handler/minidump_descriptor.cc
|
||||
third_party/breakpad/src/client/linux/log/log.cc
|
||||
third_party/breakpad/src/client/linux/dump_writer_common/thread_info.cc
|
||||
third_party/breakpad/src/client/linux/dump_writer_common/seccomp_unwinder.cc
|
||||
third_party/breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
|
||||
third_party/breakpad/src/client/linux/microdump_writer/microdump_writer.cc
|
||||
third_party/breakpad/src/client/linux/minidump_writer/linux_dumper.cc
|
||||
third_party/breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
|
||||
third_party/breakpad/src/client/linux/minidump_writer/minidump_writer.cc
|
||||
third_party/breakpad/src/client/minidump_file_writer.cc
|
||||
third_party/breakpad/src/common/android/breakpad_getcontext.S
|
||||
third_party/breakpad/src/common/convert_UTF.c
|
||||
third_party/breakpad/src/common/md5.cc
|
||||
third_party/breakpad/src/common/string_conversion.cc
|
||||
third_party/breakpad/src/common/linux/elfutils.cc
|
||||
third_party/breakpad/src/common/linux/file_id.cc
|
||||
third_party/breakpad/src/common/linux/guid_creator.cc
|
||||
third_party/breakpad/src/common/linux/linux_libc_support.cc
|
||||
third_party/breakpad/src/common/linux/memory_mapped_file.cc
|
||||
third_party/breakpad/src/common/linux/safe_readlink.cc)
|
||||
set_target_properties(breakpad PROPERTIES ANDROID_ARM_MODE arm)
|
||||
set_property(SOURCE third_party/breakpad/src/common/android/breakpad_getcontext.S PROPERTY LANGUAGE C)
|
||||
target_include_directories(breakpad PUBLIC
|
||||
third_party/breakpad/src/common/android/include
|
||||
third_party/breakpad/src)
|
||||
|
||||
|
||||
#voip
|
||||
include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt)
|
||||
|
||||
set(NATIVE_LIB "tmessages.35")
|
||||
set(NATIVE_LIB "tmessages.43")
|
||||
|
||||
#tmessages
|
||||
add_library(${NATIVE_LIB} SHARED
|
||||
|
@ -692,7 +741,12 @@ target_sources(${NATIVE_LIB} PRIVATE
|
|||
third_party/libyuv/source/scale_win.cc
|
||||
third_party/libyuv/source/scale.cc
|
||||
third_party/libyuv/source/video_common.cc
|
||||
third_party/libyuv/source/scale_uv.cc)
|
||||
third_party/libyuv/source/scale_uv.cc
|
||||
third_party/libyuv/source/rotate_lsx.cc
|
||||
third_party/libyuv/source/row_lasx.cc
|
||||
third_party/libyuv/source/row_lsx.cc
|
||||
third_party/libyuv/source/scale_lsx.cc
|
||||
third_party/libyuv/source/scale_rgb.cc)
|
||||
|
||||
target_include_directories(${NATIVE_LIB} PUBLIC
|
||||
opus/include
|
||||
|
@ -704,6 +758,7 @@ target_include_directories(${NATIVE_LIB} PUBLIC
|
|||
third_party/libyuv/include
|
||||
boringssl/include
|
||||
ffmpeg/build/${ANDROID_ABI}/include
|
||||
libvpx/build/${ANDROID_ABI}/include
|
||||
emoji
|
||||
exoplayer/include
|
||||
exoplayer/libFLAC/include
|
||||
|
@ -714,7 +769,7 @@ target_include_directories(${NATIVE_LIB} PUBLIC
|
|||
lz4)
|
||||
|
||||
target_link_libraries(${NATIVE_LIB}
|
||||
-Wl,--whole-archive voipandroid -Wl,--no-whole-archive
|
||||
-Wl,--whole-archive rnnoise openh264 voipandroid -Wl,--no-whole-archive
|
||||
tgvoip
|
||||
tgcalls
|
||||
tgcalls_tp
|
||||
|
@ -729,6 +784,8 @@ target_link_libraries(${NATIVE_LIB}
|
|||
avformat
|
||||
avcodec
|
||||
avresample
|
||||
swresample
|
||||
libvpx
|
||||
avutil
|
||||
ssl
|
||||
crypto
|
||||
|
@ -736,20 +793,12 @@ target_link_libraries(${NATIVE_LIB}
|
|||
log
|
||||
z
|
||||
GLESv2
|
||||
EGL
|
||||
android
|
||||
OpenSLES
|
||||
cpufeatures)
|
||||
cpufeatures
|
||||
breakpad)
|
||||
|
||||
if (${ANDROID_ABI} STREQUAL "x86" OR ${ANDROID_ABI} STREQUAL "x86_64")
|
||||
target_link_libraries(${NATIVE_LIB}
|
||||
-Wl,--whole-archive libvpx_yasm -Wl,--no-whole-archive)
|
||||
endif ()
|
||||
|
||||
#if (${ANDROID_ABI} STREQUAL "x86" OR ${ANDROID_ABI} STREQUAL "x86_64")
|
||||
# target_link_libraries(${NATIVE_LIB}
|
||||
# -Wl,--whole-archive vpxasm -Wl,--no-whole-archive
|
||||
# c)
|
||||
#endif()
|
||||
|
||||
include(AndroidNdkModules)
|
||||
android_ndk_import_module_cpufeatures()
|
|
@ -5,6 +5,7 @@
|
|||
#include "tgnet/ConnectionsManager.h"
|
||||
#include "tgnet/MTProtoScheme.h"
|
||||
#include "tgnet/ConnectionSocket.h"
|
||||
#include "tgnet/FileLog.h"
|
||||
|
||||
JavaVM *java;
|
||||
jclass jclass_RequestDelegateInternal;
|
||||
|
@ -65,10 +66,10 @@ jobject getJavaByteBuffer(JNIEnv *env, jclass c, jlong address) {
|
|||
|
||||
static const char *NativeByteBufferClassPathName = "org/telegram/tgnet/NativeByteBuffer";
|
||||
static JNINativeMethod NativeByteBufferMethods[] = {
|
||||
{"native_getFreeBuffer", "(I)J", (void *) getFreeBuffer},
|
||||
{"native_limit", "(J)I", (void *) limit},
|
||||
{"native_position", "(J)I", (void *) position},
|
||||
{"native_reuse", "(J)V", (void *) reuse},
|
||||
{"native_getFreeBuffer", "(I)J", (void *) getFreeBuffer},
|
||||
{"native_limit", "(J)I", (void *) limit},
|
||||
{"native_position", "(J)I", (void *) position},
|
||||
{"native_reuse", "(J)V", (void *) reuse},
|
||||
{"native_getJavaByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void *) getJavaByteBuffer}
|
||||
};
|
||||
|
||||
|
@ -99,16 +100,19 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject
|
|||
TL_api_request *request = new TL_api_request();
|
||||
request->request = (NativeByteBuffer *) (intptr_t) object;
|
||||
if (onComplete != nullptr) {
|
||||
DEBUG_REF("sendRequest onComplete");
|
||||
onComplete = env->NewGlobalRef(onComplete);
|
||||
}
|
||||
if (onQuickAck != nullptr) {
|
||||
DEBUG_REF("sendRequest onQuickAck");
|
||||
onQuickAck = env->NewGlobalRef(onQuickAck);
|
||||
}
|
||||
if (onWriteToSocket != nullptr) {
|
||||
DEBUG_REF("sendRequest onWriteToSocket");
|
||||
onWriteToSocket = env->NewGlobalRef(onWriteToSocket);
|
||||
}
|
||||
ConnectionsManager::getInstance(instanceNum).sendRequest(request, ([onComplete, instanceNum](
|
||||
TLObject *response, TL_error *error, int32_t networkType) {
|
||||
TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) {
|
||||
TL_api_response *resp = (TL_api_response *) response;
|
||||
jlong ptr = 0;
|
||||
jint errorCode = 0;
|
||||
|
@ -127,7 +131,7 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject
|
|||
}
|
||||
if (onComplete != nullptr) {
|
||||
jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr,
|
||||
errorCode, errorText, networkType);
|
||||
errorCode, errorText, networkType, responseTime);
|
||||
}
|
||||
if (errorText != nullptr) {
|
||||
jniEnv[instanceNum]->DeleteLocalRef(errorText);
|
||||
|
@ -209,12 +213,12 @@ jint getConnectionState(JNIEnv *env, jclass c, jint instanceNum) {
|
|||
return ConnectionsManager::getInstance(instanceNum).getConnectionState();
|
||||
}
|
||||
|
||||
void setUserId(JNIEnv *env, jclass c, jint instanceNum, int32_t id) {
|
||||
void setUserId(JNIEnv *env, jclass c, jint instanceNum, int64_t id) {
|
||||
ConnectionsManager::getInstance(instanceNum).setUserId(id);
|
||||
}
|
||||
|
||||
void switchBackend(JNIEnv *env, jclass c, jint instanceNum) {
|
||||
ConnectionsManager::getInstance(instanceNum).switchBackend();
|
||||
void switchBackend(JNIEnv *env, jclass c, jint instanceNum, jboolean restart) {
|
||||
ConnectionsManager::getInstance(instanceNum).switchBackend(restart);
|
||||
}
|
||||
|
||||
void pauseNetwork(JNIEnv *env, jclass c, jint instanceNum) {
|
||||
|
@ -229,8 +233,8 @@ void updateDcSettings(JNIEnv *env, jclass c, jint instanceNum) {
|
|||
ConnectionsManager::getInstance(instanceNum).updateDcSettings(0, false);
|
||||
}
|
||||
|
||||
void setUseIpv6(JNIEnv *env, jclass c, jint instanceNum, jboolean value) {
|
||||
ConnectionsManager::getInstance(instanceNum).setUseIpv6(value);
|
||||
void setIpStrategy(JNIEnv *env, jclass c, jint instanceNum, jbyte value) {
|
||||
ConnectionsManager::getInstance(instanceNum).setIpStrategy((uint8_t) value);
|
||||
}
|
||||
|
||||
void setNetworkAvailable(JNIEnv *env, jclass c, jint instanceNum, jboolean value, jint networkType,
|
||||
|
@ -262,6 +266,7 @@ checkProxy(JNIEnv *env, jclass c, jint instanceNum, jstring address, jint port,
|
|||
const char *secretStr = env->GetStringUTFChars(secret, 0);
|
||||
|
||||
if (requestTimeFunc != nullptr) {
|
||||
DEBUG_REF("sendRequest requestTimeFunc");
|
||||
requestTimeFunc = env->NewGlobalRef(requestTimeFunc);
|
||||
}
|
||||
|
||||
|
@ -320,7 +325,7 @@ class Delegate : public ConnectiosManagerDelegate {
|
|||
if (connectionType == ConnectionTypeGeneric) {
|
||||
jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager,
|
||||
jclass_ConnectionsManager_onUnparsedMessageReceived,
|
||||
(jlong) (intptr_t) buffer, instanceNum);
|
||||
(jlong) (intptr_t) buffer, instanceNum, reqMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,8 +438,8 @@ void setSystemLangCode(JNIEnv *env, jclass c, jint instanceNum, jstring langCode
|
|||
void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jint apiId,
|
||||
jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode,
|
||||
jstring systemLangCode, jstring configPath, jstring logPath, jstring regId,
|
||||
jstring cFingerprint, jstring installerId, jint timezoneOffset, jint userId,
|
||||
jboolean enablePushConnection, jboolean hasNetwork, jint networkType) {
|
||||
jstring cFingerprint, jstring installerId, jstring packageId, jint timezoneOffset, jlong userId,
|
||||
jboolean enablePushConnection, jboolean hasNetwork, jint networkType, jint performanceClass) {
|
||||
const char *deviceModelStr = env->GetStringUTFChars(deviceModel, 0);
|
||||
const char *systemVersionStr = env->GetStringUTFChars(systemVersion, 0);
|
||||
const char *appVersionStr = env->GetStringUTFChars(appVersion, 0);
|
||||
|
@ -445,6 +450,7 @@ void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jin
|
|||
const char *regIdStr = env->GetStringUTFChars(regId, 0);
|
||||
const char *cFingerprintStr = env->GetStringUTFChars(cFingerprint, 0);
|
||||
const char *installerIdStr = env->GetStringUTFChars(installerId, 0);
|
||||
const char *packageIdStr = env->GetStringUTFChars(packageId, 0);
|
||||
|
||||
ConnectionsManager::getInstance(instanceNum).init((uint32_t) version, layer, apiId,
|
||||
std::string(deviceModelStr),
|
||||
|
@ -456,9 +462,9 @@ void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jin
|
|||
std::string(logPathStr),
|
||||
std::string(regIdStr),
|
||||
std::string(cFingerprintStr),
|
||||
std::string(installerIdStr), timezoneOffset,
|
||||
std::string(installerIdStr), std::string(packageIdStr), timezoneOffset,
|
||||
userId, true, enablePushConnection,
|
||||
hasNetwork, networkType);
|
||||
hasNetwork, networkType, performanceClass);
|
||||
|
||||
if (deviceModelStr != 0) {
|
||||
env->ReleaseStringUTFChars(deviceModel, deviceModelStr);
|
||||
|
@ -490,13 +496,20 @@ void init(JNIEnv *env, jclass c, jint instanceNum, jint version, jint layer, jin
|
|||
if (installerIdStr != 0) {
|
||||
env->ReleaseStringUTFChars(installerId, installerIdStr);
|
||||
}
|
||||
if (packageIdStr != 0) {
|
||||
env->ReleaseStringUTFChars(packageId, packageIdStr);
|
||||
}
|
||||
}
|
||||
|
||||
void setJava(JNIEnv *env, jclass c, jboolean useJavaByteBuffers) {
|
||||
ConnectionsManager::useJavaVM(java, useJavaByteBuffers);
|
||||
for (int a = 0; a < MAX_ACCOUNT_COUNT; a++) {
|
||||
ConnectionsManager::getInstance(a).setDelegate(new Delegate());
|
||||
}
|
||||
|
||||
void setJava1(JNIEnv *env, jclass c, jint instanceNum) {
|
||||
if (instanceNum >= jniEnv.capacity()) {
|
||||
jniEnv.resize(instanceNum + 10, nullptr);
|
||||
}
|
||||
ConnectionsManager::getInstance(instanceNum).setDelegate(new Delegate());
|
||||
}
|
||||
|
||||
static const char *ConnectionsManagerClassPathName = "org/telegram/tgnet/ConnectionsManager";
|
||||
|
@ -515,19 +528,20 @@ static JNINativeMethod ConnectionsManagerMethods[] = {
|
|||
{"native_moveToDatacenter", "(II)V", (void *) moveToDatacenter},
|
||||
{"native_setProxySettings", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", (void *) setProxySettings},
|
||||
{"native_getConnectionState", "(I)I", (void *) getConnectionState},
|
||||
{"native_setUserId", "(II)V", (void *) setUserId},
|
||||
{"native_init", "(IIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZZI)V", (void *) init},
|
||||
{"native_setUserId", "(IJ)V", (void *) setUserId},
|
||||
{"native_init", "(IIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IJZZII)V", (void *) init},
|
||||
{"native_setLangCode", "(ILjava/lang/String;)V", (void *) setLangCode},
|
||||
{"native_setRegId", "(ILjava/lang/String;)V", (void *) setRegId},
|
||||
{"native_setSystemLangCode", "(ILjava/lang/String;)V", (void *) setSystemLangCode},
|
||||
{"native_switchBackend", "(I)V", (void *) switchBackend},
|
||||
{"native_switchBackend", "(IZ)V", (void *) switchBackend},
|
||||
{"native_pauseNetwork", "(I)V", (void *) pauseNetwork},
|
||||
{"native_resumeNetwork", "(IZ)V", (void *) resumeNetwork},
|
||||
{"native_updateDcSettings", "(I)V", (void *) updateDcSettings},
|
||||
{"native_setUseIpv6", "(IZ)V", (void *) setUseIpv6},
|
||||
{"native_setIpStrategy", "(IB)V", (void *) setIpStrategy},
|
||||
{"native_setNetworkAvailable", "(IZIZ)V", (void *) setNetworkAvailable},
|
||||
{"native_setPushConnectionEnabled", "(IZ)V", (void *) setPushConnectionEnabled},
|
||||
{"native_setJava", "(Z)V", (void *) setJava},
|
||||
{"native_setJava", "(I)V", (void *) setJava1},
|
||||
{"native_applyDnsConfig", "(IJLjava/lang/String;I)V", (void *) applyDnsConfig},
|
||||
{"native_checkProxy", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/telegram/tgnet/RequestTimeDelegate;)J", (void *) checkProxy},
|
||||
{"native_onHostNameResolved", "(Ljava/lang/String;JLjava/lang/String;Z)V", (void *) onHostNameResolved}
|
||||
|
@ -560,18 +574,19 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
|
|||
sizeof(ConnectionsManagerMethods[0]))) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
DEBUG_REF("RequestDelegateInternal class");
|
||||
jclass_RequestDelegateInternal = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/telegram/tgnet/RequestDelegateInternal"));
|
||||
if (jclass_RequestDelegateInternal == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jclass_RequestDelegateInternal_run = env->GetMethodID(jclass_RequestDelegateInternal, "run",
|
||||
"(JILjava/lang/String;I)V");
|
||||
"(JILjava/lang/String;IJJ)V");
|
||||
if (jclass_RequestDelegateInternal_run == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
DEBUG_REF("RequestTimeDelegate class");
|
||||
jclass_RequestTimeDelegate = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/telegram/tgnet/RequestTimeDelegate"));
|
||||
if (jclass_RequestTimeDelegate == 0) {
|
||||
|
@ -582,6 +597,7 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
|
|||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
DEBUG_REF("QuickAckDelegate class");
|
||||
jclass_QuickAckDelegate = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/telegram/tgnet/QuickAckDelegate"));
|
||||
if (jclass_RequestDelegateInternal == 0) {
|
||||
|
@ -592,6 +608,7 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
|
|||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
DEBUG_REF("WriteToSocketDelegate class");
|
||||
jclass_WriteToSocketDelegate = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/telegram/tgnet/WriteToSocketDelegate"));
|
||||
if (jclass_WriteToSocketDelegate == 0) {
|
||||
|
@ -601,13 +618,14 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
|
|||
if (jclass_WriteToSocketDelegate_run == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
DEBUG_REF("ConnectionsManager class");
|
||||
jclass_ConnectionsManager = (jclass) env->NewGlobalRef(
|
||||
env->FindClass("org/telegram/tgnet/ConnectionsManager"));
|
||||
if (jclass_ConnectionsManager == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jclass_ConnectionsManager_onUnparsedMessageReceived = env->GetStaticMethodID(
|
||||
jclass_ConnectionsManager, "onUnparsedMessageReceived", "(JI)V");
|
||||
jclass_ConnectionsManager, "onUnparsedMessageReceived", "(JIJ)V");
|
||||
if (jclass_ConnectionsManager_onUnparsedMessageReceived == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
|
|
@ -219,7 +219,7 @@ static int writeOggPage(ogg_page *page, FILE *os) {
|
|||
return written;
|
||||
}
|
||||
|
||||
const opus_int32 bitrate = 25000;
|
||||
const opus_int32 bitrate = OPUS_BITRATE_MAX;
|
||||
const opus_int32 frame_size = 960;
|
||||
const int with_cvbr = 1;
|
||||
const int max_ogg_delay = 0;
|
||||
|
@ -290,11 +290,13 @@ int initRecorder(const char *path, opus_int32 sampleRate) {
|
|||
rate = sampleRate;
|
||||
|
||||
if (!path) {
|
||||
LOGE("path is null");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_fileOs = fopen(path, "wb");
|
||||
_fileOs = fopen(path, "w");
|
||||
if (!_fileOs) {
|
||||
LOGE("error cannot open file: %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -302,8 +304,8 @@ int initRecorder(const char *path, opus_int32 sampleRate) {
|
|||
inopt.gain = 0;
|
||||
inopt.endianness = 0;
|
||||
inopt.copy_comments = 0;
|
||||
inopt.rawmode = 1;
|
||||
inopt.ignorelength = 1;
|
||||
inopt.rawmode = 0;
|
||||
inopt.ignorelength = 0;
|
||||
inopt.samplesize = 16;
|
||||
inopt.channels = 1;
|
||||
inopt.skip = 0;
|
||||
|
@ -322,7 +324,7 @@ int initRecorder(const char *path, opus_int32 sampleRate) {
|
|||
header.nb_streams = 1;
|
||||
|
||||
int result = OPUS_OK;
|
||||
_encoder = opus_encoder_create(coding_rate, 1, OPUS_APPLICATION_AUDIO, &result);
|
||||
_encoder = opus_encoder_create(coding_rate, 1, OPUS_APPLICATION_VOIP, &result);
|
||||
if (result != OPUS_OK) {
|
||||
LOGE("Error cannot create encoder: %s", opus_strerror(result));
|
||||
return 0;
|
||||
|
@ -332,7 +334,7 @@ int initRecorder(const char *path, opus_int32 sampleRate) {
|
|||
_packet = malloc(max_frame_bytes);
|
||||
|
||||
result = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate));
|
||||
result = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(10));
|
||||
//result = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(10));
|
||||
if (result != OPUS_OK) {
|
||||
LOGE("Error OPUS_SET_BITRATE returned: %s", opus_strerror(result));
|
||||
return 0;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 78f15a6aa9f11ab7cff736f920c4858cc38264fb
|
||||
Subproject commit 9bcc12d540c3b844ba317f042c731d64142af725
|
|
@ -7,31 +7,38 @@ function build_one {
|
|||
cd ${CPU}
|
||||
|
||||
echo "Configuring..."
|
||||
cmake -DANDROID_NATIVE_API_LEVEL=${API} -DANDROID_ABI=${CPU} -DCMAKE_BUILD_TYPE=Release -DANDROID_NDK=${NDK} -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=16 -GNinja -DCMAKE_MAKE_PROGRAM=${NINJA_PATH} ../..
|
||||
|
||||
cmake \
|
||||
-DANDROID_NATIVE_API_LEVEL=${API} \
|
||||
-DANDROID_ABI=${CPU} \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DANDROID_NDK=${NDK} \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${NDK}/build/cmake/android.toolchain.cmake \
|
||||
-GNinja -DCMAKE_MAKE_PROGRAM=${NINJA_PATH} \
|
||||
../..
|
||||
|
||||
echo "Building..."
|
||||
cmake --build .
|
||||
|
||||
|
||||
cd ..
|
||||
}
|
||||
|
||||
function checkPreRequisites {
|
||||
|
||||
if ! [ -d "boringssl" ] || ! [ "$(ls -A boringssl)" ]; then
|
||||
echo -e "\033[31mFailed! Submodule 'boringssl' not found!\033[0m"
|
||||
echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
|
||||
exit
|
||||
fi
|
||||
if ! [ -d "boringssl" ] || ! [ "$(ls -A boringssl)" ]; then
|
||||
echo -e "\033[31mFailed! Submodule 'boringssl' not found!\033[0m"
|
||||
echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$NDK" -a "$NDK" == "" ]; then
|
||||
echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$NINJA_PATH" -a "$NINJA_PATH" == "" ]; then
|
||||
echo -e "\033[31mFailed! NINJA_PATH is empty. Run 'export NINJA_PATH=[PATH_TO_NINJA]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
if [ -z "$NDK" -a "$NDK" == "" ]; then
|
||||
echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$NINJA_PATH" -a "$NINJA_PATH" == "" ]; then
|
||||
echo -e "\033[31mFailed! NINJA_PATH is empty. Run 'export NINJA_PATH=[PATH_TO_NINJA]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
ANDROID_NDK=$NDK
|
||||
|
@ -39,20 +46,41 @@ checkPreRequisites
|
|||
|
||||
cd boringssl
|
||||
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
API=16
|
||||
function build {
|
||||
for arg in "$@"; do
|
||||
case "${arg}" in
|
||||
x86_64)
|
||||
API=21
|
||||
CPU=x86_64
|
||||
build_one
|
||||
;;
|
||||
arm64)
|
||||
API=21
|
||||
CPU=arm64-v8a
|
||||
build_one
|
||||
;;
|
||||
arm)
|
||||
API=16
|
||||
CPU=armeabi-v7a
|
||||
build_one
|
||||
;;
|
||||
x86)
|
||||
API=16
|
||||
CPU=x86
|
||||
build_one
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
CPU=armeabi-v7a
|
||||
build_one
|
||||
|
||||
CPU=x86
|
||||
build_one
|
||||
|
||||
API=21
|
||||
CPU=arm64-v8a
|
||||
build_one
|
||||
|
||||
CPU=x86_64
|
||||
build_one
|
||||
if (( $# == 0 )); then
|
||||
build x86_64 arm64 arm x86
|
||||
else
|
||||
build $@
|
||||
fi
|
||||
|
|
|
@ -1,185 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
function build_one {
|
||||
|
||||
echo "Cleaning..."
|
||||
rm config.h
|
||||
make clean
|
||||
|
||||
echo "Configuring..."
|
||||
|
||||
./configure \
|
||||
--cc=$CC \
|
||||
--nm=$NM \
|
||||
--enable-stripping \
|
||||
--arch=$ARCH \
|
||||
--target-os=linux \
|
||||
--enable-cross-compile \
|
||||
--x86asmexe=$NDK/prebuilt/$BUILD_PLATFORM/bin/yasm \
|
||||
--prefix=$PREFIX \
|
||||
--enable-pic \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--enable-asm \
|
||||
--enable-inline-asm \
|
||||
--cross-prefix=$CROSS_PREFIX \
|
||||
--sysroot=$PLATFORM \
|
||||
--extra-cflags="-Wl,-Bsymbolic -Os -DCONFIG_LINUX_PERF=0 -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static -fPIC" \
|
||||
--extra-ldflags="-Wl,-Bsymbolic -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -fPIC" \
|
||||
--extra-libs="-lgcc" \
|
||||
\
|
||||
--enable-version3 \
|
||||
--enable-gpl \
|
||||
\
|
||||
--disable-linux-perf \
|
||||
\
|
||||
--disable-doc \
|
||||
--disable-htmlpages \
|
||||
--disable-avx \
|
||||
\
|
||||
--disable-everything \
|
||||
--disable-network \
|
||||
--disable-zlib \
|
||||
--disable-avfilter \
|
||||
--disable-avdevice \
|
||||
--disable-postproc \
|
||||
--disable-debug \
|
||||
--disable-programs \
|
||||
--disable-network \
|
||||
--disable-ffplay \
|
||||
--disable-ffprobe \
|
||||
--disable-postproc \
|
||||
--disable-avdevice \
|
||||
\
|
||||
--enable-runtime-cpudetect \
|
||||
--enable-pthreads \
|
||||
--enable-avresample \
|
||||
--enable-swscale \
|
||||
--enable-protocol=file \
|
||||
--enable-decoder=h264 \
|
||||
--enable-decoder=mpeg4 \
|
||||
--enable-decoder=mjpeg \
|
||||
--enable-decoder=gif \
|
||||
--enable-decoder=alac \
|
||||
--enable-demuxer=mov \
|
||||
--enable-demuxer=gif \
|
||||
--enable-hwaccels \
|
||||
--enable-runtime-cpudetect \
|
||||
$ADDITIONAL_CONFIGURE_FLAG
|
||||
|
||||
#echo "continue?"
|
||||
#read
|
||||
make -j$COMPILATION_PROC_COUNT
|
||||
make install
|
||||
|
||||
}
|
||||
|
||||
function setCurrentPlatform {
|
||||
|
||||
PLATFORM="$(uname -s)"
|
||||
case "${PLATFORM}" in
|
||||
Darwin*)
|
||||
BUILD_PLATFORM=darwin-x86_64
|
||||
COMPILATION_PROC_COUNT=`sysctl -n hw.physicalcpu`
|
||||
;;
|
||||
Linux*)
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=$(nproc)
|
||||
;;
|
||||
*)
|
||||
echo -e "\033[33mWarning! Unknown platform ${PLATFORM}! falling back to linux-x86_64\033[0m"
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "build platform: ${BUILD_PLATFORM}"
|
||||
echo "parallel jobs: ${COMPILATION_PROC_COUNT}"
|
||||
|
||||
}
|
||||
|
||||
function checkPreRequisites {
|
||||
|
||||
if ! [ -d "ffmpeg" ] || ! [ "$(ls -A ffmpeg)" ]; then
|
||||
echo -e "\033[31mFailed! Submodule 'ffmpeg' not found!\033[0m"
|
||||
echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$NDK" -a "$NDK" == "" ]; then
|
||||
echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
setCurrentPlatform
|
||||
checkPreRequisites
|
||||
|
||||
# TODO: fix env variable for NDK
|
||||
# NDK=/opt/android-sdk/ndk-bundle
|
||||
|
||||
cd ffmpeg
|
||||
|
||||
#x86_64
|
||||
PREBUILT=$NDK/toolchains/x86_64-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-21/arch-x86_64
|
||||
LD=$PREBUILT/bin/x86_64-linux-android-ld
|
||||
AR=$PREBUILT/bin/x86_64-linux-android-ar
|
||||
NM=$PREBUILT/bin/x86_64-linux-android-nm
|
||||
GCCLIB=$PREBUILT/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a
|
||||
CC=$PREBUILT/bin/x86_64-linux-android-gcc
|
||||
CROSS_PREFIX=$PREBUILT/bin/x86_64-linux-android-
|
||||
ARCH=x86_64
|
||||
CPU=x86_64
|
||||
PREFIX=./build/$CPU
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-mmx --disable-inline-asm"
|
||||
#build_one
|
||||
|
||||
#arm64-v8a
|
||||
PREBUILT=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-21/arch-arm64
|
||||
LD=$PREBUILT/bin/aarch64-linux-android-ld
|
||||
AR=$PREBUILT/bin/aarch64-linux-android-ar
|
||||
NM=$PREBUILT/bin/aarch64-linux-android-nm
|
||||
GCCLIB=$PREBUILT/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a
|
||||
CC=$PREBUILT/bin/aarch64-linux-android-gcc
|
||||
CROSS_PREFIX=$PREBUILT/bin/aarch64-linux-android-
|
||||
ARCH=arm64
|
||||
CPU=arm64-v8a
|
||||
OPTIMIZE_CFLAGS=
|
||||
PREFIX=./build/$CPU
|
||||
ADDITIONAL_CONFIGURE_FLAG="--enable-neon --enable-optimizations"
|
||||
build_one
|
||||
|
||||
|
||||
#arm v7n
|
||||
PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-16/arch-arm
|
||||
LD=$PREBUILT/bin/arm-linux-androideabi-ld
|
||||
AR=$PREBUILT/bin/arm-linux-androideabi-ar
|
||||
NM=$PREBUILT/bin/arm-linux-androideabi-nm
|
||||
GCCLIB=$PREBUILT/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a
|
||||
CC=$PREBUILT/bin/arm-linux-androideabi-gcc
|
||||
CROSS_PREFIX=$PREBUILT/bin/arm-linux-androideabi-
|
||||
ARCH=arm
|
||||
CPU=armv7-a
|
||||
OPTIMIZE_CFLAGS="-marm -march=$CPU"
|
||||
PREFIX=./build/$CPU
|
||||
ADDITIONAL_CONFIGURE_FLAG=--enable-neon
|
||||
build_one
|
||||
|
||||
#x86 platform
|
||||
PREBUILT=$NDK/toolchains/x86-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-16/arch-x86
|
||||
LD=$PREBUILT/bin/i686-linux-android-ld
|
||||
AR=$PREBUILT/bin/i686-linux-android-ar
|
||||
NM=$PREBUILT/bin/i686-linux-android-nm
|
||||
GCCLIB=$PREBUILT/lib/gcc/i686-linux-android/4.9.x/libgcc.a
|
||||
CC=$PREBUILT/bin/i686-linux-android-gcc
|
||||
CROSS_PREFIX=$PREBUILT/bin/i686-linux-android-
|
||||
ARCH=x86
|
||||
CPU=i686
|
||||
OPTIMIZE_CFLAGS="-march=$CPU"
|
||||
PREFIX=./build/$CPU
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-mmx --disable-yasm"
|
||||
build_one
|
|
@ -1,28 +1,36 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
function build_one {
|
||||
CC="${CROSS_PREFIX}clang"
|
||||
CXX="${CROSS_PREFIX}clang++"
|
||||
AS="${CROSS_PREFIX}clang"
|
||||
AR="${CROSS_PREFIX}ar"
|
||||
LD="${CROSS_PREFIX}ld"
|
||||
NM="${CROSS_PREFIX}nm"
|
||||
STRIP="${CROSS_PREFIX}strip"
|
||||
echo "Building ${ARCH}..."
|
||||
|
||||
PREBUILT=${NDK}/toolchains/${PREBUILT_ARCH}${PREBUILT_MIDDLE}-${VERSION}/prebuilt/${BUILD_PLATFORM}
|
||||
PLATFORM=${NDK}/platforms/android-${ANDROID_API}/arch-${ARCH}
|
||||
|
||||
echo "Toolchain..."
|
||||
python $NDK/build/tools/make_standalone_toolchain.py \
|
||||
--arch ${ARCH} \
|
||||
--api ${ANDROID_API} \
|
||||
--stl libc++ \
|
||||
--install-dir=${TOOLCHAIN_PREFIX}
|
||||
TOOLS_PREFIX="${LLVM_BIN}/${ARCH_NAME}-linux-${BIN_MIDDLE}-"
|
||||
|
||||
LD=${TOOLS_PREFIX}ld
|
||||
AR=${TOOLS_PREFIX}ar
|
||||
STRIP=${TOOLS_PREFIX}strip
|
||||
NM=${TOOLS_PREFIX}nm
|
||||
|
||||
CC_PREFIX="${LLVM_BIN}/${CLANG_PREFIX}-linux-${BIN_MIDDLE}${ANDROID_API}-"
|
||||
|
||||
CC=${CC_PREFIX}clang
|
||||
CXX=${CC_PREFIX}clang++
|
||||
CROSS_PREFIX=${PREBUILT}/bin/${ARCH_NAME}-linux-${BIN_MIDDLE}-
|
||||
|
||||
INCLUDES=" -I./${LIBVPXPREFIX}/include"
|
||||
LIBS=" -L./${LIBVPXPREFIX}/lib"
|
||||
|
||||
echo "Cleaning..."
|
||||
rm -f config.h
|
||||
make clean || true
|
||||
|
||||
echo "Configuring..."
|
||||
|
||||
./configure \
|
||||
--nm=${NM} \
|
||||
--ar=${AR} \
|
||||
--as=${CROSS_PREFIX}gcc \
|
||||
--strip=${STRIP} \
|
||||
--cc=${CC} \
|
||||
--cxx=${CXX} \
|
||||
|
@ -30,18 +38,19 @@ function build_one {
|
|||
--arch=$ARCH \
|
||||
--target-os=linux \
|
||||
--enable-cross-compile \
|
||||
--x86asmexe=$NDK/prebuilt/$BUILD_PLATFORM/bin/yasm \
|
||||
--x86asmexe=$NDK/prebuilt/${BUILD_PLATFORM}/bin/yasm \
|
||||
--prefix=$PREFIX \
|
||||
--enable-pic \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--enable-asm \
|
||||
--enable-inline-asm \
|
||||
--enable-x86asm \
|
||||
--enable-asm \
|
||||
--enable-inline-asm \
|
||||
--enable-x86asm \
|
||||
--cross-prefix=$CROSS_PREFIX \
|
||||
--sysroot=$SYSROOT \
|
||||
--extra-cflags="-Wl,-Bsymbolic -Os -DCONFIG_LINUX_PERF=0 -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static -fPIC" \
|
||||
--extra-ldflags="-Wl,-Bsymbolic -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -fPIC" \
|
||||
--sysroot="${LLVM_PREFIX}/sysroot" \
|
||||
--extra-cflags="${INCLUDES} -Wl,-Bsymbolic -Os -DCONFIG_LINUX_PERF=0 -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static -fPIC" \
|
||||
--extra-cxxflags="${INCLUDES} -Wl,-Bsymbolic -Os -DCONFIG_LINUX_PERF=0 -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static -fPIC" \
|
||||
--extra-ldflags="${LIBS} -Wl,-Bsymbolic -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -lc -lm -ldl -fPIC" \
|
||||
\
|
||||
--enable-version3 \
|
||||
--enable-gpl \
|
||||
|
@ -60,17 +69,18 @@ function build_one {
|
|||
--disable-postproc \
|
||||
--disable-debug \
|
||||
--disable-programs \
|
||||
--disable-network \
|
||||
--disable-ffplay \
|
||||
--disable-ffprobe \
|
||||
--disable-postproc \
|
||||
--disable-avdevice \
|
||||
\
|
||||
--enable-libvpx \
|
||||
--enable-decoder=libvpx_vp9 \
|
||||
--enable-runtime-cpudetect \
|
||||
--enable-pthreads \
|
||||
--enable-avresample \
|
||||
--enable-swscale \
|
||||
--enable-protocol=file \
|
||||
--enable-decoder=opus \
|
||||
--enable-decoder=h264 \
|
||||
--enable-decoder=mpeg4 \
|
||||
--enable-decoder=mjpeg \
|
||||
|
@ -78,6 +88,8 @@ function build_one {
|
|||
--enable-decoder=alac \
|
||||
--enable-demuxer=mov \
|
||||
--enable-demuxer=gif \
|
||||
--enable-demuxer=ogg \
|
||||
--enable-demuxer=matroska \
|
||||
--enable-hwaccels \
|
||||
$ADDITIONAL_CONFIGURE_FLAG
|
||||
|
||||
|
@ -85,50 +97,44 @@ function build_one {
|
|||
#read
|
||||
make -j$COMPILATION_PROC_COUNT
|
||||
make install
|
||||
|
||||
echo "Cleaning..."
|
||||
rm -f config.h
|
||||
make clean || true
|
||||
rm -rf ${TOOLCHAIN_PREFIX}
|
||||
|
||||
}
|
||||
|
||||
function setCurrentPlatform {
|
||||
|
||||
PLATFORM="$(uname -s)"
|
||||
case "${PLATFORM}" in
|
||||
Darwin*)
|
||||
BUILD_PLATFORM=darwin-x86_64
|
||||
COMPILATION_PROC_COUNT=`sysctl -n hw.physicalcpu`
|
||||
;;
|
||||
Linux*)
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=$(nproc)
|
||||
;;
|
||||
*)
|
||||
echo -e "\033[33mWarning! Unknown platform ${PLATFORM}! falling back to linux-x86_64\033[0m"
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=1
|
||||
;;
|
||||
esac
|
||||
CURRENT_PLATFORM="$(uname -s)"
|
||||
case "${CURRENT_PLATFORM}" in
|
||||
Darwin*)
|
||||
BUILD_PLATFORM=darwin-x86_64
|
||||
COMPILATION_PROC_COUNT=`sysctl -n hw.physicalcpu`
|
||||
;;
|
||||
Linux*)
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=$(nproc)
|
||||
;;
|
||||
*)
|
||||
echo -e "\033[33mWarning! Unknown platform ${CURRENT_PLATFORM}! falling back to linux-x86_64\033[0m"
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "build platform: ${BUILD_PLATFORM}"
|
||||
echo "parallel jobs: ${COMPILATION_PROC_COUNT}"
|
||||
echo "Build platform: ${BUILD_PLATFORM}"
|
||||
echo "Parallel jobs: ${COMPILATION_PROC_COUNT}"
|
||||
|
||||
}
|
||||
|
||||
function checkPreRequisites {
|
||||
|
||||
if ! [ -d "ffmpeg" ] || ! [ "$(ls -A ffmpeg)" ]; then
|
||||
echo -e "\033[31mFailed! Submodule 'ffmpeg' not found!\033[0m"
|
||||
echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
|
||||
exit
|
||||
fi
|
||||
if ! [ -d "ffmpeg" ] || ! [ "$(ls -A ffmpeg)" ]; then
|
||||
echo -e "\033[31mFailed! Submodule 'ffmpeg' not found!\033[0m"
|
||||
echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$NDK" -a "$NDK" == "" ]; then
|
||||
echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
if [ -z "$NDK" -a "$NDK" == "" ]; then
|
||||
echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
setCurrentPlatform
|
||||
|
@ -139,56 +145,85 @@ checkPreRequisites
|
|||
|
||||
cd ffmpeg
|
||||
|
||||
BASEDIR=`pwd`
|
||||
TOOLCHAIN_PREFIX=${BASEDIR}/toolchain-android
|
||||
|
||||
## common
|
||||
SYSROOT=${TOOLCHAIN_PREFIX}/sysroot
|
||||
LLVM_PREFIX="${NDK}/toolchains/llvm/prebuilt/linux-x86_64"
|
||||
LLVM_BIN="${LLVM_PREFIX}/bin"
|
||||
VERSION="4.9"
|
||||
|
||||
#x86_64
|
||||
ANDROID_API=21
|
||||
PREBUILT=$NDK/toolchains/x86_64-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-21/arch-x86_64
|
||||
CROSS_PREFIX=${TOOLCHAIN_PREFIX}/bin/x86_64-linux-android-
|
||||
ARCH=x86_64
|
||||
CPU=x86_64
|
||||
PREFIX=./build/$CPU
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-asm"
|
||||
build_one
|
||||
function build {
|
||||
for arg in "$@"; do
|
||||
case "${arg}" in
|
||||
x86_64)
|
||||
ANDROID_API=21
|
||||
|
||||
#arm64-v8a
|
||||
ANDROID_API=21
|
||||
PREBUILT=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-21/arch-arm64
|
||||
CROSS_PREFIX=${TOOLCHAIN_PREFIX}/bin/aarch64-linux-android-
|
||||
ARCH=arm64
|
||||
CPU=arm64-v8a
|
||||
OPTIMIZE_CFLAGS=
|
||||
PREFIX=./build/$CPU
|
||||
ADDITIONAL_CONFIGURE_FLAG="--enable-neon --enable-optimizations"
|
||||
build_one
|
||||
ARCH=x86_64
|
||||
ARCH_NAME=x86_64
|
||||
PREBUILT_ARCH=x86_64
|
||||
PREBUILT_MIDDLE=
|
||||
CLANG_PREFIX=x86_64
|
||||
BIN_MIDDLE=android
|
||||
CPU=x86_64
|
||||
PREFIX=./build/$CPU
|
||||
LIBVPXPREFIX=../libvpx/build/x86_64
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-asm"
|
||||
build_one
|
||||
;;
|
||||
arm64)
|
||||
ANDROID_API=21
|
||||
|
||||
ARCH=arm64
|
||||
ARCH_NAME=aarch64
|
||||
PREBUILT_ARCH=aarch64
|
||||
PREBUILT_MIDDLE="-linux-android"
|
||||
CLANG_PREFIX=aarch64
|
||||
BIN_MIDDLE=android
|
||||
CPU=arm64-v8a
|
||||
OPTIMIZE_CFLAGS=
|
||||
PREFIX=./build/$CPU
|
||||
LIBVPXPREFIX=../libvpx/build/arm64-v8a
|
||||
ADDITIONAL_CONFIGURE_FLAG="--enable-neon --enable-optimizations"
|
||||
build_one
|
||||
;;
|
||||
arm)
|
||||
ANDROID_API=16
|
||||
|
||||
#arm v7n
|
||||
ANDROID_API=16
|
||||
PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-16/arch-arm
|
||||
CROSS_PREFIX=${TOOLCHAIN_PREFIX}/bin/arm-linux-androideabi-
|
||||
ARCH=arm
|
||||
CPU=armv7-a
|
||||
OPTIMIZE_CFLAGS="-marm -march=$CPU"
|
||||
PREFIX=./build/armeabi-v7a
|
||||
ADDITIONAL_CONFIGURE_FLAG="--enable-neon"
|
||||
build_one
|
||||
ARCH=arm
|
||||
ARCH_NAME=arm
|
||||
PREBUILT_ARCH=arm
|
||||
PREBUILT_MIDDLE="-linux-androideabi"
|
||||
CLANG_PREFIX=armv7a
|
||||
BIN_MIDDLE=androideabi
|
||||
CPU=armv7-a
|
||||
OPTIMIZE_CFLAGS="-marm -march=$CPU"
|
||||
PREFIX=./build/armeabi-v7a
|
||||
LIBVPXPREFIX=../libvpx/build/armeabi-v7a
|
||||
ADDITIONAL_CONFIGURE_FLAG="--enable-neon"
|
||||
build_one
|
||||
;;
|
||||
x86)
|
||||
ANDROID_API=16
|
||||
|
||||
#x86 platform
|
||||
ANDROID_API=16
|
||||
PREBUILT=$NDK/toolchains/x86-4.9/prebuilt/$BUILD_PLATFORM
|
||||
PLATFORM=$NDK/platforms/android-16/arch-x86
|
||||
CROSS_PREFIX=${TOOLCHAIN_PREFIX}/bin/i686-linux-android-
|
||||
ARCH=x86
|
||||
CPU=i686
|
||||
OPTIMIZE_CFLAGS="-march=$CPU"
|
||||
PREFIX=./build/x86
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-x86asm --disable-inline-asm --disable-asm"
|
||||
build_one
|
||||
ARCH=x86
|
||||
ARCH_NAME=i686
|
||||
PREBUILT_ARCH=x86
|
||||
PREBUILT_MIDDLE=
|
||||
CLANG_PREFIX=i686
|
||||
BIN_MIDDLE=android
|
||||
CPU=i686
|
||||
OPTIMIZE_CFLAGS="-march=$CPU"
|
||||
PREFIX=./build/x86
|
||||
LIBVPXPREFIX=../libvpx/build/x86
|
||||
ADDITIONAL_CONFIGURE_FLAG="--disable-x86asm --disable-inline-asm --disable-asm"
|
||||
build_one
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
if (( $# == 0 )); then
|
||||
build x86_64 arm64 arm x86
|
||||
else
|
||||
build $@
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
function build_one {
|
||||
echo "Building ${ARCH}..."
|
||||
|
||||
PREBUILT=${NDK}/toolchains/${PREBUILT_ARCH}-${VERSION}/prebuilt/${BUILD_PLATFORM}
|
||||
PLATFORM=${NDK}/platforms/android-${ANDROID_API}/arch-${ARCH}
|
||||
|
||||
TOOLS_PREFIX="${LLVM_BIN}/${ARCH_NAME}-linux-${BIN_MIDDLE}-"
|
||||
|
||||
export LD=${TOOLS_PREFIX}ld
|
||||
export AR=${TOOLS_PREFIX}ar
|
||||
export STRIP=${TOOLS_PREFIX}strip
|
||||
export RANLIB=${TOOLS_PREFIX}ranlib
|
||||
export NM=${TOOLS_PREFIX}nm
|
||||
|
||||
export CC_PREFIX="${LLVM_BIN}/${CLANG_PREFIX}-linux-${BIN_MIDDLE}${ANDROID_API}-"
|
||||
|
||||
export CC=${CC_PREFIX}clang
|
||||
export CXX=${CC_PREFIX}clang++
|
||||
export AS=${CC_PREFIX}clang++
|
||||
export CROSS_PREFIX=${PREBUILT}/bin/${ARCH_NAME}-linux-${BIN_MIDDLE}-
|
||||
|
||||
|
||||
export CFLAGS="-DANDROID -fpic -fpie ${OPTIMIZE_CFLAGS}"
|
||||
export CPPFLAGS="${CFLAGS}"
|
||||
export CXXFLAGS="${CFLAGS} -std=c++11"
|
||||
export ASFLAGS="-D__ANDROID__"
|
||||
export LDFLAGS="-L${PLATFORM}/usr/lib"
|
||||
|
||||
if [ "x86" = ${ARCH} ]; then
|
||||
patch -p1 < ../patches/libvpx_x86_fix.patch
|
||||
fi
|
||||
echo "Cleaning..."
|
||||
make clean || true
|
||||
|
||||
echo "Configuring..."
|
||||
|
||||
|
||||
|
||||
./configure \
|
||||
--extra-cflags="-isystem ${LLVM_PREFIX}/sysroot/usr/include/${ARCH_NAME}-linux-${BIN_MIDDLE} -isystem ${LLVM_PREFIX}/sysroot/usr/include ${OPTIMIZE_CFLAGS}" \
|
||||
--libc="${LLVM_PREFIX}/sysroot" \
|
||||
--prefix=${PREFIX} \
|
||||
--target=${TARGET} \
|
||||
${CPU_DETECT} \
|
||||
--as=yasm \
|
||||
--enable-static \
|
||||
--enable-pic \
|
||||
--disable-docs \
|
||||
--enable-libyuv \
|
||||
--enable-small \
|
||||
--enable-optimizations \
|
||||
--enable-better-hw-compatibility \
|
||||
--disable-examples \
|
||||
--disable-tools \
|
||||
--disable-debug \
|
||||
--disable-unit-tests \
|
||||
--disable-install-docs \
|
||||
--enable-realtime-only \
|
||||
--enable-vp8 \
|
||||
--enable-vp9 \
|
||||
--disable-webm-io
|
||||
|
||||
make -j$COMPILATION_PROC_COUNT install
|
||||
|
||||
if [ "x86" = ${ARCH} ]; then
|
||||
patch -p1 -R < ../patches/libvpx_x86_fix.patch
|
||||
fi
|
||||
}
|
||||
|
||||
function setCurrentPlatform {
|
||||
|
||||
CURRENT_PLATFORM="$(uname -s)"
|
||||
case "${CURRENT_PLATFORM}" in
|
||||
Darwin*)
|
||||
BUILD_PLATFORM=darwin-x86_64
|
||||
COMPILATION_PROC_COUNT=`sysctl -n hw.physicalcpu`
|
||||
;;
|
||||
Linux*)
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=$(nproc)
|
||||
;;
|
||||
*)
|
||||
echo -e "\033[33mWarning! Unknown platform ${CURRENT_PLATFORM}! falling back to linux-x86_64\033[0m"
|
||||
BUILD_PLATFORM=linux-x86_64
|
||||
COMPILATION_PROC_COUNT=1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Build platform: ${BUILD_PLATFORM}"
|
||||
echo "Parallel jobs: ${COMPILATION_PROC_COUNT}"
|
||||
|
||||
}
|
||||
|
||||
function checkPreRequisites {
|
||||
|
||||
if ! [ -d "libvpx" ] || ! [ "$(ls -A libvpx)" ]; then
|
||||
echo -e "\033[31mFailed! Submodule 'libvpx' not found!\033[0m"
|
||||
echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -z "$NDK" -a "$NDK" == "" ]; then
|
||||
echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
setCurrentPlatform
|
||||
checkPreRequisites
|
||||
|
||||
cd libvpx
|
||||
|
||||
## common
|
||||
LLVM_PREFIX="${NDK}/toolchains/llvm/prebuilt/linux-x86_64"
|
||||
LLVM_BIN="${LLVM_PREFIX}/bin"
|
||||
VERSION="4.9"
|
||||
ANDROID_API=21
|
||||
|
||||
function build {
|
||||
for arg in "$@"; do
|
||||
case "${arg}" in
|
||||
x86_64)
|
||||
ANDROID_API=21
|
||||
ARCH=x86_64
|
||||
ARCH_NAME=x86_64
|
||||
PREBUILT_ARCH=x86_64
|
||||
CLANG_PREFIX=x86_64
|
||||
BIN_MIDDLE=android
|
||||
CPU=x86_64
|
||||
OPTIMIZE_CFLAGS="-O3 -march=x86-64 -mtune=intel -msse4.2 -mpopcnt -m64 -fPIC"
|
||||
TARGET="x86_64-android-gcc"
|
||||
PREFIX=./build/$CPU
|
||||
CPU_DETECT="--enable-runtime-cpu-detect"
|
||||
build_one
|
||||
;;
|
||||
x86)
|
||||
ANDROID_API=21
|
||||
ARCH=x86
|
||||
ARCH_NAME=i686
|
||||
PREBUILT_ARCH=x86
|
||||
CLANG_PREFIX=i686
|
||||
BIN_MIDDLE=android
|
||||
CPU=i686
|
||||
OPTIMIZE_CFLAGS="-O3 -march=i686 -mtune=intel -msse3 -mfpmath=sse -m32 -fPIC"
|
||||
TARGET="x86-android-gcc"
|
||||
PREFIX=./build/x86
|
||||
CPU_DETECT="--enable-runtime-cpu-detect"
|
||||
build_one
|
||||
;;
|
||||
arm64)
|
||||
ANDROID_API=21
|
||||
ARCH=arm64
|
||||
ARCH_NAME=aarch64
|
||||
PREBUILT_ARCH=aarch64
|
||||
CLANG_PREFIX=aarch64
|
||||
BIN_MIDDLE=android
|
||||
CPU=arm64-v8a
|
||||
OPTIMIZE_CFLAGS="-O3 -march=armv8-a"
|
||||
TARGET="arm64-android-gcc"
|
||||
PREFIX=./build/$CPU
|
||||
CPU_DETECT="--disable-runtime-cpu-detect"
|
||||
build_one
|
||||
;;
|
||||
arm)
|
||||
ANDROID_API=21
|
||||
ARCH=arm
|
||||
ARCH_NAME=arm
|
||||
PREBUILT_ARCH=arm
|
||||
CLANG_PREFIX=armv7a
|
||||
BIN_MIDDLE=androideabi
|
||||
CPU=armeabi-v7a
|
||||
OPTIMIZE_CFLAGS="-Os -D_LIBCPP_HAS_QUICK_EXIT -O3 -march=armv7-a -mfloat-abi=softfp -mfpu=neon -mtune=cortex-a8 -mthumb -D__thumb__"
|
||||
TARGET="armv7-android-gcc --enable-neon --disable-neon-asm"
|
||||
PREFIX=./build/$CPU
|
||||
CPU_DETECT="--disable-runtime-cpu-detect"
|
||||
build_one
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
if (( $# == 0 )); then
|
||||
build x86 x86_64 arm arm64
|
||||
else
|
||||
build $@
|
||||
fi
|
|
@ -1 +1 @@
|
|||
Subproject commit f9f95ceebfbd7b7f43c1b7ad34e25d366e6e2d2b
|
||||
Subproject commit 4bc4cafaef8a55462138d7b6f7579c1522de26dc
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef FFMPEG_MATHOPS_FIX_H
|
||||
#define FFMPEG_MATHOPS_FIX_H
|
||||
|
||||
#ifndef NEG_USR32
|
||||
# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s)))
|
||||
#endif
|
||||
|
||||
#ifndef NEG_SSR32
|
||||
# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s)))
|
||||
#endif
|
||||
|
||||
#ifndef sign_extend
|
||||
static inline av_const int sign_extend(int val, unsigned bits)
|
||||
{
|
||||
unsigned shift = 8 * sizeof(int) - bits;
|
||||
union { unsigned u; int s; } v = { (unsigned) val << shift };
|
||||
return v.s >> shift;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef zero_extend
|
||||
static inline av_const unsigned zero_extend(unsigned val, unsigned bits)
|
||||
{
|
||||
return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SUINT
|
||||
#define SUINT unsigned
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -10,21 +10,29 @@
|
|||
#include <libyuv.h>
|
||||
#include <tgnet/FileLog.h>
|
||||
#include "tgnet/ConnectionsManager.h"
|
||||
#include "voip/webrtc/common_video/h264/sps_parser.h"
|
||||
#include "voip/webrtc/common_video/h264/h264_common.h"
|
||||
#include "c_utils.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavformat/isom.h>
|
||||
#include <libavcodec/bytestream.h>
|
||||
#include <libavcodec/get_bits.h>
|
||||
#include <libavcodec/golomb.h>
|
||||
#include <libavutil/eval.h>
|
||||
#include <libavutil/intmath.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
|
||||
#define RGB8888_A(p) ((p & (0xff<<24)) >> 24 )
|
||||
|
||||
static const std::string av_make_error_str(int errnum) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
return (std::string) errbuf;
|
||||
}
|
||||
|
||||
|
||||
#undef av_err2str
|
||||
#define av_err2str(errnum) av_make_error_str(errnum).c_str()
|
||||
#define FFMPEG_AVSEEK_SIZE 0x10000
|
||||
|
@ -35,8 +43,55 @@ jmethodID jclass_AnimatedFileDrawableStream_cancel;
|
|||
jmethodID jclass_AnimatedFileDrawableStream_isFinishedLoadingFile;
|
||||
jmethodID jclass_AnimatedFileDrawableStream_getFinishedFilePath;
|
||||
|
||||
typedef struct H2645NAL {
|
||||
uint8_t *rbsp_buffer;
|
||||
int size;
|
||||
const uint8_t *data;
|
||||
int size_bits;
|
||||
int raw_size;
|
||||
const uint8_t *raw_data;
|
||||
int type;
|
||||
int temporal_id;
|
||||
int nuh_layer_id;
|
||||
int skipped_bytes;
|
||||
int skipped_bytes_pos_size;
|
||||
int *skipped_bytes_pos;
|
||||
int ref_idc;
|
||||
GetBitContext gb;
|
||||
} H2645NAL;
|
||||
|
||||
typedef struct H2645RBSP {
|
||||
uint8_t *rbsp_buffer;
|
||||
AVBufferRef *rbsp_buffer_ref;
|
||||
int rbsp_buffer_alloc_size;
|
||||
int rbsp_buffer_size;
|
||||
} H2645RBSP;
|
||||
|
||||
typedef struct H2645Packet {
|
||||
H2645NAL *nals;
|
||||
H2645RBSP rbsp;
|
||||
int nb_nals;
|
||||
int nals_allocated;
|
||||
unsigned nal_buffer_size;
|
||||
} H2645Packet;
|
||||
|
||||
void ff_h2645_packet_uninit(H2645Packet *pkt) {
|
||||
int i;
|
||||
for (i = 0; i < pkt->nals_allocated; i++) {
|
||||
av_freep(&pkt->nals[i].skipped_bytes_pos);
|
||||
}
|
||||
av_freep(&pkt->nals);
|
||||
pkt->nals_allocated = pkt->nal_buffer_size = 0;
|
||||
if (pkt->rbsp.rbsp_buffer_ref) {
|
||||
av_buffer_unref(&pkt->rbsp.rbsp_buffer_ref);
|
||||
pkt->rbsp.rbsp_buffer = NULL;
|
||||
} else
|
||||
av_freep(&pkt->rbsp.rbsp_buffer);
|
||||
pkt->rbsp.rbsp_buffer_alloc_size = pkt->rbsp.rbsp_buffer_size = 0;
|
||||
}
|
||||
|
||||
typedef struct VideoInfo {
|
||||
|
||||
|
||||
~VideoInfo() {
|
||||
if (video_dec_ctx) {
|
||||
avcodec_close(video_dec_ctx);
|
||||
|
@ -66,6 +121,7 @@ typedef struct VideoInfo {
|
|||
} else {
|
||||
attached = false;
|
||||
}
|
||||
DEBUG_DELREF("gifvideocpp stream");
|
||||
jniEnv->DeleteGlobalRef(stream);
|
||||
if (attached) {
|
||||
javaVm->DetachCurrentThread();
|
||||
|
@ -88,6 +144,7 @@ typedef struct VideoInfo {
|
|||
fd = -1;
|
||||
}
|
||||
|
||||
ff_h2645_packet_uninit(&h2645Packet);
|
||||
av_packet_unref(&orig_pkt);
|
||||
|
||||
video_stream_idx = -1;
|
||||
|
@ -108,6 +165,13 @@ typedef struct VideoInfo {
|
|||
bool stopped = false;
|
||||
bool seeking = false;
|
||||
|
||||
int firstWidth = 0;
|
||||
int firstHeight = 0;
|
||||
|
||||
bool dropFrames = false;
|
||||
|
||||
H2645Packet h2645Packet = {nullptr};
|
||||
|
||||
int32_t dst_linesize[1];
|
||||
|
||||
struct SwsContext *sws_ctx = nullptr;
|
||||
|
@ -121,12 +185,36 @@ typedef struct VideoInfo {
|
|||
int64_t last_seek_p = 0;
|
||||
};
|
||||
|
||||
void custom_log(void *ptr, int level, const char* fmt, va_list vl){
|
||||
va_list vl2;
|
||||
char line[1024];
|
||||
static int print_prefix = 1;
|
||||
|
||||
va_copy(vl2, vl);
|
||||
av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
|
||||
va_end(vl2);
|
||||
|
||||
LOGE(line);
|
||||
}
|
||||
|
||||
static enum AVPixelFormat get_format(AVCodecContext *ctx,
|
||||
const enum AVPixelFormat *pix_fmts)
|
||||
{
|
||||
const enum AVPixelFormat *p;
|
||||
|
||||
for (p = pix_fmts; *p != -1; p++) {
|
||||
LOGE("available format %d", p);
|
||||
}
|
||||
|
||||
return pix_fmts[0];
|
||||
}
|
||||
|
||||
int open_codec_context(int *stream_idx, AVCodecContext **dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type) {
|
||||
int ret, stream_index;
|
||||
AVStream *st;
|
||||
AVCodec *dec = NULL;
|
||||
AVDictionary *opts = NULL;
|
||||
|
||||
|
||||
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
|
||||
if (ret < 0) {
|
||||
LOGE("can't find %s stream in input file", av_get_media_type_string(type));
|
||||
|
@ -159,22 +247,484 @@ int open_codec_context(int *stream_idx, AVCodecContext **dec_ctx, AVFormatContex
|
|||
}
|
||||
*stream_idx = stream_index;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_MBPAIR_SIZE (256*1024)
|
||||
|
||||
int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, H2645NAL *nal)
|
||||
{
|
||||
int i, si, di;
|
||||
uint8_t *dst;
|
||||
|
||||
nal->skipped_bytes = 0;
|
||||
#define STARTCODE_TEST \
|
||||
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \
|
||||
if (src[i + 2] != 3 && src[i + 2] != 0) { \
|
||||
/* startcode, so we must be past the end */ \
|
||||
length = i; \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
for (i = 0; i + 1 < length; i += 2) {
|
||||
if (src[i])
|
||||
continue;
|
||||
if (i > 0 && src[i - 1] == 0)
|
||||
i--;
|
||||
STARTCODE_TEST;
|
||||
}
|
||||
|
||||
if (i > length)
|
||||
i = length;
|
||||
|
||||
nal->rbsp_buffer = &rbsp->rbsp_buffer[rbsp->rbsp_buffer_size];
|
||||
dst = nal->rbsp_buffer;
|
||||
|
||||
memcpy(dst, src, i);
|
||||
si = di = i;
|
||||
while (si + 2 < length) {
|
||||
if (src[si + 2] > 3) {
|
||||
dst[di++] = src[si++];
|
||||
dst[di++] = src[si++];
|
||||
} else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] != 0) {
|
||||
if (src[si + 2] == 3) {
|
||||
dst[di++] = 0;
|
||||
dst[di++] = 0;
|
||||
si += 3;
|
||||
|
||||
if (nal->skipped_bytes_pos) {
|
||||
nal->skipped_bytes++;
|
||||
if (nal->skipped_bytes_pos_size < nal->skipped_bytes) {
|
||||
nal->skipped_bytes_pos_size *= 2;
|
||||
av_reallocp_array(&nal->skipped_bytes_pos,
|
||||
nal->skipped_bytes_pos_size,
|
||||
sizeof(*nal->skipped_bytes_pos));
|
||||
if (!nal->skipped_bytes_pos) {
|
||||
nal->skipped_bytes_pos_size = 0;
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
}
|
||||
if (nal->skipped_bytes_pos)
|
||||
nal->skipped_bytes_pos[nal->skipped_bytes-1] = di - 1;
|
||||
}
|
||||
continue;
|
||||
} else // next start code
|
||||
goto nsc;
|
||||
}
|
||||
|
||||
dst[di++] = src[si++];
|
||||
}
|
||||
while (si < length)
|
||||
dst[di++] = src[si++];
|
||||
|
||||
nsc:
|
||||
memset(dst + di, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
|
||||
nal->data = dst;
|
||||
nal->size = di;
|
||||
nal->raw_data = src;
|
||||
nal->raw_size = si;
|
||||
rbsp->rbsp_buffer_size += si;
|
||||
|
||||
return si;
|
||||
}
|
||||
|
||||
static inline int get_nalsize(int nal_length_size, const uint8_t *buf, int buf_size, int *buf_index) {
|
||||
int i, nalsize = 0;
|
||||
if (*buf_index >= buf_size - nal_length_size) {
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
for (i = 0; i < nal_length_size; i++)
|
||||
nalsize = ((unsigned)nalsize << 8) | buf[(*buf_index)++];
|
||||
if (nalsize <= 0 || nalsize > buf_size - *buf_index) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
return nalsize;
|
||||
}
|
||||
|
||||
static int find_next_start_code(const uint8_t *buf, const uint8_t *next_avc) {
|
||||
int i = 0;
|
||||
if (buf + 3 >= next_avc)
|
||||
return next_avc - buf;
|
||||
while (buf + i + 3 < next_avc) {
|
||||
if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return i + 3;
|
||||
}
|
||||
|
||||
static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros) {
|
||||
int size = nal->size;
|
||||
int v;
|
||||
|
||||
while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0)
|
||||
size--;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
v = nal->data[size - 1];
|
||||
|
||||
if (size > INT_MAX / 8)
|
||||
return AVERROR(ERANGE);
|
||||
size *= 8;
|
||||
|
||||
/* remove the stop bit and following trailing zeros,
|
||||
* or nothing for damaged bitstreams */
|
||||
if (v)
|
||||
size -= ff_ctz(v) + 1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void alloc_rbsp_buffer(H2645RBSP *rbsp, unsigned int size) {
|
||||
int min_size = size;
|
||||
|
||||
if (size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
|
||||
goto fail;
|
||||
size += AV_INPUT_BUFFER_PADDING_SIZE;
|
||||
|
||||
if (rbsp->rbsp_buffer_alloc_size >= size &&
|
||||
(!rbsp->rbsp_buffer_ref || av_buffer_is_writable(rbsp->rbsp_buffer_ref))) {
|
||||
memset(rbsp->rbsp_buffer + min_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
size = FFMIN(size + size / 16 + 32, INT_MAX);
|
||||
|
||||
if (rbsp->rbsp_buffer_ref)
|
||||
av_buffer_unref(&rbsp->rbsp_buffer_ref);
|
||||
else
|
||||
av_free(rbsp->rbsp_buffer);
|
||||
|
||||
rbsp->rbsp_buffer = (uint8_t *) av_mallocz(size);
|
||||
if (!rbsp->rbsp_buffer)
|
||||
goto fail;
|
||||
rbsp->rbsp_buffer_alloc_size = size;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
rbsp->rbsp_buffer_alloc_size = 0;
|
||||
if (rbsp->rbsp_buffer_ref) {
|
||||
av_buffer_unref(&rbsp->rbsp_buffer_ref);
|
||||
rbsp->rbsp_buffer = NULL;
|
||||
} else
|
||||
av_freep(&rbsp->rbsp_buffer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int h264_parse_nal_header(H2645NAL *nal) {
|
||||
GetBitContext *gb = &nal->gb;
|
||||
|
||||
if (get_bits1(gb) != 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
nal->ref_idc = get_bits(gb, 2);
|
||||
nal->type = get_bits(gb, 5);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, int is_nalff, int nal_length_size) {
|
||||
GetByteContext bc;
|
||||
int consumed, ret = 0;
|
||||
int next_avc = is_nalff ? 0 : length;
|
||||
int64_t padding = MAX_MBPAIR_SIZE;
|
||||
|
||||
bytestream2_init(&bc, buf, length);
|
||||
alloc_rbsp_buffer(&pkt->rbsp, length + padding);
|
||||
|
||||
if (!pkt->rbsp.rbsp_buffer)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
pkt->rbsp.rbsp_buffer_size = 0;
|
||||
pkt->nb_nals = 0;
|
||||
while (bytestream2_get_bytes_left(&bc) >= 4) {
|
||||
H2645NAL *nal;
|
||||
int extract_length = 0;
|
||||
int skip_trailing_zeros = 1;
|
||||
|
||||
if (bytestream2_tell(&bc) == next_avc) {
|
||||
int i = 0;
|
||||
extract_length = get_nalsize(nal_length_size, bc.buffer, bytestream2_get_bytes_left(&bc), &i);
|
||||
if (extract_length < 0)
|
||||
return extract_length;
|
||||
|
||||
bytestream2_skip(&bc, nal_length_size);
|
||||
|
||||
next_avc = bytestream2_tell(&bc) + extract_length;
|
||||
} else {
|
||||
int buf_index;
|
||||
buf_index = find_next_start_code(bc.buffer, buf + next_avc);
|
||||
bytestream2_skip(&bc, buf_index);
|
||||
if (!bytestream2_get_bytes_left(&bc)) {
|
||||
if (pkt->nb_nals > 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
}
|
||||
extract_length = FFMIN(bytestream2_get_bytes_left(&bc), next_avc - bytestream2_tell(&bc));
|
||||
if (bytestream2_tell(&bc) >= next_avc) {
|
||||
bytestream2_skip(&bc, next_avc - bytestream2_tell(&bc));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (pkt->nals_allocated < pkt->nb_nals + 1) {
|
||||
int new_size = pkt->nals_allocated + 1;
|
||||
void *tmp;
|
||||
|
||||
if (new_size >= INT_MAX / sizeof(*pkt->nals))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
tmp = av_fast_realloc(pkt->nals, &pkt->nal_buffer_size, new_size * sizeof(*pkt->nals));
|
||||
if (!tmp)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
pkt->nals = (H2645NAL *) tmp;
|
||||
memset(pkt->nals + pkt->nals_allocated, 0, sizeof(*pkt->nals));
|
||||
|
||||
nal = &pkt->nals[pkt->nb_nals];
|
||||
nal->skipped_bytes_pos_size = 1024;
|
||||
nal->skipped_bytes_pos = (int *) av_malloc_array(nal->skipped_bytes_pos_size, sizeof(*nal->skipped_bytes_pos));
|
||||
if (!nal->skipped_bytes_pos)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
pkt->nals_allocated = new_size;
|
||||
}
|
||||
nal = &pkt->nals[pkt->nb_nals];
|
||||
|
||||
consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal);
|
||||
if (consumed < 0)
|
||||
return consumed;
|
||||
|
||||
pkt->nb_nals++;
|
||||
|
||||
bytestream2_skip(&bc, consumed);
|
||||
|
||||
/* see commit 3566042a0 */
|
||||
if (bytestream2_get_bytes_left(&bc) >= 4 &&
|
||||
bytestream2_peek_be32(&bc) == 0x000001E0)
|
||||
skip_trailing_zeros = 0;
|
||||
|
||||
nal->size_bits = get_bit_length(nal, skip_trailing_zeros);
|
||||
|
||||
ret = init_get_bits(&nal->gb, nal->data, nal->size_bits);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = h264_parse_nal_header(nal);
|
||||
if (ret <= 0 || nal->size <= 0 || nal->size_bits <= 0) {
|
||||
pkt->nb_nals--;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_SPS_COUNT 32
|
||||
|
||||
const uint8_t ff_zigzag_direct[64] = {
|
||||
0, 1, 8, 16, 9, 2, 3, 10,
|
||||
17, 24, 32, 25, 18, 11, 4, 5,
|
||||
12, 19, 26, 33, 40, 48, 41, 34,
|
||||
27, 20, 13, 6, 7, 14, 21, 28,
|
||||
35, 42, 49, 56, 57, 50, 43, 36,
|
||||
29, 22, 15, 23, 30, 37, 44, 51,
|
||||
58, 59, 52, 45, 38, 31, 39, 46,
|
||||
53, 60, 61, 54, 47, 55, 62, 63
|
||||
};
|
||||
|
||||
const uint8_t ff_zigzag_scan[16+1] = {
|
||||
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
|
||||
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
|
||||
1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4,
|
||||
3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
|
||||
};
|
||||
|
||||
static int decode_scaling_list(GetBitContext *gb, uint8_t *factors, int size) {
|
||||
int i, last = 8, next = 8;
|
||||
const uint8_t *scan = size == 16 ? ff_zigzag_scan : ff_zigzag_direct;
|
||||
if (!get_bits1(gb)) {
|
||||
|
||||
} else {
|
||||
for (i = 0; i < size; i++) {
|
||||
if (next) {
|
||||
int v = get_se_golomb(gb);
|
||||
if (v < -128 || v > 127) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
next = (last + v) & 0xff;
|
||||
}
|
||||
if (!i && !next) { /* matrix not written, we use the preset one */
|
||||
break;
|
||||
}
|
||||
last = factors[scan[i]] = next ? next : last;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_scaling_matrices(GetBitContext *gb, int chroma_format_idc, uint8_t(*scaling_matrix4)[16], uint8_t(*scaling_matrix8)[64]) {
|
||||
int ret = 0;
|
||||
if (get_bits1(gb)) {
|
||||
ret |= decode_scaling_list(gb, scaling_matrix4[0], 16); // Intra, Y
|
||||
ret |= decode_scaling_list(gb, scaling_matrix4[1], 16); // Intra, Cr
|
||||
ret |= decode_scaling_list(gb, scaling_matrix4[2], 16); // Intra, Cb
|
||||
ret |= decode_scaling_list(gb, scaling_matrix4[3], 16); // Inter, Y
|
||||
ret |= decode_scaling_list(gb, scaling_matrix4[4], 16); // Inter, Cr
|
||||
ret |= decode_scaling_list(gb, scaling_matrix4[5], 16); // Inter, Cb
|
||||
|
||||
ret |= decode_scaling_list(gb, scaling_matrix8[0], 64); // Intra, Y
|
||||
ret |= decode_scaling_list(gb, scaling_matrix8[3], 64); // Inter, Y
|
||||
if (chroma_format_idc == 3) {
|
||||
ret |= decode_scaling_list(gb, scaling_matrix8[1], 64); // Intra, Cr
|
||||
ret |= decode_scaling_list(gb, scaling_matrix8[4], 64); // Inter, Cr
|
||||
ret |= decode_scaling_list(gb, scaling_matrix8[2], 64); // Intra, Cb
|
||||
ret |= decode_scaling_list(gb, scaling_matrix8[5], 64); // Inter, Cb
|
||||
}
|
||||
if (!ret)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ff_h264_decode_seq_parameter_set(GetBitContext *gb, int &width, int &height) {
|
||||
int profile_idc, level_idc, constraint_set_flags = 0;
|
||||
unsigned int sps_id;
|
||||
int i, log2_max_frame_num_minus4;
|
||||
int ret;
|
||||
|
||||
profile_idc = get_bits(gb, 8);
|
||||
constraint_set_flags |= get_bits1(gb) << 0;
|
||||
constraint_set_flags |= get_bits1(gb) << 1;
|
||||
constraint_set_flags |= get_bits1(gb) << 2;
|
||||
constraint_set_flags |= get_bits1(gb) << 3;
|
||||
constraint_set_flags |= get_bits1(gb) << 4;
|
||||
constraint_set_flags |= get_bits1(gb) << 5;
|
||||
skip_bits(gb, 2);
|
||||
level_idc = get_bits(gb, 8);
|
||||
sps_id = get_ue_golomb_31(gb);
|
||||
|
||||
if (sps_id >= MAX_SPS_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (profile_idc == 100 || // High profile
|
||||
profile_idc == 110 || // High10 profile
|
||||
profile_idc == 122 || // High422 profile
|
||||
profile_idc == 244 || // High444 Predictive profile
|
||||
profile_idc == 44 || // Cavlc444 profile
|
||||
profile_idc == 83 || // Scalable Constrained High profile (SVC)
|
||||
profile_idc == 86 || // Scalable High Intra profile (SVC)
|
||||
profile_idc == 118 || // Stereo High profile (MVC)
|
||||
profile_idc == 128 || // Multiview High profile (MVC)
|
||||
profile_idc == 138 || // Multiview Depth High profile (MVCD)
|
||||
profile_idc == 144) { // old High444 profile
|
||||
int chroma_format_idc = get_ue_golomb_31(gb);
|
||||
if (chroma_format_idc > 3U) {
|
||||
return false;
|
||||
} else if (chroma_format_idc == 3) {
|
||||
int residual_color_transform_flag = get_bits1(gb);
|
||||
if (residual_color_transform_flag) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int bit_depth_luma = get_ue_golomb(gb) + 8;
|
||||
int bit_depth_chroma = get_ue_golomb(gb) + 8;
|
||||
if (bit_depth_chroma != bit_depth_luma) {
|
||||
return false;
|
||||
}
|
||||
if (bit_depth_luma < 8 || bit_depth_luma > 14 || bit_depth_chroma < 8 || bit_depth_chroma > 14) {
|
||||
return false;
|
||||
}
|
||||
get_bits1(gb);
|
||||
uint8_t scaling_matrix4[6][16];
|
||||
uint8_t scaling_matrix8[6][64];
|
||||
ret = decode_scaling_matrices(gb, chroma_format_idc, scaling_matrix4, scaling_matrix8);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
get_ue_golomb(gb);
|
||||
|
||||
int poc_type = get_ue_golomb_31(gb);
|
||||
|
||||
if (poc_type == 0) {
|
||||
unsigned t = get_ue_golomb(gb);
|
||||
if (t > 12) {
|
||||
return false;
|
||||
}
|
||||
} else if (poc_type == 1) {
|
||||
get_bits1(gb);
|
||||
int offset_for_non_ref_pic = get_se_golomb_long(gb);
|
||||
int offset_for_top_to_bottom_field = get_se_golomb_long(gb);
|
||||
|
||||
if (offset_for_non_ref_pic == INT32_MIN || offset_for_top_to_bottom_field == INT32_MIN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int poc_cycle_length = get_ue_golomb(gb);
|
||||
|
||||
if ((unsigned) poc_cycle_length >= 256) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < poc_cycle_length; i++) {
|
||||
int offset_for_ref_frame = get_se_golomb_long(gb);
|
||||
if (offset_for_ref_frame == INT32_MIN) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (poc_type != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_ue_golomb_31(gb);
|
||||
get_bits1(gb);
|
||||
int mb_width = get_ue_golomb(gb) + 1;
|
||||
int mb_height = get_ue_golomb(gb) + 1;
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
width = mb_width;
|
||||
height = mb_height;
|
||||
}
|
||||
return mb_width != width || mb_height != height;
|
||||
}
|
||||
|
||||
int decode_packet(VideoInfo *info, int *got_frame) {
|
||||
int ret = 0;
|
||||
int decoded = info->pkt.size;
|
||||
*got_frame = 0;
|
||||
|
||||
|
||||
if (info->pkt.stream_index == info->video_stream_idx) {
|
||||
ret = avcodec_decode_video2(info->video_dec_ctx, info->frame, got_frame, &info->pkt);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
if (info->video_stream->codecpar->codec_id == AV_CODEC_ID_H264 && decoded > 0) {
|
||||
ff_h2645_packet_split(&info->h2645Packet, info->pkt.data, info->pkt.size, 1, 4);
|
||||
for (int i = 0; i < info->h2645Packet.nb_nals; i++) {
|
||||
H2645NAL *nal = &info->h2645Packet.nals[i];
|
||||
switch (nal->type) {
|
||||
case 7: {
|
||||
GetBitContext tmp_gb = nal->gb;
|
||||
info->dropFrames = ff_h264_decode_seq_parameter_set(&tmp_gb, info->firstWidth, info->firstHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!info->dropFrames) {
|
||||
ret = avcodec_decode_video2(info->video_dec_ctx, info->frame, got_frame, &info->pkt);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
|
@ -241,8 +791,14 @@ int readCallback(void *opaque, uint8_t *buf, int buf_size) {
|
|||
if (attached) {
|
||||
javaVm->DetachCurrentThread();
|
||||
}
|
||||
if (buf_size == 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
int ret = (int) read(info->fd, buf, (size_t) buf_size);
|
||||
return ret ? ret : AVERROR_EOF;
|
||||
if (ret <= 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +943,7 @@ extern "C" JNIEXPORT void JNICALL Java_org_telegram_ui_Components_AnimatedFileDr
|
|||
|
||||
extern "C" JNIEXPORT jlong JNICALL Java_org_telegram_ui_Components_AnimatedFileDrawable_createDecoder(JNIEnv *env, jclass clazz, jstring src, jintArray data, jint account, jlong streamFileSize, jobject stream, jboolean preview) {
|
||||
VideoInfo *info = new VideoInfo();
|
||||
|
||||
|
||||
char const *srcString = env->GetStringUTFChars(src, 0);
|
||||
size_t len = strlen(srcString);
|
||||
info->src = new char[len + 1];
|
||||
|
@ -400,6 +956,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_telegram_ui_Components_AnimatedFileD
|
|||
int ret;
|
||||
if (streamFileSize != 0) {
|
||||
info->file_size = streamFileSize;
|
||||
DEBUG_REF("gifvideo.cpp new stream");
|
||||
info->stream = env->NewGlobalRef(stream);
|
||||
info->account = account;
|
||||
info->fd = open(info->src, O_RDONLY, S_IRUSR);
|
||||
|
@ -434,13 +991,13 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_telegram_ui_Components_AnimatedFileD
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((ret = avformat_find_stream_info(info->fmt_ctx, NULL)) < 0) {
|
||||
LOGE("can't find stream information %s, %s", info->src, av_err2str(ret));
|
||||
delete info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (open_codec_context(&info->video_stream_idx, &info->video_dec_ctx, info->fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
|
||||
info->video_stream = info->fmt_ctx->streams[info->video_stream_idx];
|
||||
}
|
||||
|
@ -450,14 +1007,14 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_telegram_ui_Components_AnimatedFileD
|
|||
delete info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
info->frame = av_frame_alloc();
|
||||
if (info->frame == nullptr) {
|
||||
LOGE("can't allocate frame %s", info->src);
|
||||
delete info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
av_init_packet(&info->pkt);
|
||||
info->pkt.data = NULL;
|
||||
info->pkt.size = 0;
|
||||
|
@ -481,9 +1038,9 @@ extern "C" JNIEXPORT jlong JNICALL Java_org_telegram_ui_Components_AnimatedFileD
|
|||
//(int32_t) (1000 * info->video_stream->duration * av_q2d(info->video_stream->time_base));
|
||||
env->ReleaseIntArrayElements(data, dataArr, 0);
|
||||
}
|
||||
|
||||
|
||||
//LOGD("successfully opened file %s", info->src);
|
||||
|
||||
|
||||
return (jlong) (intptr_t) info;
|
||||
}
|
||||
|
||||
|
@ -586,7 +1143,7 @@ extern "C" JNIEXPORT void JNICALL Java_org_telegram_ui_Components_AnimatedFileDr
|
|||
if (got_frame) {
|
||||
info->has_decoded_frames = true;
|
||||
bool finished = false;
|
||||
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
if (info->frame->format == AV_PIX_FMT_YUV444P || info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
int64_t pkt_pts = info->frame->best_effort_timestamp;
|
||||
if (pkt_pts >= pts) {
|
||||
finished = true;
|
||||
|
@ -602,6 +1159,11 @@ extern "C" JNIEXPORT void JNICALL Java_org_telegram_ui_Components_AnimatedFileDr
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t premultiply_channel_value(const uint32_t pixel, const uint8_t offset, const float normalizedAlpha) {
|
||||
auto multipliedValue = ((pixel >> offset) & 0xFF) * normalizedAlpha;
|
||||
return ((uint32_t)std::min(multipliedValue, 255.0f)) << offset;
|
||||
}
|
||||
|
||||
static inline void writeFrameToBitmap(JNIEnv *env, VideoInfo *info, jintArray data, jobject bitmap, jint stride) {
|
||||
jint *dataArr = env->GetIntArrayElements(data, 0);
|
||||
int32_t wantedWidth;
|
||||
|
@ -621,18 +1183,22 @@ static inline void writeFrameToBitmap(JNIEnv *env, VideoInfo *info, jintArray da
|
|||
wantedHeight = bitmapHeight;
|
||||
}
|
||||
|
||||
void *pixels;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) {
|
||||
if (wantedWidth == info->frame->width && wantedHeight == info->frame->height || wantedWidth == info->frame->height && wantedHeight == info->frame->width) {
|
||||
if (wantedWidth == info->frame->width && wantedHeight == info->frame->height || wantedWidth == info->frame->height && wantedHeight == info->frame->width) {
|
||||
void *pixels;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) {
|
||||
if (info->sws_ctx == nullptr) {
|
||||
if (info->frame->format > AV_PIX_FMT_NONE && info->frame->format < AV_PIX_FMT_NB) {
|
||||
if (info->frame->format > AV_PIX_FMT_NONE && info->frame->format < AV_PIX_FMT_NB && info->frame->format != AV_PIX_FMT_YUVA420P) {
|
||||
info->sws_ctx = sws_getContext(info->frame->width, info->frame->height, (AVPixelFormat) info->frame->format, bitmapWidth, bitmapHeight, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
} else if (info->video_dec_ctx->pix_fmt > AV_PIX_FMT_NONE && info->video_dec_ctx->pix_fmt < AV_PIX_FMT_NB) {
|
||||
} else if (info->video_dec_ctx->pix_fmt > AV_PIX_FMT_NONE && info->video_dec_ctx->pix_fmt < AV_PIX_FMT_NB && info->frame->format != AV_PIX_FMT_YUVA420P) {
|
||||
info->sws_ctx = sws_getContext(info->video_dec_ctx->width, info->video_dec_ctx->height, info->video_dec_ctx->pix_fmt, bitmapWidth, bitmapHeight, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (info->sws_ctx == nullptr || ((intptr_t) pixels) % 16 != 0) {
|
||||
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
if (info->frame->format == AV_PIX_FMT_YUVA420P) {
|
||||
libyuv::I420AlphaToARGBMatrix(info->frame->data[0], info->frame->linesize[0], info->frame->data[2], info->frame->linesize[2], info->frame->data[1], info->frame->linesize[1], info->frame->data[3], info->frame->linesize[3], (uint8_t *) pixels, bitmapWidth * 4, &libyuv::kYvuI601Constants, bitmapWidth, bitmapHeight, 1);
|
||||
} else if (info->frame->format == AV_PIX_FMT_YUV444P) {
|
||||
libyuv::H444ToARGB(info->frame->data[0], info->frame->linesize[0], info->frame->data[2], info->frame->linesize[2], info->frame->data[1], info->frame->linesize[1], (uint8_t *) pixels, bitmapWidth * 4, bitmapWidth, bitmapHeight);
|
||||
} else if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
if (info->frame->colorspace == AVColorSpace::AVCOL_SPC_BT709) {
|
||||
libyuv::H420ToARGB(info->frame->data[0], info->frame->linesize[0], info->frame->data[2], info->frame->linesize[2], info->frame->data[1], info->frame->linesize[1], (uint8_t *) pixels, bitmapWidth * 4, bitmapWidth, bitmapHeight);
|
||||
} else {
|
||||
|
@ -707,7 +1273,7 @@ extern "C" JNIEXPORT int JNICALL Java_org_telegram_ui_Components_AnimatedFileDra
|
|||
}
|
||||
if (got_frame) {
|
||||
bool finished = false;
|
||||
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
if (info->frame->format == AV_PIX_FMT_YUV444P || info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
int64_t pkt_pts = info->frame->best_effort_timestamp;
|
||||
bool isLastPacket = false;
|
||||
if (info->pkt.size == 0) {
|
||||
|
@ -801,7 +1367,7 @@ extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDr
|
|||
}
|
||||
if (got_frame) {
|
||||
//LOGD("decoded frame with w = %d, h = %d, format = %d", info->frame->width, info->frame->height, info->frame->format);
|
||||
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P) {
|
||||
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P || info->frame->format == AV_PIX_FMT_YUV444P || info->frame->format == AV_PIX_FMT_YUVA420P) {
|
||||
writeFrameToBitmap(env, info, data, bitmap, stride);
|
||||
}
|
||||
info->has_decoded_frames = true;
|
||||
|
@ -816,6 +1382,8 @@ extern "C" JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_AnimatedFileDr
|
|||
}
|
||||
|
||||
extern "C" jint videoOnJNILoad(JavaVM *vm, JNIEnv *env) {
|
||||
//av_log_set_callback(custom_log);
|
||||
DEBUG_REF("gifvideo.cpp AnimatedFileDrawableStream ref");
|
||||
jclass_AnimatedFileDrawableStream = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/messenger/AnimatedFileDrawableStream"));
|
||||
if (jclass_AnimatedFileDrawableStream == 0) {
|
||||
return JNI_FALSE;
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cstdio>
|
||||
#include <csetjmp>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <unistd.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <string>
|
||||
#include <mozjpeg/java/org_libjpegturbo_turbojpeg_TJ.h>
|
||||
#include <mozjpeg/jpeglib.h>
|
||||
#include <tgnet/FileLog.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "webp/decode.h"
|
||||
#include "webp/encode.h"
|
||||
#include "mozjpeg/turbojpeg.h"
|
||||
|
@ -24,14 +27,17 @@ jfieldID jclass_Options_outHeight;
|
|||
jfieldID jclass_Options_outWidth;
|
||||
|
||||
jint imageOnJNILoad(JavaVM *vm, JNIEnv *env) {
|
||||
DEBUG_REF("image.cpp nullpointerexception class");
|
||||
jclass_NullPointerException = (jclass) env->NewGlobalRef(env->FindClass("java/lang/NullPointerException"));
|
||||
if (jclass_NullPointerException == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
DEBUG_REF("image.cpp runtimeexception class");
|
||||
jclass_RuntimeException = (jclass) env->NewGlobalRef(env->FindClass("java/lang/RuntimeException"));
|
||||
if (jclass_RuntimeException == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
DEBUG_REF("image.cpp bitmapfactoryoptions class");
|
||||
jclass_Options = (jclass) env->NewGlobalRef(env->FindClass("android/graphics/BitmapFactory$Options"));
|
||||
if (jclass_Options == 0) {
|
||||
return JNI_FALSE;
|
||||
|
@ -150,7 +156,7 @@ static void fastBlurMore(int32_t w, int32_t h, int32_t stride, uint8_t *pix, int
|
|||
}
|
||||
|
||||
static void fastBlur(int32_t w, int32_t h, int32_t stride, uint8_t *pix, int32_t radius) {
|
||||
if (pix == NULL) {
|
||||
if (pix == nullptr) {
|
||||
return;
|
||||
}
|
||||
const int32_t r1 = radius + 1;
|
||||
|
@ -173,7 +179,7 @@ static void fastBlur(int32_t w, int32_t h, int32_t stride, uint8_t *pix, int32_t
|
|||
}
|
||||
|
||||
uint64_t *rgb = new uint64_t[w * h];
|
||||
if (rgb == NULL) {
|
||||
if (rgb == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -450,11 +456,11 @@ JNIEXPORT int Java_org_telegram_messenger_Utilities_needInvert(JNIEnv *env, jcla
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *pixels = 0;
|
||||
void *pixels = nullptr;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (pixels == NULL) {
|
||||
if (pixels == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t *pix = (uint8_t *) pixels;
|
||||
|
@ -516,7 +522,7 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_blurBitmap(JNIEnv *env, jcl
|
|||
return;
|
||||
}
|
||||
|
||||
void *pixels = 0;
|
||||
void *pixels = nullptr;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -642,7 +648,7 @@ JNIEXPORT jint Java_org_telegram_messenger_Utilities_pinBitmap(JNIEnv *env, jcla
|
|||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_unpinBitmap(JNIEnv *env, jclass clazz, jobject bitmap) {
|
||||
if (bitmap == NULL) {
|
||||
if (bitmap == nullptr) {
|
||||
return;
|
||||
}
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
|
@ -680,7 +686,7 @@ JNIEXPORT jboolean Java_org_telegram_messenger_Utilities_loadWebpImage(JNIEnv *e
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *bitmapPixels = 0;
|
||||
void *bitmapPixels = nullptr;
|
||||
if (AndroidBitmap_lockPixels(env, outputBitmap, &bitmapPixels) != ANDROID_BITMAP_RESUT_SUCCESS) {
|
||||
env->ThrowNew(jclass_RuntimeException, "Failed to lock Bitmap pixels");
|
||||
return 0;
|
||||
|
@ -723,7 +729,7 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv *env
|
|||
int h = info.height;
|
||||
int stride = info.stride;
|
||||
|
||||
unsigned char *pixels = 0;
|
||||
unsigned char *pixels = nullptr;
|
||||
AndroidBitmap_lockPixels(env, bitmap, (void **) &pixels);
|
||||
if (!pixels) {
|
||||
return;
|
||||
|
@ -1078,6 +1084,9 @@ JNIEXPORT jint Java_org_telegram_messenger_Utilities_saveProgressiveJpeg(JNIEnv
|
|||
return 0;
|
||||
}
|
||||
const char *pathStr = env->GetStringUTFChars(path, 0);
|
||||
if (pathStr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
std::string filePath = std::string(pathStr);
|
||||
if (pathStr != 0) {
|
||||
env->ReleaseStringUTFChars(path, pathStr);
|
||||
|
@ -1166,4 +1175,129 @@ JNIEXPORT jint Java_org_telegram_messenger_Utilities_saveProgressiveJpeg(JNIEnv
|
|||
return outSize;*/
|
||||
}
|
||||
|
||||
std::vector<std::pair<float, float>> gatherPositions(std::vector<std::pair<float, float>> list, int phase) {
|
||||
std::vector<std::pair<float, float>> result(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int pos = phase + i * 2;
|
||||
while (pos >= 8) {
|
||||
pos -= 8;
|
||||
}
|
||||
result[i] = list[pos];
|
||||
result[i].second = 1.0f - result[i].second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
thread_local static float *pixelCache = nullptr;
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_generateGradient(JNIEnv *env, jclass clazz, jobject bitmap, jboolean unpin, jint phase, jfloat progress, jint width, jint height, jint stride, jintArray colors) {
|
||||
if (!bitmap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *pixels = nullptr;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, (void **) &pixels) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::pair<float, float>> positions{
|
||||
{0.80f, 0.10f},
|
||||
{0.60f, 0.20f},
|
||||
{0.35f, 0.25f},
|
||||
{0.25f, 0.60f},
|
||||
{0.20f, 0.90f},
|
||||
{0.40f, 0.80f},
|
||||
{0.65f, 0.75f},
|
||||
{0.75f, 0.40f}
|
||||
};
|
||||
|
||||
int32_t previousPhase = phase + 1;
|
||||
if (previousPhase > 7) {
|
||||
previousPhase = 0;
|
||||
}
|
||||
std::vector<std::pair<float, float>> previous = gatherPositions(positions, previousPhase);
|
||||
std::vector<std::pair<float, float>> current = gatherPositions(positions, phase);
|
||||
|
||||
auto colorsArray = (uint8_t *) env->GetIntArrayElements(colors, nullptr);
|
||||
float *newPixelCache = nullptr;
|
||||
if (pixelCache == nullptr) {
|
||||
newPixelCache = new float[width * height * 2];
|
||||
}
|
||||
float directPixelY;
|
||||
float centerDistanceY;
|
||||
float centerDistanceY2;
|
||||
int32_t colorsCount = colorsArray[12] == 0 && colorsArray[13] == 0 && colorsArray[14] == 0 && colorsArray[15] == 0 ? 3 : 4;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
if (pixelCache == nullptr) {
|
||||
directPixelY = (float) y / (float) height;
|
||||
centerDistanceY = directPixelY - 0.5f;
|
||||
centerDistanceY2 = centerDistanceY * centerDistanceY;
|
||||
}
|
||||
uint32_t offset = y * stride;
|
||||
for (int x = 0; x < width; x++) {
|
||||
float pixelX;
|
||||
float pixelY;
|
||||
if (pixelCache != nullptr) {
|
||||
pixelX = pixelCache[(y * width + x) * 2];
|
||||
pixelY = pixelCache[(y * width + x) * 2 + 1];
|
||||
} else {
|
||||
float directPixelX = (float) x / (float) width;
|
||||
|
||||
float centerDistanceX = directPixelX - 0.5f;
|
||||
float centerDistance = sqrtf(centerDistanceX * centerDistanceX + centerDistanceY2);
|
||||
|
||||
float swirlFactor = 0.35f * centerDistance;
|
||||
float theta = swirlFactor * swirlFactor * 0.8f * 8.0f;
|
||||
float sinTheta = sinf(theta);
|
||||
float cosTheta = cosf(theta);
|
||||
|
||||
pixelX = newPixelCache[(y * width + x) * 2] = std::max(0.0f, std::min(1.0f, 0.5f + centerDistanceX * cosTheta - centerDistanceY * sinTheta));
|
||||
pixelY = newPixelCache[(y * width + x) * 2 + 1] = std::max(0.0f, std::min(1.0f, 0.5f + centerDistanceX * sinTheta + centerDistanceY * cosTheta));
|
||||
}
|
||||
|
||||
float distanceSum = 0.0f;
|
||||
|
||||
float r = 0.0f;
|
||||
float g = 0.0f;
|
||||
float b = 0.0f;
|
||||
|
||||
for (int i = 0; i < colorsCount; i++) {
|
||||
float colorX = previous[i].first + (current[i].first - previous[i].first) * progress;
|
||||
float colorY = previous[i].second + (current[i].second - previous[i].second) * progress;
|
||||
|
||||
float distanceX = pixelX - colorX;
|
||||
float distanceY = pixelY - colorY;
|
||||
|
||||
float distance = std::max(0.0f, 0.9f - sqrtf(distanceX * distanceX + distanceY * distanceY));
|
||||
distance = distance * distance * distance * distance;
|
||||
distanceSum += distance;
|
||||
|
||||
r = r + distance * ((float) colorsArray[i * 4] / 255.0f);
|
||||
g = g + distance * ((float) colorsArray[i * 4 + 1] / 255.0f);
|
||||
b = b + distance * ((float) colorsArray[i * 4 + 2] / 255.0f);
|
||||
}
|
||||
|
||||
pixels[offset + x * 4] = (uint8_t) (b / distanceSum * 255.0f);
|
||||
pixels[offset + x * 4 + 1] = (uint8_t) (g / distanceSum * 255.0f);
|
||||
pixels[offset + x * 4 + 2] = (uint8_t) (r / distanceSum * 255.0f);
|
||||
pixels[offset + x * 4 + 3] = 0xff;
|
||||
}
|
||||
}
|
||||
if (newPixelCache != nullptr) {
|
||||
delete [] pixelCache;
|
||||
pixelCache = newPixelCache;
|
||||
}
|
||||
|
||||
env->ReleaseIntArrayElements(colors, (jint *) colorsArray, JNI_ABORT);
|
||||
|
||||
if (unpin) {
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -36,6 +36,7 @@ static Shape cloud_extra_mask1;
|
|||
static Shape cloud_extra_mask2;
|
||||
static Shape cloud_extra_mask3;
|
||||
static Shape cloud_extra_mask4;
|
||||
static int surfaceCreated = 0;
|
||||
|
||||
static Shape cloud_cover;
|
||||
|
||||
|
@ -54,7 +55,7 @@ static TexturedShape powerful_mask, powerful_infinity, powerful_infinity_white;
|
|||
|
||||
static Shape private_bg;
|
||||
|
||||
static TexturedShape telegram_sphere, telegram_plane;
|
||||
static TexturedShape telegram_sphere, telegram_plane, telegram_mask;
|
||||
|
||||
static Shape cloud_bg;
|
||||
|
||||
|
@ -72,7 +73,7 @@ static mat4x4 ribbons_layer;
|
|||
|
||||
static TexturedShape ic_bubble_dot, ic_bubble, ic_cam_lens, ic_cam, ic_pencil, ic_pin, ic_smile_eye, ic_smile, ic_videocam;
|
||||
static GLuint ic_bubble_dot_texture, ic_bubble_texture, ic_cam_lens_texture, ic_cam_texture, ic_pencil_texture, ic_pin_texture, ic_smile_eye_texture, ic_smile_texture, ic_videocam_texture;
|
||||
static GLuint telegram_sphere_texture, telegram_plane_texture;
|
||||
static GLuint telegram_sphere_texture, telegram_plane_texture, telegram_mask_texture;
|
||||
static GLuint fast_spiral_texture, fast_body_texture, fast_arrow_texture, fast_arrow_shadow_texture;
|
||||
static GLuint free_knot_up_texture, free_knot_down_texture;
|
||||
static GLuint powerful_mask_texture, powerful_star_texture, powerful_infinity_texture, powerful_infinity_white_texture;
|
||||
|
@ -105,6 +106,7 @@ static float scroll_offset;
|
|||
static float calculated_speedometer_sin;
|
||||
float ms0_anim;
|
||||
int fps_anim;
|
||||
int last_stars_update_fps;
|
||||
int count_anim_fps;
|
||||
static float speedometer_scroll_offset = 0, free_scroll_offset = 0, private_scroll_offset = 0;
|
||||
float anim_pencil_start_time, anim_pencil_start_all_time, anim_pencil_start_all_end_time;
|
||||
|
@ -125,6 +127,8 @@ static int32_t anim_pencil_period;
|
|||
static mat4x4 private_matrix;
|
||||
float cloud_scroll_offset;
|
||||
|
||||
vec4 background_color = {1, 1, 1, 1};
|
||||
|
||||
static inline void vec2_add(vec2 r, vec2 a, vec2 b) {
|
||||
int32_t i;
|
||||
for (i = 0; i < 2; ++i) {
|
||||
|
@ -1122,6 +1126,8 @@ xyz star_initial_position(int32_t randZ, int32_t forward) {
|
|||
}
|
||||
|
||||
void draw_stars() {
|
||||
int update = last_stars_update_fps != fps_anim;
|
||||
last_stars_update_fps = fps_anim;
|
||||
float k = (float) width / (float) height;
|
||||
|
||||
set_y_offset_objects(-100 * k * 0);
|
||||
|
@ -1137,7 +1143,9 @@ void draw_stars() {
|
|||
}
|
||||
|
||||
float speed = stars_scroll_offset + transition_speed;
|
||||
stars[i].position.z += speed;
|
||||
if (update) {
|
||||
stars[i].position.z += speed;
|
||||
}
|
||||
|
||||
if (stars[i].position.z > 0 && speed > 0) {
|
||||
stars[i].position = star_initial_position(0, 1);
|
||||
|
@ -1682,8 +1690,29 @@ void draw_safe(int32_t type, float alpha, float screw_alpha) {
|
|||
draw_textured_shape(&private_screw, private_matrix, NORMAL_ONE);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_onDrawFrame(JNIEnv *env, jclass class) {
|
||||
time_local += 0.016f;
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_setBackgroundColor(JNIEnv *env, jclass class, jfloat r, jfloat g, jfloat b, jfloat a) {
|
||||
background_color[0] = r;
|
||||
background_color[1] = g;
|
||||
background_color[2] = b;
|
||||
background_color[3] = a;
|
||||
|
||||
cloud_cover = create_rectangle(CSizeMake(240, 100), background_color);
|
||||
cloud_cover.params.anchor.y = -50;
|
||||
|
||||
TexturedShape was_mask = powerful_mask;
|
||||
powerful_mask = create_textured_rectangle(CSizeMake(200, 200), powerful_mask_texture);
|
||||
powerful_mask.params = was_mask.params;
|
||||
|
||||
telegram_mask = create_textured_rectangle(CSizeMake(200, 150), telegram_mask_texture);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_onDrawFrame(JNIEnv *env, jclass class, jint deltaMs) {
|
||||
if (surfaceCreated == 0) {
|
||||
glClearColor(background_color[0], background_color[1], background_color[2], background_color[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
time_local += (float) deltaMs / 1000;
|
||||
|
||||
if (current_page != prev_page) {
|
||||
reset_ic();
|
||||
|
@ -1722,7 +1751,8 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_onDrawFrame(JNIEnv *env, jclass
|
|||
}
|
||||
}
|
||||
|
||||
fps_anim++;
|
||||
// Normalize if FPS is greater than 60
|
||||
fps_anim = (int)(time_local / 0.016f);
|
||||
if (count_anim_fps == 1 && date - ms0_anim >= duration_const) {
|
||||
count_anim_fps = 0;
|
||||
}
|
||||
|
@ -1735,7 +1765,7 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_onDrawFrame(JNIEnv *env, jclass
|
|||
|
||||
float private_back_k = .8;
|
||||
|
||||
glClearColor(1, 1, 1, 1);
|
||||
glClearColor(background_color[0], background_color[1], background_color[2], background_color[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
|
||||
|
@ -2140,15 +2170,16 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_onDrawFrame(JNIEnv *env, jclass
|
|||
draw_textured_shape(&telegram_sphere, main_matrix, NORMAL);
|
||||
|
||||
float tt = MINf(0, (float) (-M_PI * 125.0f / 180.0f + time * M_PI * 2 * 1.5f));
|
||||
float dx = sinf(tt) * 75;
|
||||
float dy = -sinf(tt) * 60;
|
||||
float dx = t(-75, 0, 0, 0.15f, EaseIn);
|
||||
float dy = t(75, 0, 0, 0.15f, EaseIn);
|
||||
telegram_plane.params.position = xyzMake(dx, dy, 0);
|
||||
float scale = (cosf(tt) + 1) * 0.5f;
|
||||
telegram_plane.params.scale = xyzMake(cosf(tt) * scale, scale, 1);
|
||||
float scale = t(0.1f, 1, 0.03f, 0.15f, EaseOut);
|
||||
telegram_plane.params.scale = xyzMake(scale, scale, 1);
|
||||
|
||||
if (tt < D2R(125)) {
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
draw_textured_shape(&telegram_plane, main_matrix, NORMAL_ONE);
|
||||
draw_textured_shape(&telegram_mask, main_matrix, NORMAL);
|
||||
}
|
||||
}
|
||||
} else if (current_page == 1) {
|
||||
|
@ -2159,18 +2190,18 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_onDrawFrame(JNIEnv *env, jclass
|
|||
|
||||
double tt = time * M_PI * 2 * 1.5f;
|
||||
|
||||
float dx = (float) sin(tt) * 75;
|
||||
float dy = (float) -sin(tt) * 60;
|
||||
float dx = t(0, 75, 0, 0.15f, EaseOut);
|
||||
float dy = t(0, -75, 0, 0.15f, EaseOut);
|
||||
|
||||
telegram_plane.params.position = xyzMake(dx, dy, 0);
|
||||
|
||||
float scale = (float) (cos(tt) + 1) * 0.5f;
|
||||
|
||||
telegram_plane.params.scale = xyzMake((float) cos(tt) * scale, scale, 1);
|
||||
float scale = t(1, 0.1f, 0.03f, 0.15f, EaseOut);
|
||||
telegram_plane.params.scale = xyzMake(scale, scale, 1);
|
||||
|
||||
if (tt < D2R(125)) {
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
draw_textured_shape(&telegram_plane, main_matrix, NORMAL_ONE);
|
||||
draw_textured_shape(&telegram_mask, main_matrix, NORMAL);
|
||||
}
|
||||
}
|
||||
} else if (current_page == 2) {
|
||||
|
@ -2601,9 +2632,10 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_setIcTextures(JNIEnv *env, jcla
|
|||
ic_videocam_texture = a_ic_videocam;
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_setTelegramTextures(JNIEnv *env, jclass class, GLuint a_telegram_sphere, GLuint a_telegram_plane) {
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_setTelegramTextures(JNIEnv *env, jclass class, GLuint a_telegram_sphere, GLuint a_telegram_plane, GLuint a_telegram_mask) {
|
||||
telegram_sphere_texture = a_telegram_sphere;
|
||||
telegram_plane_texture = a_telegram_plane;
|
||||
telegram_mask_texture = a_telegram_mask;
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_setFastTextures(JNIEnv *env, jclass class, GLuint a_fast_body, GLuint a_fast_spiral, GLuint a_fast_arrow, GLuint a_fast_arrow_shadow) {
|
||||
|
@ -2691,6 +2723,7 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_onSurfaceCreated(JNIEnv *env, j
|
|||
mask1 = create_rounded_rectangle(CSizeMake(60, 60), 0, 16, black_color);
|
||||
|
||||
telegram_sphere = create_textured_rectangle(CSizeMake(150, 150), telegram_sphere_texture);
|
||||
telegram_mask = create_textured_rectangle(CSizeMake(200, 150), telegram_mask_texture);
|
||||
telegram_plane = create_textured_rectangle(CSizeMake(82, 74), telegram_plane_texture);
|
||||
telegram_plane.params.anchor = xyzMake(6, -5, 0);
|
||||
|
||||
|
@ -2794,11 +2827,12 @@ JNIEXPORT void Java_org_telegram_messenger_Intro_onSurfaceCreated(JNIEnv *env, j
|
|||
cloud_extra_mask3 = create_circle(1, cloud_polygons_count, black_color);
|
||||
cloud_extra_mask4 = create_circle(1, cloud_polygons_count, black_color);
|
||||
|
||||
cloud_cover = create_rectangle(CSizeMake(240, 100), white_color);
|
||||
cloud_cover = create_rectangle(CSizeMake(240, 100), background_color);
|
||||
cloud_cover.params.anchor.y = -50;
|
||||
|
||||
vec4 cloud_color = {42 / 255.0f, 180 / 255.0f, 247 / 255.0f, 1};
|
||||
cloud_bg = create_rectangle(CSizeMake(160 * 2, 160 * 2), cloud_color);
|
||||
surfaceCreated = 1;
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Intro_onSurfaceChanged(JNIEnv *env, jclass class, int32_t a_width_px, int32_t a_height_px, float a_scale_factor, int32_t a1) {
|
||||
|
|
|
@ -111,7 +111,7 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesCtrDecryption(JNIEnv *en
|
|||
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, JNI_ABORT);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_aesCtrDecryptionByteArray(JNIEnv *env, jclass class, jbyteArray buffer, jbyteArray key, jbyteArray iv, jint offset, jint length, jint fileOffset) {
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_aesCtrDecryptionByteArray(JNIEnv *env, jclass class, jbyteArray buffer, jbyteArray key, jbyteArray iv, jint offset, jlong length, jint fileOffset) {
|
||||
unsigned char *bufferBuff = (unsigned char *) (*env)->GetByteArrayElements(env, buffer, NULL);
|
||||
unsigned char *keyBuff = (unsigned char *) (*env)->GetByteArrayElements(env, key, NULL);
|
||||
unsigned char *ivBuff = (unsigned char *) (*env)->GetByteArrayElements(env, iv, NULL);
|
||||
|
@ -186,6 +186,14 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesCbcEncryption(JNIEnv *en
|
|||
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, JNI_ABORT);
|
||||
}
|
||||
|
||||
#define LISTDIR_DOCTYPE_ALL 0
|
||||
#define LISTDIR_DOCTYPE_OTHER_THAN_MUSIC 1
|
||||
#define LISTDIR_DOCTYPE_MUSIC 2
|
||||
|
||||
#define LISTDIR_DOCTYPE2_EMOJI 3
|
||||
#define LISTDIR_DOCTYPE2_TEMP 4
|
||||
#define LISTDIR_DOCTYPE2_OTHER 5
|
||||
|
||||
int64_t listdir(const char *fileName, int32_t mode, int32_t docType, int64_t time, uint8_t subdirs) {
|
||||
int64_t value = 0;
|
||||
DIR *dir;
|
||||
|
@ -199,15 +207,29 @@ int64_t listdir(const char *fileName, int32_t mode, int32_t docType, int64_t tim
|
|||
if (name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
if ((docType == 1 || docType == 2) && len > 4) {
|
||||
if (name[len - 4] == '.' && (
|
||||
((name[len - 3] == 'm' || name[len - 3] == 'M') && (name[len - 2] == 'p' || name[len - 2] == 'P') && (name[len - 1] == '3')) ||
|
||||
((name[len - 3] == 'm' || name[len - 3] == 'M') && (name[len - 2] == '4') && (name[len - 1] == 'a' || name[len - 1] == 'A'))
|
||||
)) {
|
||||
if (docType == 1) {
|
||||
continue;
|
||||
}
|
||||
} else if (docType == 2) {
|
||||
if (docType > 0 && len > 4) {
|
||||
int isMusic = (
|
||||
name[len - 4] == '.' && (
|
||||
((name[len - 3] == 'm' || name[len - 3] == 'M') && (name[len - 2] == 'p' || name[len - 2] == 'P') && (name[len - 1] == '3')) || // mp3
|
||||
((name[len - 3] == 'm' || name[len - 3] == 'M') && (name[len - 2] == '4') && (name[len - 1] == 'a' || name[len - 1] == 'A')) // m4a
|
||||
));
|
||||
int isEmoji = (
|
||||
name[len - 4] == '.' && (name[len - 3] == 't' || name[len - 3] == 'T') && (name[len - 2] == 'g' || name[len - 2] == 'G') && (name[len - 1] == 's' || name[len - 1] == 'S') || // tgs
|
||||
len > 5 && name[len - 5] == '.' && (name[len - 4] == 'w' || name[len - 4] == 'W') && (name[len - 3] == 'e' || name[len - 3] == 'E') && (name[len - 2] == 'b' || name[len - 2] == 'B') && (name[len - 1] == 'm' || name[len - 1] == 'M') // webm
|
||||
);
|
||||
int isTemp = (
|
||||
name[len - 4] == '.' && (name[len - 3] == 't' || name[len - 3] == 'T') && (name[len - 2] == 'm' || name[len - 2] == 'M') && (name[len - 1] == 'p' || name[len - 1] == 'P') || // tmp
|
||||
len > 5 && name[len - 5] == '.' && (name[len - 4] == 't' || name[len - 4] == 'T') && (name[len - 3] == 'e' || name[len - 3] == 'E') && (name[len - 2] == 'm' || name[len - 2] == 'M') && (name[len - 1] == 'p' || name[len - 1] == 'P') || // temp
|
||||
len > 8 && name[len - 8] == '.' && (name[len - 7] == 'p' || name[len - 7] == 'P') && (name[len - 6] == 'r' || name[len - 6] == 'R') && (name[len - 5] == 'e' || name[len - 5] == 'E') && (name[len - 4] == 'l' || name[len - 4] == 'L') && (name[len - 3] == 'o' || name[len - 3] == 'O') && (name[len - 2] == 'a' || name[len - 2] == 'A') && (name[len - 1] == 'd' || name[len - 1] == 'D') // preload
|
||||
);
|
||||
if (
|
||||
isMusic && docType == LISTDIR_DOCTYPE_OTHER_THAN_MUSIC ||
|
||||
!isMusic && docType == LISTDIR_DOCTYPE_MUSIC ||
|
||||
isEmoji && docType == LISTDIR_DOCTYPE2_OTHER ||
|
||||
!isEmoji && docType == LISTDIR_DOCTYPE2_EMOJI ||
|
||||
isTemp && docType == LISTDIR_DOCTYPE2_OTHER ||
|
||||
!isTemp && docType == LISTDIR_DOCTYPE2_TEMP
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -219,9 +241,9 @@ int64_t listdir(const char *fileName, int32_t mode, int32_t docType, int64_t tim
|
|||
value += listdir(buff, mode, docType, time, subdirs);
|
||||
}
|
||||
} else {
|
||||
stat(buff, &attrib);
|
||||
int rc = stat(buff, &attrib);
|
||||
if (mode == 0) {
|
||||
value += 512 * attrib.st_blocks;
|
||||
value += rc == 0 ? attrib.st_size : 0;
|
||||
} else if (mode == 1) {
|
||||
if (attrib.st_atim.tv_sec != 0) {
|
||||
if (attrib.st_atim.tv_sec < time) {
|
||||
|
@ -247,6 +269,20 @@ JNIEXPORT jlong Java_org_telegram_messenger_Utilities_getDirSize(JNIEnv *env, jc
|
|||
return value;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong Java_org_telegram_messenger_Utilities_getLastUsageFileTime(JNIEnv *env, jclass class, jstring path) {
|
||||
const char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
struct stat attrib;
|
||||
stat(fileName, &attrib);
|
||||
jlong value;
|
||||
if (attrib.st_atim.tv_sec > 316000000) {
|
||||
value = attrib.st_atim.tv_sec;
|
||||
} else {
|
||||
value = attrib.st_mtim.tv_sec;
|
||||
}
|
||||
(*env)->ReleaseStringUTFChars(env, path, fileName);
|
||||
return value;
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_clearDir(JNIEnv *env, jclass class, jstring path, jint docType, jlong time, jboolean subdirs) {
|
||||
const char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
listdir(fileName, 1, docType, time, subdirs);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 626ff35955c2c35b806b3e0ecf551a1a8611cdbf
|
|
@ -1 +1 @@
|
|||
Subproject commit 17fd4ba820e59899d6938d460164147999f45bf2
|
||||
Subproject commit 113968ca47b1d1affbfe88472364b15699e239d6
|
|
@ -39,25 +39,25 @@ typedef struct LottieInfo {
|
|||
volatile uint32_t maxFrameSize = 0;
|
||||
uint32_t imageSize = 0;
|
||||
uint32_t fileOffset = 0;
|
||||
uint32_t fileFrame = 0;
|
||||
bool nextFrameIsCacheFrame = false;
|
||||
|
||||
FILE *precacheFile = nullptr;
|
||||
char *compressBuffer = nullptr;
|
||||
const char *buffer = nullptr;
|
||||
bool firstFrame = false;
|
||||
int bufferSize;
|
||||
int compressBound;
|
||||
int firstFrameSize;
|
||||
int bufferSize = 0;
|
||||
int compressBound = 0;
|
||||
int firstFrameSize = 0;
|
||||
volatile uint32_t framesAvailableInCache = 0;
|
||||
};
|
||||
|
||||
JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *env, jclass clazz, jstring src, jint w, jint h, jintArray data, jboolean precache, jintArray colorReplacement, jboolean limitFps) {
|
||||
LottieInfo *info = new LottieInfo();
|
||||
JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *env, jclass clazz, jstring src, jstring json, jint w, jint h, jintArray data, jboolean precache, jintArray colorReplacement, jboolean limitFps, jint fitzModifier) {
|
||||
auto info = new LottieInfo();
|
||||
|
||||
std::map<int32_t, int32_t> *colors = nullptr;
|
||||
int color = 0;
|
||||
if (colorReplacement != nullptr) {
|
||||
jint *arr = env->GetIntArrayElements(colorReplacement, 0);
|
||||
jint *arr = env->GetIntArrayElements(colorReplacement, nullptr);
|
||||
if (arr != nullptr) {
|
||||
jsize len = env->GetArrayLength(colorReplacement);
|
||||
colors = new std::map<int32_t, int32_t>();
|
||||
|
@ -71,10 +71,37 @@ JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *e
|
|||
}
|
||||
}
|
||||
|
||||
char const *srcString = env->GetStringUTFChars(src, 0);
|
||||
|
||||
FitzModifier modifier = FitzModifier::None;
|
||||
switch (fitzModifier) {
|
||||
case 12:
|
||||
modifier = FitzModifier::Type12;
|
||||
break;
|
||||
case 3:
|
||||
modifier = FitzModifier::Type3;
|
||||
break;
|
||||
case 4:
|
||||
modifier = FitzModifier::Type4;
|
||||
break;
|
||||
case 5:
|
||||
modifier = FitzModifier::Type5;
|
||||
break;
|
||||
case 6:
|
||||
modifier = FitzModifier::Type6;
|
||||
break;
|
||||
}
|
||||
char const *srcString = env->GetStringUTFChars(src, nullptr);
|
||||
info->path = srcString;
|
||||
info->animation = rlottie::Animation::loadFromFile(info->path, colors);
|
||||
if (srcString != 0) {
|
||||
if (json != nullptr) {
|
||||
char const *jsonString = env->GetStringUTFChars(json, nullptr);
|
||||
if (jsonString) {
|
||||
info->animation = rlottie::Animation::loadFromData(jsonString, info->path, colors, modifier);
|
||||
env->ReleaseStringUTFChars(json, jsonString);
|
||||
}
|
||||
} else {
|
||||
info->animation = rlottie::Animation::loadFromFile(info->path, colors, modifier);
|
||||
}
|
||||
if (srcString) {
|
||||
env->ReleaseStringUTFChars(src, srcString);
|
||||
}
|
||||
if (info->animation == nullptr) {
|
||||
|
@ -91,7 +118,7 @@ JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *e
|
|||
info->precache = precache;
|
||||
if (info->precache) {
|
||||
info->cacheFile = info->path;
|
||||
std::string::size_type index = info->cacheFile.find_last_of("/");
|
||||
std::string::size_type index = info->cacheFile.find_last_of('/');
|
||||
if (index != std::string::npos) {
|
||||
std::string dir = info->cacheFile.substr(0, index) + "/acache";
|
||||
mkdir(dir.c_str(), 0777);
|
||||
|
@ -119,13 +146,14 @@ JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *e
|
|||
info->maxFrameSize = maxFrameSize;
|
||||
fread(&(info->imageSize), sizeof(uint32_t), 1, precacheFile);
|
||||
info->fileOffset = 9;
|
||||
utimensat(0, info->cacheFile.c_str(), NULL, 0);
|
||||
info->fileFrame = 0;
|
||||
utimensat(0, info->cacheFile.c_str(), nullptr, 0);
|
||||
}
|
||||
fclose(precacheFile);
|
||||
}
|
||||
}
|
||||
|
||||
jint *dataArr = env->GetIntArrayElements(data, 0);
|
||||
jint *dataArr = env->GetIntArrayElements(data, nullptr);
|
||||
if (dataArr != nullptr) {
|
||||
dataArr[0] = (jint) info->frameCount;
|
||||
dataArr[1] = (jint) info->animation->frameRate();
|
||||
|
@ -138,7 +166,7 @@ JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_create(JNIEnv *e
|
|||
JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_createWithJson(JNIEnv *env, jclass clazz, jstring json, jstring name, jintArray data, jintArray colorReplacement) {
|
||||
std::map<int32_t, int32_t> *colors = nullptr;
|
||||
if (colorReplacement != nullptr) {
|
||||
jint *arr = env->GetIntArrayElements(colorReplacement, 0);
|
||||
jint *arr = env->GetIntArrayElements(colorReplacement, nullptr);
|
||||
if (arr != nullptr) {
|
||||
jsize len = env->GetArrayLength(colorReplacement);
|
||||
colors = new std::map<int32_t, int32_t>();
|
||||
|
@ -149,15 +177,15 @@ JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_createWithJson(J
|
|||
}
|
||||
}
|
||||
|
||||
LottieInfo *info = new LottieInfo();
|
||||
auto info = new LottieInfo();
|
||||
|
||||
char const *jsonString = env->GetStringUTFChars(json, 0);
|
||||
char const *nameString = env->GetStringUTFChars(name, 0);
|
||||
char const *jsonString = env->GetStringUTFChars(json, nullptr);
|
||||
char const *nameString = env->GetStringUTFChars(name, nullptr);
|
||||
info->animation = rlottie::Animation::loadFromData(jsonString, nameString, colors);
|
||||
if (jsonString != 0) {
|
||||
if (jsonString) {
|
||||
env->ReleaseStringUTFChars(json, jsonString);
|
||||
}
|
||||
if (nameString != 0) {
|
||||
if (nameString) {
|
||||
env->ReleaseStringUTFChars(name, nameString);
|
||||
}
|
||||
if (info->animation == nullptr) {
|
||||
|
@ -167,7 +195,7 @@ JNIEXPORT jlong Java_org_telegram_ui_Components_RLottieDrawable_createWithJson(J
|
|||
info->frameCount = info->animation->totalFrame();
|
||||
info->fps = (int) info->animation->frameRate();
|
||||
|
||||
jint *dataArr = env->GetIntArrayElements(data, 0);
|
||||
jint *dataArr = env->GetIntArrayElements(data, nullptr);
|
||||
if (dataArr != nullptr) {
|
||||
dataArr[0] = (int) info->frameCount;
|
||||
dataArr[1] = (int) info->animation->frameRate();
|
||||
|
@ -181,7 +209,7 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_destroy(JNIEnv *e
|
|||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
|
||||
auto info = (LottieInfo *) (intptr_t) ptr;
|
||||
delete info;
|
||||
}
|
||||
|
||||
|
@ -189,10 +217,10 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_setLayerColor(JNI
|
|||
if (!ptr || layer == nullptr) {
|
||||
return;
|
||||
}
|
||||
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
|
||||
char const *layerString = env->GetStringUTFChars(layer, 0);
|
||||
auto info = (LottieInfo *) (intptr_t) ptr;
|
||||
char const *layerString = env->GetStringUTFChars(layer, nullptr);
|
||||
info->animation->setValue<Property::Color>(layerString, Color(((color) & 0xff) / 255.0f, ((color >> 8) & 0xff) / 255.0f, ((color >> 16) & 0xff) / 255.0f));
|
||||
if (layerString != 0) {
|
||||
if (layerString) {
|
||||
env->ReleaseStringUTFChars(layer, layerString);
|
||||
}
|
||||
}
|
||||
|
@ -201,9 +229,9 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_replaceColors(JNI
|
|||
if (!ptr || colorReplacement == nullptr) {
|
||||
return;
|
||||
}
|
||||
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
|
||||
auto info = (LottieInfo *) (intptr_t) ptr;
|
||||
|
||||
jint *arr = env->GetIntArrayElements(colorReplacement, 0);
|
||||
jint *arr = env->GetIntArrayElements(colorReplacement, nullptr);
|
||||
if (arr != nullptr) {
|
||||
jsize len = env->GetArrayLength(colorReplacement);
|
||||
for (int32_t a = 0; a < len / 2; a++) {
|
||||
|
@ -214,184 +242,23 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_replaceColors(JNI
|
|||
}
|
||||
}
|
||||
|
||||
bool cacheWriteThreadCreated{false};
|
||||
LottieInfo *cacheWriteThreadTask{nullptr};
|
||||
bool cacheWriteThreadDone{false};
|
||||
std::thread worker;
|
||||
std::mutex cacheMutex;
|
||||
std::condition_variable cacheCv;
|
||||
|
||||
std::mutex cacheDoneMutex;
|
||||
std::condition_variable cacheDoneCv;
|
||||
std::atomic<bool> frameReady{false};
|
||||
|
||||
void CacheWriteThreadProc() {
|
||||
while (!cacheWriteThreadDone) {
|
||||
std::unique_lock<std::mutex> lk(cacheMutex);
|
||||
cacheCv.wait(lk, [] { return frameReady.load(); });
|
||||
std::lock_guard<std::mutex> lg(cacheDoneMutex);
|
||||
LottieInfo *task;
|
||||
if (cacheWriteThreadTask != nullptr) {
|
||||
task = cacheWriteThreadTask;
|
||||
cacheWriteThreadTask = nullptr;
|
||||
} else {
|
||||
task = nullptr;
|
||||
}
|
||||
lk.unlock();
|
||||
|
||||
if (task != nullptr) {
|
||||
uint32_t size = (uint32_t) LZ4_compress_default(task->buffer, task->compressBuffer, task->bufferSize, task->compressBound);
|
||||
if (task->firstFrame) {
|
||||
task->firstFrameSize = size;
|
||||
task->fileOffset = 9 + sizeof(uint32_t) + task->firstFrameSize;
|
||||
}
|
||||
task->maxFrameSize = MAX(task->maxFrameSize, size);
|
||||
fwrite(&size, sizeof(uint32_t), 1, task->precacheFile);
|
||||
fwrite(task->compressBuffer, sizeof(uint8_t), size, task->precacheFile);
|
||||
|
||||
fflush(task->precacheFile);
|
||||
fsync(fileno(task->precacheFile));
|
||||
task->framesAvailableInCache++;
|
||||
}
|
||||
frameReady = false;
|
||||
cacheDoneCv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_createCache(JNIEnv *env, jclass clazz, jlong ptr, jint w, jint h) {
|
||||
if (ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
|
||||
|
||||
FILE *cacheFile = fopen(info->cacheFile.c_str(), "r+");
|
||||
if (cacheFile != nullptr) {
|
||||
uint8_t temp;
|
||||
size_t read = fread(&temp, sizeof(uint8_t), 1, cacheFile);
|
||||
fclose(cacheFile);
|
||||
if (read == 1 && temp != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cacheWriteThreadCreated) {
|
||||
cacheWriteThreadCreated = true;
|
||||
worker = std::thread(CacheWriteThreadProc);
|
||||
}
|
||||
|
||||
if (info->nextFrameIsCacheFrame && info->createCache && info->frameCount != 0) {
|
||||
info->precacheFile = fopen(info->cacheFile.c_str(), "w+");
|
||||
if (info->precacheFile != nullptr) {
|
||||
fseek(info->precacheFile, info->fileOffset = 9, SEEK_SET);
|
||||
info->maxFrameSize = 0;
|
||||
info->bufferSize = w * h * 4;
|
||||
info->imageSize = (uint32_t) w * h * 4;
|
||||
info->compressBound = LZ4_compressBound(info->bufferSize);
|
||||
info->compressBuffer = new char[info->compressBound];
|
||||
uint8_t *firstBuffer = new uint8_t[info->bufferSize];
|
||||
uint8_t *secondBuffer = new uint8_t[info->bufferSize];
|
||||
//long time = ConnectionsManager::getInstance(0).getCurrentTimeMonotonicMillis();
|
||||
|
||||
Surface surface1((uint32_t *) firstBuffer, (size_t) w, (size_t) h, (size_t) w * 4);
|
||||
Surface surface2((uint32_t *) secondBuffer, (size_t) w, (size_t) h, (size_t) w * 4);
|
||||
int framesPerUpdate = !info->limitFps || info->fps < 60 ? 1 : 2;
|
||||
int num = 0;
|
||||
for (size_t a = 0; a < info->frameCount; a += framesPerUpdate) {
|
||||
Surface &surfaceToRender = num % 2 == 0 ? surface1 : surface2;
|
||||
num++;
|
||||
info->animation->renderSync(a, surfaceToRender, true);
|
||||
if (a != 0) {
|
||||
std::unique_lock<std::mutex> lk(cacheDoneMutex);
|
||||
cacheDoneCv.wait(lk, [] { return !frameReady.load(); });
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lg(cacheMutex);
|
||||
cacheWriteThreadTask = info;
|
||||
info->firstFrame = a == 0;
|
||||
info->buffer = (const char *) surfaceToRender.buffer();
|
||||
frameReady = true;
|
||||
cacheCv.notify_one();
|
||||
}
|
||||
std::unique_lock<std::mutex> lk(cacheDoneMutex);
|
||||
cacheDoneCv.wait(lk, [] { return !frameReady.load(); });
|
||||
|
||||
//DEBUG_D("sticker time = %d", (int) (ConnectionsManager::getInstance(0).getCurrentTimeMonotonicMillis() - time));
|
||||
delete[] info->compressBuffer;
|
||||
delete[] firstBuffer;
|
||||
delete[] secondBuffer;
|
||||
fseek(info->precacheFile, 0, SEEK_SET);
|
||||
uint8_t byte = 1;
|
||||
fwrite(&byte, sizeof(uint8_t), 1, info->precacheFile);
|
||||
uint32_t maxFrameSize = info->maxFrameSize;
|
||||
fwrite(&maxFrameSize, sizeof(uint32_t), 1, info->precacheFile);
|
||||
fwrite(&info->imageSize, sizeof(uint32_t), 1, info->precacheFile);
|
||||
fflush(info->precacheFile);
|
||||
fsync(fileno(info->precacheFile));
|
||||
info->createCache = false;
|
||||
fclose(info->precacheFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_org_telegram_ui_Components_RLottieDrawable_getFrame(JNIEnv *env, jclass clazz, jlong ptr, jint frame, jobject bitmap, jint w, jint h, jint stride, jboolean clear) {
|
||||
if (!ptr || bitmap == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
|
||||
|
||||
int framesPerUpdate = !info->limitFps || info->fps < 60 ? 1 : 2;
|
||||
int framesAvailableInCache = info->framesAvailableInCache;
|
||||
|
||||
if (info->createCache && info->precache && frame > 0) {
|
||||
if (frame / framesPerUpdate >= framesAvailableInCache) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
auto info = (LottieInfo *) (intptr_t) ptr;
|
||||
|
||||
void *pixels;
|
||||
bool result = false;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) {
|
||||
bool loadedFromCache = false;
|
||||
uint32_t maxFrameSize = info->maxFrameSize;
|
||||
if (info->precache && (!info->createCache || frame > 0) && w * 4 == stride && maxFrameSize <= w * h * 4 && info->imageSize == w * h * 4) {
|
||||
FILE *precacheFile = fopen(info->cacheFile.c_str(), "r");
|
||||
if (precacheFile != nullptr) {
|
||||
if (info->decompressBuffer != nullptr && info->decompressBufferSize < maxFrameSize) {
|
||||
delete[] info->decompressBuffer;
|
||||
info->decompressBuffer = nullptr;
|
||||
}
|
||||
if (info->decompressBuffer == nullptr) {
|
||||
info->decompressBufferSize = maxFrameSize;
|
||||
if (info->createCache) {
|
||||
info->decompressBufferSize += 10000;
|
||||
}
|
||||
info->decompressBuffer = new uint8_t[info->decompressBufferSize];
|
||||
}
|
||||
fseek(precacheFile, info->fileOffset, SEEK_SET);
|
||||
uint32_t frameSize;
|
||||
fread(&frameSize, sizeof(uint32_t), 1, precacheFile);
|
||||
if (frameSize > 0 && frameSize <= info->decompressBufferSize) {
|
||||
fread(info->decompressBuffer, sizeof(uint8_t), frameSize, precacheFile);
|
||||
info->fileOffset += 4 + frameSize;
|
||||
LZ4_decompress_safe((const char *) info->decompressBuffer, (char *) pixels, frameSize, w * h * 4);
|
||||
loadedFromCache = true;
|
||||
}
|
||||
fclose(precacheFile);
|
||||
if (frame + framesPerUpdate >= info->frameCount) {
|
||||
info->fileOffset = 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadedFromCache) {
|
||||
if (!info->nextFrameIsCacheFrame || !info->precache) {
|
||||
Surface surface((uint32_t *) pixels, (size_t) w, (size_t) h, (size_t) stride);
|
||||
info->animation->renderSync((size_t) frame, surface, clear);
|
||||
info->nextFrameIsCacheFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
Surface surface((uint32_t *) pixels, (size_t) w, (size_t) h, (size_t) stride);
|
||||
info->animation->renderSync((size_t) frame, surface, clear, &result);
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
}
|
||||
if (!result) {
|
||||
return -5;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1083,6 +1083,9 @@ static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr,
|
|||
offset2=_sr[srj].offset;
|
||||
/*For once, we can subtract with impunity.*/
|
||||
den=gp2-gp1;
|
||||
if (den == 0) {
|
||||
return -1;
|
||||
}
|
||||
ipart=gp2/den;
|
||||
num=offset2-offset1;
|
||||
OP_ASSERT(num>0);
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
set -e
|
||||
|
||||
patch -d ffmpeg -p1 < patches/ffmpeg/0001-compilation-magic.patch
|
||||
patch -d ffmpeg -p1 < patches/ffmpeg/0002-compilation-magic-2.patch
|
||||
|
||||
function cp {
|
||||
install -D $@
|
||||
}
|
||||
|
||||
cp ffmpeg/libavformat/dv.h ffmpeg/build/arm64-v8a/include/libavformat/dv.h
|
||||
cp ffmpeg/libavformat/isom.h ffmpeg/build/arm64-v8a/include/libavformat/isom.h
|
||||
|
@ -12,3 +17,28 @@ cp ffmpeg/libavformat/dv.h ffmpeg/build/x86/include/libavformat/dv.h
|
|||
cp ffmpeg/libavformat/isom.h ffmpeg/build/x86/include/libavformat/isom.h
|
||||
cp ffmpeg/libavformat/dv.h ffmpeg/build/x86_64/include/libavformat/dv.h
|
||||
cp ffmpeg/libavformat/isom.h ffmpeg/build/x86_64/include/libavformat/isom.h
|
||||
|
||||
cp ffmpeg/libavcodec/bytestream.h ffmpeg/build/arm64-v8a/include/libavcodec/bytestream.h
|
||||
cp ffmpeg/libavcodec/bytestream.h ffmpeg/build/armeabi-v7a/include/libavcodec/bytestream.h
|
||||
cp ffmpeg/libavcodec/bytestream.h ffmpeg/build/x86/include/libavcodec/bytestream.h
|
||||
cp ffmpeg/libavcodec/bytestream.h ffmpeg/build/x86_64/include/libavcodec/bytestream.h
|
||||
|
||||
cp ffmpeg/libavcodec/get_bits.h ffmpeg/build/arm64-v8a/include/libavcodec/get_bits.h
|
||||
cp ffmpeg/libavcodec/get_bits.h ffmpeg/build/armeabi-v7a/include/libavcodec/get_bits.h
|
||||
cp ffmpeg/libavcodec/get_bits.h ffmpeg/build/x86/include/libavcodec/get_bits.h
|
||||
cp ffmpeg/libavcodec/get_bits.h ffmpeg/build/x86_64/include/libavcodec/get_bits.h
|
||||
|
||||
cp ffmpeg/libavcodec/golomb.h ffmpeg/build/arm64-v8a/include/libavcodec/golomb.h
|
||||
cp ffmpeg/libavcodec/golomb.h ffmpeg/build/armeabi-v7a/include/libavcodec/golomb.h
|
||||
cp ffmpeg/libavcodec/golomb.h ffmpeg/build/x86/include/libavcodec/golomb.h
|
||||
cp ffmpeg/libavcodec/golomb.h ffmpeg/build/x86_64/include/libavcodec/golomb.h
|
||||
|
||||
cp ffmpeg/libavcodec/vlc.h ffmpeg/build/arm64-v8a/include/libavcodec/vlc.h
|
||||
cp ffmpeg/libavcodec/vlc.h ffmpeg/build/armeabi-v7a/include/libavcodec/vlc.h
|
||||
cp ffmpeg/libavcodec/vlc.h ffmpeg/build/x86/include/libavcodec/vlc.h
|
||||
cp ffmpeg/libavcodec/vlc.h ffmpeg/build/x86_64/include/libavcodec/vlc.h
|
||||
|
||||
cp ffmpeg/libavutil/intmath.h ffmpeg/build/arm64-v8a/include/libavutil/intmath.h
|
||||
cp ffmpeg/libavutil/intmath.h ffmpeg/build/armeabi-v7a/include/libavutil/intmath.h
|
||||
cp ffmpeg/libavutil/intmath.h ffmpeg/build/x86/include/libavutil/intmath.h
|
||||
cp ffmpeg/libavutil/intmath.h ffmpeg/build/x86_64/include/libavutil/intmath.h
|
||||
|
|
|
@ -16,7 +16,7 @@ index 30823755..b349572c 100644
|
|||
+++ b/crypto/fipsmodule/CMakeLists.txt
|
||||
@@ -198,6 +198,8 @@ else()
|
||||
bcm.c
|
||||
is_fips.c
|
||||
fips_shared_support.c
|
||||
|
||||
+ aes/aes_ige.c
|
||||
+
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
From 02952ace408e331237a1ccd724f072b3e67ceb20 Mon Sep 17 00:00:00 2001
|
||||
From: thermatk <thermatk@thermatk.com>
|
||||
Date: Wed, 23 Jan 2019 22:16:34 +0100
|
||||
Subject: [PATCH] only build what we need
|
||||
|
||||
---
|
||||
CMakeLists.txt | 36 ---------------------
|
||||
crypto/CMakeLists.txt | 74 -------------------------------------------
|
||||
ssl/CMakeLists.txt | 18 ------------------
|
||||
3 files changed, 128 deletions(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index c266e1267..81d721df4 100644
|
||||
index fd3532664..7fcfb1627 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -562,44 +562,8 @@ if(USE_CUSTOM_LIBCXX)
|
||||
target_link_libraries(libcxx libcxxabi)
|
||||
endif()
|
||||
|
||||
|
||||
-# Add minimal googletest targets. The provided one has many side-effects, and
|
||||
-# googletest has a very straightforward build.
|
||||
-add_library(boringssl_gtest third_party/googletest/src/gtest-all.cc)
|
||||
|
@ -44,14 +55,38 @@ index c266e1267..81d721df4 100644
|
|||
-add_subdirectory(util/fipstools/cavp)
|
||||
-add_subdirectory(util/fipstools/acvp/modulewrapper)
|
||||
-add_subdirectory(decrepit)
|
||||
|
||||
|
||||
if(FUZZ)
|
||||
if(LIBFUZZER_FROM_DEPS)
|
||||
@@ -616,14 +580,3 @@ endif()
|
||||
@@ -589,38 +564,3 @@ endif()
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
set(HANDSHAKER_ARGS "-handshaker-path" $<TARGET_FILE:handshaker>)
|
||||
endif()
|
||||
-
|
||||
-if(FIPS)
|
||||
- add_custom_target(
|
||||
- acvp_tests
|
||||
- COMMAND ${GO_EXECUTABLE} build -o ${CMAKE_BINARY_DIR}/acvptool
|
||||
- boringssl.googlesource.com/boringssl/util/fipstools/acvp/acvptool
|
||||
- COMMAND ${GO_EXECUTABLE} build -o ${CMAKE_BINARY_DIR}/testmodulewrapper
|
||||
- boringssl.googlesource.com/boringssl/util/fipstools/acvp/acvptool/testmodulewrapper
|
||||
- COMMAND cd util/fipstools/acvp/acvptool/test &&
|
||||
- ${GO_EXECUTABLE} run check_expected.go
|
||||
- -tool ${CMAKE_BINARY_DIR}/acvptool
|
||||
- -module-wrappers modulewrapper:$<TARGET_FILE:modulewrapper>,testmodulewrapper:${CMAKE_BINARY_DIR}/testmodulewrapper
|
||||
- -tests tests.json
|
||||
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
- DEPENDS modulewrapper
|
||||
- USES_TERMINAL)
|
||||
-
|
||||
- add_custom_target(
|
||||
- fips_specific_tests_if_any
|
||||
- DEPENDS acvp_tests
|
||||
- )
|
||||
-else()
|
||||
- add_custom_target(fips_specific_tests_if_any)
|
||||
-endif()
|
||||
-
|
||||
-add_custom_target(
|
||||
- run_tests
|
||||
- COMMAND ${GO_EXECUTABLE} run util/all_tests.go -build-dir
|
||||
|
@ -60,10 +95,10 @@ index c266e1267..81d721df4 100644
|
|||
- ${GO_EXECUTABLE} test -shim-path $<TARGET_FILE:bssl_shim>
|
||||
- ${HANDSHAKER_ARGS} ${RUNNER_ARGS}
|
||||
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
- DEPENDS all_tests bssl_shim handshaker
|
||||
- DEPENDS all_tests bssl_shim handshaker fips_specific_tests_if_any
|
||||
- USES_TERMINAL)
|
||||
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
|
||||
index d23c02eee..d84f4c1b9 100644
|
||||
index e940f7d5f..f5221d70d 100644
|
||||
--- a/crypto/CMakeLists.txt
|
||||
+++ b/crypto/CMakeLists.txt
|
||||
@@ -85,7 +85,6 @@ function(perlasm dest src)
|
||||
|
@ -74,10 +109,13 @@ index d23c02eee..d84f4c1b9 100644
|
|||
|
||||
if(FIPS_DELOCATE OR FIPS_SHARED)
|
||||
SET_SOURCE_FILES_PROPERTIES(fipsmodule/bcm.o PROPERTIES EXTERNAL_OBJECT true)
|
||||
@@ -467,92 +466,4 @@ endif()
|
||||
|
||||
# urandom_test is a separate binary because it needs to be able to observe the
|
||||
# PRNG initialisation, which means that it can't have other tests running before
|
||||
@@ -466,96 +466,3 @@ endif()
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
target_link_libraries(crypto libcxx)
|
||||
endif()
|
||||
-
|
||||
-# urandom_test is a separate binary because it needs to be able to observe the
|
||||
-# PRNG initialisation, which means that it can't have other tests running before
|
||||
-# it does.
|
||||
-add_executable(
|
||||
- urandom_test
|
||||
|
@ -96,14 +134,16 @@ index d23c02eee..d84f4c1b9 100644
|
|||
- abi_self_test.cc
|
||||
- asn1/asn1_test.cc
|
||||
- base64/base64_test.cc
|
||||
- buf/buf_test.cc
|
||||
- bio/bio_test.cc
|
||||
- blake2/blake2_test.cc
|
||||
- buf/buf_test.cc
|
||||
- bytestring/bytestring_test.cc
|
||||
- chacha/chacha_test.cc
|
||||
- cipher_extra/aead_test.cc
|
||||
- cipher_extra/cipher_test.cc
|
||||
- cmac/cmac_test.cc
|
||||
- compiler_test.cc
|
||||
- conf/conf_test.cc
|
||||
- constant_time_test.cc
|
||||
- cpu-arm-linux_test.cc
|
||||
- crypto_test.cc
|
||||
|
@ -154,7 +194,6 @@ index d23c02eee..d84f4c1b9 100644
|
|||
- x509/x509_test.cc
|
||||
- x509/x509_time_test.cc
|
||||
- x509v3/tab_test.cc
|
||||
- x509v3/v3name_test.cc
|
||||
-
|
||||
- $<TARGET_OBJECTS:crypto_test_data>
|
||||
- $<TARGET_OBJECTS:boringssl_gtest_main>
|
||||
|
@ -167,8 +206,6 @@ index d23c02eee..d84f4c1b9 100644
|
|||
- target_link_libraries(crypto_test ws2_32)
|
||||
-endif()
|
||||
-add_dependencies(all_tests crypto_test)
|
||||
+# it does.
|
||||
\ No newline at end of file
|
||||
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
|
||||
index 0fb532eae..f5cab9807 100644
|
||||
--- a/ssl/CMakeLists.txt
|
||||
|
@ -195,3 +232,6 @@ index 0fb532eae..f5cab9807 100644
|
|||
- target_link_libraries(ssl_test ws2_32)
|
||||
-endif()
|
||||
-add_dependencies(all_tests ssl_test)
|
||||
--
|
||||
2.20.1
|
||||
|
||||
|
|
|
@ -0,0 +1,580 @@
|
|||
Index: libavcodec/golomb.h
|
||||
IDEA additional info:
|
||||
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
||||
<+>UTF-8
|
||||
===================================================================
|
||||
diff --git a/libavcodec/golomb.h b/libavcodec/golomb.h
|
||||
--- a/libavcodec/golomb.h (revision a77521cd5d27e955b16e8097eecefc779ffdcb6d)
|
||||
+++ b/libavcodec/golomb.h (date 1647179346628)
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "get_bits.h"
|
||||
-#include "put_bits.h"
|
||||
|
||||
#define INVALID_VLC 0x80000000
|
||||
|
||||
@@ -422,144 +421,6 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
-/**
|
||||
- * read unsigned golomb rice code (jpegls).
|
||||
- */
|
||||
-static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit,
|
||||
- int esc_len)
|
||||
-{
|
||||
- unsigned int buf;
|
||||
- int log;
|
||||
-
|
||||
-#if CACHED_BITSTREAM_READER
|
||||
- buf = show_bits_long(gb, 32);
|
||||
-
|
||||
- log = av_log2(buf);
|
||||
-
|
||||
- if (log - k >= 1 && 32 - log < limit) {
|
||||
- buf >>= log - k;
|
||||
- buf += (30 - log) << k;
|
||||
- skip_bits_long(gb, 32 + k - log);
|
||||
-
|
||||
- return buf;
|
||||
- } else {
|
||||
- int i;
|
||||
- for (i = 0;
|
||||
- i < limit && get_bits1(gb) == 0 && get_bits_left(gb) > 0;
|
||||
- i++);
|
||||
-
|
||||
- if (i < limit - 1) {
|
||||
- buf = get_bits_long(gb, k);
|
||||
-
|
||||
- return buf + (i << k);
|
||||
- } else if (i == limit - 1) {
|
||||
- buf = get_bits_long(gb, esc_len);
|
||||
-
|
||||
- return buf + 1;
|
||||
- } else
|
||||
- return -1;
|
||||
- }
|
||||
-#else
|
||||
- OPEN_READER(re, gb);
|
||||
- UPDATE_CACHE(re, gb);
|
||||
- buf = GET_CACHE(re, gb);
|
||||
-
|
||||
- log = av_log2(buf);
|
||||
-
|
||||
- av_assert2(k <= 31);
|
||||
-
|
||||
- if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) &&
|
||||
- 32 - log < limit) {
|
||||
- buf >>= log - k;
|
||||
- buf += (30U - log) << k;
|
||||
- LAST_SKIP_BITS(re, gb, 32 + k - log);
|
||||
- CLOSE_READER(re, gb);
|
||||
-
|
||||
- return buf;
|
||||
- } else {
|
||||
- int i;
|
||||
- for (i = 0; i + MIN_CACHE_BITS <= limit && SHOW_UBITS(re, gb, MIN_CACHE_BITS) == 0; i += MIN_CACHE_BITS) {
|
||||
- if (gb->size_in_bits <= re_index) {
|
||||
- CLOSE_READER(re, gb);
|
||||
- return -1;
|
||||
- }
|
||||
- LAST_SKIP_BITS(re, gb, MIN_CACHE_BITS);
|
||||
- UPDATE_CACHE(re, gb);
|
||||
- }
|
||||
- for (; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) {
|
||||
- SKIP_BITS(re, gb, 1);
|
||||
- }
|
||||
- LAST_SKIP_BITS(re, gb, 1);
|
||||
- UPDATE_CACHE(re, gb);
|
||||
-
|
||||
- if (i < limit - 1) {
|
||||
- if (k) {
|
||||
- if (k > MIN_CACHE_BITS - 1) {
|
||||
- buf = SHOW_UBITS(re, gb, 16) << (k-16);
|
||||
- LAST_SKIP_BITS(re, gb, 16);
|
||||
- UPDATE_CACHE(re, gb);
|
||||
- buf |= SHOW_UBITS(re, gb, k-16);
|
||||
- LAST_SKIP_BITS(re, gb, k-16);
|
||||
- } else {
|
||||
- buf = SHOW_UBITS(re, gb, k);
|
||||
- LAST_SKIP_BITS(re, gb, k);
|
||||
- }
|
||||
- } else {
|
||||
- buf = 0;
|
||||
- }
|
||||
-
|
||||
- buf += ((SUINT)i << k);
|
||||
- } else if (i == limit - 1) {
|
||||
- buf = SHOW_UBITS(re, gb, esc_len);
|
||||
- LAST_SKIP_BITS(re, gb, esc_len);
|
||||
-
|
||||
- buf ++;
|
||||
- } else {
|
||||
- buf = -1;
|
||||
- }
|
||||
- CLOSE_READER(re, gb);
|
||||
- return buf;
|
||||
- }
|
||||
-#endif
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * read signed golomb rice code (ffv1).
|
||||
- */
|
||||
-static inline int get_sr_golomb(GetBitContext *gb, int k, int limit,
|
||||
- int esc_len)
|
||||
-{
|
||||
- unsigned v = get_ur_golomb(gb, k, limit, esc_len);
|
||||
- return (v >> 1) ^ -(v & 1);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * read signed golomb rice code (flac).
|
||||
- */
|
||||
-static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit,
|
||||
- int esc_len)
|
||||
-{
|
||||
- unsigned v = get_ur_golomb_jpegls(gb, k, limit, esc_len);
|
||||
- return (v >> 1) ^ -(v & 1);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * read unsigned golomb rice code (shorten).
|
||||
- */
|
||||
-static inline unsigned int get_ur_golomb_shorten(GetBitContext *gb, int k)
|
||||
-{
|
||||
- return get_ur_golomb_jpegls(gb, k, INT_MAX, 0);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * read signed golomb rice code (shorten).
|
||||
- */
|
||||
-static inline int get_sr_golomb_shorten(GetBitContext *gb, int k)
|
||||
-{
|
||||
- int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0);
|
||||
- return (uvar >> 1) ^ -(uvar & 1);
|
||||
-}
|
||||
-
|
||||
#ifdef TRACE
|
||||
|
||||
static inline int get_ue(GetBitContext *s, const char *file, const char *func,
|
||||
@@ -614,134 +475,4 @@
|
||||
|
||||
#endif /* TRACE */
|
||||
|
||||
-/**
|
||||
- * write unsigned exp golomb code. 2^16 - 2 at most
|
||||
- */
|
||||
-static inline void set_ue_golomb(PutBitContext *pb, int i)
|
||||
-{
|
||||
- av_assert2(i >= 0);
|
||||
- av_assert2(i <= 0xFFFE);
|
||||
-
|
||||
- if (i < 256)
|
||||
- put_bits(pb, ff_ue_golomb_len[i], i + 1);
|
||||
- else {
|
||||
- int e = av_log2(i + 1);
|
||||
- put_bits(pb, 2 * e + 1, i + 1);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write unsigned exp golomb code. 2^32-2 at most.
|
||||
- */
|
||||
-static inline void set_ue_golomb_long(PutBitContext *pb, uint32_t i)
|
||||
-{
|
||||
- av_assert2(i <= (UINT32_MAX - 1));
|
||||
-
|
||||
- if (i < 256)
|
||||
- put_bits(pb, ff_ue_golomb_len[i], i + 1);
|
||||
- else {
|
||||
- int e = av_log2(i + 1);
|
||||
- put_bits64(pb, 2 * e + 1, i + 1);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write truncated unsigned exp golomb code.
|
||||
- */
|
||||
-static inline void set_te_golomb(PutBitContext *pb, int i, int range)
|
||||
-{
|
||||
- av_assert2(range >= 1);
|
||||
- av_assert2(i <= range);
|
||||
-
|
||||
- if (range == 2)
|
||||
- put_bits(pb, 1, i ^ 1);
|
||||
- else
|
||||
- set_ue_golomb(pb, i);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write signed exp golomb code. 16 bits at most.
|
||||
- */
|
||||
-static inline void set_se_golomb(PutBitContext *pb, int i)
|
||||
-{
|
||||
- i = 2 * i - 1;
|
||||
- if (i < 0)
|
||||
- i ^= -1; //FIXME check if gcc does the right thing
|
||||
- set_ue_golomb(pb, i);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write unsigned golomb rice code (ffv1).
|
||||
- */
|
||||
-static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit,
|
||||
- int esc_len)
|
||||
-{
|
||||
- int e;
|
||||
-
|
||||
- av_assert2(i >= 0);
|
||||
-
|
||||
- e = i >> k;
|
||||
- if (e < limit)
|
||||
- put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k));
|
||||
- else
|
||||
- put_bits(pb, limit + esc_len, i - limit + 1);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write unsigned golomb rice code (jpegls).
|
||||
- */
|
||||
-static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k,
|
||||
- int limit, int esc_len)
|
||||
-{
|
||||
- int e;
|
||||
-
|
||||
- av_assert2(i >= 0);
|
||||
-
|
||||
- e = (i >> k) + 1;
|
||||
- if (e < limit) {
|
||||
- while (e > 31) {
|
||||
- put_bits(pb, 31, 0);
|
||||
- e -= 31;
|
||||
- }
|
||||
- put_bits(pb, e, 1);
|
||||
- if (k)
|
||||
- put_sbits(pb, k, i);
|
||||
- } else {
|
||||
- while (limit > 31) {
|
||||
- put_bits(pb, 31, 0);
|
||||
- limit -= 31;
|
||||
- }
|
||||
- put_bits(pb, limit, 1);
|
||||
- put_bits(pb, esc_len, i - 1);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write signed golomb rice code (ffv1).
|
||||
- */
|
||||
-static inline void set_sr_golomb(PutBitContext *pb, int i, int k, int limit,
|
||||
- int esc_len)
|
||||
-{
|
||||
- int v;
|
||||
-
|
||||
- v = -2 * i - 1;
|
||||
- v ^= (v >> 31);
|
||||
-
|
||||
- set_ur_golomb(pb, v, k, limit, esc_len);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * write signed golomb rice code (flac).
|
||||
- */
|
||||
-static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k,
|
||||
- int limit, int esc_len)
|
||||
-{
|
||||
- int v;
|
||||
-
|
||||
- v = -2 * i - 1;
|
||||
- v ^= (v >> 31);
|
||||
-
|
||||
- set_ur_golomb_jpegls(pb, v, k, limit, esc_len);
|
||||
-}
|
||||
-
|
||||
#endif /* AVCODEC_GOLOMB_H */
|
||||
Index: libavcodec/get_bits.h
|
||||
IDEA additional info:
|
||||
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
||||
<+>UTF-8
|
||||
===================================================================
|
||||
diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
|
||||
--- a/libavcodec/get_bits.h (revision a77521cd5d27e955b16e8097eecefc779ffdcb6d)
|
||||
+++ b/libavcodec/get_bits.h (date 1647179363911)
|
||||
@@ -29,13 +29,9 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
-#include "libavutil/common.h"
|
||||
-#include "libavutil/intreadwrite.h"
|
||||
-#include "libavutil/log.h"
|
||||
-#include "libavutil/avassert.h"
|
||||
-#include "avcodec.h"
|
||||
-#include "mathops.h"
|
||||
-#include "vlc.h"
|
||||
+#ifndef NEG_USR32
|
||||
+# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s)))
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* Safe bitstream reading:
|
||||
@@ -312,73 +308,13 @@
|
||||
s->bits_left -= n;
|
||||
}
|
||||
#endif
|
||||
-
|
||||
-/**
|
||||
- * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
|
||||
- * if MSB not set it is negative
|
||||
- * @param n length in bits
|
||||
- */
|
||||
-static inline int get_xbits(GetBitContext *s, int n)
|
||||
-{
|
||||
-#if CACHED_BITSTREAM_READER
|
||||
- int32_t cache = show_bits(s, 32);
|
||||
- int sign = ~cache >> 31;
|
||||
- skip_remaining(s, n);
|
||||
-
|
||||
- return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign;
|
||||
-#else
|
||||
- register int sign;
|
||||
- register int32_t cache;
|
||||
- OPEN_READER(re, s);
|
||||
- av_assert2(n>0 && n<=25);
|
||||
- UPDATE_CACHE(re, s);
|
||||
- cache = GET_CACHE(re, s);
|
||||
- sign = ~cache >> 31;
|
||||
- LAST_SKIP_BITS(re, s, n);
|
||||
- CLOSE_READER(re, s);
|
||||
- return (NEG_USR32(sign ^ cache, n) ^ sign) - sign;
|
||||
-#endif
|
||||
-}
|
||||
-
|
||||
-#if !CACHED_BITSTREAM_READER
|
||||
-static inline int get_xbits_le(GetBitContext *s, int n)
|
||||
-{
|
||||
- register int sign;
|
||||
- register int32_t cache;
|
||||
- OPEN_READER(re, s);
|
||||
- av_assert2(n>0 && n<=25);
|
||||
- UPDATE_CACHE_LE(re, s);
|
||||
- cache = GET_CACHE(re, s);
|
||||
- sign = sign_extend(~cache, n) >> 31;
|
||||
- LAST_SKIP_BITS(re, s, n);
|
||||
- CLOSE_READER(re, s);
|
||||
- return (zero_extend(sign ^ cache, n) ^ sign) - sign;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
-static inline int get_sbits(GetBitContext *s, int n)
|
||||
-{
|
||||
- register int tmp;
|
||||
-#if CACHED_BITSTREAM_READER
|
||||
- av_assert2(n>0 && n<=25);
|
||||
- tmp = sign_extend(get_bits(s, n), n);
|
||||
-#else
|
||||
- OPEN_READER(re, s);
|
||||
- av_assert2(n>0 && n<=25);
|
||||
- UPDATE_CACHE(re, s);
|
||||
- tmp = SHOW_SBITS(re, s, n);
|
||||
- LAST_SKIP_BITS(re, s, n);
|
||||
- CLOSE_READER(re, s);
|
||||
-#endif
|
||||
- return tmp;
|
||||
-}
|
||||
|
||||
/**
|
||||
* Read 1-25 bits.
|
||||
*/
|
||||
static inline unsigned int get_bits(GetBitContext *s, int n)
|
||||
{
|
||||
- register unsigned int tmp;
|
||||
+ unsigned int tmp;
|
||||
#if CACHED_BITSTREAM_READER
|
||||
|
||||
av_assert2(n>0 && n<=32);
|
||||
@@ -409,61 +345,6 @@
|
||||
return tmp;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * Read 0-25 bits.
|
||||
- */
|
||||
-static av_always_inline int get_bitsz(GetBitContext *s, int n)
|
||||
-{
|
||||
- return n ? get_bits(s, n) : 0;
|
||||
-}
|
||||
-
|
||||
-static inline unsigned int get_bits_le(GetBitContext *s, int n)
|
||||
-{
|
||||
-#if CACHED_BITSTREAM_READER
|
||||
- av_assert2(n>0 && n<=32);
|
||||
- if (n > s->bits_left) {
|
||||
- refill_32(s, 1);
|
||||
- if (s->bits_left < 32)
|
||||
- s->bits_left = n;
|
||||
- }
|
||||
-
|
||||
- return get_val(s, n, 1);
|
||||
-#else
|
||||
- register int tmp;
|
||||
- OPEN_READER(re, s);
|
||||
- av_assert2(n>0 && n<=25);
|
||||
- UPDATE_CACHE_LE(re, s);
|
||||
- tmp = SHOW_UBITS_LE(re, s, n);
|
||||
- LAST_SKIP_BITS(re, s, n);
|
||||
- CLOSE_READER(re, s);
|
||||
- return tmp;
|
||||
-#endif
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * Show 1-25 bits.
|
||||
- */
|
||||
-static inline unsigned int show_bits(GetBitContext *s, int n)
|
||||
-{
|
||||
- register unsigned int tmp;
|
||||
-#if CACHED_BITSTREAM_READER
|
||||
- if (n > s->bits_left)
|
||||
-#ifdef BITSTREAM_READER_LE
|
||||
- refill_32(s, 1);
|
||||
-#else
|
||||
- refill_32(s, 0);
|
||||
-#endif
|
||||
-
|
||||
- tmp = show_val(s, n);
|
||||
-#else
|
||||
- OPEN_READER_NOSIZE(re, s);
|
||||
- av_assert2(n>0 && n<=25);
|
||||
- UPDATE_CACHE(re, s);
|
||||
- tmp = SHOW_UBITS(re, s, n);
|
||||
-#endif
|
||||
- return tmp;
|
||||
-}
|
||||
-
|
||||
static inline void skip_bits(GetBitContext *s, int n)
|
||||
{
|
||||
#if CACHED_BITSTREAM_READER
|
||||
@@ -530,11 +411,6 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
-static inline unsigned int show_bits1(GetBitContext *s)
|
||||
-{
|
||||
- return show_bits(s, 1);
|
||||
-}
|
||||
-
|
||||
static inline void skip_bits1(GetBitContext *s)
|
||||
{
|
||||
skip_bits(s, 1);
|
||||
@@ -584,31 +460,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
-/**
|
||||
- * Read 0-32 bits as a signed integer.
|
||||
- */
|
||||
-static inline int get_sbits_long(GetBitContext *s, int n)
|
||||
-{
|
||||
- // sign_extend(x, 0) is undefined
|
||||
- if (!n)
|
||||
- return 0;
|
||||
-
|
||||
- return sign_extend(get_bits_long(s, n), n);
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * Show 0-32 bits.
|
||||
- */
|
||||
-static inline unsigned int show_bits_long(GetBitContext *s, int n)
|
||||
-{
|
||||
- if (n <= MIN_CACHE_BITS) {
|
||||
- return show_bits(s, n);
|
||||
- } else {
|
||||
- GetBitContext gb = *s;
|
||||
- return get_bits_long(&gb, n);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
|
||||
{
|
||||
int bit = get_bits1(s);
|
||||
@@ -772,62 +623,6 @@
|
||||
SKIP_BITS(name, gb, n); \
|
||||
} while (0)
|
||||
|
||||
-/* Return the LUT element for the given bitstream configuration. */
|
||||
-static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits,
|
||||
- VLC_TYPE (*table)[2])
|
||||
-{
|
||||
- unsigned idx;
|
||||
-
|
||||
- *nb_bits = -*n;
|
||||
- idx = show_bits(s, *nb_bits) + code;
|
||||
- *n = table[idx][1];
|
||||
-
|
||||
- return table[idx][0];
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * Parse a vlc code.
|
||||
- * @param bits is the number of bits which will be read at once, must be
|
||||
- * identical to nb_bits in init_vlc()
|
||||
- * @param max_depth is the number of times bits bits must be read to completely
|
||||
- * read the longest vlc code
|
||||
- * = (max_vlc_length + bits - 1) / bits
|
||||
- * @returns the code parsed or -1 if no vlc matches
|
||||
- */
|
||||
-static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2],
|
||||
- int bits, int max_depth)
|
||||
-{
|
||||
-#if CACHED_BITSTREAM_READER
|
||||
- int nb_bits;
|
||||
- unsigned idx = show_bits(s, bits);
|
||||
- int code = table[idx][0];
|
||||
- int n = table[idx][1];
|
||||
-
|
||||
- if (max_depth > 1 && n < 0) {
|
||||
- skip_remaining(s, bits);
|
||||
- code = set_idx(s, code, &n, &nb_bits, table);
|
||||
- if (max_depth > 2 && n < 0) {
|
||||
- skip_remaining(s, nb_bits);
|
||||
- code = set_idx(s, code, &n, &nb_bits, table);
|
||||
- }
|
||||
- }
|
||||
- skip_remaining(s, n);
|
||||
-
|
||||
- return code;
|
||||
-#else
|
||||
- int code;
|
||||
-
|
||||
- OPEN_READER(re, s);
|
||||
- UPDATE_CACHE(re, s);
|
||||
-
|
||||
- GET_VLC(code, re, s, table, bits, max_depth);
|
||||
-
|
||||
- CLOSE_READER(re, s);
|
||||
-
|
||||
- return code;
|
||||
-#endif
|
||||
-}
|
||||
-
|
||||
static inline int decode012(GetBitContext *gb)
|
||||
{
|
||||
int n;
|
||||
@@ -865,4 +660,14 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static inline unsigned int show_bits_long(GetBitContext *s, int n)
|
||||
+{
|
||||
+ if (n <= MIN_CACHE_BITS) {
|
||||
+ return show_bits(s, n);
|
||||
+ } else {
|
||||
+ GetBitContext gb = *s;
|
||||
+ return get_bits_long(&gb, n);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#endif /* AVCODEC_GET_BITS_H */
|
|
@ -0,0 +1,17 @@
|
|||
Index: vpx_dsp/add_noise.c
|
||||
IDEA additional info:
|
||||
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
|
||||
<+>UTF-8
|
||||
===================================================================
|
||||
diff --git a/vpx_dsp/add_noise.c b/vpx_dsp/add_noise.c
|
||||
--- a/vpx_dsp/add_noise.c (revision 626ff35955c2c35b806b3e0ecf551a1a8611cdbf)
|
||||
+++ b/vpx_dsp/add_noise.c (date 1643957537362)
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "vpx_dsp/postproc.h"
|
||||
#include "vpx_ports/mem.h"
|
||||
|
||||
+#define rand() ((int)lrand48())
|
||||
+
|
||||
void vpx_plane_add_noise_c(uint8_t *start, const int8_t *noise, int blackclamp,
|
||||
int whiteclamp, int width, int height, int pitch) {
|
||||
int i, j;
|
|
@ -52,6 +52,15 @@ struct LOTLayerNode;
|
|||
|
||||
namespace rlottie {
|
||||
|
||||
enum class FitzModifier {
|
||||
None,
|
||||
Type12,
|
||||
Type3,
|
||||
Type4,
|
||||
Type5,
|
||||
Type6
|
||||
};
|
||||
|
||||
struct Color {
|
||||
Color() = default;
|
||||
Color(float r, float g , float b):_r(r), _g(g), _b(b){}
|
||||
|
@ -258,7 +267,7 @@ public:
|
|||
* @internal
|
||||
*/
|
||||
static std::unique_ptr<Animation>
|
||||
loadFromFile(const std::string &path, std::map<int32_t, int32_t> *colorReplacement);
|
||||
loadFromFile(const std::string &path, std::map<int32_t, int32_t> *colorReplacement, FitzModifier fitzModifier);
|
||||
|
||||
/**
|
||||
* @brief Constructs an animation object from JSON string data.
|
||||
|
@ -273,7 +282,7 @@ public:
|
|||
* @internal
|
||||
*/
|
||||
static std::unique_ptr<Animation>
|
||||
loadFromData(std::string jsonData, const std::string &key, std::map<int32_t, int32_t> *colorReplacement, const std::string &resourcePath="");
|
||||
loadFromData(std::string jsonData, const std::string &key, std::map<int32_t, int32_t> *colorReplacement, FitzModifier fitzModifier = FitzModifier::None, const std::string &resourcePath="");
|
||||
|
||||
/**
|
||||
* @brief Returns default framerate of the Lottie resource.
|
||||
|
@ -345,7 +354,7 @@ public:
|
|||
*
|
||||
* @internal
|
||||
*/
|
||||
void renderSync(size_t frameNo, Surface &surface, bool clear);
|
||||
void renderSync(size_t frameNo, Surface &surface, bool clear, bool* result);
|
||||
|
||||
/**
|
||||
* @brief Returns root layer of the composition updated with
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
double frameRate() const { return mModel->frameRate(); }
|
||||
size_t totalFrame() const { return mModel->totalFrame(); }
|
||||
size_t frameAtPos(double pos) const { return mModel->frameAtPos(pos); }
|
||||
Surface render(size_t frameNo, const Surface &surface, bool clear);
|
||||
Surface render(size_t frameNo, const Surface &surface, bool clear, bool* result);
|
||||
const LOTLayerNode * renderTree(size_t frameNo, const VSize &size);
|
||||
|
||||
const LayerInfoList &layerInfoList() const
|
||||
|
@ -60,7 +60,7 @@ private:
|
|||
std::shared_ptr<LOTModel> mModel;
|
||||
std::unique_ptr<LOTCompItem> mCompItem;
|
||||
SharedRenderTask mTask;
|
||||
std::atomic<bool> mRenderInProgress;
|
||||
std::atomic<bool> mRenderInProgress{false};
|
||||
};
|
||||
|
||||
void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value)
|
||||
|
@ -93,11 +93,12 @@ bool AnimationImpl::update(size_t frameNo, const VSize &size)
|
|||
return mCompItem->update(frameNo);
|
||||
}
|
||||
|
||||
Surface AnimationImpl::render(size_t frameNo, const Surface &surface, bool clear)
|
||||
Surface AnimationImpl::render(size_t frameNo, const Surface &surface, bool clear, bool* result)
|
||||
{
|
||||
bool renderInProgress = mRenderInProgress.load();
|
||||
if (renderInProgress) {
|
||||
vCritical << "Already Rendering Scheduled for this Animation";
|
||||
*result = false;
|
||||
return surface;
|
||||
}
|
||||
|
||||
|
@ -106,6 +107,7 @@ Surface AnimationImpl::render(size_t frameNo, const Surface &surface, bool clear
|
|||
VSize(surface.drawRegionWidth(), surface.drawRegionHeight()));
|
||||
mCompItem->render(surface, clear);
|
||||
mRenderInProgress.store(false);
|
||||
*result = true;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
@ -125,6 +127,7 @@ void AnimationImpl::init(const std::shared_ptr<LOTModel> &model)
|
|||
std::unique_ptr<Animation> Animation::loadFromData(
|
||||
std::string jsonData, const std::string &key,
|
||||
std::map<int32_t, int32_t> *colorReplacement,
|
||||
FitzModifier fitzModifier,
|
||||
const std::string &resourcePath)
|
||||
{
|
||||
if (jsonData.empty()) {
|
||||
|
@ -135,19 +138,17 @@ std::unique_ptr<Animation> Animation::loadFromData(
|
|||
LottieLoader loader;
|
||||
if (loader.loadFromData(std::move(jsonData), key,
|
||||
colorReplacement,
|
||||
(resourcePath.empty() ? " " : resourcePath))) {
|
||||
(resourcePath.empty() ? " " : resourcePath), fitzModifier)) {
|
||||
auto animation = std::unique_ptr<Animation>(new Animation);
|
||||
animation->colorMap = colorReplacement;
|
||||
animation->d->init(loader.model());
|
||||
return animation;
|
||||
}
|
||||
if (colorReplacement != nullptr) {
|
||||
delete colorReplacement;
|
||||
}
|
||||
delete colorReplacement;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path, std::map<int32_t, int32_t> *colorReplacement)
|
||||
std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path, std::map<int32_t, int32_t> *colorReplacement, FitzModifier fitzModifier)
|
||||
{
|
||||
if (path.empty()) {
|
||||
vWarning << "File path is empty";
|
||||
|
@ -155,15 +156,13 @@ std::unique_ptr<Animation> Animation::loadFromFile(const std::string &path, std:
|
|||
}
|
||||
|
||||
LottieLoader loader;
|
||||
if (loader.load(path, colorReplacement)) {
|
||||
if (loader.load(path, colorReplacement, fitzModifier)) {
|
||||
auto animation = std::unique_ptr<Animation>(new Animation);
|
||||
animation->colorMap = colorReplacement;
|
||||
animation->d->init(loader.model());
|
||||
return animation;
|
||||
}
|
||||
if (colorReplacement != nullptr) {
|
||||
delete colorReplacement;
|
||||
}
|
||||
delete colorReplacement;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -201,9 +200,9 @@ const LOTLayerNode *Animation::renderTree(size_t frameNo, size_t width,
|
|||
return d->renderTree(frameNo, VSize(width, height));
|
||||
}
|
||||
|
||||
void Animation::renderSync(size_t frameNo, Surface &surface, bool clear)
|
||||
void Animation::renderSync(size_t frameNo, Surface &surface, bool clear, bool* res)
|
||||
{
|
||||
d->render(frameNo, surface, clear);
|
||||
d->render(frameNo, surface, clear, res);
|
||||
}
|
||||
|
||||
const LayerInfoList &Animation::layers() const
|
||||
|
|
|
@ -75,7 +75,7 @@ static std::string dirname(const std::string &path)
|
|||
return std::string(path, 0, len);
|
||||
}
|
||||
|
||||
bool LottieLoader::load(const std::string &path, std::map<int32_t, int32_t> *colorReplacement)
|
||||
bool LottieLoader::load(const std::string &path, std::map<int32_t, int32_t> *colorReplacement, rlottie::FitzModifier fitzModifier)
|
||||
{
|
||||
mModel = LottieFileCache::instance().find(path);
|
||||
if (mModel) return true;
|
||||
|
@ -95,7 +95,7 @@ bool LottieLoader::load(const std::string &path, std::map<int32_t, int32_t> *col
|
|||
if (content.empty()) return false;
|
||||
|
||||
const char *str = content.c_str();
|
||||
LottieParser parser(const_cast<char *>(str), dirname(path).c_str(), colorReplacement);
|
||||
LottieParser parser(const_cast<char *>(str), dirname(path).c_str(), colorReplacement, fitzModifier);
|
||||
if (parser.hasParsingError()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -111,12 +111,12 @@ bool LottieLoader::load(const std::string &path, std::map<int32_t, int32_t> *col
|
|||
|
||||
bool LottieLoader::loadFromData(std::string &&jsonData, const std::string &key,
|
||||
std::map<int32_t, int32_t> *colorReplacement,
|
||||
const std::string &resourcePath)
|
||||
const std::string &resourcePath, rlottie::FitzModifier fitzModifier)
|
||||
{
|
||||
mModel = LottieFileCache::instance().find(key);
|
||||
if (mModel) return true;
|
||||
|
||||
LottieParser parser(const_cast<char *>(jsonData.c_str()), resourcePath.c_str(), colorReplacement);
|
||||
LottieParser parser(const_cast<char *>(jsonData.c_str()), resourcePath.c_str(), colorReplacement, fitzModifier);
|
||||
mModel = parser.model();
|
||||
|
||||
if (!mModel) return false;
|
||||
|
|
|
@ -22,13 +22,14 @@
|
|||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <rlottie.h>
|
||||
|
||||
class LOTModel;
|
||||
class LottieLoader
|
||||
{
|
||||
public:
|
||||
bool load(const std::string &filePath, std::map<int32_t, int32_t> *colorReplacement);
|
||||
bool loadFromData(std::string &&jsonData, const std::string &key, std::map<int32_t, int32_t> *colorReplacement, const std::string &resourcePath);
|
||||
bool load(const std::string &filePath, std::map<int32_t, int32_t> *colorReplacement, rlottie::FitzModifier fitzModifier);
|
||||
bool loadFromData(std::string &&jsonData, const std::string &key, std::map<int32_t, int32_t> *colorReplacement, const std::string &resourcePath, rlottie::FitzModifier fitzModifier);
|
||||
std::shared_ptr<LOTModel> model();
|
||||
private:
|
||||
std::shared_ptr<LOTModel> mModel;
|
||||
|
|
|
@ -182,8 +182,8 @@ protected:
|
|||
|
||||
class LottieParserImpl : protected LookaheadParserHandler {
|
||||
public:
|
||||
LottieParserImpl(char *str, const char *dir_path, std::map<int32_t, int32_t> *colorReplacement)
|
||||
: LookaheadParserHandler(str), mDirPath(dir_path), colorMap(colorReplacement)
|
||||
LottieParserImpl(char *str, const char *dir_path, std::map<int32_t, int32_t> *colorReplacement, rlottie::FitzModifier fitzModifier)
|
||||
: LookaheadParserHandler(str), mDirPath(dir_path), colorMap(colorReplacement), mFitzModifier(fitzModifier)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -270,6 +270,9 @@ public:
|
|||
void parseShapeProperty(LOTAnimatable<LottieShapeData> &obj);
|
||||
void parseDashProperty(LOTDashProperty &dash);
|
||||
|
||||
void parseFitzColorReplacements();
|
||||
void parseFitzColorReplacement();
|
||||
|
||||
std::shared_ptr<VInterpolator> interpolator(VPointF, VPointF, std::string);
|
||||
|
||||
LottieColor toColor(const char *str);
|
||||
|
@ -279,6 +282,7 @@ public:
|
|||
bool hasParsingError();
|
||||
|
||||
protected:
|
||||
const rlottie::FitzModifier mFitzModifier;
|
||||
std::unordered_map<std::string, std::shared_ptr<VInterpolator>>
|
||||
mInterpolatorCache;
|
||||
std::shared_ptr<LOTCompositionData> mComposition;
|
||||
|
@ -611,6 +615,8 @@ void LottieParserImpl::parseComposition() {
|
|||
parseAssets(comp);
|
||||
} else if (0 == strcmp(key, "layers")) {
|
||||
parseLayers(comp);
|
||||
} else if (0 == strcmp(key, "fitz")) {
|
||||
parseFitzColorReplacements();
|
||||
} else {
|
||||
#ifdef DEBUG_PARSER
|
||||
vWarning << "Composition Attribute Skipped : " << key;
|
||||
|
@ -659,6 +665,79 @@ void LottieParserImpl::parseAssets(LOTCompositionData *composition) {
|
|||
// update the precomp layers with the actual layer object
|
||||
}
|
||||
|
||||
void LottieParserImpl::parseFitzColorReplacements()
|
||||
{
|
||||
RAPIDJSON_ASSERT(PeekType() == kArrayType);
|
||||
EnterArray();
|
||||
while (NextArrayValue()) {
|
||||
parseFitzColorReplacement();
|
||||
}
|
||||
}
|
||||
|
||||
void LottieParserImpl::parseFitzColorReplacement()
|
||||
{
|
||||
uint32_t original = 0;
|
||||
uint32_t type12 = 0;
|
||||
uint32_t type3 = 0;
|
||||
uint32_t type4 = 0;
|
||||
uint32_t type5 = 0;
|
||||
uint32_t type6 = 0;
|
||||
|
||||
EnterObject();
|
||||
while (const char *key = NextObjectKey()) {
|
||||
if (0 == strcmp(key, "o")) {
|
||||
RAPIDJSON_ASSERT(PeekType() == kNumberType);
|
||||
original = GetInt();
|
||||
} else if (0 == strcmp(key, "f12")) {
|
||||
RAPIDJSON_ASSERT(PeekType() == kNumberType);
|
||||
type12 = GetInt();
|
||||
} else if (0 == strcmp(key, "f3")) {
|
||||
RAPIDJSON_ASSERT(PeekType() == kNumberType);
|
||||
type3 = GetInt();
|
||||
} else if (0 == strcmp(key, "f4")) {
|
||||
RAPIDJSON_ASSERT(PeekType() == kNumberType);
|
||||
type4 = GetInt();
|
||||
} else if (0 == strcmp(key, "f5")) {
|
||||
RAPIDJSON_ASSERT(PeekType() == kNumberType);
|
||||
type5 = GetInt();
|
||||
} else if (0 == strcmp(key, "f6")) {
|
||||
RAPIDJSON_ASSERT(PeekType() == kNumberType);
|
||||
type6 = GetInt();
|
||||
} else {
|
||||
Skip(key);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t replacedType = 0;
|
||||
|
||||
switch (mFitzModifier) {
|
||||
case rlottie::FitzModifier::None:
|
||||
break;
|
||||
case rlottie::FitzModifier::Type12:
|
||||
replacedType = type12;
|
||||
break;
|
||||
case rlottie::FitzModifier::Type3:
|
||||
replacedType = type3;
|
||||
break;
|
||||
case rlottie::FitzModifier::Type4:
|
||||
replacedType = type4;
|
||||
break;
|
||||
case rlottie::FitzModifier::Type5:
|
||||
replacedType = type5;
|
||||
break;
|
||||
case rlottie::FitzModifier::Type6:
|
||||
replacedType = type6;
|
||||
break;
|
||||
}
|
||||
|
||||
if (replacedType != 0) {
|
||||
if (colorMap == NULL) {
|
||||
colorMap = new std::map<int32_t, int32_t>();
|
||||
}
|
||||
colorMap->insert(std::pair<int32_t, int32_t>(original, replacedType));
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr const unsigned char B64index[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -2654,8 +2733,8 @@ LottieParser::~LottieParser()
|
|||
delete d;
|
||||
}
|
||||
|
||||
LottieParser::LottieParser(char *str, const char *dir_path, std::map<int32_t, int32_t> *colorReplacement)
|
||||
: d(new LottieParserImpl(str, dir_path, colorReplacement))
|
||||
LottieParser::LottieParser(char *str, const char *dir_path, std::map<int32_t, int32_t> *colorReplacement, rlottie::FitzModifier fitzModifier)
|
||||
: d(new LottieParserImpl(str, dir_path, colorReplacement, fitzModifier))
|
||||
{
|
||||
d->parseComposition();
|
||||
if (d->hasParsingError()) {
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
|
||||
#include "lottiemodel.h"
|
||||
#include <map>
|
||||
#include <rlottie.h>
|
||||
|
||||
class LottieParserImpl;
|
||||
class LottieParser {
|
||||
public:
|
||||
~LottieParser();
|
||||
LottieParser(char* str, const char *dir_path, std::map<int32_t, int32_t> *colorReplacement);
|
||||
LottieParser(char* str, const char *dir_path, std::map<int32_t, int32_t> *colorReplacement, rlottie::FitzModifier fitzModifier = rlottie::FitzModifier::None);
|
||||
std::shared_ptr<LOTModel> model();
|
||||
bool hasParsingError();
|
||||
private:
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||
#else
|
||||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // no std::string support by default
|
||||
#endif
|
||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
|
|
|
@ -679,63 +679,69 @@ static void
|
|||
gray_render_conic( RAS_ARG_ const SW_FT_Vector* control,
|
||||
const SW_FT_Vector* to )
|
||||
{
|
||||
SW_FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */
|
||||
SW_FT_Vector* arc = bez_stack;
|
||||
TPos dx, dy;
|
||||
int draw, split;
|
||||
TPos dx, dy;
|
||||
TPos min, max, y;
|
||||
int top, level;
|
||||
int* levels;
|
||||
SW_FT_Vector* arc;
|
||||
|
||||
levels = ras.lev_stack;
|
||||
|
||||
arc[0].x = UPSCALE( to->x );
|
||||
arc[0].y = UPSCALE( to->y );
|
||||
arc[1].x = UPSCALE( control->x );
|
||||
arc[1].y = UPSCALE( control->y );
|
||||
arc = ras.bez_stack;
|
||||
arc[0].x = UPSCALE(to->x);
|
||||
arc[0].y = UPSCALE(to->y);
|
||||
arc[1].x = UPSCALE(control->x);
|
||||
arc[1].y = UPSCALE(control->y);
|
||||
arc[2].x = ras.x;
|
||||
arc[2].y = ras.y;
|
||||
top = 0;
|
||||
|
||||
dx = SW_FT_ABS(arc[2].x + arc[0].x - 2 * arc[1].x);
|
||||
dy = SW_FT_ABS(arc[2].y + arc[0].y - 2 * arc[1].y);
|
||||
if (dx < dy) dx = dy;
|
||||
|
||||
if (dx < ONE_PIXEL / 4) goto Draw;
|
||||
|
||||
/* short-cut the arc that crosses the current band */
|
||||
if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
|
||||
TRUNC( arc[1].y ) >= ras.max_ey &&
|
||||
TRUNC( arc[2].y ) >= ras.max_ey ) ||
|
||||
( TRUNC( arc[0].y ) < ras.min_ey &&
|
||||
TRUNC( arc[1].y ) < ras.min_ey &&
|
||||
TRUNC( arc[2].y ) < ras.min_ey ) )
|
||||
{
|
||||
ras.x = arc[0].x;
|
||||
ras.y = arc[0].y;
|
||||
return;
|
||||
}
|
||||
min = max = arc[0].y;
|
||||
|
||||
dx = SW_FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
|
||||
dy = SW_FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
|
||||
if ( dx < dy )
|
||||
dx = dy;
|
||||
y = arc[1].y;
|
||||
if (y < min) min = y;
|
||||
if (y > max) max = y;
|
||||
|
||||
/* We can calculate the number of necessary bisections because */
|
||||
/* each bisection predictably reduces deviation exactly 4-fold. */
|
||||
/* Even 32-bit deviation would vanish after 16 bisections. */
|
||||
draw = 1;
|
||||
while ( dx > ONE_PIXEL / 4 )
|
||||
{
|
||||
dx >>= 2;
|
||||
draw <<= 1;
|
||||
}
|
||||
y = arc[2].y;
|
||||
if (y < min) min = y;
|
||||
if (y > max) max = y;
|
||||
|
||||
/* We use decrement counter to count the total number of segments */
|
||||
/* to draw starting from 2^level. Before each draw we split as */
|
||||
/* many times as there are trailing zeros in the counter. */
|
||||
do
|
||||
{
|
||||
split = draw & ( -draw ); /* isolate the rightmost 1-bit */
|
||||
while ( ( split >>= 1 ) )
|
||||
{
|
||||
gray_split_conic( arc );
|
||||
if (TRUNC(min) >= ras.max_ey || TRUNC(max) < ras.min_ey) goto Draw;
|
||||
|
||||
level = 0;
|
||||
do {
|
||||
dx >>= 2;
|
||||
level++;
|
||||
} while (dx > ONE_PIXEL / 4);
|
||||
|
||||
levels[0] = level;
|
||||
|
||||
do {
|
||||
level = levels[top];
|
||||
if (level > 0) {
|
||||
gray_split_conic(arc);
|
||||
arc += 2;
|
||||
top++;
|
||||
|
||||
if (top + 1 > 32) return;
|
||||
|
||||
levels[top] = levels[top - 1] = level - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
|
||||
Draw:
|
||||
gray_render_line(RAS_VAR_ arc[0].x, arc[0].y);
|
||||
top--;
|
||||
arc -= 2;
|
||||
|
||||
} while ( --draw );
|
||||
} while (top >= 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -809,7 +815,7 @@ gray_render_cubic( RAS_ARG_ const SW_FT_Vector* control1,
|
|||
/* with each split, control points quickly converge towards */
|
||||
/* chord trisection points and the vanishing distances below */
|
||||
/* indicate when the segment is flat enough to draw */
|
||||
if (num < 0 || num >= count) {
|
||||
if (num < 0 || num + 7 >= count) {
|
||||
return;
|
||||
}
|
||||
if ( SW_FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 ||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -22,7 +22,7 @@ Bool *Bool::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in Bool", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in Bool", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -40,7 +40,7 @@ void TL_boolFalse::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_dcOption *TL_dcOption::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_dcOption::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_dcOption", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_dcOption", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_dcOption *result = new TL_dcOption();
|
||||
|
@ -55,6 +55,8 @@ void TL_dcOption::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool
|
|||
tcpo_only = (flags & 4) != 0;
|
||||
cdn = (flags & 8) != 0;
|
||||
isStatic = (flags & 16) != 0;
|
||||
thisPortOnly = (flags & 32) != 0;
|
||||
force_try_ipv6 = (flags & 16384) != 0;
|
||||
id = stream->readInt32(&error);
|
||||
ip_address = stream->readString(&error);
|
||||
port = stream->readInt32(&error);
|
||||
|
@ -70,6 +72,8 @@ void TL_dcOption::serializeToStream(NativeByteBuffer *stream) {
|
|||
flags = tcpo_only ? (flags | 4) : (flags &~ 4);
|
||||
flags = cdn ? (flags | 8) : (flags &~ 8);
|
||||
flags = isStatic ? (flags | 16) : (flags &~ 16);
|
||||
flags = thisPortOnly ? (flags | 32) : (flags &~ 32);
|
||||
flags = force_try_ipv6 ? (flags | 16384) : (flags &~ 16384);
|
||||
stream->writeInt32(flags);
|
||||
stream->writeInt32(id);
|
||||
stream->writeString(ip_address);
|
||||
|
@ -82,7 +86,7 @@ void TL_dcOption::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_cdnPublicKey *TL_cdnPublicKey::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_cdnPublicKey::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_cdnPublicKey", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_cdnPublicKey", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_cdnPublicKey *result = new TL_cdnPublicKey();
|
||||
|
@ -104,7 +108,7 @@ void TL_cdnPublicKey::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_cdnConfig *TL_cdnConfig::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_cdnConfig::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_cdnConfig", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_cdnConfig", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_cdnConfig *result = new TL_cdnConfig();
|
||||
|
@ -116,7 +120,7 @@ void TL_cdnConfig::readParams(NativeByteBuffer *stream, int32_t instanceNum, boo
|
|||
int magic = stream->readInt32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_cdnConfig, got %x", magic);
|
||||
return;
|
||||
}
|
||||
int count = stream->readInt32(&error);
|
||||
|
@ -154,7 +158,7 @@ void TL_help_getCdnConfig::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_config *TL_config::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_config::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_config", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_config", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_config *result = new TL_config();
|
||||
|
@ -171,7 +175,7 @@ void TL_config::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_config, got %x", magic);
|
||||
return;
|
||||
}
|
||||
int32_t count = stream->readInt32(&error);
|
||||
|
@ -194,19 +198,19 @@ void TL_config::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &
|
|||
notify_default_delay_ms = stream->readInt32(&error);
|
||||
push_chat_period_ms = stream->readInt32(&error);
|
||||
push_chat_limit = stream->readInt32(&error);
|
||||
saved_gifs_limit = stream->readInt32(&error);
|
||||
// saved_gifs_limit = stream->readInt32(&error);
|
||||
edit_time_limit = stream->readInt32(&error);
|
||||
revoke_time_limit = stream->readInt32(&error);
|
||||
revoke_pm_time_limit = stream->readInt32(&error);
|
||||
rating_e_decay = stream->readInt32(&error);
|
||||
stickers_recent_limit = stream->readInt32(&error);
|
||||
stickers_faved_limit = stream->readInt32(&error);
|
||||
// stickers_faved_limit = stream->readInt32(&error);
|
||||
channels_read_media_period = stream->readInt32(&error);
|
||||
if ((flags & 1) != 0) {
|
||||
tmp_sessions = stream->readInt32(&error);
|
||||
}
|
||||
pinned_dialogs_count_max = stream->readInt32(&error);
|
||||
pinned_infolder_count_max = stream->readInt32(&error);
|
||||
// pinned_dialogs_count_max = stream->readInt32(&error);
|
||||
// pinned_infolder_count_max = stream->readInt32(&error);
|
||||
call_receive_timeout_ms = stream->readInt32(&error);
|
||||
call_ring_timeout_ms = stream->readInt32(&error);
|
||||
call_connect_timeout_ms = stream->readInt32(&error);
|
||||
|
@ -239,6 +243,12 @@ void TL_config::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &
|
|||
if ((flags & 4) != 0) {
|
||||
base_lang_pack_version = stream->readInt32(&error);
|
||||
}
|
||||
if ((flags & 32768) != 0) {
|
||||
reactions_default = std::unique_ptr<Reaction>(Reaction::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
}
|
||||
if ((flags & 65536) != 0) {
|
||||
autologin_token = stream->readString(&error);
|
||||
}
|
||||
}
|
||||
|
||||
void TL_config::serializeToStream(NativeByteBuffer *stream) {
|
||||
|
@ -266,19 +276,19 @@ void TL_config::serializeToStream(NativeByteBuffer *stream) {
|
|||
stream->writeInt32(notify_default_delay_ms);
|
||||
stream->writeInt32(push_chat_period_ms);
|
||||
stream->writeInt32(push_chat_limit);
|
||||
stream->writeInt32(saved_gifs_limit);
|
||||
// stream->writeInt32(saved_gifs_limit);
|
||||
stream->writeInt32(edit_time_limit);
|
||||
stream->writeInt32(revoke_time_limit);
|
||||
stream->writeInt32(revoke_pm_time_limit);
|
||||
stream->writeInt32(rating_e_decay);
|
||||
stream->writeInt32(stickers_recent_limit);
|
||||
stream->writeInt32(stickers_faved_limit);
|
||||
// stream->writeInt32(stickers_faved_limit);
|
||||
stream->writeInt32(channels_read_media_period);
|
||||
if ((flags & 1) != 0) {
|
||||
stream->writeInt32(tmp_sessions);
|
||||
}
|
||||
stream->writeInt32(pinned_dialogs_count_max);
|
||||
stream->writeInt32(pinned_infolder_count_max);
|
||||
// stream->writeInt32(pinned_dialogs_count_max);
|
||||
// stream->writeInt32(pinned_infolder_count_max);
|
||||
stream->writeInt32(call_receive_timeout_ms);
|
||||
stream->writeInt32(call_ring_timeout_ms);
|
||||
stream->writeInt32(call_connect_timeout_ms);
|
||||
|
@ -311,6 +321,12 @@ void TL_config::serializeToStream(NativeByteBuffer *stream) {
|
|||
if ((flags & 4) != 0) {
|
||||
stream->writeInt32(base_lang_pack_version);
|
||||
}
|
||||
if ((flags & 32768) != 0 && reactions_default != nullptr) {
|
||||
reactions_default->serializeToStream(stream);
|
||||
}
|
||||
if ((flags & 65536) != 0) {
|
||||
stream->writeString(autologin_token);
|
||||
}
|
||||
}
|
||||
|
||||
TLObject *TL_help_getConfig::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
|
@ -342,7 +358,7 @@ void TL_account_registerDevice::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_restrictionReason *TL_restrictionReason::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_restrictionReason::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_restrictionReason", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_restrictionReason", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_restrictionReason *result = new TL_restrictionReason();
|
||||
|
@ -350,6 +366,17 @@ TL_restrictionReason *TL_restrictionReason::TLdeserialize(NativeByteBuffer *stre
|
|||
return result;
|
||||
}
|
||||
|
||||
TL_username *TL_username::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_username::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_username", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_username *result = new TL_username();
|
||||
result->readParams(stream, instanceNum, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
void TL_restrictionReason::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
platform = stream->readString(&error);
|
||||
reason = stream->readString(&error);
|
||||
|
@ -363,18 +390,33 @@ void TL_restrictionReason::serializeToStream(NativeByteBuffer *stream) {
|
|||
stream->writeString(text);
|
||||
}
|
||||
|
||||
void TL_username::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
flags = stream->readInt32(&error);
|
||||
editable = (flags & 1) != 0;
|
||||
active = (flags & 2) != 0;
|
||||
username = stream->readString(&error);
|
||||
}
|
||||
|
||||
void TL_username::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
flags = editable ? (flags | 1) : (flags &~ 1);
|
||||
flags = active ? (flags | 2) : (flags &~ 2);
|
||||
stream->writeInt32(flags);
|
||||
stream->writeString(username);
|
||||
}
|
||||
|
||||
User *User::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
User *result = nullptr;
|
||||
switch (constructor) {
|
||||
case 0x200250ba:
|
||||
case TL_userEmpty::constructor:
|
||||
result = new TL_userEmpty();
|
||||
break;
|
||||
case 0x938458c1:
|
||||
case TL_user::constructor:
|
||||
result = new TL_user();
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in User", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in User", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -382,17 +424,18 @@ User *User::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_
|
|||
}
|
||||
|
||||
void TL_userEmpty::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
id = stream->readInt32(&error);
|
||||
id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_userEmpty::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(id);
|
||||
stream->writeInt64(id);
|
||||
}
|
||||
|
||||
void TL_user::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
flags = stream->readInt32(&error);
|
||||
id = stream->readInt32(&error);
|
||||
flags2 = stream->readInt32(&error);
|
||||
id = stream->readInt64(&error);
|
||||
if ((flags & 1) != 0) {
|
||||
access_hash = stream->readInt64(&error);
|
||||
}
|
||||
|
@ -421,7 +464,7 @@ void TL_user::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &er
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_user, got %x", magic);
|
||||
return;
|
||||
}
|
||||
int32_t count = stream->readInt32(&error);
|
||||
|
@ -439,12 +482,45 @@ void TL_user::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &er
|
|||
if ((flags & 4194304) != 0) {
|
||||
lang_code = stream->readString(&error);
|
||||
}
|
||||
if ((flags & 1073741824) != 0) {
|
||||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic == 0x2de11aae) {
|
||||
// emojiStatusEmpty
|
||||
} else if (magic == 0x929b619d) {
|
||||
// emojiStatus
|
||||
int64_t document_id = stream->readInt64(&error);
|
||||
} else if (magic == 0xfa30a8c7) {
|
||||
// emojiStatusUntil
|
||||
int64_t document_id = stream->readInt64(&error);
|
||||
int until = stream->readInt32(&error);
|
||||
} else {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong EmojiStatus magic, got %x", magic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((flags2 & 1) != 0) {
|
||||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_user (2), got %x", magic);
|
||||
return;
|
||||
}
|
||||
int32_t count = stream->readInt32(&error);
|
||||
for (int32_t a = 0; a < count; a++) {
|
||||
TL_username *object = TL_username::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error);
|
||||
if (object == nullptr) {
|
||||
return;
|
||||
}
|
||||
usernames.push_back(std::unique_ptr<TL_username>(object));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TL_user::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(flags);
|
||||
stream->writeInt32(id);
|
||||
stream->writeInt64(id);
|
||||
if ((flags & 1) != 0) {
|
||||
stream->writeInt64(access_hash);
|
||||
}
|
||||
|
@ -491,19 +567,19 @@ InputPeer *InputPeer::TLdeserialize(NativeByteBuffer *stream, uint32_t construct
|
|||
case 0x7da07ec9:
|
||||
result = new TL_inputPeerSelf();
|
||||
break;
|
||||
case 0x7b8e7de6:
|
||||
case 0xdde8a54c:
|
||||
result = new TL_inputPeerUser();
|
||||
break;
|
||||
case 0x179be863:
|
||||
case 0x35a95cb9:
|
||||
result = new TL_inputPeerChat();
|
||||
break;
|
||||
case 0x17bae2e6:
|
||||
case 0xa87b0a1c:
|
||||
result = new TL_inputPeerUserFromMessage();
|
||||
break;
|
||||
case 0x9c95f7bb:
|
||||
case 0xbd2a0840:
|
||||
result = new TL_inputPeerChannelFromMessage();
|
||||
break;
|
||||
case 0x20adaef8:
|
||||
case 0x27bcbbfc:
|
||||
result = new TL_inputPeerChannel();
|
||||
break;
|
||||
case 0x7f3b18ea:
|
||||
|
@ -511,7 +587,7 @@ InputPeer *InputPeer::TLdeserialize(NativeByteBuffer *stream, uint32_t construct
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in InputPeer", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in InputPeer", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -523,59 +599,59 @@ void TL_inputPeerSelf::serializeToStream(NativeByteBuffer *stream) {
|
|||
}
|
||||
|
||||
void TL_inputPeerUser::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
user_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt64(&error);
|
||||
access_hash = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputPeerUser::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(user_id);
|
||||
stream->writeInt64(user_id);
|
||||
stream->writeInt64(access_hash);
|
||||
}
|
||||
|
||||
void TL_inputPeerChat::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
chat_id = stream->readInt32(&error);
|
||||
chat_id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputPeerChat::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(chat_id);
|
||||
stream->writeInt64(chat_id);
|
||||
}
|
||||
|
||||
void TL_inputPeerUserFromMessage::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
peer = std::unique_ptr<InputPeer>(InputPeer::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
msg_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputPeerUserFromMessage::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
peer->serializeToStream(stream);
|
||||
stream->writeInt32(msg_id);
|
||||
stream->writeInt32(user_id);
|
||||
stream->writeInt64(user_id);
|
||||
}
|
||||
|
||||
void TL_inputPeerChannelFromMessage::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
peer = std::unique_ptr<InputPeer>(InputPeer::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
msg_id = stream->readInt32(&error);
|
||||
channel_id = stream->readInt32(&error);
|
||||
channel_id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputPeerChannelFromMessage::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
peer->serializeToStream(stream);
|
||||
stream->writeInt32(msg_id);
|
||||
stream->writeInt32(channel_id);
|
||||
stream->writeInt64(channel_id);
|
||||
}
|
||||
|
||||
void TL_inputPeerChannel::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
channel_id = stream->readInt32(&error);
|
||||
channel_id = stream->readInt64(&error);
|
||||
access_hash = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputPeerChannel::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(channel_id);
|
||||
stream->writeInt64(channel_id);
|
||||
stream->writeInt64(access_hash);
|
||||
}
|
||||
|
||||
|
@ -589,18 +665,18 @@ InputUser *InputUser::TLdeserialize(NativeByteBuffer *stream, uint32_t construct
|
|||
case 0xf7c1b13f:
|
||||
result = new TL_inputUserSelf();
|
||||
break;
|
||||
case 0xd8292816:
|
||||
case 0xf21158c6:
|
||||
result = new TL_inputUser();
|
||||
break;
|
||||
case 0xb98886cf:
|
||||
result = new TL_inputUserEmpty();
|
||||
break;
|
||||
case 0x2d117597:
|
||||
case 0x1da448e2:
|
||||
result = new TL_inputUserFromMessage();
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in InputUser", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in InputUser", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -612,13 +688,13 @@ void TL_inputUserSelf::serializeToStream(NativeByteBuffer *stream) {
|
|||
}
|
||||
|
||||
void TL_inputUser::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
user_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt64(&error);
|
||||
access_hash = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputUser::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(user_id);
|
||||
stream->writeInt64(user_id);
|
||||
stream->writeInt64(access_hash);
|
||||
}
|
||||
|
||||
|
@ -629,14 +705,14 @@ void TL_inputUserEmpty::serializeToStream(NativeByteBuffer *stream) {
|
|||
void TL_inputUserFromMessage::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
peer = std::unique_ptr<InputPeer>(InputPeer::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
msg_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_inputUserFromMessage::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
peer->serializeToStream(stream);
|
||||
stream->writeInt32(msg_id);
|
||||
stream->writeInt32(user_id);
|
||||
stream->writeInt64(user_id);
|
||||
}
|
||||
|
||||
MessageEntity *MessageEntity::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
|
@ -666,7 +742,7 @@ MessageEntity *MessageEntity::TLdeserialize(NativeByteBuffer *stream, uint32_t c
|
|||
case 0xfa04579d:
|
||||
result = new TL_messageEntityMention();
|
||||
break;
|
||||
case 0x352dca58:
|
||||
case 0xdc7b1140:
|
||||
result = new TL_messageEntityMentionName();
|
||||
break;
|
||||
case 0x208e68c9:
|
||||
|
@ -698,7 +774,7 @@ MessageEntity *MessageEntity::TLdeserialize(NativeByteBuffer *stream, uint32_t c
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in MessageEntity", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in MessageEntity", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -800,14 +876,14 @@ void TL_messageEntityMention::serializeToStream(NativeByteBuffer *stream) {
|
|||
void TL_messageEntityMentionName::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
offset = stream->readInt32(&error);
|
||||
length = stream->readInt32(&error);
|
||||
user_id = stream->readInt32(&error);
|
||||
user_id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_messageEntityMentionName::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(offset);
|
||||
stream->writeInt32(length);
|
||||
stream->writeInt32(user_id);
|
||||
stream->writeInt64(user_id);
|
||||
}
|
||||
|
||||
void TL_inputMessageEntityMentionName::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
|
@ -914,7 +990,7 @@ void TL_messageEntityPhone::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_dataJSON *TL_dataJSON::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_dataJSON::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_dataJSON", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_dataJSON", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_dataJSON *result = new TL_dataJSON();
|
||||
|
@ -934,7 +1010,7 @@ void TL_dataJSON::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_help_termsOfService *TL_help_termsOfService::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_help_termsOfService::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_help_termsOfService", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_help_termsOfService", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_help_termsOfService *result = new TL_help_termsOfService();
|
||||
|
@ -950,7 +1026,7 @@ void TL_help_termsOfService::readParams(NativeByteBuffer *stream, int32_t instan
|
|||
int magic = stream->readInt32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_help_termsOfService, got %x", magic);
|
||||
return;
|
||||
}
|
||||
int count = stream->readInt32(&error);
|
||||
|
@ -989,12 +1065,12 @@ auth_Authorization *auth_Authorization::TLdeserialize(NativeByteBuffer *stream,
|
|||
case 0x44747e9a:
|
||||
result = new TL_auth_authorizationSignUpRequired();
|
||||
break;
|
||||
case 0xcd050916:
|
||||
case 0x2ea2c0d4:
|
||||
result = new TL_auth_authorization();
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in auth_Authorization", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in auth_Authorization", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -1018,9 +1094,15 @@ void TL_auth_authorizationSignUpRequired::serializeToStream(NativeByteBuffer *st
|
|||
|
||||
void TL_auth_authorization::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
flags = stream->readInt32(&error);
|
||||
if ((flags & 2) != 0) {
|
||||
otherwise_relogin_days = stream->readInt32(&error);
|
||||
}
|
||||
if ((flags & 1) != 0) {
|
||||
tmp_sessions = stream->readInt32(&error);
|
||||
}
|
||||
if ((flags & 4) != 0) {
|
||||
future_auth_token = std::unique_ptr<ByteArray>(stream->readByteArray(&error));
|
||||
}
|
||||
user = std::unique_ptr<User>(User::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
}
|
||||
|
||||
|
@ -1036,7 +1118,7 @@ void TL_auth_authorization::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_auth_exportedAuthorization *TL_auth_exportedAuthorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_auth_exportedAuthorization::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_auth_exportedAuthorization", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_auth_exportedAuthorization", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_auth_exportedAuthorization *result = new TL_auth_exportedAuthorization();
|
||||
|
@ -1045,7 +1127,7 @@ TL_auth_exportedAuthorization *TL_auth_exportedAuthorization::TLdeserialize(Nati
|
|||
}
|
||||
|
||||
void TL_auth_exportedAuthorization::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
id = stream->readInt32(&error);
|
||||
id = stream->readInt64(&error);
|
||||
bytes = std::unique_ptr<ByteArray>(stream->readByteArray(&error));
|
||||
}
|
||||
|
||||
|
@ -1072,7 +1154,7 @@ TLObject *TL_auth_importAuthorization::deserializeResponse(NativeByteBuffer *str
|
|||
|
||||
void TL_auth_importAuthorization::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt32(id);
|
||||
stream->writeInt64(id);
|
||||
stream->writeByteArray(bytes.get());
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1181,7 @@ UserStatus *UserStatus::TLdeserialize(NativeByteBuffer *stream, uint32_t constru
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in UserStatus", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in UserStatus", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -1148,7 +1230,7 @@ FileLocation *FileLocation::TLdeserialize(NativeByteBuffer *stream, uint32_t con
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in FileLocation", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in FileLocation", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -1172,12 +1254,12 @@ UserProfilePhoto *UserProfilePhoto::TLdeserialize(NativeByteBuffer *stream, uint
|
|||
case 0x4f11bae1:
|
||||
result = new TL_userProfilePhotoEmpty();
|
||||
break;
|
||||
case 0x69d3ab26:
|
||||
case 0x82d1f706:
|
||||
result = new TL_userProfilePhoto();
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in UserProfilePhoto", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in UserProfilePhoto", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -1192,8 +1274,9 @@ void TL_userProfilePhoto::readParams(NativeByteBuffer *stream, int32_t instanceN
|
|||
flags = stream->readInt32(&error);
|
||||
has_video = (flags & 1) != 0;
|
||||
photo_id = stream->readInt64(&error);
|
||||
photo_small = std::unique_ptr<FileLocation>(FileLocation::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
photo_big = std::unique_ptr<FileLocation>(FileLocation::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error));
|
||||
if ((flags & 2) != 0) {
|
||||
stripped_thumb = std::unique_ptr<ByteArray>(stream->readByteArray(&error));
|
||||
}
|
||||
dc_id = stream->readInt32(&error);
|
||||
}
|
||||
|
||||
|
@ -1202,11 +1285,61 @@ void TL_userProfilePhoto::serializeToStream(NativeByteBuffer *stream) {
|
|||
flags = has_video ? (flags | 1) : (flags &~ 1);
|
||||
stream->writeInt32(flags);
|
||||
stream->writeInt64(photo_id);
|
||||
photo_small->serializeToStream(stream);
|
||||
photo_big->serializeToStream(stream);
|
||||
if ((flags & 2) != 0) {
|
||||
stream->writeByteArray(stripped_thumb.get());
|
||||
}
|
||||
stream->writeInt32(dc_id);
|
||||
}
|
||||
|
||||
void TL_updatesTooLong::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
}
|
||||
|
||||
Reaction *Reaction::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
Reaction *result = nullptr;
|
||||
switch (constructor) {
|
||||
case 0x79f5d419:
|
||||
result = new TL_reactionEmpty();
|
||||
break;
|
||||
case 0x8935fc73:
|
||||
result = new TL_reactionCustomEmoji();
|
||||
break;
|
||||
case 0x1b2286b8:
|
||||
result = new TL_reactionEmoji();
|
||||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in Reaction", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
void TL_reactionEmpty::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
|
||||
}
|
||||
|
||||
void TL_reactionEmpty::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
}
|
||||
|
||||
void TL_reactionCustomEmoji::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
document_id = stream->readInt64(&error);
|
||||
}
|
||||
|
||||
void TL_reactionCustomEmoji::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeInt64(document_id);
|
||||
}
|
||||
|
||||
void TL_reactionEmoji::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error) {
|
||||
emoticon = stream->readString(&error);
|
||||
}
|
||||
|
||||
void TL_reactionEmoji::serializeToStream(NativeByteBuffer *stream) {
|
||||
stream->writeInt32(constructor);
|
||||
stream->writeString(emoticon);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
bool tcpo_only;
|
||||
bool cdn;
|
||||
bool isStatic;
|
||||
bool thisPortOnly;
|
||||
bool force_try_ipv6;
|
||||
int32_t id;
|
||||
std::string ip_address;
|
||||
int32_t port;
|
||||
|
@ -94,10 +96,17 @@ public:
|
|||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
class Reaction : public TLObject {
|
||||
|
||||
public:
|
||||
static Reaction *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
};
|
||||
|
||||
|
||||
class TL_config : public TLObject {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x330b4067;
|
||||
static const uint32_t constructor = 0xcc1a241e;
|
||||
|
||||
int32_t flags;
|
||||
int32_t date;
|
||||
|
@ -117,17 +126,17 @@ public:
|
|||
int32_t notify_default_delay_ms;
|
||||
int32_t push_chat_period_ms;
|
||||
int32_t push_chat_limit;
|
||||
int32_t saved_gifs_limit;
|
||||
// int32_t saved_gifs_limit;
|
||||
int32_t edit_time_limit;
|
||||
int32_t revoke_time_limit;
|
||||
int32_t revoke_pm_time_limit;
|
||||
int32_t rating_e_decay;
|
||||
int32_t stickers_recent_limit;
|
||||
int32_t stickers_faved_limit;
|
||||
// int32_t stickers_faved_limit;
|
||||
int32_t channels_read_media_period;
|
||||
int32_t tmp_sessions;
|
||||
int32_t pinned_dialogs_count_max;
|
||||
int32_t pinned_infolder_count_max;
|
||||
// int32_t pinned_dialogs_count_max;
|
||||
// int32_t pinned_infolder_count_max;
|
||||
int32_t call_receive_timeout_ms;
|
||||
int32_t call_ring_timeout_ms;
|
||||
int32_t call_connect_timeout_ms;
|
||||
|
@ -144,6 +153,8 @@ public:
|
|||
std::string suggested_lang_code;
|
||||
int32_t lang_pack_version;
|
||||
int32_t base_lang_pack_version;
|
||||
std::unique_ptr<Reaction> reactions_default;
|
||||
std::string autologin_token;
|
||||
|
||||
static TL_config *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
|
@ -255,8 +266,7 @@ public:
|
|||
int32_t flags;
|
||||
bool has_video;
|
||||
int64_t photo_id;
|
||||
std::unique_ptr<FileLocation> photo_small;
|
||||
std::unique_ptr<FileLocation> photo_big;
|
||||
std::unique_ptr<ByteArray> stripped_thumb;
|
||||
int32_t dc_id;
|
||||
|
||||
static UserProfilePhoto *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
|
@ -273,7 +283,7 @@ public:
|
|||
class TL_userProfilePhoto : public UserProfilePhoto {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x69d3ab26;
|
||||
static const uint32_t constructor = 0x82d1f706;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -293,10 +303,24 @@ public:
|
|||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
class TL_username : public TLObject {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0xb4073647;
|
||||
int32_t flags;
|
||||
bool editable;
|
||||
bool active;
|
||||
std::string username;
|
||||
|
||||
static TL_username *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
class User : public TLObject {
|
||||
|
||||
public:
|
||||
int32_t id;
|
||||
int64_t id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::string username;
|
||||
|
@ -305,10 +329,12 @@ public:
|
|||
std::unique_ptr<UserProfilePhoto> photo;
|
||||
std::unique_ptr<UserStatus> status;
|
||||
int32_t flags;
|
||||
int32_t flags2;
|
||||
int32_t bot_info_version;
|
||||
std::vector<std::unique_ptr<TL_restrictionReason>> restriction_reason;
|
||||
std::string bot_inline_placeholder;
|
||||
std::string lang_code;
|
||||
std::vector<std::unique_ptr<TL_username>> usernames;
|
||||
|
||||
static User *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
};
|
||||
|
@ -316,7 +342,7 @@ public:
|
|||
class TL_userEmpty : public User {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x200250ba;
|
||||
static const uint32_t constructor = 0xd3bc4b7a;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -325,7 +351,7 @@ public:
|
|||
class TL_user : public User {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x938458c1;
|
||||
static const uint32_t constructor = 0x8f97c628;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -334,9 +360,9 @@ public:
|
|||
class InputPeer : public TLObject {
|
||||
|
||||
public:
|
||||
int32_t user_id;
|
||||
int32_t chat_id;
|
||||
int32_t channel_id;
|
||||
int64_t user_id;
|
||||
int64_t chat_id;
|
||||
int64_t channel_id;
|
||||
int64_t access_hash;
|
||||
|
||||
static InputPeer *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
|
@ -353,7 +379,7 @@ public:
|
|||
class TL_inputPeerUser : public InputPeer {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x7b8e7de6;
|
||||
static const uint32_t constructor = 0xdde8a54c;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -362,7 +388,7 @@ public:
|
|||
class TL_inputPeerChat : public InputPeer {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x179be863;
|
||||
static const uint32_t constructor = 0x35a95cb9;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -371,7 +397,7 @@ public:
|
|||
class TL_inputPeerUserFromMessage : public InputPeer {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x17bae2e6;
|
||||
static const uint32_t constructor = 0xa87b0a1c;
|
||||
|
||||
std::unique_ptr<InputPeer> peer;
|
||||
int32_t msg_id;
|
||||
|
@ -383,7 +409,7 @@ public:
|
|||
class TL_inputPeerChannelFromMessage : public InputPeer {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x9c95f7bb;
|
||||
static const uint32_t constructor = 0xbd2a0840;
|
||||
|
||||
std::unique_ptr<InputPeer> peer;
|
||||
int32_t msg_id;
|
||||
|
@ -395,7 +421,7 @@ public:
|
|||
class TL_inputPeerChannel : public InputPeer {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x20adaef8;
|
||||
static const uint32_t constructor = 0x27bcbbfc;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -412,7 +438,7 @@ public:
|
|||
class InputUser : public TLObject {
|
||||
|
||||
public:
|
||||
int32_t user_id;
|
||||
int64_t user_id;
|
||||
int64_t access_hash;
|
||||
|
||||
static InputUser *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
|
@ -429,7 +455,7 @@ public:
|
|||
class TL_inputUser : public InputUser {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0xd8292816;
|
||||
static const uint32_t constructor = 0xf21158c6;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -446,7 +472,7 @@ public:
|
|||
class TL_inputUserFromMessage : public InputUser {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x2d117597;
|
||||
static const uint32_t constructor = 0x1da448e2;
|
||||
|
||||
std::unique_ptr<InputPeer> peer;
|
||||
int32_t msg_id;
|
||||
|
@ -540,9 +566,9 @@ public:
|
|||
class TL_messageEntityMentionName : public MessageEntity {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x352dca58;
|
||||
static const uint32_t constructor = 0xdc7b1140;
|
||||
|
||||
int32_t user_id;
|
||||
int64_t user_id;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
|
@ -681,10 +707,12 @@ public:
|
|||
class TL_auth_authorization : public auth_Authorization {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0xcd050916;
|
||||
static const uint32_t constructor = 0x2ea2c0d4;
|
||||
|
||||
int32_t flags;
|
||||
int32_t tmp_sessions;
|
||||
int32_t otherwise_relogin_days;
|
||||
std::unique_ptr<ByteArray> future_auth_token;
|
||||
std::unique_ptr<User> user;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
|
@ -694,9 +722,9 @@ public:
|
|||
class TL_auth_exportedAuthorization : public TLObject {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0xdf969c2d;
|
||||
static const uint32_t constructor = 0xb434e2b8;
|
||||
|
||||
int32_t id;
|
||||
int64_t id;
|
||||
std::unique_ptr<ByteArray> bytes;
|
||||
|
||||
static TL_auth_exportedAuthorization *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error);
|
||||
|
@ -718,9 +746,9 @@ public:
|
|||
class TL_auth_importAuthorization : public TLObject {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0xe3ef9613;
|
||||
static const uint32_t constructor = 0xa57a7dad;
|
||||
|
||||
int32_t id;
|
||||
int64_t id;
|
||||
std::unique_ptr<ByteArray> bytes;
|
||||
|
||||
bool isNeedLayer();
|
||||
|
@ -736,4 +764,37 @@ public:
|
|||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
|
||||
class TL_reactionCustomEmoji : public Reaction {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x8935fc73;
|
||||
int64_t document_id;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
|
||||
class TL_reactionEmoji : public Reaction {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x1b2286b8;
|
||||
std::string emoticon;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TL_reactionEmpty : public Reaction {
|
||||
|
||||
public:
|
||||
static const uint32_t constructor = 0x79f5d419;
|
||||
|
||||
void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error);
|
||||
void serializeToStream(NativeByteBuffer *stream);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -127,7 +127,7 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) {
|
|||
currentDatacenter->storeCurrentAddressAndPortNum();
|
||||
isTryingNextPort = false;
|
||||
if (connectionType == ConnectionTypeProxy) {
|
||||
setTimeout(5);
|
||||
setTimeout(25);
|
||||
} else if (connectionType == ConnectionTypePush) {
|
||||
setTimeout(60 * 15);
|
||||
} else if (connectionType == ConnectionTypeUpload) {
|
||||
|
@ -286,14 +286,35 @@ void Connection::connect() {
|
|||
ConnectionsManager::getInstance(currentDatacenter->instanceNum).onConnectionClosed(this, 0);
|
||||
return;
|
||||
}
|
||||
if (connectionState == TcpConnectionStageConnected || connectionState == TcpConnectionStageConnecting) {
|
||||
if (connectionState == TcpConnectionStageConnected ||
|
||||
connectionState == TcpConnectionStageConnecting) {
|
||||
return;
|
||||
}
|
||||
connectionInProcess = true;
|
||||
connectionState = TcpConnectionStageConnecting;
|
||||
isMediaConnection = false;
|
||||
uint32_t ipv6 = ConnectionsManager::getInstance(currentDatacenter->instanceNum).isIpv6Enabled() ? TcpAddressFlagIpv6 : 0;
|
||||
uint32_t isStatic = connectionType == ConnectionTypeProxy || !ConnectionsManager::getInstance(currentDatacenter->instanceNum).proxyAddress.empty() ? TcpAddressFlagStatic : 0;
|
||||
uint8_t strategy = ConnectionsManager::getInstance(
|
||||
currentDatacenter->instanceNum).getIpStratagy();
|
||||
uint32_t ipv6;
|
||||
if (strategy == USE_IPV6_ONLY) {
|
||||
ipv6 = TcpAddressFlagIpv6;
|
||||
} else if (strategy == USE_IPV4_IPV6_RANDOM) {
|
||||
if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).lastProtocolUsefullData) {
|
||||
ipv6 = ConnectionsManager::getInstance(currentDatacenter->instanceNum).lastProtocolIsIpv6 ? TcpAddressFlagIpv6 : 0;
|
||||
} else {
|
||||
uint8_t value;
|
||||
RAND_bytes(&value, 1);
|
||||
ipv6 = value % 3 == 0 ? TcpAddressFlagIpv6 : 0;
|
||||
ConnectionsManager::getInstance(currentDatacenter->instanceNum).lastProtocolIsIpv6 = ipv6 != 0;
|
||||
}
|
||||
if (connectionType == ConnectionTypeGeneric) {
|
||||
ConnectionsManager::getInstance(currentDatacenter->instanceNum).lastProtocolUsefullData = false;
|
||||
}
|
||||
} else {
|
||||
ipv6 = 0;
|
||||
}
|
||||
uint32_t isStatic = connectionType == ConnectionTypeProxy || !ConnectionsManager::getInstance(
|
||||
currentDatacenter->instanceNum).proxyAddress.empty() ? TcpAddressFlagStatic : 0;
|
||||
TcpAddress *tcpAddress = nullptr;
|
||||
if (isMediaConnectionType(connectionType)) {
|
||||
currentAddressFlags = TcpAddressFlagDownload | isStatic;
|
||||
|
@ -352,7 +373,7 @@ void Connection::connect() {
|
|||
hasSomeDataSinceLastConnect = false;
|
||||
openConnection(hostAddress, hostPort, secret, ipv6 != 0, ConnectionsManager::getInstance(currentDatacenter->instanceNum).currentNetworkType);
|
||||
if (connectionType == ConnectionTypeProxy) {
|
||||
setTimeout(5);
|
||||
setTimeout(25);
|
||||
} else if (connectionType == ConnectionTypePush) {
|
||||
if (isTryingNextPort) {
|
||||
setTimeout(20);
|
||||
|
@ -678,6 +699,10 @@ void Connection::onDisconnectedInternal(int32_t reason, int32_t error) {
|
|||
isTryingNextPort = true;
|
||||
if (failedConnectionCount > willRetryConnectCount || switchToNextPort) {
|
||||
currentDatacenter->nextAddressOrPort(currentAddressFlags);
|
||||
if (currentDatacenter->isRepeatCheckingAddresses() && (ConnectionsManager::getInstance(currentDatacenter->instanceNum).getIpStratagy() == USE_IPV4_ONLY || ConnectionsManager::getInstance(currentDatacenter->instanceNum).getIpStratagy() == USE_IPV6_ONLY)) {
|
||||
if (LOGS_ENABLED) DEBUG_D("started retrying connection, set ipv4 ipv6 random strategy");
|
||||
ConnectionsManager::getInstance(currentDatacenter->instanceNum).setIpStrategy(USE_IPV4_IPV6_RANDOM);
|
||||
}
|
||||
failedConnectionCount = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright Nikolai Kudashov, 2015-2018.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <cerrno>
|
||||
|
@ -364,15 +365,20 @@ void ConnectionSocket::openConnection(std::string address, uint16_t port, std::s
|
|||
std::string *proxyAddress = &overrideProxyAddress;
|
||||
std::string *proxySecret = &overrideProxySecret;
|
||||
uint16_t proxyPort = overrideProxyPort;
|
||||
bool isProxyIpv6 = false;
|
||||
if (proxyAddress->empty()) {
|
||||
proxyAddress = &ConnectionsManager::getInstance(instanceNum).proxyAddress;
|
||||
proxyPort = ConnectionsManager::getInstance(instanceNum).proxyPort;
|
||||
proxySecret = &ConnectionsManager::getInstance(instanceNum).proxySecret;
|
||||
|
||||
// NekoX: Check whether proxyAddress is an ipv6 addr
|
||||
struct sockaddr_in6 addr;
|
||||
isProxyIpv6 = inet_pton(AF_INET6, proxyAddress->c_str(), &(addr.sin6_addr)) != 0;
|
||||
}
|
||||
|
||||
if (!proxyAddress->empty()) {
|
||||
if (LOGS_ENABLED) DEBUG_D("connection(%p) connecting via proxy %s:%d secret[%d]", this, proxyAddress->c_str(), proxyPort, (int) proxySecret->size());
|
||||
if ((socketFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
if (LOGS_ENABLED) DEBUG_D("connection(%p) connecting via proxy %s:%d secret[%d] ipv6:%d", this, proxyAddress->c_str(), proxyPort, (int) proxySecret->size(), isProxyIpv6);
|
||||
if ((socketFd = socket(isProxyIpv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) can't create proxy socket", this);
|
||||
closeSocket(1, -1);
|
||||
return;
|
||||
|
@ -400,6 +406,8 @@ void ConnectionSocket::openConnection(std::string address, uint16_t port, std::s
|
|||
}
|
||||
socketAddress.sin_family = AF_INET;
|
||||
socketAddress.sin_port = htons(proxyPort);
|
||||
socketAddress6.sin6_family = AF_INET6;
|
||||
socketAddress6.sin6_port = htons(proxyPort);
|
||||
bool continueCheckAddress;
|
||||
if (inet_pton(AF_INET, proxyAddress->c_str(), &socketAddress.sin_addr.s_addr) != 1) {
|
||||
continueCheckAddress = true;
|
||||
|
@ -494,6 +502,15 @@ void ConnectionSocket::openConnectionInternal(bool ipv6) {
|
|||
if (setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(int))) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) set TCP_NODELAY failed", this);
|
||||
}
|
||||
#ifdef DEBUG_VERSION
|
||||
int size = 4 * 1024 * 1024;
|
||||
if (setsockopt(socketFd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int))) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) set SO_SNDBUF failed", this);
|
||||
}
|
||||
if (setsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int))) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) set SO_RCVBUF failed", this);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fcntl(socketFd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) set O_NONBLOCK failed", this);
|
||||
|
@ -501,6 +518,8 @@ void ConnectionSocket::openConnectionInternal(bool ipv6) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(LOGS_ENABLED) DEBUG_D("connection(%p) socketAddress6, port: %d, family:%d", this, socketAddress6.sin6_port, socketAddress6.sin6_family);
|
||||
|
||||
if (connect(socketFd, (ipv6 ? (sockaddr *) &socketAddress6 : (sockaddr *) &socketAddress), (socklen_t) (ipv6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in))) == -1 && errno != EINPROGRESS) {
|
||||
closeSocket(1, -1);
|
||||
} else {
|
||||
|
@ -1018,12 +1037,26 @@ void ConnectionSocket::onHostNameResolved(std::string host, std::string ip, bool
|
|||
ConnectionsManager::getInstance(instanceNum).scheduleTask([&, host, ip, ipv6] {
|
||||
if (waitingForHostResolve == host) {
|
||||
waitingForHostResolve = "";
|
||||
if (ip.empty() || inet_pton(AF_INET, ip.c_str(), &socketAddress.sin_addr.s_addr) != 1) {
|
||||
if (ip.empty() || (inet_pton(AF_INET, ip.c_str(), &socketAddress.sin_addr.s_addr) != 1 && inet_pton(AF_INET6, ip.c_str(), &socketAddress6.sin6_addr.s6_addr) != 1)) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) can't resolve host %s address via delegate", this, host.c_str());
|
||||
closeSocket(1, -1);
|
||||
return;
|
||||
}
|
||||
if (LOGS_ENABLED) DEBUG_D("connection(%p) resolved host %s address %s via delegate", this, host.c_str(), ip.c_str());
|
||||
if (LOGS_ENABLED) DEBUG_D("connection(%p) resolved host %s address %s via delegate ipv6:%d", this, host.c_str(), ip.c_str(), ipv6);
|
||||
// NekoX: ipv6 Proxy with domain resolved, fix socket
|
||||
// Since default socket type is IPv4 (isProxyIPv6 == false)
|
||||
if (!ConnectionsManager::getInstance(instanceNum).proxyAddress.empty() && ipv6) {
|
||||
if (LOGS_ENABLED) DEBUG_D("connection(%p) recreate proxy socket when use resolved ipv6 address, host:%s, ip:%s, port:%d isIPv6: %d", this, host.c_str(), ip.c_str(), ConnectionsManager::getInstance(instanceNum).proxyPort, ipv6);
|
||||
// recreate socket
|
||||
close(socketFd);
|
||||
if ((socketFd = socket(AF_INET6 , SOCK_STREAM, 0)) < 0) {
|
||||
if (LOGS_ENABLED) DEBUG_E("connection(%p) can't recreate proxy socket when use resolved ipv6 address", this);
|
||||
closeSocket(1, -1);
|
||||
return;
|
||||
}
|
||||
socketAddress6.sin6_port = htons(ConnectionsManager::getInstance(instanceNum).proxyPort);
|
||||
socketAddress6.sin6_family = AF_INET6;
|
||||
}
|
||||
openConnectionInternal(ipv6);
|
||||
}
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,7 @@
|
|||
#include <sys/epoll.h>
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <unordered_set>
|
||||
#include "Defines.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
|
@ -57,13 +58,13 @@ public:
|
|||
void applyDatacenterAddress(uint32_t datacenterId, std::string ipAddress, uint32_t port);
|
||||
void setDelegate(ConnectiosManagerDelegate *connectiosManagerDelegate);
|
||||
ConnectionState getConnectionState();
|
||||
void setUserId(int32_t userId);
|
||||
void switchBackend();
|
||||
void setUserId(int64_t userId);
|
||||
void switchBackend(bool restart);
|
||||
void resumeNetwork(bool partial);
|
||||
void pauseNetwork();
|
||||
void setNetworkAvailable(bool value, int32_t type, bool slow);
|
||||
void setUseIpv6(bool value);
|
||||
void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, std::string regId, std::string cFingerprint, std::string installerId, int32_t timezoneOffset, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType);
|
||||
void setIpStrategy(uint8_t value);
|
||||
void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, std::string regId, std::string cFingerprint, std::string installerId, std::string packageId, int32_t timezoneOffset, int64_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType, int32_t performanceClass);
|
||||
void setProxySettings(std::string address, uint16_t port, std::string username, std::string password, std::string secret);
|
||||
void setLangCode(std::string langCode);
|
||||
void setRegId(std::string regId);
|
||||
|
@ -71,10 +72,8 @@ public:
|
|||
void updateDcSettings(uint32_t datacenterId, bool workaround);
|
||||
void setPushConnectionEnabled(bool value);
|
||||
void applyDnsConfig(NativeByteBuffer *buffer, std::string phone, int32_t date);
|
||||
void setMtProtoVersion(int version);
|
||||
void moveToDatacenter(uint32_t datacenterId);
|
||||
|
||||
int32_t getMtProtoVersion();
|
||||
int64_t checkProxy(std::string address, uint16_t port, std::string username, std::string password, std::string secret, onRequestTimeFunc requestTimeFunc, jobject ptr1);
|
||||
|
||||
#ifdef ANDROID
|
||||
|
@ -84,6 +83,7 @@ public:
|
|||
|
||||
private:
|
||||
static void *ThreadProc(void *data);
|
||||
static std::vector<ConnectionsManager*> _instances;
|
||||
|
||||
void initDatacenters();
|
||||
void loadConfig();
|
||||
|
@ -124,7 +124,7 @@ private:
|
|||
void onDatacenterHandshakeComplete(Datacenter *datacenter, HandshakeType type, int32_t timeDiff);
|
||||
void onDatacenterExportAuthorizationComplete(Datacenter *datacenter);
|
||||
int64_t generateMessageId();
|
||||
bool isIpv6Enabled();
|
||||
uint8_t getIpStratagy();
|
||||
bool isNetworkAvailable();
|
||||
|
||||
void scheduleCheckProxyInternal(ProxyCheckInfo *proxyCheckInfo);
|
||||
|
@ -193,7 +193,9 @@ private:
|
|||
int64_t lastOutgoingMessageId = 0;
|
||||
bool networkAvailable = true;
|
||||
bool networkSlow = false;
|
||||
bool ipv6Enabled = false;
|
||||
uint8_t ipStrategy = USE_IPV4_ONLY;
|
||||
bool lastProtocolIsIpv6 = false;
|
||||
bool lastProtocolUsefullData = false;
|
||||
std::vector<ConnectionSocket *> activeConnections;
|
||||
std::vector<ConnectionSocket *> activeConnectionsCopy;
|
||||
int epolFd;
|
||||
|
@ -204,7 +206,9 @@ private:
|
|||
requestsList requestsQueue;
|
||||
requestsList runningRequests;
|
||||
std::vector<uint32_t> requestingSaltsForDc;
|
||||
std::unordered_set<int32_t> tokensToBeCancelled;
|
||||
int32_t lastPingId = 0;
|
||||
int64_t lastInvokeAfterMessageId = 0;
|
||||
|
||||
int32_t currentNetworkType = NETWORK_TYPE_WIFI;
|
||||
uint32_t currentVersion = 1;
|
||||
|
@ -217,14 +221,15 @@ private:
|
|||
std::string currentRegId;
|
||||
std::string certFingerprint;
|
||||
std::string installer;
|
||||
std::string package;
|
||||
int32_t currentDeviceTimezone = 0;
|
||||
std::string currentSystemLangCode;
|
||||
std::string currentConfigPath;
|
||||
std::string currentLogPath;
|
||||
int32_t currentUserId = 0;
|
||||
int64_t currentUserId = 0;
|
||||
bool registeredForInternalPush = false;
|
||||
bool pushConnectionEnabled = true;
|
||||
int32_t mtProtoVersion = 2;
|
||||
int32_t currentPerformanceClass = -1;
|
||||
|
||||
std::map<uint32_t, std::vector<std::unique_ptr<NetworkMessage>>> genericMessagesToDatacenters;
|
||||
std::map<uint32_t, std::vector<std::unique_ptr<NetworkMessage>>> genericMediaMessagesToDatacenters;
|
||||
|
@ -247,12 +252,12 @@ private:
|
|||
friend class Config;
|
||||
friend class FileLog;
|
||||
friend class Handshake;
|
||||
|
||||
};
|
||||
|
||||
#ifdef ANDROID
|
||||
extern JavaVM *javaVm;
|
||||
extern JNIEnv *jniEnv[MAX_ACCOUNT_COUNT];
|
||||
//extern JNIEnv *jniEnv[MAX_ACCOUNT_COUNT];
|
||||
extern std::vector<JNIEnv*> jniEnv;
|
||||
extern jclass jclass_ByteBuffer;
|
||||
extern jmethodID jclass_ByteBuffer_allocateDirect;
|
||||
#endif
|
||||
|
|
|
@ -32,27 +32,27 @@ thread_local static SHA256_CTX sha256Ctx;
|
|||
Datacenter::Datacenter(int32_t instance, uint32_t id) {
|
||||
instanceNum = instance;
|
||||
datacenterId = id;
|
||||
for (uint32_t a = 0; a < UPLOAD_CONNECTIONS_COUNT; a++) {
|
||||
uploadConnection[a] = nullptr;
|
||||
for (auto & a : uploadConnection) {
|
||||
a = nullptr;
|
||||
}
|
||||
for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) {
|
||||
downloadConnection[a] = nullptr;
|
||||
for (auto & a : downloadConnection) {
|
||||
a = nullptr;
|
||||
}
|
||||
for (uint32_t a = 0; a < PROXY_CONNECTIONS_COUNT; a++) {
|
||||
proxyConnection[a] = nullptr;
|
||||
for (auto & a : proxyConnection) {
|
||||
a = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Datacenter::Datacenter(int32_t instance, NativeByteBuffer *data) {
|
||||
instanceNum = instance;
|
||||
for (uint32_t a = 0; a < UPLOAD_CONNECTIONS_COUNT; a++) {
|
||||
uploadConnection[a] = nullptr;
|
||||
for (auto & a : uploadConnection) {
|
||||
a = nullptr;
|
||||
}
|
||||
for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) {
|
||||
downloadConnection[a] = nullptr;
|
||||
for (auto & a : downloadConnection) {
|
||||
a = nullptr;
|
||||
}
|
||||
for (uint32_t a = 0; a < PROXY_CONNECTIONS_COUNT; a++) {
|
||||
proxyConnection[a] = nullptr;
|
||||
for (auto & a : proxyConnection) {
|
||||
a = nullptr;
|
||||
}
|
||||
uint32_t currentVersion = data->readUint32(nullptr);
|
||||
if (currentVersion >= 2 && currentVersion <= configVersion) {
|
||||
|
@ -146,7 +146,7 @@ Datacenter::Datacenter(int32_t instance, NativeByteBuffer *data) {
|
|||
authorized = data->readInt32(nullptr) != 0;
|
||||
len = data->readUint32(nullptr);
|
||||
for (uint32_t a = 0; a < len; a++) {
|
||||
TL_future_salt *salt = new TL_future_salt();
|
||||
auto salt = new TL_future_salt();
|
||||
salt->valid_since = data->readInt32(nullptr);
|
||||
salt->valid_until = data->readInt32(nullptr);
|
||||
salt->salt = data->readInt64(nullptr);
|
||||
|
@ -155,7 +155,7 @@ Datacenter::Datacenter(int32_t instance, NativeByteBuffer *data) {
|
|||
if (currentVersion >= 13) {
|
||||
len = data->readUint32(nullptr);
|
||||
for (uint32_t a = 0; a < len; a++) {
|
||||
TL_future_salt *salt = new TL_future_salt();
|
||||
auto salt = new TL_future_salt();
|
||||
salt->valid_since = data->readInt32(nullptr);
|
||||
salt->valid_until = data->readInt32(nullptr);
|
||||
salt->salt = data->readInt64(nullptr);
|
||||
|
@ -223,9 +223,9 @@ TcpAddress *Datacenter::getCurrentAddress(uint32_t flags) {
|
|||
return nullptr;
|
||||
}
|
||||
if ((flags & TcpAddressFlagStatic) != 0) {
|
||||
for (std::vector<TcpAddress>::iterator iter = addresses->begin(); iter != addresses->end(); iter++) {
|
||||
if ((iter->flags & TcpAddressFlagStatic) != 0) {
|
||||
return &(*iter);
|
||||
for (auto & addresse : *addresses) {
|
||||
if ((addresse.flags & TcpAddressFlagStatic) != 0) {
|
||||
return &addresse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,8 +288,8 @@ int32_t Datacenter::getCurrentPort(uint32_t flags) {
|
|||
|
||||
if ((flags & TcpAddressFlagStatic) != 0) {
|
||||
uint32_t num = 0;
|
||||
for (std::vector<TcpAddress>::iterator iter = addresses->begin(); iter != addresses->end(); iter++) {
|
||||
if ((iter->flags & TcpAddressFlagStatic) != 0) {
|
||||
for (auto & addresse : *addresses) {
|
||||
if ((addresse.flags & TcpAddressFlagStatic) != 0) {
|
||||
currentAddressNum = num;
|
||||
break;
|
||||
}
|
||||
|
@ -362,8 +362,8 @@ void Datacenter::addAddressAndPort(std::string address, uint32_t port, uint32_t
|
|||
addresses = &addressesIpv4;
|
||||
}
|
||||
}
|
||||
for (std::vector<TcpAddress>::iterator iter = addresses->begin(); iter != addresses->end(); iter++) {
|
||||
if (iter->address == address && iter->port == port) {
|
||||
for (auto & addresse : *addresses) {
|
||||
if (addresse.address == address && addresse.port == port) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -414,6 +414,7 @@ void Datacenter::nextAddressOrPort(uint32_t flags) {
|
|||
if (currentAddressNum + 1 < addresses->size()) {
|
||||
currentAddressNum++;
|
||||
} else {
|
||||
repeatCheckingAddresses = true;
|
||||
currentAddressNum = 0;
|
||||
}
|
||||
currentPortNum = 0;
|
||||
|
@ -749,14 +750,14 @@ void Datacenter::suspendConnections(bool suspendPush) {
|
|||
if (tempConnection != nullptr) {
|
||||
tempConnection->suspendConnection();
|
||||
}
|
||||
for (uint32_t a = 0; a < UPLOAD_CONNECTIONS_COUNT; a++) {
|
||||
if (uploadConnection[a] != nullptr) {
|
||||
uploadConnection[a]->suspendConnection();
|
||||
for (auto & a : uploadConnection) {
|
||||
if (a != nullptr) {
|
||||
a->suspendConnection();
|
||||
}
|
||||
}
|
||||
for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) {
|
||||
if (downloadConnection[a] != nullptr) {
|
||||
downloadConnection[a]->suspendConnection();
|
||||
for (auto & a : downloadConnection) {
|
||||
if (a != nullptr) {
|
||||
a->suspendConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -771,19 +772,19 @@ void Datacenter::getSessions(std::vector<int64_t> &sessions) {
|
|||
if (tempConnection != nullptr) {
|
||||
sessions.push_back(tempConnection->getSessionId());
|
||||
}
|
||||
for (uint32_t a = 0; a < UPLOAD_CONNECTIONS_COUNT; a++) {
|
||||
if (uploadConnection[a] != nullptr) {
|
||||
sessions.push_back(uploadConnection[a]->getSessionId());
|
||||
for (auto & a : uploadConnection) {
|
||||
if (a != nullptr) {
|
||||
sessions.push_back(a->getSessionId());
|
||||
}
|
||||
}
|
||||
for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) {
|
||||
if (downloadConnection[a] != nullptr) {
|
||||
sessions.push_back(downloadConnection[a]->getSessionId());
|
||||
for (auto & a : downloadConnection) {
|
||||
if (a != nullptr) {
|
||||
sessions.push_back(a->getSessionId());
|
||||
}
|
||||
}
|
||||
for (uint32_t a = 0; a < PROXY_CONNECTIONS_COUNT; a++) {
|
||||
if (proxyConnection[a] != nullptr) {
|
||||
sessions.push_back(proxyConnection[a]->getSessionId());
|
||||
for (auto & a : proxyConnection) {
|
||||
if (a != nullptr) {
|
||||
sessions.push_back(a->getSessionId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -796,21 +797,21 @@ void Datacenter::recreateSessions(HandshakeType type) {
|
|||
if (tempConnection != nullptr) {
|
||||
tempConnection->recreateSession();
|
||||
}
|
||||
for (uint32_t a = 0; a < UPLOAD_CONNECTIONS_COUNT; a++) {
|
||||
if (uploadConnection[a] != nullptr) {
|
||||
uploadConnection[a]->recreateSession();
|
||||
for (auto & a : uploadConnection) {
|
||||
if (a != nullptr) {
|
||||
a->recreateSession();
|
||||
}
|
||||
}
|
||||
for (uint32_t a = 0; a < PROXY_CONNECTIONS_COUNT; a++) {
|
||||
if (proxyConnection[a] != nullptr) {
|
||||
proxyConnection[a]->recreateSession();
|
||||
for (auto & a : proxyConnection) {
|
||||
if (a != nullptr) {
|
||||
a->recreateSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == HandshakeTypeAll || type == HandshakeTypeMediaTemp || type == HandshakeTypePerm) {
|
||||
for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) {
|
||||
if (downloadConnection[a] != nullptr) {
|
||||
downloadConnection[a]->recreateSession();
|
||||
for (auto & a : downloadConnection) {
|
||||
if (a != nullptr) {
|
||||
a->recreateSession();
|
||||
}
|
||||
}
|
||||
if (genericMediaConnection != nullptr) {
|
||||
|
@ -883,8 +884,8 @@ bool Datacenter::isHandshaking(bool media) {
|
|||
if (media && (isCdnDatacenter || !PFS_ENABLED)) {
|
||||
media = false;
|
||||
}
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if (handshake->getType() == HandshakeTypePerm || (media && handshake->getType() == HandshakeTypeMediaTemp) || (!media && handshake->getType() != HandshakeTypeMediaTemp)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -896,8 +897,8 @@ bool Datacenter::isHandshaking(HandshakeType type) {
|
|||
if (handshakes.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if (handshake->getType() == type) {
|
||||
return true;
|
||||
}
|
||||
|
@ -907,28 +908,28 @@ bool Datacenter::isHandshaking(HandshakeType type) {
|
|||
|
||||
void Datacenter::beginHandshake(HandshakeType handshakeType, bool reconnect) {
|
||||
if (handshakeType == HandshakeTypeCurrent) {
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
handshake->beginHandshake(reconnect);
|
||||
}
|
||||
} else {
|
||||
if (authKeyPerm == nullptr) {
|
||||
if (!isHandshaking(HandshakeTypePerm)) {
|
||||
Handshake *handshake = new Handshake(this, HandshakeTypePerm, this);
|
||||
auto handshake = new Handshake(this, HandshakeTypePerm, this);
|
||||
handshakes.push_back(std::unique_ptr<Handshake>(handshake));
|
||||
handshake->beginHandshake(reconnect);
|
||||
}
|
||||
} else if (PFS_ENABLED) {
|
||||
if (handshakeType == HandshakeTypeAll || handshakeType == HandshakeTypeTemp) {
|
||||
if (!isHandshaking(HandshakeTypeTemp)) {
|
||||
Handshake *handshake = new Handshake(this, HandshakeTypeTemp, this);
|
||||
auto handshake = new Handshake(this, HandshakeTypeTemp, this);
|
||||
handshakes.push_back(std::unique_ptr<Handshake>(handshake));
|
||||
handshake->beginHandshake(reconnect);
|
||||
}
|
||||
}
|
||||
if ((handshakeType == HandshakeTypeAll || handshakeType == HandshakeTypeMediaTemp) && hasMediaAddress()) {
|
||||
if (!isHandshaking(HandshakeTypeMediaTemp)) {
|
||||
Handshake *handshake = new Handshake(this, HandshakeTypeMediaTemp, this);
|
||||
auto handshake = new Handshake(this, HandshakeTypeMediaTemp, this);
|
||||
handshakes.push_back(std::unique_ptr<Handshake>(handshake));
|
||||
handshake->beginHandshake(reconnect);
|
||||
}
|
||||
|
@ -942,9 +943,9 @@ void Datacenter::onHandshakeConnectionClosed(Connection *connection) {
|
|||
return;
|
||||
}
|
||||
bool media = connection->getConnectionType() == ConnectionTypeGenericMedia;
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
if (media && handshake->getType() == HandshakeTypeMediaTemp || !media && handshake->getType() != HandshakeTypeMediaTemp) {
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if ((media && handshake->getType() == HandshakeTypeMediaTemp) || (!media && handshake->getType() != HandshakeTypeMediaTemp)) {
|
||||
handshake->onHandshakeConnectionClosed();
|
||||
}
|
||||
}
|
||||
|
@ -955,9 +956,9 @@ void Datacenter::onHandshakeConnectionConnected(Connection *connection) {
|
|||
return;
|
||||
}
|
||||
bool media = connection->getConnectionType() == ConnectionTypeGenericMedia;
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
if (media && handshake->getType() == HandshakeTypeMediaTemp || !media && handshake->getType() != HandshakeTypeMediaTemp) {
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if ((media && handshake->getType() == HandshakeTypeMediaTemp) || (!media && handshake->getType() != HandshakeTypeMediaTemp)) {
|
||||
handshake->onHandshakeConnectionConnected();
|
||||
}
|
||||
}
|
||||
|
@ -986,9 +987,9 @@ void Datacenter::processHandshakeResponse(bool media, TLObject *message, int64_t
|
|||
if (handshakes.empty()) {
|
||||
return;
|
||||
}
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
if (media && handshake->getType() == HandshakeTypeMediaTemp || !media && handshake->getType() != HandshakeTypeMediaTemp) {
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if ((media && handshake->getType() == HandshakeTypeMediaTemp) || (!media && handshake->getType() != HandshakeTypeMediaTemp)) {
|
||||
handshake->processHandshakeResponse(message, messageId);
|
||||
}
|
||||
}
|
||||
|
@ -998,9 +999,9 @@ TLObject *Datacenter::getCurrentHandshakeRequest(bool media) {
|
|||
if (handshakes.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
if (media && handshake->getType() == HandshakeTypeMediaTemp || !media && handshake->getType() != HandshakeTypeMediaTemp) {
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if ((media && handshake->getType() == HandshakeTypeMediaTemp) || (!media && handshake->getType() != HandshakeTypeMediaTemp)) {
|
||||
return handshake->getCurrentHandshakeRequest();
|
||||
}
|
||||
}
|
||||
|
@ -1069,9 +1070,9 @@ ByteArray *Datacenter::getAuthKey(ConnectionType connectionType, bool perm, int6
|
|||
bool media = Connection::isMediaConnectionType(connectionType) && hasMediaAddress();
|
||||
ByteArray *authKeyPending = nullptr;
|
||||
int64_t authKeyPendingId = 0;
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
Handshake *handshake = iter->get();
|
||||
if (media && handshake->getType() == HandshakeTypeMediaTemp || !media && handshake->getType() == HandshakeTypeTemp) {
|
||||
for (auto & iter : handshakes) {
|
||||
Handshake *handshake = iter.get();
|
||||
if ((media && handshake->getType() == HandshakeTypeMediaTemp) || (!media && handshake->getType() == HandshakeTypeTemp)) {
|
||||
authKeyPending = handshake->getPendingAuthKey();
|
||||
authKeyPendingId = handshake->getPendingAuthKeyId();
|
||||
break;
|
||||
|
@ -1118,12 +1119,12 @@ NativeByteBuffer *Datacenter::createRequestsData(std::vector<std::unique_ptr<Net
|
|||
}
|
||||
if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) send message (session: 0x%" PRIx64 ", seqno: %d, messageid: 0x%" PRIx64 "): %s(%p)", connection, instanceNum, datacenterId, connection->getConnectionType(), (uint64_t) connection->getSessionId(), networkMessage->message->seqno, (uint64_t) networkMessage->message->msg_id, typeid(*messageBody).name(), messageBody);
|
||||
|
||||
int64_t messageTime = (int64_t) (networkMessage->message->msg_id / 4294967296.0 * 1000);
|
||||
auto messageTime = (int64_t) (networkMessage->message->msg_id / 4294967296.0 * 1000);
|
||||
int64_t currentTime = ConnectionsManager::getInstance(instanceNum).getCurrentTimeMillis() + (int64_t) ConnectionsManager::getInstance(instanceNum).getTimeDifference() * 1000;
|
||||
|
||||
if (!pfsInit && (messageTime < currentTime - 30000 || messageTime > currentTime + 25000)) {
|
||||
if (!pfsInit && (networkMessage->forceContainer || messageTime < currentTime - 30000 || messageTime > currentTime + 25000)) {
|
||||
if (LOGS_ENABLED) DEBUG_D("wrap message in container");
|
||||
TL_msg_container *messageContainer = new TL_msg_container();
|
||||
auto messageContainer = new TL_msg_container();
|
||||
messageContainer->messages.push_back(std::move(networkMessage->message));
|
||||
|
||||
messageId = ConnectionsManager::getInstance(instanceNum).generateMessageId();
|
||||
|
@ -1136,7 +1137,7 @@ NativeByteBuffer *Datacenter::createRequestsData(std::vector<std::unique_ptr<Net
|
|||
}
|
||||
} else {
|
||||
if (LOGS_ENABLED) DEBUG_D("start write messages to container");
|
||||
TL_msg_container *messageContainer = new TL_msg_container();
|
||||
auto messageContainer = new TL_msg_container();
|
||||
size_t count = requests.size();
|
||||
for (uint32_t a = 0; a < count; a++) {
|
||||
NetworkMessage *networkMessage = requests[a].get();
|
||||
|
@ -1158,7 +1159,7 @@ NativeByteBuffer *Datacenter::createRequestsData(std::vector<std::unique_ptr<Net
|
|||
if (pfsInit) {
|
||||
mtProtoVersion = 1;
|
||||
} else {
|
||||
mtProtoVersion = ConnectionsManager::getInstance(instanceNum).getMtProtoVersion();
|
||||
mtProtoVersion = 2;
|
||||
}
|
||||
uint32_t messageSize = messageBody->getObjectSize();
|
||||
uint32_t additionalSize = (32 + messageSize) % 16;
|
||||
|
@ -1235,43 +1236,29 @@ bool Datacenter::decryptServerResponse(int64_t keyId, uint8_t *key, uint8_t *dat
|
|||
if (authKey == nullptr) {
|
||||
return false;
|
||||
}
|
||||
bool error = false;
|
||||
if (authKeyId != keyId) {
|
||||
error = true;
|
||||
}
|
||||
bool error = authKeyId != keyId;
|
||||
thread_local static uint8_t messageKey[96];
|
||||
int mtProtoVersion = ConnectionsManager::getInstance(instanceNum).getMtProtoVersion();
|
||||
generateMessageKey(instanceNum, authKey->bytes, key, messageKey + 32, true, mtProtoVersion);
|
||||
generateMessageKey(instanceNum, authKey->bytes, key, messageKey + 32, true, 2);
|
||||
aesIgeEncryption(data, messageKey + 32, messageKey + 64, false, false, length);
|
||||
|
||||
uint32_t messageLength;
|
||||
memcpy(&messageLength, data + 28, sizeof(uint32_t));
|
||||
uint32_t paddingLength = (int32_t) length - (messageLength + 32);
|
||||
if (messageLength > length - 32) {
|
||||
error = true;
|
||||
} else if (paddingLength < 12 || paddingLength > 1024) {
|
||||
error = true;
|
||||
}
|
||||
messageLength += 32;
|
||||
if (messageLength > length) {
|
||||
messageLength = length;
|
||||
uint32_t paddingLength = length - (messageLength + 32);
|
||||
|
||||
error |= (messageLength > length - 32);
|
||||
error |= (paddingLength < 12);
|
||||
error |= (paddingLength > 1024);
|
||||
|
||||
SHA256_Init(&sha256Ctx);
|
||||
SHA256_Update(&sha256Ctx, authKey->bytes + 88 + 8, 32);
|
||||
SHA256_Update(&sha256Ctx, data, length);
|
||||
SHA256_Final(messageKey, &sha256Ctx);
|
||||
|
||||
for (uint32_t i = 0; i < 16; i++) {
|
||||
error |= (messageKey[i + 8] != key[i]);
|
||||
}
|
||||
|
||||
switch (mtProtoVersion) {
|
||||
case 2: {
|
||||
SHA256_Init(&sha256Ctx);
|
||||
SHA256_Update(&sha256Ctx, authKey->bytes + 88 + 8, 32);
|
||||
SHA256_Update(&sha256Ctx, data, length);
|
||||
SHA256_Final(messageKey, &sha256Ctx);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SHA1(data, messageLength, messageKey + 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return memcmp(messageKey + 8, key, 16) == 0 && !error;
|
||||
return !error;
|
||||
}
|
||||
|
||||
bool Datacenter::hasPermanentAuthKey() {
|
||||
|
@ -1414,7 +1401,7 @@ Connection *Datacenter::getConnectionByType(uint32_t connectionType, bool create
|
|||
|
||||
void Datacenter::onHandshakeComplete(Handshake *handshake, int64_t keyId, ByteArray *authKey, int32_t timeDifference) {
|
||||
HandshakeType type = handshake->getType();
|
||||
for (std::vector<std::unique_ptr<Handshake>>::iterator iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
for (auto iter = handshakes.begin(); iter != handshakes.end(); iter++) {
|
||||
if (iter->get() == handshake) {
|
||||
handshakes.erase(iter);
|
||||
if (type == HandshakeTypePerm) {
|
||||
|
@ -1445,17 +1432,17 @@ void Datacenter::exportAuthorization() {
|
|||
return;
|
||||
}
|
||||
exportingAuthorization = true;
|
||||
TL_auth_exportAuthorization *request = new TL_auth_exportAuthorization();
|
||||
auto request = new TL_auth_exportAuthorization();
|
||||
request->dc_id = datacenterId;
|
||||
if (LOGS_ENABLED) DEBUG_D("dc%u begin export authorization", datacenterId);
|
||||
ConnectionsManager::getInstance(instanceNum).sendRequest(request, [&](TLObject *response, TL_error *error, int32_t networkType) {
|
||||
ConnectionsManager::getInstance(instanceNum).sendRequest(request, [&](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) {
|
||||
if (error == nullptr) {
|
||||
TL_auth_exportedAuthorization *res = (TL_auth_exportedAuthorization *) response;
|
||||
TL_auth_importAuthorization *request2 = new TL_auth_importAuthorization();
|
||||
auto res = (TL_auth_exportedAuthorization *) response;
|
||||
auto request2 = new TL_auth_importAuthorization();
|
||||
request2->bytes = std::move(res->bytes);
|
||||
request2->id = res->id;
|
||||
if (LOGS_ENABLED) DEBUG_D("dc%u begin import authorization", datacenterId);
|
||||
ConnectionsManager::getInstance(instanceNum).sendRequest(request2, [&](TLObject *response2, TL_error *error2, int32_t networkType) {
|
||||
ConnectionsManager::getInstance(instanceNum).sendRequest(request2, [&](TLObject *response2, TL_error *error2, int32_t networkType, int64_t responseTime, int64_t msgId) {
|
||||
if (error2 == nullptr) {
|
||||
authorized = true;
|
||||
ConnectionsManager::getInstance(instanceNum).onDatacenterExportAuthorizationComplete(this);
|
||||
|
@ -1477,7 +1464,8 @@ bool Datacenter::isExportingAuthorization() {
|
|||
|
||||
bool Datacenter::hasMediaAddress() {
|
||||
std::vector<TcpAddress> *addresses;
|
||||
if (ConnectionsManager::getInstance(instanceNum).isIpv6Enabled()) {
|
||||
int strategy = ConnectionsManager::getInstance(instanceNum).getIpStratagy();
|
||||
if (strategy == USE_IPV6_ONLY) {
|
||||
addresses = &addressesIpv6Download;
|
||||
} else {
|
||||
addresses = &addressesIpv4Download;
|
||||
|
@ -1490,6 +1478,12 @@ void Datacenter::resetInitVersion() {
|
|||
lastInitMediaVersion = 0;
|
||||
}
|
||||
|
||||
bool Datacenter::isRepeatCheckingAddresses() {
|
||||
bool b = repeatCheckingAddresses;
|
||||
repeatCheckingAddresses = false;
|
||||
return b;
|
||||
}
|
||||
|
||||
TL_help_configSimple *Datacenter::decodeSimpleConfig(NativeByteBuffer *buffer) {
|
||||
TL_help_configSimple *result = nullptr;
|
||||
|
||||
|
@ -1510,7 +1504,7 @@ TL_help_configSimple *Datacenter::decodeSimpleConfig(NativeByteBuffer *buffer) {
|
|||
BIO *keyBio = BIO_new(BIO_s_mem());
|
||||
BIO_write(keyBio, public_key.c_str(), (int) public_key.length());
|
||||
|
||||
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL);
|
||||
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, nullptr, nullptr, nullptr);
|
||||
if (rsaKey == nullptr) {
|
||||
if (rsaKey == nullptr) {
|
||||
if (LOGS_ENABLED) DEBUG_E("Invalid rsa public key");
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
bool isExportingAuthorization();
|
||||
bool hasMediaAddress();
|
||||
void resetInitVersion();
|
||||
bool isRepeatCheckingAddresses();
|
||||
|
||||
Connection *getDownloadConnection(uint8_t num, bool create);
|
||||
Connection *getProxyConnection(uint8_t num, bool create, bool connect);
|
||||
|
@ -121,6 +122,7 @@ private:
|
|||
int64_t authKeyMediaTempId = 0;
|
||||
Config *config = nullptr;
|
||||
bool isCdnDatacenter = false;
|
||||
bool repeatCheckingAddresses = false;
|
||||
|
||||
std::vector<std::unique_ptr<Handshake>> handshakes;
|
||||
|
||||
|
|
|
@ -17,9 +17,8 @@
|
|||
#include "ByteArray.h"
|
||||
|
||||
#define USE_DEBUG_SESSION false
|
||||
#define READ_BUFFER_SIZE 1024 * 128
|
||||
#define READ_BUFFER_SIZE 1024 * 1024 * 2
|
||||
//#define DEBUG_VERSION
|
||||
#define USE_OLD_KEYS
|
||||
#define PFS_ENABLED 1
|
||||
#define DEFAULT_DATACENTER_ID INT_MAX
|
||||
#define DC_UPDATE_TIME 60 * 60
|
||||
|
@ -28,9 +27,13 @@
|
|||
#define DOWNLOAD_CONNECTIONS_COUNT 2
|
||||
#define UPLOAD_CONNECTIONS_COUNT 4
|
||||
#define CONNECTION_BACKGROUND_KEEP_TIME 10000
|
||||
#define MAX_ACCOUNT_COUNT 32
|
||||
//#define MAX_ACCOUNT_COUNT 16
|
||||
#define USE_DELEGATE_HOST_RESOLVE
|
||||
|
||||
#define USE_IPV4_ONLY 0
|
||||
#define USE_IPV6_ONLY 1
|
||||
#define USE_IPV4_IPV6_RANDOM 2
|
||||
|
||||
#define NETWORK_TYPE_MOBILE 0
|
||||
#define NETWORK_TYPE_WIFI 1
|
||||
#define NETWORK_TYPE_ROAMING 2
|
||||
|
@ -44,7 +47,7 @@ class NativeByteBuffer;
|
|||
class Handshake;
|
||||
class ConnectionSocket;
|
||||
|
||||
typedef std::function<void(TLObject *response, TL_error *error, int32_t networkType)> onCompleteFunc;
|
||||
typedef std::function<void(TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId)> onCompleteFunc;
|
||||
typedef std::function<void()> onQuickAckFunc;
|
||||
typedef std::function<void()> onWriteToSocketFunc;
|
||||
typedef std::function<void(int64_t messageId)> fillParamsFunc;
|
||||
|
@ -56,6 +59,7 @@ typedef struct NetworkMessage {
|
|||
std::unique_ptr<TL_message> message;
|
||||
bool invokeAfter = false;
|
||||
bool needQuickAck = false;
|
||||
bool forceContainer = false;
|
||||
int32_t requestId;
|
||||
} NetworkMessage;
|
||||
|
||||
|
@ -164,7 +168,9 @@ enum RequestFlag {
|
|||
RequestFlagForceDownload = 32,
|
||||
RequestFlagInvokeAfter = 64,
|
||||
RequestFlagNeedQuickAck = 128,
|
||||
RequestFlagUseUnboundKey = 256
|
||||
RequestFlagUseUnboundKey = 256,
|
||||
RequestFlagResendAfter = 512,
|
||||
RequestFlagIgnoreFloodWait = 1024
|
||||
};
|
||||
|
||||
inline std::string to_string_int32(int32_t value) {
|
||||
|
|
|
@ -22,6 +22,8 @@ bool LOGS_ENABLED = true;
|
|||
bool LOGS_ENABLED = false;
|
||||
#endif
|
||||
|
||||
bool REF_LOGS_ENABLED = false;
|
||||
|
||||
FileLog &FileLog::getInstance() {
|
||||
static FileLog instance;
|
||||
return instance;
|
||||
|
@ -39,6 +41,41 @@ void FileLog::init(std::string path) {
|
|||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void FileLog::fatal(const char *message, ...) {
|
||||
if (!LOGS_ENABLED) {
|
||||
return;
|
||||
}
|
||||
va_list argptr;
|
||||
va_start(argptr, message);
|
||||
time_t t = time(0);
|
||||
struct tm *now = localtime(&t);
|
||||
#ifdef ANDROID
|
||||
__android_log_vprint(ANDROID_LOG_FATAL, "tgnet", message, argptr);
|
||||
va_end(argptr);
|
||||
va_start(argptr, message);
|
||||
#else
|
||||
printf("%d-%d %02d:%02d:%02d FATAL ERROR: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
|
||||
vprintf(message, argptr);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
va_end(argptr);
|
||||
va_start(argptr, message);
|
||||
#endif
|
||||
FILE *logFile = getInstance().logFile;
|
||||
if (logFile) {
|
||||
fprintf(logFile, "%d-%d %02d:%02d:%02d FATAL ERROR: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
|
||||
vfprintf(logFile, message, argptr);
|
||||
fprintf(logFile, "\n");
|
||||
fflush(logFile);
|
||||
}
|
||||
|
||||
va_end(argptr);
|
||||
|
||||
#ifdef DEBUG_VERSION
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileLog::e(const char *message, ...) {
|
||||
if (!LOGS_ENABLED) {
|
||||
return;
|
||||
|
@ -131,3 +168,43 @@ void FileLog::d(const char *message, ...) {
|
|||
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
static int refsCount = 0;
|
||||
|
||||
void FileLog::ref(const char *message, ...) {
|
||||
if (!REF_LOGS_ENABLED) {
|
||||
return;
|
||||
}
|
||||
va_list argptr;
|
||||
va_start(argptr, message);
|
||||
time_t t = time(0);
|
||||
struct tm *now = localtime(&t);
|
||||
refsCount++;
|
||||
#ifdef ANDROID
|
||||
std::ostringstream s;
|
||||
s << refsCount << " refs (+ref): " << message;
|
||||
__android_log_vprint(ANDROID_LOG_VERBOSE, "tgnetREF", s.str().c_str(), argptr);
|
||||
va_end(argptr);
|
||||
va_start(argptr, message);
|
||||
#endif
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
void FileLog::delref(const char *message, ...) {
|
||||
if (!REF_LOGS_ENABLED) {
|
||||
return;
|
||||
}
|
||||
va_list argptr;
|
||||
va_start(argptr, message);
|
||||
time_t t = time(0);
|
||||
struct tm *now = localtime(&t);
|
||||
refsCount--;
|
||||
#ifdef ANDROID
|
||||
std::ostringstream s;
|
||||
s << refsCount << " refs (-ref): " << message;
|
||||
__android_log_vprint(ANDROID_LOG_VERBOSE, "tgnetREF", s.str().c_str(), argptr);
|
||||
va_end(argptr);
|
||||
va_start(argptr, message);
|
||||
#endif
|
||||
va_end(argptr);
|
||||
}
|
|
@ -15,9 +15,12 @@ class FileLog {
|
|||
public:
|
||||
FileLog();
|
||||
void init(std::string path);
|
||||
static void fatal(const char *message, ...) __attribute__((format (printf, 1, 2)));
|
||||
static void e(const char *message, ...) __attribute__((format (printf, 1, 2)));
|
||||
static void w(const char *message, ...) __attribute__((format (printf, 1, 2)));
|
||||
static void d(const char *message, ...) __attribute__((format (printf, 1, 2)));
|
||||
static void ref(const char *message, ...) __attribute__((format (printf, 1, 2)));
|
||||
static void delref(const char *message, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
static FileLog &getInstance();
|
||||
|
||||
|
@ -28,8 +31,12 @@ private:
|
|||
|
||||
extern bool LOGS_ENABLED;
|
||||
|
||||
#define DEBUG_FATAL FileLog::getInstance().fatal
|
||||
#define DEBUG_E FileLog::getInstance().e
|
||||
#define DEBUG_W FileLog::getInstance().w
|
||||
#define DEBUG_D FileLog::getInstance().d
|
||||
|
||||
#define DEBUG_REF FileLog::getInstance().ref
|
||||
#define DEBUG_DELREF FileLog::getInstance().delref
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/bn.h>
|
||||
|
@ -55,19 +56,11 @@ void Handshake::beginHandshake(bool reconnect) {
|
|||
connection->connect();
|
||||
}
|
||||
|
||||
#ifdef USE_OLD_KEYS
|
||||
TL_req_pq *request = new TL_req_pq();
|
||||
request->nonce = std::unique_ptr<ByteArray>(new ByteArray(16));
|
||||
auto request = new TL_req_pq_multi();
|
||||
request->nonce = std::make_unique<ByteArray>(16);
|
||||
RAND_bytes(request->nonce->bytes, 16);
|
||||
authNonce = new ByteArray(request->nonce.get());
|
||||
sendRequestData(request, true);
|
||||
#else
|
||||
TL_req_pq_multi *request = new TL_req_pq_multi();
|
||||
request->nonce = std::unique_ptr<ByteArray>(new ByteArray(16));
|
||||
RAND_bytes(request->nonce->bytes, 16);
|
||||
authNonce = new ByteArray(request->nonce.get());
|
||||
sendRequestData(request, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Handshake::cleanupHandshake() {
|
||||
|
@ -197,7 +190,7 @@ inline bool factorizeValue(uint64_t what, uint32_t &p, uint32_t &q) {
|
|||
}
|
||||
return true;
|
||||
} else {
|
||||
if (LOGS_ENABLED) DEBUG_E("factorization failed for %" PRIu64, what);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("factorization failed for %" PRIu64, what);
|
||||
p = 0;
|
||||
q = 0;
|
||||
return false;
|
||||
|
@ -207,7 +200,7 @@ inline bool factorizeValue(uint64_t what, uint32_t &p, uint32_t &q) {
|
|||
inline bool check_prime(BIGNUM *p) {
|
||||
int result = 0;
|
||||
if (!BN_primality_test(&result, p, 64, bnContext, 0, NULL)) {
|
||||
if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_primality_test");
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("OpenSSL error at BN_primality_test");
|
||||
return false;
|
||||
}
|
||||
return result != 0;
|
||||
|
@ -222,20 +215,20 @@ inline bool isGoodPrime(BIGNUM *p, uint32_t g) {
|
|||
BIGNUM *dh_g = BN_new();
|
||||
|
||||
if (!BN_set_word(dh_g, 4 * g)) {
|
||||
if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_set_word(dh_g, 4 * g)");
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("OpenSSL error at BN_set_word(dh_g, 4 * g)");
|
||||
BN_free(t);
|
||||
BN_free(dh_g);
|
||||
return false;
|
||||
}
|
||||
if (!BN_mod(t, p, dh_g, bnContext)) {
|
||||
if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_mod");
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("OpenSSL error at BN_mod");
|
||||
BN_free(t);
|
||||
BN_free(dh_g);
|
||||
return false;
|
||||
}
|
||||
uint64_t x = BN_get_word(t);
|
||||
if (x >= 4 * g) {
|
||||
if (LOGS_ENABLED) DEBUG_E("OpenSSL error at BN_get_word");
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("OpenSSL error at BN_get_word");
|
||||
BN_free(t);
|
||||
BN_free(dh_g);
|
||||
return false;
|
||||
|
@ -323,6 +316,11 @@ inline bool isGoodGaAndGb(BIGNUM *g_a, BIGNUM *p) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Handshake::cleanupServerKeys() {
|
||||
serverPublicKeys.clear();
|
||||
serverPublicKeysFingerprints.clear();
|
||||
}
|
||||
|
||||
void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
||||
if (handshakeState == 0) {
|
||||
return;
|
||||
|
@ -335,14 +333,14 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
}
|
||||
|
||||
handshakeState = 2;
|
||||
TL_resPQ *result = (TL_resPQ *) message;
|
||||
auto result = (TL_resPQ *) message;
|
||||
if (authNonce->isEqualTo(result->nonce.get())) {
|
||||
std::string key;
|
||||
std::string key = "";
|
||||
int64_t keyFingerprint = 0;
|
||||
|
||||
size_t count1 = result->server_public_key_fingerprints.size();
|
||||
if (currentDatacenter->isCdnDatacenter) {
|
||||
std::map<int32_t, uint64_t>::iterator iter = cdnPublicKeysFingerprints.find(currentDatacenter->datacenterId);
|
||||
auto iter = cdnPublicKeysFingerprints.find(currentDatacenter->datacenterId);
|
||||
if (iter != cdnPublicKeysFingerprints.end()) {
|
||||
for (uint32_t a = 0; a < count1; a++) {
|
||||
if ((uint64_t) result->server_public_key_fingerprints[a] == iter->second) {
|
||||
|
@ -353,95 +351,35 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
}
|
||||
} else {
|
||||
if (serverPublicKeys.empty()) {
|
||||
#ifdef USE_OLD_KEYS
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n"
|
||||
"lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\n"
|
||||
"an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw\n"
|
||||
"Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n"
|
||||
"8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n"
|
||||
"Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0xc3b42b026ce86b21LL);
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAxq7aeLAqJR20tkQQMfRn+ocfrtMlJsQ2Uksfs7Xcoo77jAid0bRt\n"
|
||||
"ksiVmT2HEIJUlRxfABoPBV8wY9zRTUMaMA654pUX41mhyVN+XoerGxFvrs9dF1Ru\n"
|
||||
"vCHbI02dM2ppPvyytvvMoefRoL5BTcpAihFgm5xCaakgsJ/tH5oVl74CdhQw8J5L\n"
|
||||
"xI/K++KJBUyZ26Uba1632cOiq05JBUW0Z2vWIOk4BLysk7+U9z+SxynKiZR3/xdi\n"
|
||||
"XvFKk01R3BHV+GUKM2RYazpS/P8v7eyKhAbKxOdRcFpHLlVwfjyM1VlDQrEZxsMp\n"
|
||||
"NTLYXb6Sce1Uov0YtNx5wEowlREH1WOTlwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0x9a996a1db11c729bLL);
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAsQZnSWVZNfClk29RcDTJQ76n8zZaiTGuUsi8sUhW8AS4PSbPKDm+\n"
|
||||
"DyJgdHDWdIF3HBzl7DHeFrILuqTs0vfS7Pa2NW8nUBwiaYQmPtwEa4n7bTmBVGsB\n"
|
||||
"1700/tz8wQWOLUlL2nMv+BPlDhxq4kmJCyJfgrIrHlX8sGPcPA4Y6Rwo0MSqYn3s\n"
|
||||
"g1Pu5gOKlaT9HKmE6wn5Sut6IiBjWozrRQ6n5h2RXNtO7O2qCDqjgB2vBxhV7B+z\n"
|
||||
"hRbLbCmW0tYMDsvPpX5M8fsO05svN+lKtCAuz1leFns8piZpptpSCFn7bWxiA9/f\n"
|
||||
"x5x17D7pfah3Sy2pA+NDXyzSlGcKdaUmwQIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0xb05b2a6f70cdea78LL);
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAwqjFW0pi4reKGbkc9pK83Eunwj/k0G8ZTioMMPbZmW99GivMibwa\n"
|
||||
"xDM9RDWabEMyUtGoQC2ZcDeLWRK3W8jMP6dnEKAlvLkDLfC4fXYHzFO5KHEqF06i\n"
|
||||
"qAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc\n"
|
||||
"/n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks\n"
|
||||
"WV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t\n"
|
||||
"UiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0x71e025b6c76033e3LL);
|
||||
#endif
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAruw2yP/BCcsJliRoW5eBVBVle9dtjJw+OYED160Wybum9SXtBBLX\n"
|
||||
"riwt4rROd9csv0t0OHCaTmRqBcQ0J8fxhN6/cpR1GWgOZRUAiQxoMnlt0R93LCX/\n"
|
||||
"j1dnVa/gVbCjdSxpbrfY2g2L4frzjJvdl84Kd9ORYjDEAyFnEA7dD556OptgLQQ2\n"
|
||||
"e2iVNq8NZLYTzLp5YpOdO1doK+ttrltggTCy5SrKeLoCPPbOgGsdxJxyz5KKcZnS\n"
|
||||
"Lj16yE5HvJQn0CNpRdENvRUXe6tBP78O39oJ8BTHp9oIjd6XWXAsp2CvK45Ol8wF\n"
|
||||
"XGF710w9lwCGNbmNxNYhtIkdqfsEcwR5JwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0xbc35f3509f7b7a5LL);
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAvfLHfYH2r9R70w8prHblWt/nDkh+XkgpflqQVcnAfSuTtO05lNPs\n"
|
||||
"pQmL8Y2XjVT4t8cT6xAkdgfmmvnvRPOOKPi0OfJXoRVylFzAQG/j83u5K3kRLbae\n"
|
||||
"7fLccVhKZhY46lvsueI1hQdLgNV9n1cQ3TDS2pQOCtovG4eDl9wacrXOJTG2990V\n"
|
||||
"jgnIKNA0UMoP+KF03qzryqIt3oTvZq03DyWdGK+AZjgBLaDKSnC6qD2cFY81UryR\n"
|
||||
"WOab8zKkWAnhw2kFpcqhI0jdV5QaSCExvnsjVaX0Y1N0870931/5Jb9ICe4nweZ9\n"
|
||||
"kSDF/gip3kWLG0o8XQpChDfyvsqB9OLV/wIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0x15ae5fa8b5529542LL);
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAs/ditzm+mPND6xkhzwFIz6J/968CtkcSE/7Z2qAJiXbmZ3UDJPGr\n"
|
||||
"zqTDHkO30R8VeRM/Kz2f4nR05GIFiITl4bEjvpy7xqRDspJcCFIOcyXm8abVDhF+\n"
|
||||
"th6knSU0yLtNKuQVP6voMrnt9MV1X92LGZQLgdHZbPQz0Z5qIpaKhdyA8DEvWWvS\n"
|
||||
"Uwwc+yi1/gGaybwlzZwqXYoPOhwMebzKUk0xW14htcJrRrq+PXXQbRzTMynseCoP\n"
|
||||
"Ioke0dtCodbA3qQxQovE16q9zz4Otv2k4j63cz53J+mhkVWAeWxVGI0lltJmWtEY\n"
|
||||
"K6er8VqqWot3nqmWMXogrgRLggv/NbbooQIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0xaeae98e13cd7f94fLL);
|
||||
|
||||
serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAvmpxVY7ld/8DAjz6F6q05shjg8/4p6047bn6/m8yPy1RBsvIyvuD\n"
|
||||
"uGnP/RzPEhzXQ9UJ5Ynmh2XJZgHoE9xbnfxL5BXHplJhMtADXKM9bWB11PU1Eioc\n"
|
||||
"3+AXBB8QiNFBn2XI5UkO5hPhbb9mJpjA9Uhw8EdfqJP8QetVsI/xrCEbwEXe0xvi\n"
|
||||
"fRLJbY08/Gp66KpQvy7g8w7VB8wlgePexW3pT13Ap6vuC+mQuJPyiHvSxjEKHgqe\n"
|
||||
"Pji9NP3tJUFQjcECqcm0yV7/2d0t/pbCm+ZH1sadZspQCEPPrtbkQBlvHb4OLiIW\n"
|
||||
"PGHKSMeRFvp3IWcmdJqXahxLCUS1Eh6MAQIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0x5a181b2235057d98LL);
|
||||
if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) {
|
||||
serverPublicKeys.emplace_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR\n"
|
||||
"yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv\n"
|
||||
"plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/\n"
|
||||
"j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1\n"
|
||||
"aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO\n"
|
||||
"j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0xb25898df208d2603);
|
||||
} else {
|
||||
serverPublicKeys.emplace_back("-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g\n"
|
||||
"5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO\n"
|
||||
"62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/\n"
|
||||
"+aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9\n"
|
||||
"t6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs\n"
|
||||
"5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----");
|
||||
serverPublicKeysFingerprints.push_back(0xd09d1d85de64fd85);
|
||||
}
|
||||
}
|
||||
|
||||
size_t count2 = serverPublicKeysFingerprints.size();
|
||||
for (uint32_t a = 0; a < count2; a++) {
|
||||
for (uint32_t b = 0; b < count1; b++) {
|
||||
if ((uint64_t) result->server_public_key_fingerprints[b] == serverPublicKeysFingerprints[a]) {
|
||||
keyFingerprint = result->server_public_key_fingerprints[b];
|
||||
key = serverPublicKeys[a];
|
||||
for (uint32_t a = 0; a < count1; a++) {
|
||||
for (uint32_t b = 0; b < count2; b++) {
|
||||
if ((uint64_t) result->server_public_key_fingerprints[a] == serverPublicKeysFingerprints[b]) {
|
||||
keyFingerprint = result->server_public_key_fingerprints[a];
|
||||
key = serverPublicKeys[b];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -457,6 +395,8 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
loadCdnConfig(currentDatacenter);
|
||||
} else {
|
||||
if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: can't find valid server public key, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, handshakeType);
|
||||
serverPublicKeys.clear();
|
||||
serverPublicKeysFingerprints.clear();
|
||||
beginHandshake(false);
|
||||
}
|
||||
return;
|
||||
|
@ -478,15 +418,15 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
return;
|
||||
}
|
||||
|
||||
TL_req_DH_params *request = new TL_req_DH_params();
|
||||
request->nonce = std::unique_ptr<ByteArray>(new ByteArray(authNonce));
|
||||
request->server_nonce = std::unique_ptr<ByteArray>(new ByteArray(authServerNonce));
|
||||
request->p = std::unique_ptr<ByteArray>(new ByteArray(4));
|
||||
auto request = new TL_req_DH_params();
|
||||
request->nonce = std::make_unique<ByteArray>(new ByteArray(authNonce));
|
||||
request->server_nonce = std::make_unique<ByteArray>(new ByteArray(authServerNonce));
|
||||
request->p = std::make_unique<ByteArray>(new ByteArray(4));
|
||||
request->p->bytes[3] = (uint8_t) p;
|
||||
request->p->bytes[2] = (uint8_t) (p >> 8);
|
||||
request->p->bytes[1] = (uint8_t) (p >> 16);
|
||||
request->p->bytes[0] = (uint8_t) (p >> 24);
|
||||
request->q = std::unique_ptr<ByteArray>(new ByteArray(4));
|
||||
request->q = std::make_unique<ByteArray>(new ByteArray(4));
|
||||
request->q->bytes[3] = (uint8_t) q;
|
||||
request->q->bytes[2] = (uint8_t) (q >> 8);
|
||||
request->q->bytes[1] = (uint8_t) (q >> 16);
|
||||
|
@ -495,13 +435,13 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
|
||||
TLObject *innerData;
|
||||
if (handshakeType == HandshakeTypePerm) {
|
||||
TL_p_q_inner_data_dc *tl_p_q_inner_data = new TL_p_q_inner_data_dc();
|
||||
tl_p_q_inner_data->nonce = std::unique_ptr<ByteArray>(new ByteArray(authNonce));
|
||||
tl_p_q_inner_data->server_nonce = std::unique_ptr<ByteArray>(new ByteArray(authServerNonce));
|
||||
tl_p_q_inner_data->pq = std::unique_ptr<ByteArray>(new ByteArray(result->pq.get()));
|
||||
tl_p_q_inner_data->p = std::unique_ptr<ByteArray>(new ByteArray(request->p.get()));
|
||||
tl_p_q_inner_data->q = std::unique_ptr<ByteArray>(new ByteArray(request->q.get()));
|
||||
tl_p_q_inner_data->new_nonce = std::unique_ptr<ByteArray>(new ByteArray(32));
|
||||
auto tl_p_q_inner_data = new TL_p_q_inner_data_dc();
|
||||
tl_p_q_inner_data->nonce = std::make_unique<ByteArray>(authNonce);
|
||||
tl_p_q_inner_data->server_nonce = std::make_unique<ByteArray>(authServerNonce);
|
||||
tl_p_q_inner_data->pq = std::make_unique<ByteArray>(new ByteArray(result->pq.get()));
|
||||
tl_p_q_inner_data->p = std::make_unique<ByteArray>(new ByteArray(request->p.get()));
|
||||
tl_p_q_inner_data->q = std::make_unique<ByteArray>(new ByteArray(request->q.get()));
|
||||
tl_p_q_inner_data->new_nonce = std::make_unique<ByteArray>(new ByteArray(32));
|
||||
if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) {
|
||||
tl_p_q_inner_data->dc = 10000 + currentDatacenter->datacenterId;
|
||||
} else {
|
||||
|
@ -511,13 +451,13 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
authNewNonce = new ByteArray(tl_p_q_inner_data->new_nonce.get());
|
||||
innerData = tl_p_q_inner_data;
|
||||
} else {
|
||||
TL_p_q_inner_data_temp_dc *tl_p_q_inner_data_temp = new TL_p_q_inner_data_temp_dc();
|
||||
tl_p_q_inner_data_temp->nonce = std::unique_ptr<ByteArray>(new ByteArray(authNonce));
|
||||
tl_p_q_inner_data_temp->server_nonce = std::unique_ptr<ByteArray>(new ByteArray(authServerNonce));
|
||||
tl_p_q_inner_data_temp->pq = std::unique_ptr<ByteArray>(new ByteArray(result->pq.get()));
|
||||
tl_p_q_inner_data_temp->p = std::unique_ptr<ByteArray>(new ByteArray(request->p.get()));
|
||||
tl_p_q_inner_data_temp->q = std::unique_ptr<ByteArray>(new ByteArray(request->q.get()));
|
||||
tl_p_q_inner_data_temp->new_nonce = std::unique_ptr<ByteArray>(new ByteArray(32));
|
||||
auto tl_p_q_inner_data_temp = new TL_p_q_inner_data_temp_dc();
|
||||
tl_p_q_inner_data_temp->nonce = std::make_unique<ByteArray>(new ByteArray(authNonce));
|
||||
tl_p_q_inner_data_temp->server_nonce = std::make_unique<ByteArray>(new ByteArray(authServerNonce));
|
||||
tl_p_q_inner_data_temp->pq = std::make_unique<ByteArray>(new ByteArray(result->pq.get()));
|
||||
tl_p_q_inner_data_temp->p = std::make_unique<ByteArray>(new ByteArray(request->p.get()));
|
||||
tl_p_q_inner_data_temp->q = std::make_unique<ByteArray>(new ByteArray(request->q.get()));
|
||||
tl_p_q_inner_data_temp->new_nonce = std::make_unique<ByteArray>(new ByteArray(32));
|
||||
if (handshakeType == HandshakeTypeMediaTemp) {
|
||||
if (ConnectionsManager::getInstance(currentDatacenter->instanceNum).testBackend) {
|
||||
tl_p_q_inner_data_temp->dc = -(10000 + currentDatacenter->datacenterId);
|
||||
|
@ -538,32 +478,83 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
}
|
||||
|
||||
uint32_t innerDataSize = innerData->getObjectSize();
|
||||
uint32_t additionalSize = innerDataSize + SHA_DIGEST_LENGTH < 255 ? 255 - (innerDataSize + SHA_DIGEST_LENGTH) : 0;
|
||||
NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(innerDataSize + additionalSize + SHA_DIGEST_LENGTH);
|
||||
innerDataBuffer->position(SHA_DIGEST_LENGTH);
|
||||
if (innerDataSize > 144) {
|
||||
if (LOGS_ENABLED) DEBUG_E("account%u dc%u handshake: inner data too large %d, type = %d", currentDatacenter->instanceNum, currentDatacenter->datacenterId, innerDataSize, handshakeType);
|
||||
delete innerData;
|
||||
beginHandshake(false);
|
||||
return;
|
||||
}
|
||||
uint32_t keySize = 32;
|
||||
uint32_t ivSize = 32;
|
||||
uint32_t paddedDataSize = 192;
|
||||
uint32_t encryptedDataSize = keySize + paddedDataSize + SHA256_DIGEST_LENGTH;
|
||||
uint32_t additionalSize = innerDataSize < paddedDataSize ? paddedDataSize - innerDataSize : 0;
|
||||
NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH + 256);
|
||||
|
||||
innerDataBuffer->position(encryptedDataSize);
|
||||
innerData->serializeToStream(innerDataBuffer);
|
||||
delete innerData;
|
||||
|
||||
SHA1(innerDataBuffer->bytes() + SHA_DIGEST_LENGTH, innerDataSize, innerDataBuffer->bytes());
|
||||
if (additionalSize != 0) {
|
||||
RAND_bytes(innerDataBuffer->bytes() + SHA_DIGEST_LENGTH + innerDataSize, additionalSize);
|
||||
}
|
||||
|
||||
BIO *keyBio = BIO_new(BIO_s_mem());
|
||||
BIO_write(keyBio, key.c_str(), (int) key.length());
|
||||
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL);
|
||||
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, nullptr, nullptr, nullptr);
|
||||
BIO_free(keyBio);
|
||||
|
||||
while (true) {
|
||||
RAND_bytes(innerDataBuffer->bytes() + encryptedDataSize + innerDataSize, additionalSize);
|
||||
for (uint32_t i = 0; i < paddedDataSize; i++) {
|
||||
innerDataBuffer->bytes()[keySize + i] = innerDataBuffer->bytes()[encryptedDataSize + paddedDataSize - i - 1];
|
||||
}
|
||||
|
||||
RAND_bytes(innerDataBuffer->bytes(), keySize);
|
||||
SHA256_CTX sha256Ctx;
|
||||
SHA256_Init(&sha256Ctx);
|
||||
SHA256_Update(&sha256Ctx, innerDataBuffer->bytes(), keySize);
|
||||
SHA256_Update(&sha256Ctx, innerDataBuffer->bytes() + encryptedDataSize, paddedDataSize);
|
||||
SHA256_Final(innerDataBuffer->bytes() + keySize + paddedDataSize, &sha256Ctx);
|
||||
|
||||
memset(innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize, 0, ivSize);
|
||||
Datacenter::aesIgeEncryption(innerDataBuffer->bytes() + keySize, innerDataBuffer->bytes(), innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize, true, true, paddedDataSize + SHA256_DIGEST_LENGTH);
|
||||
|
||||
SHA256_Init(&sha256Ctx);
|
||||
SHA256_Update(&sha256Ctx, innerDataBuffer->bytes() + keySize, paddedDataSize + SHA256_DIGEST_LENGTH);
|
||||
SHA256_Final(innerDataBuffer->bytes() + encryptedDataSize + paddedDataSize + ivSize, &sha256Ctx);
|
||||
|
||||
for (uint32_t i = 0; i < keySize; i++) {
|
||||
innerDataBuffer->bytes()[i] ^= innerDataBuffer->bytes()[encryptedDataSize + paddedDataSize + ivSize + i];
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
uint32_t offset = encryptedDataSize + paddedDataSize + ivSize + SHA256_DIGEST_LENGTH;
|
||||
size_t resLen = BN_bn2bin(rsaKey->n, innerDataBuffer->bytes() + offset);
|
||||
const auto shift = (256 - resLen);
|
||||
|
||||
for (auto i = 0; i != 256; ++i) {
|
||||
const auto a = innerDataBuffer->bytes()[i];
|
||||
const auto b = (i < shift) ? 0 : innerDataBuffer->bytes()[offset + i - shift];
|
||||
if (a > b) {
|
||||
break;
|
||||
} else if (a < b) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bnContext == nullptr) {
|
||||
bnContext = BN_CTX_new();
|
||||
}
|
||||
BIGNUM *a = BN_bin2bn(innerDataBuffer->bytes(), innerDataBuffer->limit(), NULL);
|
||||
BIGNUM *a = BN_bin2bn(innerDataBuffer->bytes(), encryptedDataSize, nullptr);
|
||||
BIGNUM *r = BN_new();
|
||||
BN_mod_exp(r, a, rsaKey->e, rsaKey->n, bnContext);
|
||||
uint32_t size = BN_num_bytes(r);
|
||||
ByteArray *rsaEncryptedData = new ByteArray(size >= 256 ? size : 256);
|
||||
size_t resLen = BN_bn2bin(r, rsaEncryptedData->bytes);
|
||||
if (256 - resLen > 0) {
|
||||
memset(rsaEncryptedData->bytes + resLen, 0, 256 - resLen);
|
||||
auto rsaEncryptedData = new ByteArray(size >= 256 ? size : 256);
|
||||
BN_bn2bin(r, rsaEncryptedData->bytes + (size < 256 ? (256 - size) : 0));
|
||||
if (256 - size > 0) {
|
||||
memset(rsaEncryptedData->bytes, 0, 256 - size);
|
||||
}
|
||||
BN_free(a);
|
||||
BN_free(r);
|
||||
|
@ -849,7 +840,7 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
inner->temp_session_id = connection->getSessionId();
|
||||
|
||||
NetworkMessage *networkMessage = new NetworkMessage();
|
||||
networkMessage->message = std::unique_ptr<TL_message>(new TL_message());
|
||||
networkMessage->message = std::make_unique<TL_message>();
|
||||
networkMessage->message->msg_id = authKeyPendingMessageId = messageId;
|
||||
networkMessage->message->bytes = inner->getObjectSize();
|
||||
networkMessage->message->body = std::unique_ptr<TLObject>(inner);
|
||||
|
@ -864,7 +855,7 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
request->encrypted_message = currentDatacenter->createRequestsData(array, nullptr, connection, true);
|
||||
};
|
||||
|
||||
authKeyPendingRequestId = ConnectionsManager::getInstance(currentDatacenter->instanceNum).sendRequest(request, [&](TLObject *response, TL_error *error, int32_t networkType) {
|
||||
authKeyPendingRequestId = ConnectionsManager::getInstance(currentDatacenter->instanceNum).sendRequest(request, [&](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) {
|
||||
authKeyPendingMessageId = 0;
|
||||
authKeyPendingRequestId = 0;
|
||||
if (response != nullptr && typeid(*response) == typeid(TL_boolTrue)) {
|
||||
|
@ -911,9 +902,10 @@ void Handshake::processHandshakeResponse(TLObject *message, int64_t messageId) {
|
|||
}
|
||||
|
||||
void Handshake::sendAckRequest(int64_t messageId) {
|
||||
TL_msgs_ack *msgsAck = new TL_msgs_ack();
|
||||
/*
|
||||
auto msgsAck = new TL_msgs_ack();
|
||||
msgsAck->msg_ids.push_back(messageId);
|
||||
sendRequestData(msgsAck, false);
|
||||
sendRequestData(msgsAck, false);*/
|
||||
}
|
||||
|
||||
TLObject *Handshake::getCurrentHandshakeRequest() {
|
||||
|
@ -923,10 +915,10 @@ TLObject *Handshake::getCurrentHandshakeRequest() {
|
|||
void Handshake::saveCdnConfigInternal(NativeByteBuffer *buffer) {
|
||||
buffer->writeInt32(1);
|
||||
buffer->writeInt32((int32_t) cdnPublicKeys.size());
|
||||
for (std::map<int32_t, std::string>::iterator iter = cdnPublicKeys.begin(); iter != cdnPublicKeys.end(); iter++) {
|
||||
buffer->writeInt32(iter->first);
|
||||
buffer->writeString(iter->second);
|
||||
buffer->writeInt64(cdnPublicKeysFingerprints[iter->first]);
|
||||
for (auto & cdnPublicKey : cdnPublicKeys) {
|
||||
buffer->writeInt32(cdnPublicKey.first);
|
||||
buffer->writeString(cdnPublicKey.second);
|
||||
buffer->writeInt64(cdnPublicKeysFingerprints[cdnPublicKey.first]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -934,7 +926,7 @@ void Handshake::saveCdnConfig(Datacenter *datacenter) {
|
|||
if (cdnConfig == nullptr) {
|
||||
cdnConfig = new Config(datacenter->instanceNum, "cdnkeys.dat");
|
||||
}
|
||||
thread_local static NativeByteBuffer *sizeCalculator = new NativeByteBuffer(true);
|
||||
thread_local static auto sizeCalculator = new NativeByteBuffer(true);
|
||||
sizeCalculator->clearCapacity();
|
||||
saveCdnConfigInternal(sizeCalculator);
|
||||
NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(sizeCalculator->capacity());
|
||||
|
@ -978,11 +970,11 @@ void Handshake::loadCdnConfig(Datacenter *datacenter) {
|
|||
}
|
||||
}
|
||||
loadingCdnKeys = true;
|
||||
TL_help_getCdnConfig *request = new TL_help_getCdnConfig();
|
||||
auto request = new TL_help_getCdnConfig();
|
||||
|
||||
ConnectionsManager::getInstance(datacenter->instanceNum).sendRequest(request, [&, datacenter](TLObject *response, TL_error *error, int32_t networkType) {
|
||||
ConnectionsManager::getInstance(datacenter->instanceNum).sendRequest(request, [&, datacenter](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) {
|
||||
if (response != nullptr) {
|
||||
TL_cdnConfig *config = (TL_cdnConfig *) response;
|
||||
auto config = (TL_cdnConfig *) response;
|
||||
size_t count = config->public_keys.size();
|
||||
BIO *keyBio = BIO_new(BIO_s_mem());
|
||||
NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(1024);
|
||||
|
@ -992,7 +984,7 @@ void Handshake::loadCdnConfig(Datacenter *datacenter) {
|
|||
cdnPublicKeys[publicKey->dc_id] = publicKey->public_key;
|
||||
|
||||
BIO_write(keyBio, publicKey->public_key.c_str(), (int) publicKey->public_key.length());
|
||||
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL);
|
||||
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, nullptr, nullptr, nullptr);
|
||||
|
||||
int nBytes = BN_num_bytes(rsaKey->n);
|
||||
int eBytes = BN_num_bytes(rsaKey->e);
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
void processHandshakeResponse(TLObject *message, int64_t messageId);
|
||||
void onHandshakeConnectionConnected();
|
||||
void onHandshakeConnectionClosed();
|
||||
static void cleanupServerKeys();
|
||||
HandshakeType getType();
|
||||
ByteArray *getPendingAuthKey();
|
||||
int64_t getPendingAuthKeyId();
|
||||
|
|
|
@ -111,7 +111,7 @@ void TL_api_response::readParamsEx(NativeByteBuffer *stream, uint32_t bytes, boo
|
|||
TL_future_salt *TL_future_salt::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_future_salt::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_future_salt", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_future_salt", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_future_salt *result = new TL_future_salt();
|
||||
|
@ -128,7 +128,7 @@ void TL_future_salt::readParams(NativeByteBuffer *stream, int32_t instanceNum, b
|
|||
TL_msgs_state_info *TL_msgs_state_info::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msgs_state_info::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msgs_state_info", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msgs_state_info", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msgs_state_info *result = new TL_msgs_state_info();
|
||||
|
@ -158,7 +158,7 @@ Server_DH_Params *Server_DH_Params::TLdeserialize(NativeByteBuffer *stream, uint
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in Server_DH_Params", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in Server_DH_Params", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -180,7 +180,7 @@ void TL_server_DH_params_ok::readParams(NativeByteBuffer *stream, int32_t instan
|
|||
TL_resPQ *TL_resPQ::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_resPQ::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_resPQ", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_resPQ", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_resPQ *result = new TL_resPQ();
|
||||
|
@ -195,7 +195,7 @@ void TL_resPQ::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &e
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_resPQ, got %x", magic);
|
||||
return;
|
||||
}
|
||||
uint32_t count = stream->readUint32(&error);
|
||||
|
@ -297,7 +297,7 @@ void TL_auth_dropTempAuthKeys::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_pong *TL_pong::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_pong::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_pong", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_pong", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_pong *result = new TL_pong();
|
||||
|
@ -313,7 +313,7 @@ void TL_pong::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &er
|
|||
TL_future_salts *TL_future_salts::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_future_salts::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_future_salts", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_future_salts", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_future_salts *result = new TL_future_salts();
|
||||
|
@ -349,7 +349,7 @@ RpcDropAnswer *RpcDropAnswer::TLdeserialize(NativeByteBuffer *stream, uint32_t c
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in RpcDropAnswer", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in RpcDropAnswer", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -384,7 +384,7 @@ Set_client_DH_params_answer *Set_client_DH_params_answer::TLdeserialize(NativeBy
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in Set_client_DH_params_answer", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in Set_client_DH_params_answer", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -420,7 +420,7 @@ BadMsgNotification *BadMsgNotification::TLdeserialize(NativeByteBuffer *stream,
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in BadMsgNotification", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in BadMsgNotification", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -443,7 +443,7 @@ void TL_bad_server_salt::readParams(NativeByteBuffer *stream, int32_t instanceNu
|
|||
TL_msgs_state_req *TL_msgs_state_req::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msgs_state_req::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msgs_state_req", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msgs_state_req", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msgs_state_req *result = new TL_msgs_state_req();
|
||||
|
@ -455,7 +455,7 @@ void TL_msgs_state_req::readParams(NativeByteBuffer *stream, int32_t instanceNum
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_msgs_state_req, got %x", magic);
|
||||
return;
|
||||
}
|
||||
uint32_t count = stream->readUint32(&error);
|
||||
|
@ -489,7 +489,7 @@ MsgDetailedInfo *MsgDetailedInfo::TLdeserialize(NativeByteBuffer *stream, uint32
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in MsgDetailedInfo", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in MsgDetailedInfo", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -512,7 +512,7 @@ void TL_msg_detailed_info::readParams(NativeByteBuffer *stream, int32_t instance
|
|||
TL_msg_copy *TL_msg_copy::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msg_copy::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msg_copy", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msg_copy", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msg_copy *result = new TL_msg_copy();
|
||||
|
@ -532,7 +532,7 @@ void TL_msg_copy::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_msgs_all_info *TL_msgs_all_info::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msgs_all_info::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msgs_all_info", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msgs_all_info", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msgs_all_info *result = new TL_msgs_all_info();
|
||||
|
@ -544,7 +544,7 @@ void TL_msgs_all_info::readParams(NativeByteBuffer *stream, int32_t instanceNum,
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_msgs_all_info, got %x", magic);
|
||||
return;
|
||||
}
|
||||
uint32_t count = stream->readUint32(&error);
|
||||
|
@ -586,7 +586,7 @@ DestroySessionRes *DestroySessionRes::TLdeserialize(NativeByteBuffer *stream, ui
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in DestroySessionRes", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in DestroySessionRes", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -604,7 +604,7 @@ void TL_destroy_session_none::readParams(NativeByteBuffer *stream, int32_t insta
|
|||
TL_msgs_ack *TL_msgs_ack::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msgs_ack::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msgs_ack", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msgs_ack", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msgs_ack *result = new TL_msgs_ack();
|
||||
|
@ -616,7 +616,7 @@ void TL_msgs_ack::readParams(NativeByteBuffer *stream, int32_t instanceNum, bool
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_msgs_ack, got %x", magic);
|
||||
return;
|
||||
}
|
||||
uint32_t count = stream->readUint32(&error);
|
||||
|
@ -642,7 +642,7 @@ void TL_msgs_ack::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_msg_container *TL_msg_container::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msg_container::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msg_container", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msg_container", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msg_container *result = new TL_msg_container();
|
||||
|
@ -674,7 +674,7 @@ void TL_msg_container::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_message *TL_message::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_message::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_message", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_message", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_message *result = new TL_message();
|
||||
|
@ -709,7 +709,7 @@ void TL_message::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_msg_resend_req *TL_msg_resend_req::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_msg_resend_req::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_msg_resend_req", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_msg_resend_req", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_msg_resend_req *result = new TL_msg_resend_req();
|
||||
|
@ -721,7 +721,7 @@ void TL_msg_resend_req::readParams(NativeByteBuffer *stream, int32_t instanceNum
|
|||
uint32_t magic = stream->readUint32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_msg_resend_req, got %x", magic);
|
||||
return;
|
||||
}
|
||||
uint32_t count = stream->readUint32(&error);
|
||||
|
@ -771,7 +771,7 @@ void TL_client_DH_inner_data::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_server_DH_inner_data *TL_server_DH_inner_data::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_server_DH_inner_data::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_server_DH_inner_data", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_server_DH_inner_data", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_server_DH_inner_data *result = new TL_server_DH_inner_data();
|
||||
|
@ -906,7 +906,7 @@ void TL_gzip_packed::serializeToStream(NativeByteBuffer *stream) {
|
|||
TL_error *TL_error::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_error::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_error", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_error", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_error *result = new TL_error();
|
||||
|
@ -971,7 +971,7 @@ JSONValue *JSONValue::TLdeserialize(NativeByteBuffer *stream, uint32_t construct
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in JSONValue", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in JSONValue", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -981,7 +981,7 @@ JSONValue *JSONValue::TLdeserialize(NativeByteBuffer *stream, uint32_t construct
|
|||
TL_jsonObjectValue *TL_jsonObjectValue::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_jsonObjectValue::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_jsonObjectValue", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_jsonObjectValue", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_jsonObjectValue *result = new TL_jsonObjectValue();
|
||||
|
@ -1028,7 +1028,7 @@ void TL_jsonArray::readParams(NativeByteBuffer *stream, int32_t instanceNum, boo
|
|||
int magic = stream->readInt32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_jsonArray, got %x", magic);
|
||||
return;
|
||||
}
|
||||
int count = stream->readInt32(&error);
|
||||
|
@ -1055,7 +1055,7 @@ void TL_jsonObject::readParams(NativeByteBuffer *stream, int32_t instanceNum, bo
|
|||
int magic = stream->readInt32(&error);
|
||||
if (magic != 0x1cb5c415) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("wrong Vector magic, got %x", magic);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("wrong Vector magic in TL_jsonObject, got %x", magic);
|
||||
return;
|
||||
}
|
||||
int count = stream->readInt32(&error);
|
||||
|
@ -1117,7 +1117,7 @@ IpPort *IpPort::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, in
|
|||
break;
|
||||
default:
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in IpPort", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in IpPort", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
result->readParams(stream, instanceNum, error);
|
||||
|
@ -1155,7 +1155,7 @@ void TL_accessPointRule::readParams(NativeByteBuffer *stream, int32_t instanceNu
|
|||
TL_help_configSimple *TL_help_configSimple::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, int32_t instanceNum, bool &error) {
|
||||
if (TL_help_configSimple::constructor != constructor) {
|
||||
error = true;
|
||||
if (LOGS_ENABLED) DEBUG_E("can't parse magic %x in TL_help_configSimple", constructor);
|
||||
if (LOGS_ENABLED) DEBUG_FATAL("can't parse magic %x in TL_help_configSimple", constructor);
|
||||
return nullptr;
|
||||
}
|
||||
TL_help_configSimple *result = new TL_help_configSimple();
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "ConnectionsManager.h"
|
||||
#include "BuffersStorage.h"
|
||||
|
||||
static int buffersCount = 0;
|
||||
|
||||
NativeByteBuffer::NativeByteBuffer(uint32_t size) {
|
||||
#ifdef ANDROID
|
||||
if (jclass_ByteBuffer != nullptr) {
|
||||
|
@ -27,6 +29,7 @@ NativeByteBuffer::NativeByteBuffer(uint32_t size) {
|
|||
if (LOGS_ENABLED) DEBUG_E("can't create javaByteBuffer");
|
||||
exit(1);
|
||||
}
|
||||
DEBUG_REF("nativebytebuffer");
|
||||
jobject globalRef = env->NewGlobalRef(javaByteBuffer);
|
||||
env->DeleteLocalRef(javaByteBuffer);
|
||||
javaByteBuffer = globalRef;
|
||||
|
@ -43,6 +46,7 @@ NativeByteBuffer::NativeByteBuffer(uint32_t size) {
|
|||
if (LOGS_ENABLED) DEBUG_E("can't allocate NativeByteBuffer buffer");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_limit = _capacity = size;
|
||||
}
|
||||
|
||||
|
@ -64,6 +68,7 @@ NativeByteBuffer::~NativeByteBuffer() {
|
|||
if (LOGS_ENABLED) DEBUG_E("can't get jnienv");
|
||||
exit(1);
|
||||
}
|
||||
DEBUG_DELREF("nativebytebuffer");
|
||||
env->DeleteGlobalRef(javaByteBuffer);
|
||||
javaByteBuffer = nullptr;
|
||||
}
|
||||
|
@ -694,6 +699,7 @@ jobject NativeByteBuffer::getJavaByteBuffer() {
|
|||
if (LOGS_ENABLED) DEBUG_E("can't allocate NativeByteBuffer buffer");
|
||||
exit(1);
|
||||
}
|
||||
DEBUG_REF("nativebytebuffer");
|
||||
jobject globalRef = env->NewGlobalRef(javaByteBuffer);
|
||||
env->DeleteLocalRef(javaByteBuffer);
|
||||
javaByteBuffer = globalRef;
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
|
||||
#include "ProxyCheckInfo.h"
|
||||
#include "ConnectionsManager.h"
|
||||
#include "FileLog.h"
|
||||
|
||||
ProxyCheckInfo::~ProxyCheckInfo() {
|
||||
#ifdef ANDROID
|
||||
if (ptr1 != nullptr) {
|
||||
DEBUG_DELREF("tgnet (2) request ptr1");
|
||||
jniEnv[instanceNum]->DeleteGlobalRef(ptr1);
|
||||
ptr1 = nullptr;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "ConnectionsManager.h"
|
||||
#include "Datacenter.h"
|
||||
#include "Connection.h"
|
||||
#include "FileLog.h"
|
||||
|
||||
Request::Request(int32_t instance, int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc) {
|
||||
requestToken = token;
|
||||
|
@ -29,14 +30,17 @@ Request::Request(int32_t instance, int32_t token, ConnectionType type, uint32_t
|
|||
Request::~Request() {
|
||||
#ifdef ANDROID
|
||||
if (ptr1 != nullptr) {
|
||||
DEBUG_DELREF("tgnet request ptr1");
|
||||
jniEnv[instanceNum]->DeleteGlobalRef(ptr1);
|
||||
ptr1 = nullptr;
|
||||
}
|
||||
if (ptr2 != nullptr) {
|
||||
DEBUG_DELREF("tgnet request ptr2");
|
||||
jniEnv[instanceNum]->DeleteGlobalRef(ptr2);
|
||||
ptr2 = nullptr;
|
||||
}
|
||||
if (ptr3 != nullptr) {
|
||||
DEBUG_DELREF("tgnet request ptr3");
|
||||
jniEnv[instanceNum]->DeleteGlobalRef(ptr3);
|
||||
ptr3 = nullptr;
|
||||
}
|
||||
|
@ -61,9 +65,9 @@ void Request::clear(bool time) {
|
|||
}
|
||||
}
|
||||
|
||||
void Request::onComplete(TLObject *result, TL_error *error, int32_t networkType) {
|
||||
void Request::onComplete(TLObject *result, TL_error *error, int32_t networkType, int64_t responseTime, int64_t requestMsgId) {
|
||||
if (onCompleteRequestCallback != nullptr && (result != nullptr || error != nullptr)) {
|
||||
onCompleteRequestCallback(result, error, networkType);
|
||||
onCompleteRequestCallback(result, error, networkType, responseTime, requestMsgId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
int64_t startTimeMillis = 0;
|
||||
int32_t minStartTime = 0;
|
||||
int32_t lastResendTime = 0;
|
||||
bool isResending = false;
|
||||
int32_t instanceNum = 0;
|
||||
uint32_t serverFailureCount = 0;
|
||||
TLObject *rawRequest;
|
||||
|
@ -58,7 +59,7 @@ public:
|
|||
void addRespondMessageId(int64_t id);
|
||||
bool respondsToMessageId(int64_t id);
|
||||
void clear(bool time);
|
||||
void onComplete(TLObject *result, TL_error *error, int32_t networkType);
|
||||
void onComplete(TLObject *result, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msg_id);
|
||||
void onQuickAck();
|
||||
void onWriteToSocket();
|
||||
bool isMediaRequest();
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
# Copyright (c) 2012, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# ndk-build module definition for the Google Breakpad client library
|
||||
#
|
||||
# To use this file, do the following:
|
||||
#
|
||||
# 1/ Include this file from your own Android.mk, either directly
|
||||
# or with through the NDK's import-module function.
|
||||
#
|
||||
# 2/ Use the client static library in your project with:
|
||||
#
|
||||
# LOCAL_STATIC_LIBRARIES += breakpad_client
|
||||
#
|
||||
# 3/ In your source code, include "src/client/linux/exception_handler.h"
|
||||
# and use the Linux instructions to use it.
|
||||
#
|
||||
# This module works with either the STLport or GNU libstdc++, but you need
|
||||
# to select one in your Application.mk
|
||||
#
|
||||
|
||||
# The top Google Breakpad directory.
|
||||
# We assume this Android.mk to be under 'android/google_breakpad'
|
||||
|
||||
LOCAL_PATH := $(call my-dir)/
|
||||
|
||||
# Defube the client library module, as a simple static library that
|
||||
# exports the right include path / linker flags to its users.
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := breakpad_client
|
||||
|
||||
LOCAL_CPP_EXTENSION := .cc
|
||||
|
||||
# Breakpad uses inline ARM assembly that requires the library
|
||||
# to be built in ARM mode. Otherwise, the build will fail with
|
||||
# cryptic assembler messages like:
|
||||
# Compile++ thumb : google_breakpad_client <= crash_generation_client.cc
|
||||
# /tmp/cc8aMSoD.s: Assembler messages:
|
||||
# /tmp/cc8aMSoD.s:132: Error: invalid immediate: 288 is out of range
|
||||
# /tmp/cc8aMSoD.s:244: Error: invalid immediate: 296 is out of range
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
# List of client source files, directly taken from Makefile.am
|
||||
LOCAL_SRC_FILES := \
|
||||
src/client/linux/crash_generation/crash_generation_client.cc \
|
||||
src/client/linux/handler/exception_handler.cc \
|
||||
src/client/linux/handler/minidump_descriptor.cc \
|
||||
src/client/linux/log/log.cc \
|
||||
src/client/linux/dump_writer_common/thread_info.cc \
|
||||
src/client/linux/dump_writer_common/seccomp_unwinder.cc \
|
||||
src/client/linux/dump_writer_common/ucontext_reader.cc \
|
||||
src/client/linux/microdump_writer/microdump_writer.cc \
|
||||
src/client/linux/minidump_writer/linux_dumper.cc \
|
||||
src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
|
||||
src/client/linux/minidump_writer/minidump_writer.cc \
|
||||
src/client/minidump_file_writer.cc \
|
||||
src/common/android/breakpad_getcontext.S \
|
||||
src/common/convert_UTF.c \
|
||||
src/common/md5.cc \
|
||||
src/common/string_conversion.cc \
|
||||
src/common/linux/elfutils.cc \
|
||||
src/common/linux/file_id.cc \
|
||||
src/common/linux/guid_creator.cc \
|
||||
src/common/linux/linux_libc_support.cc \
|
||||
src/common/linux/memory_mapped_file.cc \
|
||||
src/common/linux/safe_readlink.cc
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src/common/android/include \
|
||||
$(LOCAL_PATH)/src
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_EXPORT_LDLIBS := -llog
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# Done.
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__
|
||||
#define BREAKPAD_GOOGLETEST_INCLUDES_H__
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "testing/include/gmock/gmock.h"
|
||||
|
||||
// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
|
||||
// (illegal instruction) instead of SIGSEGV (segmentation fault). Also,
|
||||
// the number of memory regions differs, so there is no point in running
|
||||
// this test if AddressSanitizer is used.
|
||||
//
|
||||
// Ideally we'd use this attribute to disable ASAN on a per-func basis,
|
||||
// but this doesn't seem to actually work, and it's changed names over
|
||||
// time. So just stick with disabling the actual tests.
|
||||
// http://crbug.com/304575
|
||||
//#define NO_ASAN __attribute__((no_sanitize_address))
|
||||
#if defined(__clang__) && defined(__has_feature)
|
||||
// Have to keep this check sep from above as newer gcc will barf on it.
|
||||
# if __has_feature(address_sanitizer)
|
||||
# define ADDRESS_SANITIZER
|
||||
# endif
|
||||
#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__)
|
||||
# define ADDRESS_SANITIZER
|
||||
#else
|
||||
# undef ADDRESS_SANITIZER
|
||||
#endif
|
||||
|
||||
#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__
|
53
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/client_info.h
vendored
Normal file
53
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/client_info.h
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
|
||||
#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class CrashGenerationServer;
|
||||
|
||||
class ClientInfo {
|
||||
public:
|
||||
ClientInfo(pid_t pid, CrashGenerationServer* crash_server)
|
||||
: crash_server_(crash_server),
|
||||
pid_(pid) {}
|
||||
|
||||
CrashGenerationServer* crash_server() const { return crash_server_; }
|
||||
pid_t pid() const { return pid_; }
|
||||
|
||||
private:
|
||||
CrashGenerationServer* crash_server_;
|
||||
pid_t pid_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
|
105
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/crash_generation_client.cc
vendored
Normal file
105
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/crash_generation_client.cc
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "client/linux/crash_generation/crash_generation_client.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/ignore_ret.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
class CrashGenerationClientImpl : public CrashGenerationClient {
|
||||
public:
|
||||
explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {}
|
||||
virtual ~CrashGenerationClientImpl() {}
|
||||
|
||||
virtual bool RequestDump(const void* blob, size_t blob_size) {
|
||||
int fds[2];
|
||||
if (sys_pipe(fds) < 0)
|
||||
return false;
|
||||
static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int));
|
||||
|
||||
struct kernel_iovec iov;
|
||||
iov.iov_base = const_cast<void*>(blob);
|
||||
iov.iov_len = blob_size;
|
||||
|
||||
struct kernel_msghdr msg = { 0 };
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
char cmsg[kControlMsgSize] = "";
|
||||
msg.msg_control = cmsg;
|
||||
msg.msg_controllen = sizeof(cmsg);
|
||||
|
||||
struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg);
|
||||
hdr->cmsg_level = SOL_SOCKET;
|
||||
hdr->cmsg_type = SCM_RIGHTS;
|
||||
hdr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
int* p = reinterpret_cast<int*>(CMSG_DATA(hdr));
|
||||
*p = fds[1];
|
||||
|
||||
ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0));
|
||||
sys_close(fds[1]);
|
||||
if (ret < 0) {
|
||||
sys_close(fds[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for an ACK from the server.
|
||||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1)));
|
||||
sys_close(fds[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int server_fd_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) {
|
||||
if (server_fd < 0)
|
||||
return NULL;
|
||||
return new CrashGenerationClientImpl(server_fd);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
|
||||
#include "common/basictypes.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// CrashGenerationClient is an interface for implementing out-of-process crash
|
||||
// dumping. The default implementation, accessed via the TryCreate() factory,
|
||||
// works in conjunction with the CrashGenerationServer to generate a minidump
|
||||
// via a remote process.
|
||||
class CrashGenerationClient {
|
||||
public:
|
||||
CrashGenerationClient() {}
|
||||
virtual ~CrashGenerationClient() {}
|
||||
|
||||
// Request the crash server to generate a dump. |blob| is an opaque
|
||||
// CrashContext pointer from exception_handler.h.
|
||||
// Returns true if the dump was successful; false otherwise.
|
||||
virtual bool RequestDump(const void* blob, size_t blob_size) = 0;
|
||||
|
||||
// Returns a new CrashGenerationClient if |server_fd| is valid and
|
||||
// connects to a CrashGenerationServer. Otherwise, return NULL.
|
||||
// The returned CrashGenerationClient* is owned by the caller of
|
||||
// this function.
|
||||
static CrashGenerationClient* TryCreate(int server_fd);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
330
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/crash_generation_server.cc
vendored
Normal file
330
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/crash_generation_server.cc
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "client/linux/crash_generation/crash_generation_server.h"
|
||||
#include "client/linux/crash_generation/client_info.h"
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/guid_creator.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
|
||||
static const char kCommandQuit = 'x';
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
CrashGenerationServer::CrashGenerationServer(
|
||||
const int listen_fd,
|
||||
OnClientDumpRequestCallback dump_callback,
|
||||
void* dump_context,
|
||||
OnClientExitingCallback exit_callback,
|
||||
void* exit_context,
|
||||
bool generate_dumps,
|
||||
const string* dump_path) :
|
||||
server_fd_(listen_fd),
|
||||
dump_callback_(dump_callback),
|
||||
dump_context_(dump_context),
|
||||
exit_callback_(exit_callback),
|
||||
exit_context_(exit_context),
|
||||
generate_dumps_(generate_dumps),
|
||||
started_(false)
|
||||
{
|
||||
if (dump_path)
|
||||
dump_dir_ = *dump_path;
|
||||
else
|
||||
dump_dir_ = "/tmp";
|
||||
}
|
||||
|
||||
CrashGenerationServer::~CrashGenerationServer()
|
||||
{
|
||||
if (started_)
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool
|
||||
CrashGenerationServer::Start()
|
||||
{
|
||||
if (started_ || 0 > server_fd_)
|
||||
return false;
|
||||
|
||||
int control_pipe[2];
|
||||
if (pipe(control_pipe))
|
||||
return false;
|
||||
|
||||
if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC))
|
||||
return false;
|
||||
if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC))
|
||||
return false;
|
||||
|
||||
if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK))
|
||||
return false;
|
||||
|
||||
control_pipe_in_ = control_pipe[0];
|
||||
control_pipe_out_ = control_pipe[1];
|
||||
|
||||
if (pthread_create(&thread_, NULL,
|
||||
ThreadMain, reinterpret_cast<void*>(this)))
|
||||
return false;
|
||||
|
||||
started_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CrashGenerationServer::Stop()
|
||||
{
|
||||
assert(pthread_self() != thread_);
|
||||
|
||||
if (!started_)
|
||||
return;
|
||||
|
||||
HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1));
|
||||
|
||||
void* dummy;
|
||||
pthread_join(thread_, &dummy);
|
||||
|
||||
started_ = false;
|
||||
}
|
||||
|
||||
//static
|
||||
bool
|
||||
CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
|
||||
{
|
||||
int fds[2];
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds))
|
||||
return false;
|
||||
|
||||
static const int on = 1;
|
||||
// Enable passcred on the server end of the socket
|
||||
if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)))
|
||||
return false;
|
||||
|
||||
if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
|
||||
return false;
|
||||
if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
|
||||
return false;
|
||||
|
||||
*client_fd = fds[0];
|
||||
*server_fd = fds[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
// The following methods/functions execute on the server thread
|
||||
|
||||
void
|
||||
CrashGenerationServer::Run()
|
||||
{
|
||||
struct pollfd pollfds[2];
|
||||
memset(&pollfds, 0, sizeof(pollfds));
|
||||
|
||||
pollfds[0].fd = server_fd_;
|
||||
pollfds[0].events = POLLIN;
|
||||
|
||||
pollfds[1].fd = control_pipe_in_;
|
||||
pollfds[1].events = POLLIN;
|
||||
|
||||
while (true) {
|
||||
// infinite timeout
|
||||
int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
|
||||
if (-1 == nevents) {
|
||||
if (EINTR == errno) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
|
||||
return;
|
||||
|
||||
if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CrashGenerationServer::ClientEvent(short revents)
|
||||
{
|
||||
if (POLLHUP & revents)
|
||||
return false;
|
||||
assert(POLLIN & revents);
|
||||
|
||||
// A process has crashed and has signaled us by writing a datagram
|
||||
// to the death signal socket. The datagram contains the crash context needed
|
||||
// for writing the minidump as well as a file descriptor and a credentials
|
||||
// block so that they can't lie about their pid.
|
||||
|
||||
// The length of the control message:
|
||||
static const unsigned kControlMsgSize =
|
||||
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
|
||||
// The length of the regular payload:
|
||||
static const unsigned kCrashContextSize =
|
||||
sizeof(google_breakpad::ExceptionHandler::CrashContext);
|
||||
|
||||
struct msghdr msg = {0};
|
||||
struct iovec iov[1];
|
||||
char crash_context[kCrashContextSize];
|
||||
char control[kControlMsgSize];
|
||||
const ssize_t expected_msg_size = sizeof(crash_context);
|
||||
|
||||
iov[0].iov_base = crash_context;
|
||||
iov[0].iov_len = sizeof(crash_context);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = kControlMsgSize;
|
||||
|
||||
const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0));
|
||||
if (msg_size != expected_msg_size)
|
||||
return true;
|
||||
|
||||
if (msg.msg_controllen != kControlMsgSize ||
|
||||
msg.msg_flags & ~MSG_TRUNC)
|
||||
return true;
|
||||
|
||||
// Walk the control payload and extract the file descriptor and validated pid.
|
||||
pid_t crashing_pid = -1;
|
||||
int signal_fd = -1;
|
||||
for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
|
||||
hdr = CMSG_NXTHDR(&msg, hdr)) {
|
||||
if (hdr->cmsg_level != SOL_SOCKET)
|
||||
continue;
|
||||
if (hdr->cmsg_type == SCM_RIGHTS) {
|
||||
const unsigned len = hdr->cmsg_len -
|
||||
(((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
|
||||
assert(len % sizeof(int) == 0u);
|
||||
const unsigned num_fds = len / sizeof(int);
|
||||
if (num_fds > 1 || num_fds == 0) {
|
||||
// A nasty process could try and send us too many descriptors and
|
||||
// force a leak.
|
||||
for (unsigned i = 0; i < num_fds; ++i)
|
||||
close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]);
|
||||
return true;
|
||||
} else {
|
||||
signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
|
||||
}
|
||||
} else if (hdr->cmsg_type == SCM_CREDENTIALS) {
|
||||
const struct ucred *cred =
|
||||
reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
|
||||
crashing_pid = cred->pid;
|
||||
}
|
||||
}
|
||||
|
||||
if (crashing_pid == -1 || signal_fd == -1) {
|
||||
if (signal_fd)
|
||||
close(signal_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
string minidump_filename;
|
||||
if (!MakeMinidumpFilename(minidump_filename))
|
||||
return true;
|
||||
|
||||
if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
|
||||
crashing_pid, crash_context,
|
||||
kCrashContextSize)) {
|
||||
close(signal_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dump_callback_) {
|
||||
ClientInfo info(crashing_pid, this);
|
||||
|
||||
dump_callback_(dump_context_, &info, &minidump_filename);
|
||||
}
|
||||
|
||||
// Send the done signal to the process: it can exit now.
|
||||
// (Closing this will make the child's sys_read unblock and return 0.)
|
||||
close(signal_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CrashGenerationServer::ControlEvent(short revents)
|
||||
{
|
||||
if (POLLHUP & revents)
|
||||
return false;
|
||||
assert(POLLIN & revents);
|
||||
|
||||
char command;
|
||||
if (read(control_pipe_in_, &command, 1))
|
||||
return false;
|
||||
|
||||
switch (command) {
|
||||
case kCommandQuit:
|
||||
return false;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CrashGenerationServer::MakeMinidumpFilename(string& outFilename)
|
||||
{
|
||||
GUID guid;
|
||||
char guidString[kGUIDStringLength+1];
|
||||
|
||||
if (!(CreateGUID(&guid)
|
||||
&& GUIDToString(&guid, guidString, sizeof(guidString))))
|
||||
return false;
|
||||
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
|
||||
|
||||
outFilename = path;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void*
|
||||
CrashGenerationServer::ThreadMain(void *arg)
|
||||
{
|
||||
reinterpret_cast<CrashGenerationServer*>(arg)->Run();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
135
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/crash_generation_server.h
vendored
Normal file
135
TMessagesProj/jni/third_party/breakpad/src/client/linux/crash_generation/crash_generation_server.h
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
|
||||
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class ClientInfo;
|
||||
|
||||
class CrashGenerationServer {
|
||||
public:
|
||||
// WARNING: callbacks may be invoked on a different thread
|
||||
// than that which creates the CrashGenerationServer. They must
|
||||
// be thread safe.
|
||||
typedef void (*OnClientDumpRequestCallback)(void* context,
|
||||
const ClientInfo* client_info,
|
||||
const string* file_path);
|
||||
|
||||
typedef void (*OnClientExitingCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
// Create an instance with the given parameters.
|
||||
//
|
||||
// Parameter listen_fd: The server fd created by CreateReportChannel().
|
||||
// Parameter dump_callback: Callback for a client crash dump request.
|
||||
// Parameter dump_context: Context for client crash dump request callback.
|
||||
// Parameter exit_callback: Callback for client process exit.
|
||||
// Parameter exit_context: Context for client exit callback.
|
||||
// Parameter generate_dumps: Whether to automatically generate dumps.
|
||||
// Client code of this class might want to generate dumps explicitly
|
||||
// in the crash dump request callback. In that case, false can be
|
||||
// passed for this parameter.
|
||||
// Parameter dump_path: Path for generating dumps; required only if true is
|
||||
// passed for generateDumps parameter; NULL can be passed otherwise.
|
||||
CrashGenerationServer(const int listen_fd,
|
||||
OnClientDumpRequestCallback dump_callback,
|
||||
void* dump_context,
|
||||
OnClientExitingCallback exit_callback,
|
||||
void* exit_context,
|
||||
bool generate_dumps,
|
||||
const string* dump_path);
|
||||
|
||||
~CrashGenerationServer();
|
||||
|
||||
// Perform initialization steps needed to start listening to clients.
|
||||
//
|
||||
// Return true if initialization is successful; false otherwise.
|
||||
bool Start();
|
||||
|
||||
// Stop the server.
|
||||
void Stop();
|
||||
|
||||
// Create a "channel" that can be used by clients to report crashes
|
||||
// to a CrashGenerationServer. |*server_fd| should be passed to
|
||||
// this class's constructor, and |*client_fd| should be passed to
|
||||
// the ExceptionHandler constructor in the client process.
|
||||
static bool CreateReportChannel(int* server_fd, int* client_fd);
|
||||
|
||||
private:
|
||||
// Run the server's event loop
|
||||
void Run();
|
||||
|
||||
// Invoked when an child process (client) event occurs
|
||||
// Returning true => "keep running", false => "exit loop"
|
||||
bool ClientEvent(short revents);
|
||||
|
||||
// Invoked when the controlling thread (main) event occurs
|
||||
// Returning true => "keep running", false => "exit loop"
|
||||
bool ControlEvent(short revents);
|
||||
|
||||
// Return a unique filename at which a minidump can be written
|
||||
bool MakeMinidumpFilename(string& outFilename);
|
||||
|
||||
// Trampoline to |Run()|
|
||||
static void* ThreadMain(void* arg);
|
||||
|
||||
int server_fd_;
|
||||
|
||||
OnClientDumpRequestCallback dump_callback_;
|
||||
void* dump_context_;
|
||||
|
||||
OnClientExitingCallback exit_callback_;
|
||||
void* exit_context_;
|
||||
|
||||
bool generate_dumps_;
|
||||
|
||||
string dump_dir_;
|
||||
|
||||
bool started_;
|
||||
|
||||
pthread_t thread_;
|
||||
int control_pipe_in_;
|
||||
int control_pipe_out_;
|
||||
|
||||
// disable these
|
||||
CrashGenerationServer(const CrashGenerationServer&);
|
||||
CrashGenerationServer& operator=(const CrashGenerationServer&);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
|
3
TMessagesProj/jni/third_party/breakpad/src/client/linux/data/linux-gate-amd.sym
vendored
Normal file
3
TMessagesProj/jni/third_party/breakpad/src/client/linux/data/linux-gate-amd.sym
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
MODULE Linux x86 B8CFDE93002D54DA1900A40AA1BD67690 linux-gate.so
|
||||
PUBLIC 400 0 __kernel_vsyscall
|
||||
STACK WIN 4 400 100 1 1 0 0 0 0 0 1
|
3
TMessagesProj/jni/third_party/breakpad/src/client/linux/data/linux-gate-intel.sym
vendored
Normal file
3
TMessagesProj/jni/third_party/breakpad/src/client/linux/data/linux-gate-intel.sym
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
MODULE Linux x86 4FBDA58B5A1DF5A379E3CF19A235EA090 linux-gate.so
|
||||
PUBLIC 400 0 __kernel_vsyscall
|
||||
STACK WIN 4 400 200 3 3 0 0 0 0 0 1
|
61
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/mapping_info.h
vendored
Normal file
61
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/mapping_info.h
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
|
||||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
|
||||
|
||||
#include <limits.h>
|
||||
#include <list>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// One of these is produced for each mapping in the process (i.e. line in
|
||||
// /proc/$x/maps).
|
||||
struct MappingInfo {
|
||||
uintptr_t start_addr;
|
||||
size_t size;
|
||||
size_t offset; // offset into the backed file.
|
||||
bool exec; // true if the mapping has the execute bit set.
|
||||
char name[NAME_MAX];
|
||||
};
|
||||
|
||||
struct MappingEntry {
|
||||
MappingInfo first;
|
||||
uint8_t second[sizeof(MDGUID)];
|
||||
};
|
||||
|
||||
// A list of <MappingInfo, GUID>
|
||||
typedef std::list<MappingEntry> MappingList;
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
|
53
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h
vendored
Normal file
53
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
|
||||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
|
||||
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
#if defined(__i386__)
|
||||
typedef MDRawContextX86 RawContextCPU;
|
||||
#elif defined(__x86_64)
|
||||
typedef MDRawContextAMD64 RawContextCPU;
|
||||
#elif defined(__ARM_EABI__)
|
||||
typedef MDRawContextARM RawContextCPU;
|
||||
#elif defined(__aarch64__)
|
||||
typedef MDRawContextARM64 RawContextCPU;
|
||||
#elif defined(__mips__)
|
||||
typedef MDRawContextMIPS RawContextCPU;
|
||||
#else
|
||||
#error "This code has not been ported to your platform yet."
|
||||
#endif
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
|
154
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/seccomp_unwinder.cc
vendored
Normal file
154
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/seccomp_unwinder.cc
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "client/linux/dump_writer_common/seccomp_unwinder.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu,
|
||||
const MDRawThread& thread,
|
||||
uint8_t* stack_copy) {
|
||||
#if defined(__x86_64)
|
||||
uint64_t bp = cpu->rbp;
|
||||
uint64_t top = thread.stack.start_of_memory_range;
|
||||
for (int i = 4; i--; ) {
|
||||
if (bp < top ||
|
||||
bp > thread.stack.start_of_memory_range +
|
||||
thread.stack.memory.data_size - sizeof(bp) ||
|
||||
bp & 1) {
|
||||
break;
|
||||
}
|
||||
uint64_t old_top = top;
|
||||
top = bp;
|
||||
uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
|
||||
my_memcpy(&bp, bp_addr, sizeof(bp));
|
||||
if (bp == 0xDEADBEEFDEADBEEFull) {
|
||||
struct {
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rbx;
|
||||
uint64_t deadbeef;
|
||||
uint64_t rbp;
|
||||
uint64_t fakeret;
|
||||
uint64_t ret;
|
||||
/* char redzone[128]; */
|
||||
} seccomp_stackframe;
|
||||
if (top - offsetof(__typeof__(seccomp_stackframe), deadbeef) < old_top ||
|
||||
top - offsetof(__typeof__(seccomp_stackframe), deadbeef) +
|
||||
sizeof(seccomp_stackframe) >
|
||||
thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
|
||||
break;
|
||||
}
|
||||
my_memcpy(&seccomp_stackframe,
|
||||
bp_addr - offsetof(__typeof__(seccomp_stackframe), deadbeef),
|
||||
sizeof(seccomp_stackframe));
|
||||
cpu->rbx = seccomp_stackframe.rbx;
|
||||
cpu->rcx = seccomp_stackframe.rcx;
|
||||
cpu->rdx = seccomp_stackframe.rdx;
|
||||
cpu->rsi = seccomp_stackframe.rsi;
|
||||
cpu->rdi = seccomp_stackframe.rdi;
|
||||
cpu->rbp = seccomp_stackframe.rbp;
|
||||
cpu->rsp = top + 4*sizeof(uint64_t) + 128;
|
||||
cpu->r8 = seccomp_stackframe.r8;
|
||||
cpu->r9 = seccomp_stackframe.r9;
|
||||
cpu->r10 = seccomp_stackframe.r10;
|
||||
cpu->r11 = seccomp_stackframe.r11;
|
||||
cpu->r12 = seccomp_stackframe.r12;
|
||||
cpu->r13 = seccomp_stackframe.r13;
|
||||
cpu->r14 = seccomp_stackframe.r14;
|
||||
cpu->r15 = seccomp_stackframe.r15;
|
||||
cpu->rip = seccomp_stackframe.fakeret;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
uint32_t bp = cpu->ebp;
|
||||
uint32_t top = thread.stack.start_of_memory_range;
|
||||
for (int i = 4; i--; ) {
|
||||
if (bp < top ||
|
||||
bp > thread.stack.start_of_memory_range +
|
||||
thread.stack.memory.data_size - sizeof(bp) ||
|
||||
bp & 1) {
|
||||
break;
|
||||
}
|
||||
uint32_t old_top = top;
|
||||
top = bp;
|
||||
uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
|
||||
my_memcpy(&bp, bp_addr, sizeof(bp));
|
||||
if (bp == 0xDEADBEEFu) {
|
||||
struct {
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t ebx;
|
||||
uint32_t deadbeef;
|
||||
uint32_t ebp;
|
||||
uint32_t fakeret;
|
||||
uint32_t ret;
|
||||
} seccomp_stackframe;
|
||||
if (top - offsetof(__typeof__(seccomp_stackframe), deadbeef) < old_top ||
|
||||
top - offsetof(__typeof__(seccomp_stackframe), deadbeef) +
|
||||
sizeof(seccomp_stackframe) >
|
||||
thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
|
||||
break;
|
||||
}
|
||||
my_memcpy(&seccomp_stackframe,
|
||||
bp_addr - offsetof(__typeof__(seccomp_stackframe), deadbeef),
|
||||
sizeof(seccomp_stackframe));
|
||||
cpu->ebx = seccomp_stackframe.ebx;
|
||||
cpu->ecx = seccomp_stackframe.ecx;
|
||||
cpu->edx = seccomp_stackframe.edx;
|
||||
cpu->esi = seccomp_stackframe.esi;
|
||||
cpu->edi = seccomp_stackframe.edi;
|
||||
cpu->ebp = seccomp_stackframe.ebp;
|
||||
cpu->esp = top + 4*sizeof(void*);
|
||||
cpu->eip = seccomp_stackframe.fakeret;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
50
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/seccomp_unwinder.h
vendored
Normal file
50
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/seccomp_unwinder.h
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
|
||||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
|
||||
|
||||
#include "client/linux/dump_writer_common/raw_context_cpu.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
struct SeccompUnwinder {
|
||||
|
||||
// Check if the top of the stack is part of a system call that has been
|
||||
// redirected by the seccomp sandbox. If so, try to pop the stack frames
|
||||
// all the way back to the point where the interception happened.
|
||||
static void PopSeccompStackFrame(RawContextCPU* cpu,
|
||||
const MDRawThread& thread,
|
||||
uint8_t* stack_copy);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
|
299
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/thread_info.cc
vendored
Normal file
299
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/thread_info.cc
vendored
Normal file
|
@ -0,0 +1,299 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "client/linux/dump_writer_common/thread_info.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(__i386__)
|
||||
// Write a uint16_t to memory
|
||||
// out: memory location to write to
|
||||
// v: value to write.
|
||||
void U16(void* out, uint16_t v) {
|
||||
my_memcpy(out, &v, sizeof(v));
|
||||
}
|
||||
|
||||
// Write a uint32_t to memory
|
||||
// out: memory location to write to
|
||||
// v: value to write.
|
||||
void U32(void* out, uint32_t v) {
|
||||
my_memcpy(out, &v, sizeof(v));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
uintptr_t ThreadInfo::GetInstructionPointer() const {
|
||||
return regs.eip;
|
||||
}
|
||||
|
||||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->context_flags = MD_CONTEXT_X86_ALL;
|
||||
|
||||
out->dr0 = dregs[0];
|
||||
out->dr1 = dregs[1];
|
||||
out->dr2 = dregs[2];
|
||||
out->dr3 = dregs[3];
|
||||
// 4 and 5 deliberatly omitted because they aren't included in the minidump
|
||||
// format.
|
||||
out->dr6 = dregs[6];
|
||||
out->dr7 = dregs[7];
|
||||
|
||||
out->gs = regs.xgs;
|
||||
out->fs = regs.xfs;
|
||||
out->es = regs.xes;
|
||||
out->ds = regs.xds;
|
||||
|
||||
out->edi = regs.edi;
|
||||
out->esi = regs.esi;
|
||||
out->ebx = regs.ebx;
|
||||
out->edx = regs.edx;
|
||||
out->ecx = regs.ecx;
|
||||
out->eax = regs.eax;
|
||||
|
||||
out->ebp = regs.ebp;
|
||||
out->eip = regs.eip;
|
||||
out->cs = regs.xcs;
|
||||
out->eflags = regs.eflags;
|
||||
out->esp = regs.esp;
|
||||
out->ss = regs.xss;
|
||||
|
||||
out->float_save.control_word = fpregs.cwd;
|
||||
out->float_save.status_word = fpregs.swd;
|
||||
out->float_save.tag_word = fpregs.twd;
|
||||
out->float_save.error_offset = fpregs.fip;
|
||||
out->float_save.error_selector = fpregs.fcs;
|
||||
out->float_save.data_offset = fpregs.foo;
|
||||
out->float_save.data_selector = fpregs.fos;
|
||||
|
||||
// 8 registers * 10 bytes per register.
|
||||
my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8);
|
||||
|
||||
// This matches the Intel fpsave format.
|
||||
U16(out->extended_registers + 0, fpregs.cwd);
|
||||
U16(out->extended_registers + 2, fpregs.swd);
|
||||
U16(out->extended_registers + 4, fpregs.twd);
|
||||
U16(out->extended_registers + 6, fpxregs.fop);
|
||||
U32(out->extended_registers + 8, fpxregs.fip);
|
||||
U16(out->extended_registers + 12, fpxregs.fcs);
|
||||
U32(out->extended_registers + 16, fpregs.foo);
|
||||
U16(out->extended_registers + 20, fpregs.fos);
|
||||
U32(out->extended_registers + 24, fpxregs.mxcsr);
|
||||
|
||||
my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128);
|
||||
my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128);
|
||||
}
|
||||
|
||||
#elif defined(__x86_64)
|
||||
|
||||
uintptr_t ThreadInfo::GetInstructionPointer() const {
|
||||
return regs.rip;
|
||||
}
|
||||
|
||||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->context_flags = MD_CONTEXT_AMD64_FULL |
|
||||
MD_CONTEXT_AMD64_SEGMENTS;
|
||||
|
||||
out->cs = regs.cs;
|
||||
|
||||
out->ds = regs.ds;
|
||||
out->es = regs.es;
|
||||
out->fs = regs.fs;
|
||||
out->gs = regs.gs;
|
||||
|
||||
out->ss = regs.ss;
|
||||
out->eflags = regs.eflags;
|
||||
|
||||
out->dr0 = dregs[0];
|
||||
out->dr1 = dregs[1];
|
||||
out->dr2 = dregs[2];
|
||||
out->dr3 = dregs[3];
|
||||
// 4 and 5 deliberatly omitted because they aren't included in the minidump
|
||||
// format.
|
||||
out->dr6 = dregs[6];
|
||||
out->dr7 = dregs[7];
|
||||
|
||||
out->rax = regs.rax;
|
||||
out->rcx = regs.rcx;
|
||||
out->rdx = regs.rdx;
|
||||
out->rbx = regs.rbx;
|
||||
|
||||
out->rsp = regs.rsp;
|
||||
|
||||
out->rbp = regs.rbp;
|
||||
out->rsi = regs.rsi;
|
||||
out->rdi = regs.rdi;
|
||||
out->r8 = regs.r8;
|
||||
out->r9 = regs.r9;
|
||||
out->r10 = regs.r10;
|
||||
out->r11 = regs.r11;
|
||||
out->r12 = regs.r12;
|
||||
out->r13 = regs.r13;
|
||||
out->r14 = regs.r14;
|
||||
out->r15 = regs.r15;
|
||||
|
||||
out->rip = regs.rip;
|
||||
|
||||
out->flt_save.control_word = fpregs.cwd;
|
||||
out->flt_save.status_word = fpregs.swd;
|
||||
out->flt_save.tag_word = fpregs.ftw;
|
||||
out->flt_save.error_opcode = fpregs.fop;
|
||||
out->flt_save.error_offset = fpregs.rip;
|
||||
out->flt_save.error_selector = 0; // We don't have this.
|
||||
out->flt_save.data_offset = fpregs.rdp;
|
||||
out->flt_save.data_selector = 0; // We don't have this.
|
||||
out->flt_save.mx_csr = fpregs.mxcsr;
|
||||
out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
|
||||
|
||||
my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
|
||||
my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
|
||||
}
|
||||
|
||||
#elif defined(__ARM_EABI__)
|
||||
|
||||
uintptr_t ThreadInfo::GetInstructionPointer() const {
|
||||
return regs.uregs[15];
|
||||
}
|
||||
|
||||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->context_flags = MD_CONTEXT_ARM_FULL;
|
||||
|
||||
for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
|
||||
out->iregs[i] = regs.uregs[i];
|
||||
// No CPSR register in ThreadInfo(it's not accessible via ptrace)
|
||||
out->cpsr = 0;
|
||||
#if !defined(__ANDROID__)
|
||||
out->float_save.fpscr = fpregs.fpsr |
|
||||
(static_cast<uint64_t>(fpregs.fpcr) << 32);
|
||||
// TODO: sort this out, actually collect floating point registers
|
||||
my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
|
||||
my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
uintptr_t ThreadInfo::GetInstructionPointer() const {
|
||||
return regs.pc;
|
||||
}
|
||||
|
||||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->context_flags = MD_CONTEXT_ARM64_FULL;
|
||||
|
||||
out->cpsr = static_cast<uint32_t>(regs.pstate);
|
||||
for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
|
||||
out->iregs[i] = regs.regs[i];
|
||||
out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp;
|
||||
out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc;
|
||||
|
||||
out->float_save.fpsr = fpregs.fpsr;
|
||||
out->float_save.fpcr = fpregs.fpcr;
|
||||
my_memcpy(&out->float_save.regs, &fpregs.vregs,
|
||||
MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
|
||||
}
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
uintptr_t ThreadInfo::GetInstructionPointer() const {
|
||||
return mcontext.pc;
|
||||
}
|
||||
|
||||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->context_flags = MD_CONTEXT_MIPS_FULL;
|
||||
|
||||
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
|
||||
out->iregs[i] = mcontext.gregs[i];
|
||||
|
||||
out->mdhi = mcontext.mdhi;
|
||||
out->mdlo = mcontext.mdlo;
|
||||
out->dsp_control = mcontext.dsp;
|
||||
|
||||
out->hi[0] = mcontext.hi1;
|
||||
out->lo[0] = mcontext.lo1;
|
||||
out->hi[1] = mcontext.hi2;
|
||||
out->lo[1] = mcontext.lo2;
|
||||
out->hi[2] = mcontext.hi3;
|
||||
out->lo[2] = mcontext.lo3;
|
||||
|
||||
out->epc = mcontext.pc;
|
||||
out->badvaddr = 0; // Not stored in mcontext
|
||||
out->status = 0; // Not stored in mcontext
|
||||
out->cause = 0; // Not stored in mcontext
|
||||
|
||||
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
|
||||
out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs;
|
||||
|
||||
out->float_save.fpcsr = mcontext.fpc_csr;
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
out->float_save.fir = mcontext.fpc_eir;
|
||||
#endif
|
||||
}
|
||||
#endif // __mips__
|
||||
|
||||
void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
|
||||
assert(gp_regs || size);
|
||||
#if defined(__mips__)
|
||||
if (gp_regs)
|
||||
*gp_regs = mcontext.gregs;
|
||||
if (size)
|
||||
*size = sizeof(mcontext.gregs);
|
||||
#else
|
||||
if (gp_regs)
|
||||
*gp_regs = ®s;
|
||||
if (size)
|
||||
*size = sizeof(regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
|
||||
assert(fp_regs || size);
|
||||
#if defined(__mips__)
|
||||
if (fp_regs)
|
||||
*fp_regs = &mcontext.fpregs;
|
||||
if (size)
|
||||
*size = sizeof(mcontext.fpregs);
|
||||
#else
|
||||
if (fp_regs)
|
||||
*fp_regs = &fpregs;
|
||||
if (size)
|
||||
*size = sizeof(fpregs);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
91
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/thread_info.h
vendored
Normal file
91
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/thread_info.h
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
|
||||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "client/linux/dump_writer_common/raw_context_cpu.h"
|
||||
#include "common/memory.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
typedef __typeof__(((struct user*) 0)->u_debugreg[0]) debugreg_t;
|
||||
#endif
|
||||
|
||||
// We produce one of these structures for each thread in the crashed process.
|
||||
struct ThreadInfo {
|
||||
pid_t tgid; // thread group id
|
||||
pid_t ppid; // parent process
|
||||
|
||||
uintptr_t stack_pointer; // thread stack pointer
|
||||
|
||||
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
user_regs_struct regs;
|
||||
user_fpregs_struct fpregs;
|
||||
static const unsigned kNumDebugRegisters = 8;
|
||||
debugreg_t dregs[8];
|
||||
#if defined(__i386)
|
||||
user_fpxregs_struct fpxregs;
|
||||
#endif // defined(__i386)
|
||||
|
||||
#elif defined(__ARM_EABI__)
|
||||
// Mimicking how strace does this(see syscall.c, search for GETREGS)
|
||||
struct user_regs regs;
|
||||
struct user_fpregs fpregs;
|
||||
#elif defined(__aarch64__)
|
||||
// Use the structures defined in <asm/ptrace.h>
|
||||
struct user_pt_regs regs;
|
||||
struct user_fpsimd_state fpregs;
|
||||
#elif defined(__mips__)
|
||||
// Use the structure defined in <sys/ucontext.h>.
|
||||
mcontext_t mcontext;
|
||||
#endif
|
||||
|
||||
// Returns the instruction pointer (platform-dependent impl.).
|
||||
uintptr_t GetInstructionPointer() const;
|
||||
|
||||
// Fills a RawContextCPU using the context in the ThreadInfo object.
|
||||
void FillCPUContext(RawContextCPU* out) const;
|
||||
|
||||
// Returns the pointer and size of general purpose register area.
|
||||
void GetGeneralPurposeRegisters(void** gp_regs, size_t* size);
|
||||
|
||||
// Returns the pointer and size of float point register area.
|
||||
void GetFloatingPointRegisters(void** fp_regs, size_t* size);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
|
253
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
vendored
Normal file
253
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
vendored
Normal file
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "client/linux/dump_writer_common/ucontext_reader.h"
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Minidump defines register structures which are different from the raw
|
||||
// structures which we get from the kernel. These are platform specific
|
||||
// functions to juggle the ucontext and user structures into minidump format.
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.gregs[REG_ESP];
|
||||
}
|
||||
|
||||
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.gregs[REG_EIP];
|
||||
}
|
||||
|
||||
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
|
||||
const struct _libc_fpstate* fp) {
|
||||
const greg_t* regs = uc->uc_mcontext.gregs;
|
||||
|
||||
out->context_flags = MD_CONTEXT_X86_FULL |
|
||||
MD_CONTEXT_X86_FLOATING_POINT;
|
||||
|
||||
out->gs = regs[REG_GS];
|
||||
out->fs = regs[REG_FS];
|
||||
out->es = regs[REG_ES];
|
||||
out->ds = regs[REG_DS];
|
||||
|
||||
out->edi = regs[REG_EDI];
|
||||
out->esi = regs[REG_ESI];
|
||||
out->ebx = regs[REG_EBX];
|
||||
out->edx = regs[REG_EDX];
|
||||
out->ecx = regs[REG_ECX];
|
||||
out->eax = regs[REG_EAX];
|
||||
|
||||
out->ebp = regs[REG_EBP];
|
||||
out->eip = regs[REG_EIP];
|
||||
out->cs = regs[REG_CS];
|
||||
out->eflags = regs[REG_EFL];
|
||||
out->esp = regs[REG_UESP];
|
||||
out->ss = regs[REG_SS];
|
||||
|
||||
out->float_save.control_word = fp->cw;
|
||||
out->float_save.status_word = fp->sw;
|
||||
out->float_save.tag_word = fp->tag;
|
||||
out->float_save.error_offset = fp->ipoff;
|
||||
out->float_save.error_selector = fp->cssel;
|
||||
out->float_save.data_offset = fp->dataoff;
|
||||
out->float_save.data_selector = fp->datasel;
|
||||
|
||||
// 8 registers * 10 bytes per register.
|
||||
my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
|
||||
}
|
||||
|
||||
#elif defined(__x86_64)
|
||||
|
||||
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.gregs[REG_RSP];
|
||||
}
|
||||
|
||||
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.gregs[REG_RIP];
|
||||
}
|
||||
|
||||
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
|
||||
const struct _libc_fpstate* fpregs) {
|
||||
const greg_t* regs = uc->uc_mcontext.gregs;
|
||||
|
||||
out->context_flags = MD_CONTEXT_AMD64_FULL;
|
||||
|
||||
out->cs = regs[REG_CSGSFS] & 0xffff;
|
||||
|
||||
out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
|
||||
out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
|
||||
|
||||
out->eflags = regs[REG_EFL];
|
||||
|
||||
out->rax = regs[REG_RAX];
|
||||
out->rcx = regs[REG_RCX];
|
||||
out->rdx = regs[REG_RDX];
|
||||
out->rbx = regs[REG_RBX];
|
||||
|
||||
out->rsp = regs[REG_RSP];
|
||||
out->rbp = regs[REG_RBP];
|
||||
out->rsi = regs[REG_RSI];
|
||||
out->rdi = regs[REG_RDI];
|
||||
out->r8 = regs[REG_R8];
|
||||
out->r9 = regs[REG_R9];
|
||||
out->r10 = regs[REG_R10];
|
||||
out->r11 = regs[REG_R11];
|
||||
out->r12 = regs[REG_R12];
|
||||
out->r13 = regs[REG_R13];
|
||||
out->r14 = regs[REG_R14];
|
||||
out->r15 = regs[REG_R15];
|
||||
|
||||
out->rip = regs[REG_RIP];
|
||||
|
||||
out->flt_save.control_word = fpregs->cwd;
|
||||
out->flt_save.status_word = fpregs->swd;
|
||||
out->flt_save.tag_word = fpregs->ftw;
|
||||
out->flt_save.error_opcode = fpregs->fop;
|
||||
out->flt_save.error_offset = fpregs->rip;
|
||||
out->flt_save.data_offset = fpregs->rdp;
|
||||
out->flt_save.error_selector = 0; // We don't have this.
|
||||
out->flt_save.data_selector = 0; // We don't have this.
|
||||
out->flt_save.mx_csr = fpregs->mxcsr;
|
||||
out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
|
||||
my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
|
||||
my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
|
||||
}
|
||||
|
||||
#elif defined(__ARM_EABI__)
|
||||
|
||||
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.arm_sp;
|
||||
}
|
||||
|
||||
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.arm_pc;
|
||||
}
|
||||
|
||||
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
|
||||
out->context_flags = MD_CONTEXT_ARM_FULL;
|
||||
|
||||
out->iregs[0] = uc->uc_mcontext.arm_r0;
|
||||
out->iregs[1] = uc->uc_mcontext.arm_r1;
|
||||
out->iregs[2] = uc->uc_mcontext.arm_r2;
|
||||
out->iregs[3] = uc->uc_mcontext.arm_r3;
|
||||
out->iregs[4] = uc->uc_mcontext.arm_r4;
|
||||
out->iregs[5] = uc->uc_mcontext.arm_r5;
|
||||
out->iregs[6] = uc->uc_mcontext.arm_r6;
|
||||
out->iregs[7] = uc->uc_mcontext.arm_r7;
|
||||
out->iregs[8] = uc->uc_mcontext.arm_r8;
|
||||
out->iregs[9] = uc->uc_mcontext.arm_r9;
|
||||
out->iregs[10] = uc->uc_mcontext.arm_r10;
|
||||
|
||||
out->iregs[11] = uc->uc_mcontext.arm_fp;
|
||||
out->iregs[12] = uc->uc_mcontext.arm_ip;
|
||||
out->iregs[13] = uc->uc_mcontext.arm_sp;
|
||||
out->iregs[14] = uc->uc_mcontext.arm_lr;
|
||||
out->iregs[15] = uc->uc_mcontext.arm_pc;
|
||||
|
||||
out->cpsr = uc->uc_mcontext.arm_cpsr;
|
||||
|
||||
// TODO: fix this after fixing ExceptionHandler
|
||||
out->float_save.fpscr = 0;
|
||||
my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
|
||||
my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.sp;
|
||||
}
|
||||
|
||||
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.pc;
|
||||
}
|
||||
|
||||
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
|
||||
const struct fpsimd_context* fpregs) {
|
||||
out->context_flags = MD_CONTEXT_ARM64_FULL;
|
||||
|
||||
out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
|
||||
for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
|
||||
out->iregs[i] = uc->uc_mcontext.regs[i];
|
||||
out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp;
|
||||
out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc;
|
||||
|
||||
out->float_save.fpsr = fpregs->fpsr;
|
||||
out->float_save.fpcr = fpregs->fpcr;
|
||||
my_memcpy(&out->float_save.regs, &fpregs->vregs,
|
||||
MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
|
||||
}
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
|
||||
}
|
||||
|
||||
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
|
||||
return uc->uc_mcontext.pc;
|
||||
}
|
||||
|
||||
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
|
||||
out->context_flags = MD_CONTEXT_MIPS_FULL;
|
||||
|
||||
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
|
||||
out->iregs[i] = uc->uc_mcontext.gregs[i];
|
||||
|
||||
out->mdhi = uc->uc_mcontext.mdhi;
|
||||
out->mdlo = uc->uc_mcontext.mdlo;
|
||||
|
||||
out->hi[0] = uc->uc_mcontext.hi1;
|
||||
out->hi[1] = uc->uc_mcontext.hi2;
|
||||
out->hi[2] = uc->uc_mcontext.hi3;
|
||||
out->lo[0] = uc->uc_mcontext.lo1;
|
||||
out->lo[1] = uc->uc_mcontext.lo2;
|
||||
out->lo[2] = uc->uc_mcontext.lo3;
|
||||
out->dsp_control = uc->uc_mcontext.dsp;
|
||||
|
||||
out->epc = uc->uc_mcontext.pc;
|
||||
out->badvaddr = 0; // Not reported in signal context.
|
||||
out->status = 0; // Not reported in signal context.
|
||||
out->cause = 0; // Not reported in signal context.
|
||||
|
||||
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
|
||||
out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
|
||||
|
||||
out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace google_breakpad
|
64
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/ucontext_reader.h
vendored
Normal file
64
TMessagesProj/jni/third_party/breakpad/src/client/linux/dump_writer_common/ucontext_reader.h
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
|
||||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "client/linux/dump_writer_common/raw_context_cpu.h"
|
||||
#include "common/memory.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Wraps platform-dependent implementations of accessors to ucontext structs.
|
||||
struct UContextReader {
|
||||
static uintptr_t GetStackPointer(const struct ucontext* uc);
|
||||
|
||||
static uintptr_t GetInstructionPointer(const struct ucontext* uc);
|
||||
|
||||
// Juggle a arch-specific ucontext into a minidump format
|
||||
// out: the minidump structure
|
||||
// info: the collection of register structures.
|
||||
#if defined(__i386__) || defined(__x86_64)
|
||||
static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
|
||||
const struct _libc_fpstate* fp);
|
||||
#elif defined(__aarch64__)
|
||||
static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
|
||||
const struct fpsimd_context* fpregs);
|
||||
#else
|
||||
static void FillCPUContext(RawContextCPU *out, const ucontext *uc);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
|
743
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/exception_handler.cc
vendored
Normal file
743
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/exception_handler.cc
vendored
Normal file
|
@ -0,0 +1,743 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The ExceptionHandler object installs signal handlers for a number of
|
||||
// signals. We rely on the signal handler running on the thread which crashed
|
||||
// in order to identify it. This is true of the synchronous signals (SEGV etc),
|
||||
// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
|
||||
// uses ExceptionHandler, you need to use tgkill to direct it to the current
|
||||
// thread.
|
||||
//
|
||||
// The signal flow looks like this:
|
||||
//
|
||||
// SignalHandler (uses a global stack of ExceptionHandler objects to find
|
||||
// | one to handle the signal. If the first rejects it, try
|
||||
// | the second etc...)
|
||||
// V
|
||||
// HandleSignal ----------------------------| (clones a new process which
|
||||
// | | shares an address space with
|
||||
// (wait for cloned | the crashed process. This
|
||||
// process) | allows us to ptrace the crashed
|
||||
// | | process)
|
||||
// V V
|
||||
// (set signal handler to ThreadEntry (static function to bounce
|
||||
// SIG_DFL and rethrow, | back into the object)
|
||||
// killing the crashed |
|
||||
// process) V
|
||||
// DoDump (writes minidump)
|
||||
// |
|
||||
// V
|
||||
// sys_exit
|
||||
//
|
||||
|
||||
// This code is a little fragmented. Different functions of the ExceptionHandler
|
||||
// class run in a number of different contexts. Some of them run in a normal
|
||||
// context and are easy to code, others run in a compromised context and the
|
||||
// restrictions at the top of minidump_writer.cc apply: no libc and use the
|
||||
// alternative malloc. Each function should have comment above it detailing the
|
||||
// context which it runs in.
|
||||
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/limits.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/signal.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/user.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/basictypes.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/memory.h"
|
||||
#include "client/linux/log/log.h"
|
||||
#include "client/linux/microdump_writer/microdump_writer.h"
|
||||
#include "client/linux/minidump_writer/linux_dumper.h"
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include "linux/sched.h"
|
||||
#endif
|
||||
|
||||
#ifndef PR_SET_PTRACER
|
||||
#define PR_SET_PTRACER 0x59616d61
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
// The list of signals which we consider to be crashes. The default action for
|
||||
// all these signals must be Core (see man 7 signal) because we rethrow the
|
||||
// signal after handling it and expect that it'll be fatal.
|
||||
const int kExceptionSignals[] = {
|
||||
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS
|
||||
};
|
||||
const int kNumHandledSignals =
|
||||
sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]);
|
||||
struct sigaction old_handlers[kNumHandledSignals];
|
||||
bool handlers_installed = false;
|
||||
|
||||
// InstallAlternateStackLocked will store the newly installed stack in new_stack
|
||||
// and (if it exists) the previously installed stack in old_stack.
|
||||
stack_t old_stack;
|
||||
stack_t new_stack;
|
||||
bool stack_installed = false;
|
||||
|
||||
// Create an alternative stack to run the signal handlers on. This is done since
|
||||
// the signal might have been caused by a stack overflow.
|
||||
// Runs before crashing: normal context.
|
||||
void InstallAlternateStackLocked() {
|
||||
if (stack_installed)
|
||||
return;
|
||||
|
||||
memset(&old_stack, 0, sizeof(old_stack));
|
||||
memset(&new_stack, 0, sizeof(new_stack));
|
||||
|
||||
// SIGSTKSZ may be too small to prevent the signal handlers from overrunning
|
||||
// the alternative stack. Ensure that the size of the alternative stack is
|
||||
// large enough.
|
||||
static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ);
|
||||
|
||||
// Only set an alternative stack if there isn't already one, or if the current
|
||||
// one is too small.
|
||||
if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp ||
|
||||
old_stack.ss_size < kSigStackSize) {
|
||||
new_stack.ss_sp = calloc(1, kSigStackSize);
|
||||
new_stack.ss_size = kSigStackSize;
|
||||
|
||||
if (sys_sigaltstack(&new_stack, NULL) == -1) {
|
||||
free(new_stack.ss_sp);
|
||||
return;
|
||||
}
|
||||
stack_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Runs before crashing: normal context.
|
||||
void RestoreAlternateStackLocked() {
|
||||
if (!stack_installed)
|
||||
return;
|
||||
|
||||
stack_t current_stack;
|
||||
if (sys_sigaltstack(NULL, ¤t_stack) == -1)
|
||||
return;
|
||||
|
||||
// Only restore the old_stack if the current alternative stack is the one
|
||||
// installed by the call to InstallAlternateStackLocked.
|
||||
if (current_stack.ss_sp == new_stack.ss_sp) {
|
||||
if (old_stack.ss_sp) {
|
||||
if (sys_sigaltstack(&old_stack, NULL) == -1)
|
||||
return;
|
||||
} else {
|
||||
stack_t disable_stack;
|
||||
disable_stack.ss_flags = SS_DISABLE;
|
||||
if (sys_sigaltstack(&disable_stack, NULL) == -1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
free(new_stack.ss_sp);
|
||||
stack_installed = false;
|
||||
}
|
||||
|
||||
void InstallDefaultHandler(int sig) {
|
||||
#if defined(__ANDROID__)
|
||||
// Android L+ expose signal and sigaction symbols that override the system
|
||||
// ones. There is a bug in these functions where a request to set the handler
|
||||
// to SIG_DFL is ignored. In that case, an infinite loop is entered as the
|
||||
// signal is repeatedly sent to breakpad's signal handler.
|
||||
// To work around this, directly call the system's sigaction.
|
||||
struct kernel_sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sys_sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler_ = SIG_DFL;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t));
|
||||
#else
|
||||
signal(sig, SIG_DFL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The global exception handler stack. This is needed because there may exist
|
||||
// multiple ExceptionHandler instances in a process. Each will have itself
|
||||
// registered in this stack.
|
||||
std::vector<ExceptionHandler*>* g_handler_stack_ = NULL;
|
||||
pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
} // namespace
|
||||
|
||||
// Runs before crashing: normal context.
|
||||
ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
bool install_handler,
|
||||
const int server_fd)
|
||||
: filter_(filter),
|
||||
callback_(callback),
|
||||
callback_context_(callback_context),
|
||||
minidump_descriptor_(descriptor),
|
||||
crash_handler_(NULL) {
|
||||
if (server_fd >= 0)
|
||||
crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd));
|
||||
|
||||
if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() &&
|
||||
!minidump_descriptor_.IsMicrodumpOnConsole())
|
||||
minidump_descriptor_.UpdatePath();
|
||||
|
||||
pthread_mutex_lock(&g_handler_stack_mutex_);
|
||||
if (!g_handler_stack_)
|
||||
g_handler_stack_ = new std::vector<ExceptionHandler*>;
|
||||
if (install_handler) {
|
||||
InstallAlternateStackLocked();
|
||||
InstallHandlersLocked();
|
||||
}
|
||||
g_handler_stack_->push_back(this);
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
}
|
||||
|
||||
// Runs before crashing: normal context.
|
||||
ExceptionHandler::~ExceptionHandler() {
|
||||
pthread_mutex_lock(&g_handler_stack_mutex_);
|
||||
std::vector<ExceptionHandler*>::iterator handler =
|
||||
std::find(g_handler_stack_->begin(), g_handler_stack_->end(), this);
|
||||
g_handler_stack_->erase(handler);
|
||||
if (g_handler_stack_->empty()) {
|
||||
delete g_handler_stack_;
|
||||
g_handler_stack_ = NULL;
|
||||
RestoreAlternateStackLocked();
|
||||
RestoreHandlersLocked();
|
||||
}
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
}
|
||||
|
||||
// Runs before crashing: normal context.
|
||||
// static
|
||||
bool ExceptionHandler::InstallHandlersLocked() {
|
||||
if (handlers_installed)
|
||||
return false;
|
||||
|
||||
// Fail if unable to store all the old handlers.
|
||||
for (int i = 0; i < kNumHandledSignals; ++i) {
|
||||
if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
// Mask all exception signals when we're handling one of them.
|
||||
for (int i = 0; i < kNumHandledSignals; ++i)
|
||||
sigaddset(&sa.sa_mask, kExceptionSignals[i]);
|
||||
|
||||
sa.sa_sigaction = SignalHandler;
|
||||
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
||||
|
||||
for (int i = 0; i < kNumHandledSignals; ++i) {
|
||||
if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) {
|
||||
// At this point it is impractical to back out changes, and so failure to
|
||||
// install a signal is intentionally ignored.
|
||||
}
|
||||
}
|
||||
handlers_installed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
// Runs on the crashing thread.
|
||||
// static
|
||||
void ExceptionHandler::RestoreHandlersLocked() {
|
||||
if (!handlers_installed)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < kNumHandledSignals; ++i) {
|
||||
if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
|
||||
InstallDefaultHandler(kExceptionSignals[i]);
|
||||
}
|
||||
}
|
||||
handlers_installed = false;
|
||||
}
|
||||
|
||||
// void ExceptionHandler::set_crash_handler(HandlerCallback callback) {
|
||||
// crash_handler_ = callback;
|
||||
// }
|
||||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
// Runs on the crashing thread.
|
||||
// static
|
||||
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
// All the exception signals are blocked at this point.
|
||||
pthread_mutex_lock(&g_handler_stack_mutex_);
|
||||
|
||||
// Sometimes, Breakpad runs inside a process where some other buggy code
|
||||
// saves and restores signal handlers temporarily with 'signal'
|
||||
// instead of 'sigaction'. This loses the SA_SIGINFO flag associated
|
||||
// with this function. As a consequence, the values of 'info' and 'uc'
|
||||
// become totally bogus, generally inducing a crash.
|
||||
//
|
||||
// The following code tries to detect this case. When it does, it
|
||||
// resets the signal handlers with sigaction + SA_SIGINFO and returns.
|
||||
// This forces the signal to be thrown again, but this time the kernel
|
||||
// will call the function with the right arguments.
|
||||
struct sigaction cur_handler;
|
||||
if (sigaction(sig, NULL, &cur_handler) == 0 &&
|
||||
(cur_handler.sa_flags & SA_SIGINFO) == 0) {
|
||||
// Reset signal handler with the right flags.
|
||||
sigemptyset(&cur_handler.sa_mask);
|
||||
sigaddset(&cur_handler.sa_mask, sig);
|
||||
|
||||
cur_handler.sa_sigaction = SignalHandler;
|
||||
cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
||||
|
||||
if (sigaction(sig, &cur_handler, NULL) == -1) {
|
||||
// When resetting the handler fails, try to reset the
|
||||
// default one to avoid an infinite loop here.
|
||||
InstallDefaultHandler(sig);
|
||||
}
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
return;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
for (int i = g_handler_stack_->size() - 1; !handled && i >= 0; --i) {
|
||||
handled = (*g_handler_stack_)[i]->HandleSignal(sig, info, uc);
|
||||
}
|
||||
|
||||
// Upon returning from this signal handler, sig will become unmasked and then
|
||||
// it will be retriggered. If one of the ExceptionHandlers handled it
|
||||
// successfully, restore the default handler. Otherwise, restore the
|
||||
// previously installed handler. Then, when the signal is retriggered, it will
|
||||
// be delivered to the appropriate handler.
|
||||
if (handled) {
|
||||
InstallDefaultHandler(sig);
|
||||
} else {
|
||||
RestoreHandlersLocked();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
|
||||
// info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
|
||||
if (info->si_code <= 0 || sig == SIGABRT) {
|
||||
// This signal was triggered by somebody sending us the signal with kill().
|
||||
// In order to retrigger it, we have to queue a new signal by calling
|
||||
// kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
|
||||
// due to the kernel sending a SIGABRT from a user request via SysRQ.
|
||||
if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) {
|
||||
// If we failed to kill ourselves (e.g. because a sandbox disallows us
|
||||
// to do so), we instead resort to terminating our process. This will
|
||||
// result in an incorrect exit code.
|
||||
_exit(1);
|
||||
}
|
||||
} else {
|
||||
// This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV).
|
||||
// No need to reissue the signal. It will automatically trigger again,
|
||||
// when we return from the signal handler.
|
||||
}
|
||||
}
|
||||
|
||||
struct ThreadArgument {
|
||||
pid_t pid; // the crashing process
|
||||
const MinidumpDescriptor* minidump_descriptor;
|
||||
ExceptionHandler* handler;
|
||||
const void* context; // a CrashContext structure
|
||||
size_t context_size;
|
||||
};
|
||||
|
||||
// This is the entry function for the cloned process. We are in a compromised
|
||||
// context here: see the top of the file.
|
||||
// static
|
||||
int ExceptionHandler::ThreadEntry(void *arg) {
|
||||
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
|
||||
|
||||
// Block here until the crashing process unblocks us when
|
||||
// we're allowed to use ptrace
|
||||
thread_arg->handler->WaitForContinueSignal();
|
||||
|
||||
return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
|
||||
thread_arg->context_size) == false;
|
||||
}
|
||||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
// Runs on the crashing thread.
|
||||
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
|
||||
// Allow ourselves to be dumped if the signal is trusted.
|
||||
bool signal_trusted = info->si_code > 0;
|
||||
bool signal_pid_trusted = info->si_code == SI_USER ||
|
||||
info->si_code == SI_TKILL;
|
||||
if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) {
|
||||
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
}
|
||||
CrashContext context;
|
||||
// Fill in all the holes in the struct to make Valgrind happy.
|
||||
memset(&context, 0, sizeof(context));
|
||||
memcpy(&context.siginfo, info, sizeof(siginfo_t));
|
||||
memcpy(&context.context, uc, sizeof(struct ucontext));
|
||||
#if defined(__aarch64__)
|
||||
struct ucontext *uc_ptr = (struct ucontext*)uc;
|
||||
struct fpsimd_context *fp_ptr =
|
||||
(struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved;
|
||||
if (fp_ptr->head.magic == FPSIMD_MAGIC) {
|
||||
memcpy(&context.float_state, fp_ptr, sizeof(context.float_state));
|
||||
}
|
||||
#elif !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
// FP state is not part of user ABI on ARM Linux.
|
||||
// In case of MIPS Linux FP state is already part of struct ucontext
|
||||
// and 'float_state' is not a member of CrashContext.
|
||||
struct ucontext *uc_ptr = (struct ucontext*)uc;
|
||||
if (uc_ptr->uc_mcontext.fpregs) {
|
||||
memcpy(&context.float_state,
|
||||
uc_ptr->uc_mcontext.fpregs,
|
||||
sizeof(context.float_state));
|
||||
}
|
||||
#endif
|
||||
context.tid = syscall(__NR_gettid);
|
||||
if (crash_handler_ != NULL) {
|
||||
if (crash_handler_(&context, sizeof(context), callback_context_)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return GenerateDump(&context);
|
||||
}
|
||||
|
||||
// This is a public interface to HandleSignal that allows the client to
|
||||
// generate a crash dump. This function may run in a compromised context.
|
||||
bool ExceptionHandler::SimulateSignalDelivery(int sig) {
|
||||
siginfo_t siginfo = {};
|
||||
// Mimic a trusted signal to allow tracing the process (see
|
||||
// ExceptionHandler::HandleSignal().
|
||||
siginfo.si_code = SI_USER;
|
||||
siginfo.si_pid = getpid();
|
||||
struct ucontext context;
|
||||
getcontext(&context);
|
||||
return HandleSignal(sig, &siginfo, &context);
|
||||
}
|
||||
|
||||
// This function may run in a compromised context: see the top of the file.
|
||||
bool ExceptionHandler::GenerateDump(CrashContext *context) {
|
||||
if (IsOutOfProcess())
|
||||
return crash_generation_client_->RequestDump(context, sizeof(*context));
|
||||
|
||||
// Allocating too much stack isn't a problem, and better to err on the side
|
||||
// of caution than smash it into random locations.
|
||||
static const unsigned kChildStackSize = 16000;
|
||||
PageAllocator allocator;
|
||||
uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize));
|
||||
if (!stack)
|
||||
return false;
|
||||
// clone() needs the top-most address. (scrub just to be safe)
|
||||
stack += kChildStackSize;
|
||||
my_memset(stack - 16, 0, 16);
|
||||
|
||||
ThreadArgument thread_arg;
|
||||
thread_arg.handler = this;
|
||||
thread_arg.minidump_descriptor = &minidump_descriptor_;
|
||||
thread_arg.pid = getpid();
|
||||
thread_arg.context = context;
|
||||
thread_arg.context_size = sizeof(*context);
|
||||
|
||||
// We need to explicitly enable ptrace of parent processes on some
|
||||
// kernels, but we need to know the PID of the cloned process before we
|
||||
// can do this. Create a pipe here which we can use to block the
|
||||
// cloned process after creating it, until we have explicitly enabled ptrace
|
||||
if (sys_pipe(fdes) == -1) {
|
||||
// Creating the pipe failed. We'll log an error but carry on anyway,
|
||||
// as we'll probably still get a useful crash report. All that will happen
|
||||
// is the write() and read() calls will fail with EBADF
|
||||
static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump "
|
||||
"sys_pipe failed:";
|
||||
logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1);
|
||||
logger::write(strerror(errno), strlen(strerror(errno)));
|
||||
logger::write("\n", 1);
|
||||
|
||||
// Ensure fdes[0] and fdes[1] are invalid file descriptors.
|
||||
fdes[0] = fdes[1] = -1;
|
||||
}
|
||||
|
||||
const pid_t child = sys_clone(
|
||||
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
|
||||
&thread_arg, NULL, NULL, NULL);
|
||||
if (child == -1) {
|
||||
sys_close(fdes[0]);
|
||||
sys_close(fdes[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow the child to ptrace us
|
||||
sys_prctl(PR_SET_PTRACER, child, 0, 0, 0);
|
||||
SendContinueSignalToChild();
|
||||
int status;
|
||||
const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL));
|
||||
|
||||
sys_close(fdes[0]);
|
||||
sys_close(fdes[1]);
|
||||
|
||||
if (r == -1) {
|
||||
static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:";
|
||||
logger::write(msg, sizeof(msg) - 1);
|
||||
logger::write(strerror(errno), strlen(strerror(errno)));
|
||||
logger::write("\n", 1);
|
||||
}
|
||||
|
||||
bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
if (callback_)
|
||||
success = callback_(minidump_descriptor_, callback_context_, success);
|
||||
return success;
|
||||
}
|
||||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
void ExceptionHandler::SendContinueSignalToChild() {
|
||||
static const char okToContinueMessage = 'a';
|
||||
int r;
|
||||
r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char)));
|
||||
if (r == -1) {
|
||||
static const char msg[] = "ExceptionHandler::SendContinueSignalToChild "
|
||||
"sys_write failed:";
|
||||
logger::write(msg, sizeof(msg) - 1);
|
||||
logger::write(strerror(errno), strlen(strerror(errno)));
|
||||
logger::write("\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
// Runs on the cloned process.
|
||||
void ExceptionHandler::WaitForContinueSignal() {
|
||||
int r;
|
||||
char receivedMessage;
|
||||
r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char)));
|
||||
if (r == -1) {
|
||||
static const char msg[] = "ExceptionHandler::WaitForContinueSignal "
|
||||
"sys_read failed:";
|
||||
logger::write(msg, sizeof(msg) - 1);
|
||||
logger::write(strerror(errno), strlen(strerror(errno)));
|
||||
logger::write("\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
// This function runs in a compromised context: see the top of the file.
|
||||
// Runs on the cloned process.
|
||||
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
|
||||
size_t context_size) {
|
||||
if (minidump_descriptor_.IsMicrodumpOnConsole()) {
|
||||
return google_breakpad::WriteMicrodump(
|
||||
crashing_process,
|
||||
context,
|
||||
context_size,
|
||||
mapping_list_,
|
||||
minidump_descriptor_.microdump_build_fingerprint(),
|
||||
minidump_descriptor_.microdump_product_info());
|
||||
}
|
||||
if (minidump_descriptor_.IsFD()) {
|
||||
return google_breakpad::WriteMinidump(minidump_descriptor_.fd(),
|
||||
minidump_descriptor_.size_limit(),
|
||||
crashing_process,
|
||||
context,
|
||||
context_size,
|
||||
mapping_list_,
|
||||
app_memory_list_);
|
||||
}
|
||||
return google_breakpad::WriteMinidump(minidump_descriptor_.path(),
|
||||
minidump_descriptor_.size_limit(),
|
||||
crashing_process,
|
||||
context,
|
||||
context_size,
|
||||
mapping_list_,
|
||||
app_memory_list_);
|
||||
}
|
||||
|
||||
// static
|
||||
bool ExceptionHandler::WriteMinidump(const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context) {
|
||||
MinidumpDescriptor descriptor(dump_path);
|
||||
ExceptionHandler eh(descriptor, NULL, callback, callback_context, false, -1);
|
||||
return eh.WriteMinidump();
|
||||
}
|
||||
|
||||
// In order to making using EBP to calculate the desired value for ESP
|
||||
// a valid operation, ensure that this function is compiled with a
|
||||
// frame pointer using the following attribute. This attribute
|
||||
// is supported on GCC but not on clang.
|
||||
#if defined(__i386__) && defined(__GNUC__) && !defined(__clang__)
|
||||
__attribute__((optimize("no-omit-frame-pointer")))
|
||||
#endif
|
||||
bool ExceptionHandler::WriteMinidump() {
|
||||
if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() &&
|
||||
!minidump_descriptor_.IsMicrodumpOnConsole()) {
|
||||
// Update the path of the minidump so that this can be called multiple times
|
||||
// and new files are created for each minidump. This is done before the
|
||||
// generation happens, as clients may want to access the MinidumpDescriptor
|
||||
// after this call to find the exact path to the minidump file.
|
||||
minidump_descriptor_.UpdatePath();
|
||||
} else if (minidump_descriptor_.IsFD()) {
|
||||
// Reposition the FD to its beginning and resize it to get rid of the
|
||||
// previous minidump info.
|
||||
lseek(minidump_descriptor_.fd(), 0, SEEK_SET);
|
||||
ignore_result(ftruncate(minidump_descriptor_.fd(), 0));
|
||||
}
|
||||
|
||||
// Allow this process to be dumped.
|
||||
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
|
||||
CrashContext context;
|
||||
int getcontext_result = getcontext(&context.context);
|
||||
if (getcontext_result)
|
||||
return false;
|
||||
|
||||
#if defined(__i386__)
|
||||
// In CPUFillFromUContext in minidumpwriter.cc the stack pointer is retrieved
|
||||
// from REG_UESP instead of from REG_ESP. REG_UESP is the user stack pointer
|
||||
// and it only makes sense when running in kernel mode with a different stack
|
||||
// pointer. When WriteMiniDump is called during normal processing REG_UESP is
|
||||
// zero which leads to bad minidump files.
|
||||
if (!context.context.uc_mcontext.gregs[REG_UESP]) {
|
||||
// If REG_UESP is set to REG_ESP then that includes the stack space for the
|
||||
// CrashContext object in this function, which is about 128 KB. Since the
|
||||
// Linux dumper only records 32 KB of stack this would mean that nothing
|
||||
// useful would be recorded. A better option is to set REG_UESP to REG_EBP,
|
||||
// perhaps with a small negative offset in case there is any code that
|
||||
// objects to them being equal.
|
||||
context.context.uc_mcontext.gregs[REG_UESP] =
|
||||
context.context.uc_mcontext.gregs[REG_EBP] - 16;
|
||||
// The stack saving is based off of REG_ESP so it must be set to match the
|
||||
// new REG_UESP.
|
||||
context.context.uc_mcontext.gregs[REG_ESP] =
|
||||
context.context.uc_mcontext.gregs[REG_UESP];
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__)
|
||||
// FPU state is not part of ARM EABI ucontext_t.
|
||||
memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
|
||||
sizeof(context.float_state));
|
||||
#endif
|
||||
context.tid = sys_gettid();
|
||||
|
||||
// Add an exception stream to the minidump for better reporting.
|
||||
memset(&context.siginfo, 0, sizeof(context.siginfo));
|
||||
context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED;
|
||||
#if defined(__i386__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_EIP]);
|
||||
#elif defined(__x86_64__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_RIP]);
|
||||
#elif defined(__arm__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc);
|
||||
#elif defined(__aarch64__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.pc);
|
||||
#elif defined(__mips__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.pc);
|
||||
#else
|
||||
#error "This code has not been ported to your platform yet."
|
||||
#endif
|
||||
|
||||
return GenerateDump(&context);
|
||||
}
|
||||
|
||||
void ExceptionHandler::AddMappingInfo(const string& name,
|
||||
const uint8_t identifier[sizeof(MDGUID)],
|
||||
uintptr_t start_address,
|
||||
size_t mapping_size,
|
||||
size_t file_offset) {
|
||||
MappingInfo info;
|
||||
info.start_addr = start_address;
|
||||
info.size = mapping_size;
|
||||
info.offset = file_offset;
|
||||
strncpy(info.name, name.c_str(), sizeof(info.name) - 1);
|
||||
info.name[sizeof(info.name) - 1] = '\0';
|
||||
|
||||
MappingEntry mapping;
|
||||
mapping.first = info;
|
||||
memcpy(mapping.second, identifier, sizeof(MDGUID));
|
||||
mapping_list_.push_back(mapping);
|
||||
}
|
||||
|
||||
void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) {
|
||||
AppMemoryList::iterator iter =
|
||||
std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr);
|
||||
if (iter != app_memory_list_.end()) {
|
||||
// Don't allow registering the same pointer twice.
|
||||
return;
|
||||
}
|
||||
|
||||
AppMemory app_memory;
|
||||
app_memory.ptr = ptr;
|
||||
app_memory.length = length;
|
||||
app_memory_list_.push_back(app_memory);
|
||||
}
|
||||
|
||||
void ExceptionHandler::UnregisterAppMemory(void* ptr) {
|
||||
AppMemoryList::iterator iter =
|
||||
std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr);
|
||||
if (iter != app_memory_list_.end()) {
|
||||
app_memory_list_.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool ExceptionHandler::WriteMinidumpForChild(pid_t child,
|
||||
pid_t child_blamed_thread,
|
||||
const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context) {
|
||||
// This function is not run in a compromised context.
|
||||
MinidumpDescriptor descriptor(dump_path);
|
||||
descriptor.UpdatePath();
|
||||
if (!google_breakpad::WriteMinidump(descriptor.path(),
|
||||
child,
|
||||
child_blamed_thread))
|
||||
return false;
|
||||
|
||||
return callback ? callback(descriptor, callback_context, true) : true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
278
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/exception_handler.h
vendored
Normal file
278
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/exception_handler.h
vendored
Normal file
|
@ -0,0 +1,278 @@
|
|||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
|
||||
#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "client/linux/crash_generation/crash_generation_client.h"
|
||||
#include "client/linux/handler/minidump_descriptor.h"
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// ExceptionHandler
|
||||
//
|
||||
// ExceptionHandler can write a minidump file when an exception occurs,
|
||||
// or when WriteMinidump() is called explicitly by your program.
|
||||
//
|
||||
// To have the exception handler write minidumps when an uncaught exception
|
||||
// (crash) occurs, you should create an instance early in the execution
|
||||
// of your program, and keep it around for the entire time you want to
|
||||
// have crash handling active (typically, until shutdown).
|
||||
// (NOTE): There should be only be one this kind of exception handler
|
||||
// object per process.
|
||||
//
|
||||
// If you want to write minidumps without installing the exception handler,
|
||||
// you can create an ExceptionHandler with install_handler set to false,
|
||||
// then call WriteMinidump. You can also use this technique if you want to
|
||||
// use different minidump callbacks for different call sites.
|
||||
//
|
||||
// In either case, a callback function is called when a minidump is written,
|
||||
// which receives the full path or file descriptor of the minidump. The
|
||||
// caller can collect and write additional application state to that minidump,
|
||||
// and launch an external crash-reporting application.
|
||||
//
|
||||
// Caller should try to make the callbacks as crash-friendly as possible,
|
||||
// it should avoid use heap memory allocation as much as possible.
|
||||
|
||||
class ExceptionHandler {
|
||||
public:
|
||||
// A callback function to run before Breakpad performs any substantial
|
||||
// processing of an exception. A FilterCallback is called before writing
|
||||
// a minidump. |context| is the parameter supplied by the user as
|
||||
// callback_context when the handler was created.
|
||||
//
|
||||
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||
// attempting to write a minidump. If a FilterCallback returns false,
|
||||
// Breakpad will immediately report the exception as unhandled without
|
||||
// writing a minidump, allowing another handler the opportunity to handle it.
|
||||
typedef bool (*FilterCallback)(void *context);
|
||||
|
||||
// A callback function to run after the minidump has been written.
|
||||
// |descriptor| contains the file descriptor or file path containing the
|
||||
// minidump. |context| is the parameter supplied by the user as
|
||||
// callback_context when the handler was created. |succeeded| indicates
|
||||
// whether a minidump file was successfully written.
|
||||
//
|
||||
// If an exception occurred and the callback returns true, Breakpad will
|
||||
// treat the exception as fully-handled, suppressing any other handlers from
|
||||
// being notified of the exception. If the callback returns false, Breakpad
|
||||
// will treat the exception as unhandled, and allow another handler to handle
|
||||
// it. If there are no other handlers, Breakpad will report the exception to
|
||||
// the system as unhandled, allowing a debugger or native crash dialog the
|
||||
// opportunity to handle the exception. Most callback implementations
|
||||
// should normally return the value of |succeeded|, or when they wish to
|
||||
// not report an exception of handled, false. Callbacks will rarely want to
|
||||
// return true directly (unless |succeeded| is true).
|
||||
typedef bool (*MinidumpCallback)(const MinidumpDescriptor& descriptor,
|
||||
void* context,
|
||||
bool succeeded);
|
||||
|
||||
// In certain cases, a user may wish to handle the generation of the minidump
|
||||
// themselves. In this case, they can install a handler callback which is
|
||||
// called when a crash has occurred. If this function returns true, no other
|
||||
// processing of occurs and the process will shortly be crashed. If this
|
||||
// returns false, the normal processing continues.
|
||||
typedef bool (*HandlerCallback)(const void* crash_context,
|
||||
size_t crash_context_size,
|
||||
void* context);
|
||||
|
||||
// Creates a new ExceptionHandler instance to handle writing minidumps.
|
||||
// Before writing a minidump, the optional |filter| callback will be called.
|
||||
// Its return value determines whether or not Breakpad should write a
|
||||
// minidump. The minidump content will be written to the file path or file
|
||||
// descriptor from |descriptor|, and the optional |callback| is called after
|
||||
// writing the dump file, as described above.
|
||||
// If install_handler is true, then a minidump will be written whenever
|
||||
// an unhandled exception occurs. If it is false, minidumps will only
|
||||
// be written when WriteMinidump is called.
|
||||
// If |server_fd| is valid, the minidump is generated out-of-process. If it
|
||||
// is -1, in-process generation will always be used.
|
||||
ExceptionHandler(const MinidumpDescriptor& descriptor,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
bool install_handler,
|
||||
const int server_fd);
|
||||
~ExceptionHandler();
|
||||
|
||||
const MinidumpDescriptor& minidump_descriptor() const {
|
||||
return minidump_descriptor_;
|
||||
}
|
||||
|
||||
void set_minidump_descriptor(const MinidumpDescriptor& descriptor) {
|
||||
minidump_descriptor_ = descriptor;
|
||||
}
|
||||
|
||||
void set_crash_handler(HandlerCallback callback) {
|
||||
crash_handler_ = callback;
|
||||
}
|
||||
|
||||
void set_crash_generation_client(CrashGenerationClient* client) {
|
||||
crash_generation_client_.reset(client);
|
||||
}
|
||||
|
||||
// Writes a minidump immediately. This can be used to capture the execution
|
||||
// state independently of a crash.
|
||||
// Returns true on success.
|
||||
// If the ExceptionHandler has been created with a path, a new file is
|
||||
// generated for each minidump. The file path can be retrieved in the
|
||||
// MinidumpDescriptor passed to the MinidumpCallback or by accessing the
|
||||
// MinidumpDescriptor directly from the ExceptionHandler (with
|
||||
// minidump_descriptor()).
|
||||
// If the ExceptionHandler has been created with a file descriptor, the file
|
||||
// descriptor is repositioned to its beginning and the previous generated
|
||||
// minidump is overwritten.
|
||||
// Note that this method is not supposed to be called from a compromised
|
||||
// context as it uses the heap.
|
||||
bool WriteMinidump();
|
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
// Write a minidump of |child| immediately. This can be used to
|
||||
// capture the execution state of |child| independently of a crash.
|
||||
// Pass a meaningful |child_blamed_thread| to make that thread in
|
||||
// the child process the one from which a crash signature is
|
||||
// extracted.
|
||||
//
|
||||
// WARNING: the return of this function *must* happen before
|
||||
// the code that will eventually reap |child| executes.
|
||||
// Otherwise there's a pernicious race condition in which |child|
|
||||
// exits, is reaped, another process created with its pid, then that
|
||||
// new process dumped.
|
||||
static bool WriteMinidumpForChild(pid_t child,
|
||||
pid_t child_blamed_thread,
|
||||
const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
// This structure is passed to minidump_writer.h:WriteMinidump via an opaque
|
||||
// blob. It shouldn't be needed in any user code.
|
||||
struct CrashContext {
|
||||
siginfo_t siginfo;
|
||||
pid_t tid; // the crashing thread.
|
||||
struct ucontext context;
|
||||
#if !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
// #ifdef this out because FP state is not part of user ABI for Linux ARM.
|
||||
// In case of MIPS Linux FP state is already part of struct
|
||||
// ucontext so 'float_state' is not required.
|
||||
fpstate_t float_state;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Returns whether out-of-process dump generation is used or not.
|
||||
bool IsOutOfProcess() const {
|
||||
return crash_generation_client_.get() != NULL;
|
||||
}
|
||||
|
||||
// Add information about a memory mapping. This can be used if
|
||||
// a custom library loader is used that maps things in a way
|
||||
// that the linux dumper can't handle by reading the maps file.
|
||||
void AddMappingInfo(const string& name,
|
||||
const uint8_t identifier[sizeof(MDGUID)],
|
||||
uintptr_t start_address,
|
||||
size_t mapping_size,
|
||||
size_t file_offset);
|
||||
|
||||
// Register a block of memory of length bytes starting at address ptr
|
||||
// to be copied to the minidump when a crash happens.
|
||||
void RegisterAppMemory(void* ptr, size_t length);
|
||||
|
||||
// Unregister a block of memory that was registered with RegisterAppMemory.
|
||||
void UnregisterAppMemory(void* ptr);
|
||||
|
||||
// Force signal handling for the specified signal.
|
||||
bool SimulateSignalDelivery(int sig);
|
||||
|
||||
// Report a crash signal from an SA_SIGINFO signal handler.
|
||||
bool HandleSignal(int sig, siginfo_t* info, void* uc);
|
||||
|
||||
private:
|
||||
// Save the old signal handlers and install new ones.
|
||||
static bool InstallHandlersLocked();
|
||||
// Restore the old signal handlers.
|
||||
static void RestoreHandlersLocked();
|
||||
|
||||
void PreresolveSymbols();
|
||||
bool GenerateDump(CrashContext *context);
|
||||
void SendContinueSignalToChild();
|
||||
void WaitForContinueSignal();
|
||||
|
||||
static void SignalHandler(int sig, siginfo_t* info, void* uc);
|
||||
static int ThreadEntry(void* arg);
|
||||
bool DoDump(pid_t crashing_process, const void* context,
|
||||
size_t context_size);
|
||||
|
||||
const FilterCallback filter_;
|
||||
const MinidumpCallback callback_;
|
||||
void* const callback_context_;
|
||||
|
||||
scoped_ptr<CrashGenerationClient> crash_generation_client_;
|
||||
|
||||
MinidumpDescriptor minidump_descriptor_;
|
||||
|
||||
// Must be volatile. The compiler is unaware of the code which runs in
|
||||
// the signal handler which reads this variable. Without volatile the
|
||||
// compiler is free to optimise away writes to this variable which it
|
||||
// believes are never read.
|
||||
volatile HandlerCallback crash_handler_;
|
||||
|
||||
// We need to explicitly enable ptrace of parent processes on some
|
||||
// kernels, but we need to know the PID of the cloned process before we
|
||||
// can do this. We create a pipe which we can use to block the
|
||||
// cloned process after creating it, until we have explicitly enabled
|
||||
// ptrace. This is used to store the file descriptors for the pipe
|
||||
int fdes[2];
|
||||
|
||||
// Callers can add extra info about mappings for cases where the
|
||||
// dumper code cannot extract enough information from /proc/<pid>/maps.
|
||||
MappingList mapping_list_;
|
||||
|
||||
// Callers can request additional memory regions to be included in
|
||||
// the dump.
|
||||
AppMemoryList app_memory_list_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
|
1195
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/exception_handler_unittest.cc
vendored
Normal file
1195
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/exception_handler_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
100
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/minidump_descriptor.cc
vendored
Normal file
100
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/minidump_descriptor.cc
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) 2012 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "client/linux/handler/minidump_descriptor.h"
|
||||
|
||||
#include "common/linux/guid_creator.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//static
|
||||
const MinidumpDescriptor::MicrodumpOnConsole
|
||||
MinidumpDescriptor::kMicrodumpOnConsole = {};
|
||||
|
||||
MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
|
||||
: mode_(descriptor.mode_),
|
||||
fd_(descriptor.fd_),
|
||||
directory_(descriptor.directory_),
|
||||
c_path_(NULL),
|
||||
size_limit_(descriptor.size_limit_),
|
||||
microdump_build_fingerprint_(descriptor.microdump_build_fingerprint_),
|
||||
microdump_product_info_(descriptor.microdump_product_info_) {
|
||||
// The copy constructor is not allowed to be called on a MinidumpDescriptor
|
||||
// with a valid path_, as getting its c_path_ would require the heap which
|
||||
// can cause problems in compromised environments.
|
||||
assert(descriptor.path_.empty());
|
||||
}
|
||||
|
||||
MinidumpDescriptor& MinidumpDescriptor::operator=(
|
||||
const MinidumpDescriptor& descriptor) {
|
||||
assert(descriptor.path_.empty());
|
||||
|
||||
mode_ = descriptor.mode_;
|
||||
fd_ = descriptor.fd_;
|
||||
directory_ = descriptor.directory_;
|
||||
path_.clear();
|
||||
if (c_path_) {
|
||||
// This descriptor already had a path set, so generate a new one.
|
||||
c_path_ = NULL;
|
||||
UpdatePath();
|
||||
}
|
||||
size_limit_ = descriptor.size_limit_;
|
||||
microdump_build_fingerprint_ = descriptor.microdump_build_fingerprint_;
|
||||
microdump_product_info_ = descriptor.microdump_product_info_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MinidumpDescriptor::UpdatePath() {
|
||||
assert(mode_ == kWriteMinidumpToFile && !directory_.empty());
|
||||
|
||||
GUID guid;
|
||||
char guid_str[kGUIDStringLength + 1];
|
||||
if (!CreateGUID(&guid) || !GUIDToString(&guid, guid_str, sizeof(guid_str))) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
path_.clear();
|
||||
path_ = directory_ + "/" + guid_str + ".dmp";
|
||||
c_path_ = path_.c_str();
|
||||
}
|
||||
|
||||
void MinidumpDescriptor::SetMicrodumpBuildFingerprint(
|
||||
const char* build_fingerprint) {
|
||||
assert(mode_ == kWriteMicrodumpToConsole);
|
||||
microdump_build_fingerprint_ = build_fingerprint;
|
||||
}
|
||||
|
||||
void MinidumpDescriptor::SetMicrodumpProductInfo(const char* product_info) {
|
||||
assert(mode_ == kWriteMicrodumpToConsole);
|
||||
microdump_product_info_ = product_info;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
161
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/minidump_descriptor.h
vendored
Normal file
161
TMessagesProj/jni/third_party/breakpad/src/client/linux/handler/minidump_descriptor.h
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
// Copyright (c) 2012 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_
|
||||
#define CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
// This class describes how a crash dump should be generated, either:
|
||||
// - Writing a full minidump to a file in a given directory (the actual path,
|
||||
// inside the directory, is determined by this class).
|
||||
// - Writing a full minidump to a given fd.
|
||||
// - Writing a reduced microdump to the console (logcat on Android).
|
||||
namespace google_breakpad {
|
||||
|
||||
class MinidumpDescriptor {
|
||||
public:
|
||||
struct MicrodumpOnConsole {};
|
||||
static const MicrodumpOnConsole kMicrodumpOnConsole;
|
||||
|
||||
MinidumpDescriptor() : mode_(kUninitialized),
|
||||
fd_(-1),
|
||||
size_limit_(-1),
|
||||
microdump_build_fingerprint_(NULL),
|
||||
microdump_product_info_(NULL) {}
|
||||
|
||||
explicit MinidumpDescriptor(const string& directory)
|
||||
: mode_(kWriteMinidumpToFile),
|
||||
fd_(-1),
|
||||
directory_(directory),
|
||||
c_path_(NULL),
|
||||
size_limit_(-1),
|
||||
microdump_build_fingerprint_(NULL),
|
||||
microdump_product_info_(NULL) {
|
||||
assert(!directory.empty());
|
||||
}
|
||||
|
||||
explicit MinidumpDescriptor(int fd)
|
||||
: mode_(kWriteMinidumpToFd),
|
||||
fd_(fd),
|
||||
c_path_(NULL),
|
||||
size_limit_(-1),
|
||||
microdump_build_fingerprint_(NULL),
|
||||
microdump_product_info_(NULL) {
|
||||
assert(fd != -1);
|
||||
}
|
||||
|
||||
explicit MinidumpDescriptor(const MicrodumpOnConsole&)
|
||||
: mode_(kWriteMicrodumpToConsole),
|
||||
fd_(-1),
|
||||
size_limit_(-1),
|
||||
microdump_build_fingerprint_(NULL),
|
||||
microdump_product_info_(NULL) {}
|
||||
|
||||
explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor);
|
||||
MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor);
|
||||
|
||||
static MinidumpDescriptor getMicrodumpDescriptor();
|
||||
|
||||
bool IsFD() const { return mode_ == kWriteMinidumpToFd; }
|
||||
|
||||
int fd() const { return fd_; }
|
||||
|
||||
string directory() const { return directory_; }
|
||||
|
||||
const char* path() const { return c_path_; }
|
||||
|
||||
bool IsMicrodumpOnConsole() const {
|
||||
return mode_ == kWriteMicrodumpToConsole;
|
||||
}
|
||||
|
||||
// Updates the path so it is unique.
|
||||
// Should be called from a normal context: this methods uses the heap.
|
||||
void UpdatePath();
|
||||
|
||||
off_t size_limit() const { return size_limit_; }
|
||||
void set_size_limit(off_t limit) { size_limit_ = limit; }
|
||||
|
||||
// TODO(primiano): make this and product info (below) just part of the
|
||||
// microdump ctor once it is rolled stably into Chrome. ETA: June 2015.
|
||||
void SetMicrodumpBuildFingerprint(const char* build_fingerprint);
|
||||
const char* microdump_build_fingerprint() const {
|
||||
return microdump_build_fingerprint_;
|
||||
}
|
||||
|
||||
void SetMicrodumpProductInfo(const char* product_info);
|
||||
const char* microdump_product_info() const {
|
||||
return microdump_product_info_;
|
||||
}
|
||||
|
||||
private:
|
||||
enum DumpMode {
|
||||
kUninitialized = 0,
|
||||
kWriteMinidumpToFile,
|
||||
kWriteMinidumpToFd,
|
||||
kWriteMicrodumpToConsole
|
||||
};
|
||||
|
||||
// Specifies the dump mode (see DumpMode).
|
||||
DumpMode mode_;
|
||||
|
||||
// The file descriptor where the minidump is generated.
|
||||
int fd_;
|
||||
|
||||
// The directory where the minidump should be generated.
|
||||
string directory_;
|
||||
|
||||
// The full path to the generated minidump.
|
||||
string path_;
|
||||
|
||||
// The C string of |path_|. Precomputed so it can be access from a compromised
|
||||
// context.
|
||||
const char* c_path_;
|
||||
|
||||
off_t size_limit_;
|
||||
|
||||
// The product name/version and build fingerprint that should be appended to
|
||||
// the dump (microdump only). Microdumps don't have the ability of appending
|
||||
// extra metadata after the dump is generated (as opposite to minidumps
|
||||
// MIME fields), therefore the product details must be provided upfront.
|
||||
// The string pointers are supposed to be valid through all the lifetime of
|
||||
// the process (read: the caller has to guarantee that they are stored in
|
||||
// global static storage).
|
||||
const char* microdump_build_fingerprint_;
|
||||
const char* microdump_product_info_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2012 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "client/linux/log/log.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#else
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
#endif
|
||||
|
||||
namespace logger {
|
||||
|
||||
int write(const char* buf, size_t nbytes) {
|
||||
#if defined(__ANDROID__)
|
||||
return __android_log_write(ANDROID_LOG_WARN, "google-breakpad", buf);
|
||||
#else
|
||||
return sys_write(2, buf, nbytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace logger
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_LOG_LOG_H_
|
||||
#define CLIENT_LINUX_LOG_LOG_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace logger {
|
||||
|
||||
int write(const char* buf, size_t nbytes);
|
||||
|
||||
} // namespace logger
|
||||
|
||||
#endif // CLIENT_LINUX_LOG_LOG_H_
|
423
TMessagesProj/jni/third_party/breakpad/src/client/linux/microdump_writer/microdump_writer.cc
vendored
Normal file
423
TMessagesProj/jni/third_party/breakpad/src/client/linux/microdump_writer/microdump_writer.cc
vendored
Normal file
|
@ -0,0 +1,423 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This translation unit generates microdumps into the console (logcat on
|
||||
// Android). See crbug.com/410294 for more info and design docs.
|
||||
|
||||
#include "client/linux/microdump_writer/microdump_writer.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "client/linux/dump_writer_common/seccomp_unwinder.h"
|
||||
#include "client/linux/dump_writer_common/thread_info.h"
|
||||
#include "client/linux/dump_writer_common/ucontext_reader.h"
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#include "client/linux/log/log.h"
|
||||
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using google_breakpad::ExceptionHandler;
|
||||
using google_breakpad::LinuxDumper;
|
||||
using google_breakpad::LinuxPtraceDumper;
|
||||
using google_breakpad::MappingInfo;
|
||||
using google_breakpad::MappingList;
|
||||
using google_breakpad::RawContextCPU;
|
||||
using google_breakpad::SeccompUnwinder;
|
||||
using google_breakpad::ThreadInfo;
|
||||
using google_breakpad::UContextReader;
|
||||
|
||||
const size_t kLineBufferSize = 2048;
|
||||
|
||||
class MicrodumpWriter {
|
||||
public:
|
||||
MicrodumpWriter(const ExceptionHandler::CrashContext* context,
|
||||
const MappingList& mappings,
|
||||
const char* build_fingerprint,
|
||||
const char* product_info,
|
||||
LinuxDumper* dumper)
|
||||
: ucontext_(context ? &context->context : NULL),
|
||||
#if !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
float_state_(context ? &context->float_state : NULL),
|
||||
#endif
|
||||
dumper_(dumper),
|
||||
mapping_list_(mappings),
|
||||
build_fingerprint_(build_fingerprint),
|
||||
product_info_(product_info),
|
||||
log_line_(NULL) {
|
||||
log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
|
||||
if (log_line_)
|
||||
log_line_[0] = '\0'; // Clear out the log line buffer.
|
||||
}
|
||||
|
||||
~MicrodumpWriter() { dumper_->ThreadsResume(); }
|
||||
|
||||
bool Init() {
|
||||
// In the exceptional case where the system was out of memory and there
|
||||
// wasn't even room to allocate the line buffer, bail out. There is nothing
|
||||
// useful we can possibly achieve without the ability to Log. At least let's
|
||||
// try to not crash.
|
||||
if (!dumper_->Init() || !log_line_)
|
||||
return false;
|
||||
return dumper_->ThreadsSuspend();
|
||||
}
|
||||
|
||||
bool Dump() {
|
||||
bool success;
|
||||
LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
|
||||
DumpProductInformation();
|
||||
DumpOSInformation();
|
||||
success = DumpCrashingThread();
|
||||
if (success)
|
||||
success = DumpMappings();
|
||||
LogLine("-----END BREAKPAD MICRODUMP-----");
|
||||
dumper_->ThreadsResume();
|
||||
return success;
|
||||
}
|
||||
|
||||
private:
|
||||
// Writes one line to the system log.
|
||||
void LogLine(const char* msg) {
|
||||
logger::write(msg, my_strlen(msg));
|
||||
#if !defined(__ANDROID__)
|
||||
logger::write("\n", 1); // Android logger appends the \n. Linux's doesn't.
|
||||
#endif
|
||||
}
|
||||
|
||||
// Stages the given string in the current line buffer.
|
||||
void LogAppend(const char* str) {
|
||||
my_strlcat(log_line_, str, kLineBufferSize);
|
||||
}
|
||||
|
||||
// As above (required to take precedence over template specialization below).
|
||||
void LogAppend(char* str) {
|
||||
LogAppend(const_cast<const char*>(str));
|
||||
}
|
||||
|
||||
// Stages the hex repr. of the given int type in the current line buffer.
|
||||
template<typename T>
|
||||
void LogAppend(T value) {
|
||||
// Make enough room to hex encode the largest int type + NUL.
|
||||
static const char HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
char hexstr[sizeof(T) * 2 + 1];
|
||||
for (int i = sizeof(T) * 2 - 1; i >= 0; --i, value >>= 4)
|
||||
hexstr[i] = HEX[static_cast<uint8_t>(value) & 0x0F];
|
||||
hexstr[sizeof(T) * 2] = '\0';
|
||||
LogAppend(hexstr);
|
||||
}
|
||||
|
||||
// Stages the buffer content hex-encoded in the current line buffer.
|
||||
void LogAppend(const void* buf, size_t length) {
|
||||
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(buf);
|
||||
for (size_t i = 0; i < length; ++i, ++ptr)
|
||||
LogAppend(*ptr);
|
||||
}
|
||||
|
||||
// Writes out the current line buffer on the system log.
|
||||
void LogCommitLine() {
|
||||
LogLine(log_line_);
|
||||
my_strlcpy(log_line_, "", kLineBufferSize);
|
||||
}
|
||||
|
||||
void DumpProductInformation() {
|
||||
LogAppend("V ");
|
||||
if (product_info_) {
|
||||
LogAppend(product_info_);
|
||||
} else {
|
||||
LogAppend("UNKNOWN:0.0.0.0");
|
||||
}
|
||||
LogCommitLine();
|
||||
}
|
||||
|
||||
void DumpOSInformation() {
|
||||
const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
const char kOSId[] = "A";
|
||||
#else
|
||||
const char kOSId[] = "L";
|
||||
#endif
|
||||
|
||||
// We cannot depend on uts.machine. On multiarch devices it always returns the
|
||||
// primary arch, not the one that match the executable being run.
|
||||
#if defined(__aarch64__)
|
||||
const char kArch[] = "arm64";
|
||||
#elif defined(__ARMEL__)
|
||||
const char kArch[] = "arm";
|
||||
#elif defined(__x86_64__)
|
||||
const char kArch[] = "x86_64";
|
||||
#elif defined(__i386__)
|
||||
const char kArch[] = "x86";
|
||||
#elif defined(__mips__)
|
||||
const char kArch[] = "mips";
|
||||
#else
|
||||
#error "This code has not been ported to your platform yet"
|
||||
#endif
|
||||
|
||||
LogAppend("O ");
|
||||
LogAppend(kOSId);
|
||||
LogAppend(" ");
|
||||
LogAppend(kArch);
|
||||
LogAppend(" ");
|
||||
LogAppend(n_cpus);
|
||||
LogAppend(" ");
|
||||
// If the client has attached a build fingerprint to the MinidumpDescriptor
|
||||
// use that one. Otherwise try to get some basic info from uname().
|
||||
if (build_fingerprint_) {
|
||||
LogAppend(build_fingerprint_);
|
||||
} else {
|
||||
struct utsname uts;
|
||||
if (uname(&uts) == 0) {
|
||||
LogAppend(uts.machine);
|
||||
LogAppend(" ");
|
||||
LogAppend(uts.release);
|
||||
LogAppend(" ");
|
||||
LogAppend(uts.version);
|
||||
} else {
|
||||
LogAppend("no build fingerprint available");
|
||||
}
|
||||
}
|
||||
LogCommitLine();
|
||||
}
|
||||
|
||||
bool DumpThreadStack(uint32_t thread_id,
|
||||
uintptr_t stack_pointer,
|
||||
int max_stack_len,
|
||||
uint8_t** stack_copy) {
|
||||
*stack_copy = NULL;
|
||||
const void* stack;
|
||||
size_t stack_len;
|
||||
|
||||
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
|
||||
// The stack pointer might not be available. In this case we don't hard
|
||||
// fail, just produce a (almost useless) microdump w/o a stack section.
|
||||
return true;
|
||||
}
|
||||
|
||||
LogAppend("S 0 ");
|
||||
LogAppend(stack_pointer);
|
||||
LogAppend(" ");
|
||||
LogAppend(reinterpret_cast<uintptr_t>(stack));
|
||||
LogAppend(" ");
|
||||
LogAppend(stack_len);
|
||||
LogCommitLine();
|
||||
|
||||
if (max_stack_len >= 0 &&
|
||||
stack_len > static_cast<unsigned int>(max_stack_len)) {
|
||||
stack_len = max_stack_len;
|
||||
}
|
||||
|
||||
*stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
|
||||
dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len);
|
||||
|
||||
// Dump the content of the stack, splicing it into chunks which size is
|
||||
// compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD).
|
||||
const size_t STACK_DUMP_CHUNK_SIZE = 384;
|
||||
for (size_t stack_off = 0; stack_off < stack_len;
|
||||
stack_off += STACK_DUMP_CHUNK_SIZE) {
|
||||
LogAppend("S ");
|
||||
LogAppend(reinterpret_cast<uintptr_t>(stack) + stack_off);
|
||||
LogAppend(" ");
|
||||
LogAppend(*stack_copy + stack_off,
|
||||
std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off));
|
||||
LogCommitLine();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write information about the crashing thread.
|
||||
bool DumpCrashingThread() {
|
||||
const unsigned num_threads = dumper_->threads().size();
|
||||
|
||||
for (unsigned i = 0; i < num_threads; ++i) {
|
||||
MDRawThread thread;
|
||||
my_memset(&thread, 0, sizeof(thread));
|
||||
thread.thread_id = dumper_->threads()[i];
|
||||
|
||||
// Dump only the crashing thread.
|
||||
if (static_cast<pid_t>(thread.thread_id) != dumper_->crash_thread())
|
||||
continue;
|
||||
|
||||
assert(ucontext_);
|
||||
assert(!dumper_->IsPostMortem());
|
||||
|
||||
uint8_t* stack_copy;
|
||||
const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
|
||||
if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy))
|
||||
return false;
|
||||
|
||||
RawContextCPU cpu;
|
||||
my_memset(&cpu, 0, sizeof(RawContextCPU));
|
||||
#if !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
|
||||
#else
|
||||
UContextReader::FillCPUContext(&cpu, ucontext_);
|
||||
#endif
|
||||
if (stack_copy)
|
||||
SeccompUnwinder::PopSeccompStackFrame(&cpu, thread, stack_copy);
|
||||
DumpCPUState(&cpu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DumpCPUState(RawContextCPU* cpu) {
|
||||
LogAppend("C ");
|
||||
LogAppend(cpu, sizeof(*cpu));
|
||||
LogCommitLine();
|
||||
}
|
||||
|
||||
// If there is caller-provided information about this mapping
|
||||
// in the mapping_list_ list, return true. Otherwise, return false.
|
||||
bool HaveMappingInfo(const MappingInfo& mapping) {
|
||||
for (MappingList::const_iterator iter = mapping_list_.begin();
|
||||
iter != mapping_list_.end();
|
||||
++iter) {
|
||||
// Ignore any mappings that are wholly contained within
|
||||
// mappings in the mapping_info_ list.
|
||||
if (mapping.start_addr >= iter->first.start_addr &&
|
||||
(mapping.start_addr + mapping.size) <=
|
||||
(iter->first.start_addr + iter->first.size)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dump information about the provided |mapping|. If |identifier| is non-NULL,
|
||||
// use it instead of calculating a file ID from the mapping.
|
||||
void DumpModule(const MappingInfo& mapping,
|
||||
bool member,
|
||||
unsigned int mapping_id,
|
||||
const uint8_t* identifier) {
|
||||
MDGUID module_identifier;
|
||||
if (identifier) {
|
||||
// GUID was provided by caller.
|
||||
my_memcpy(&module_identifier, identifier, sizeof(MDGUID));
|
||||
} else {
|
||||
dumper_->ElfFileIdentifierForMapping(
|
||||
mapping,
|
||||
member,
|
||||
mapping_id,
|
||||
reinterpret_cast<uint8_t*>(&module_identifier));
|
||||
}
|
||||
|
||||
char file_name[NAME_MAX];
|
||||
char file_path[NAME_MAX];
|
||||
LinuxDumper::GetMappingEffectiveNameAndPath(
|
||||
mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
|
||||
|
||||
LogAppend("M ");
|
||||
LogAppend(static_cast<uintptr_t>(mapping.start_addr));
|
||||
LogAppend(" ");
|
||||
LogAppend(mapping.offset);
|
||||
LogAppend(" ");
|
||||
LogAppend(mapping.size);
|
||||
LogAppend(" ");
|
||||
LogAppend(module_identifier.data1);
|
||||
LogAppend(module_identifier.data2);
|
||||
LogAppend(module_identifier.data3);
|
||||
LogAppend(module_identifier.data4[0]);
|
||||
LogAppend(module_identifier.data4[1]);
|
||||
LogAppend(module_identifier.data4[2]);
|
||||
LogAppend(module_identifier.data4[3]);
|
||||
LogAppend(module_identifier.data4[4]);
|
||||
LogAppend(module_identifier.data4[5]);
|
||||
LogAppend(module_identifier.data4[6]);
|
||||
LogAppend(module_identifier.data4[7]);
|
||||
LogAppend("0 "); // Age is always 0 on Linux.
|
||||
LogAppend(file_name);
|
||||
LogCommitLine();
|
||||
}
|
||||
|
||||
// Write information about the mappings in effect.
|
||||
bool DumpMappings() {
|
||||
// First write all the mappings from the dumper
|
||||
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
|
||||
const MappingInfo& mapping = *dumper_->mappings()[i];
|
||||
if (mapping.name[0] == 0 || // only want modules with filenames.
|
||||
!mapping.exec || // only want executable mappings.
|
||||
mapping.size < 4096 || // too small to get a signature for.
|
||||
HaveMappingInfo(mapping)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DumpModule(mapping, true, i, NULL);
|
||||
}
|
||||
// Next write all the mappings provided by the caller
|
||||
for (MappingList::const_iterator iter = mapping_list_.begin();
|
||||
iter != mapping_list_.end();
|
||||
++iter) {
|
||||
DumpModule(iter->first, false, 0, iter->second);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
|
||||
|
||||
const struct ucontext* const ucontext_;
|
||||
#if !defined(__ARM_EABI__) && !defined(__mips__)
|
||||
const google_breakpad::fpstate_t* const float_state_;
|
||||
#endif
|
||||
LinuxDumper* dumper_;
|
||||
const MappingList& mapping_list_;
|
||||
const char* const build_fingerprint_;
|
||||
const char* const product_info_;
|
||||
char* log_line_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
bool WriteMicrodump(pid_t crashing_process,
|
||||
const void* blob,
|
||||
size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const char* build_fingerprint,
|
||||
const char* product_info) {
|
||||
LinuxPtraceDumper dumper(crashing_process);
|
||||
const ExceptionHandler::CrashContext* context = NULL;
|
||||
if (blob) {
|
||||
if (blob_size != sizeof(ExceptionHandler::CrashContext))
|
||||
return false;
|
||||
context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
|
||||
dumper.set_crash_address(
|
||||
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
|
||||
dumper.set_crash_signal(context->siginfo.si_signo);
|
||||
dumper.set_crash_thread(context->tid);
|
||||
}
|
||||
MicrodumpWriter writer(context, mappings, build_fingerprint, product_info,
|
||||
&dumper);
|
||||
if (!writer.Init())
|
||||
return false;
|
||||
return writer.Dump();
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
64
TMessagesProj/jni/third_party/breakpad/src/client/linux/microdump_writer/microdump_writer.h
vendored
Normal file
64
TMessagesProj/jni/third_party/breakpad/src/client/linux/microdump_writer/microdump_writer.h
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2014, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
|
||||
#define CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "client/linux/dump_writer_common/mapping_info.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Writes a microdump (a reduced dump containing only the state of the crashing
|
||||
// thread) on the console (logcat on Android). These functions do not malloc nor
|
||||
// use libc functions which may. Thus, it can be used in contexts where the
|
||||
// state of the heap may be corrupt.
|
||||
// Args:
|
||||
// crashing_process: the pid of the crashing process. This must be trusted.
|
||||
// blob: a blob of data from the crashing process. See exception_handler.h
|
||||
// blob_size: the length of |blob| in bytes.
|
||||
// mappings: a list of additional mappings provided by the application.
|
||||
// build_fingerprint: a (optional) C string which determines the OS
|
||||
// build fingerprint (e.g., aosp/occam/mako:5.1.1/LMY47W/1234:eng/dev-keys).
|
||||
// product_info: a (optional) C string which determines the product name and
|
||||
// version (e.g., WebView:42.0.2311.136).
|
||||
//
|
||||
// Returns true iff successful.
|
||||
bool WriteMicrodump(pid_t crashing_process,
|
||||
const void* blob,
|
||||
size_t blob_size,
|
||||
const MappingList& mappings,
|
||||
const char* build_fingerprint,
|
||||
const char* product_info);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
|
|
@ -0,0 +1,164 @@
|
|||
// Copyright (c) 2014 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#include "client/linux/microdump_writer/microdump_writer.h"
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/ignore_ret.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef testing::Test MicrodumpWriterTest;
|
||||
|
||||
void CrashAndGetMicrodump(
|
||||
const MappingList& mappings,
|
||||
const char* build_fingerprint,
|
||||
const char* product_info,
|
||||
scoped_array<char>* buf) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string stderr_file = temp_dir.path() + "/stderr.log";
|
||||
int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
ASSERT_NE(-1, err_fd);
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
ExceptionHandler::CrashContext context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
// Set a non-zero tid to avoid tripping asserts.
|
||||
context.tid = child;
|
||||
|
||||
// Redirect temporarily stderr to the stderr.log file.
|
||||
int save_err = dup(STDERR_FILENO);
|
||||
ASSERT_NE(-1, save_err);
|
||||
ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO));
|
||||
|
||||
ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings,
|
||||
build_fingerprint, product_info));
|
||||
|
||||
// Revert stderr back to the console.
|
||||
dup2(save_err, STDERR_FILENO);
|
||||
close(save_err);
|
||||
|
||||
// Read back the stderr file and check for the microdump marker.
|
||||
fsync(err_fd);
|
||||
lseek(err_fd, 0, SEEK_SET);
|
||||
const size_t kBufSize = 64 * 1024;
|
||||
buf->reset(new char[kBufSize]);
|
||||
ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0);
|
||||
|
||||
close(err_fd);
|
||||
close(fds[1]);
|
||||
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----"));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf->get(), "-----END BREAKPAD MICRODUMP-----"));
|
||||
|
||||
}
|
||||
|
||||
TEST(MicrodumpWriterTest, BasicWithMappings) {
|
||||
// Push some extra mapping to check the MappingList logic.
|
||||
const uint32_t memory_size = sysconf(_SC_PAGESIZE);
|
||||
const char* kMemoryName = "libfoo.so";
|
||||
const uint8_t kModuleGUID[sizeof(MDGUID)] = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
|
||||
};
|
||||
|
||||
MappingInfo info;
|
||||
info.start_addr = memory_size;
|
||||
info.size = memory_size;
|
||||
info.offset = 42;
|
||||
strcpy(info.name, kMemoryName);
|
||||
|
||||
MappingList mappings;
|
||||
MappingEntry mapping;
|
||||
mapping.first = info;
|
||||
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
|
||||
mappings.push_back(mapping);
|
||||
|
||||
scoped_array<char> buf;
|
||||
CrashAndGetMicrodump(mappings, NULL, NULL, &buf);
|
||||
|
||||
#ifdef __LP64__
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
#else
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "M 00001000 0000002A 00001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
#endif
|
||||
|
||||
// In absence of a product info in the minidump, the writer should just write
|
||||
// an unknown marker.
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "V UNKNOWN:0.0.0.0"));
|
||||
}
|
||||
|
||||
// Ensure that the product info and build fingerprint metadata show up in the
|
||||
// final microdump if present.
|
||||
TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) {
|
||||
const char kProductInfo[] = "MockProduct:42.0.2311.99";
|
||||
const char kBuildFingerprint[] =
|
||||
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
|
||||
scoped_array<char> buf;
|
||||
MappingList no_mappings;
|
||||
|
||||
CrashAndGetMicrodump(no_mappings, kBuildFingerprint, kProductInfo, &buf);
|
||||
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(buf.get(), kBuildFingerprint));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(buf.get(), kProductInfo));
|
||||
}
|
||||
|
||||
} // namespace
|
144
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/cpu_set.h
vendored
Normal file
144
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/cpu_set.h
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Copyright (c) 2013, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_
|
||||
#define CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Helper class used to model a set of CPUs, as read from sysfs
|
||||
// files like /sys/devices/system/cpu/present
|
||||
// See See http://www.kernel.org/doc/Documentation/cputopology.txt
|
||||
class CpuSet {
|
||||
public:
|
||||
// The maximum number of supported CPUs.
|
||||
static const size_t kMaxCpus = 1024;
|
||||
|
||||
CpuSet() {
|
||||
my_memset(mask_, 0, sizeof(mask_));
|
||||
}
|
||||
|
||||
// Parse a sysfs file to extract the corresponding CPU set.
|
||||
bool ParseSysFile(int fd) {
|
||||
char buffer[512];
|
||||
int ret = sys_read(fd, buffer, sizeof(buffer)-1);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
buffer[ret] = '\0';
|
||||
|
||||
// Expected format: comma-separated list of items, where each
|
||||
// item can be a decimal integer, or two decimal integers separated
|
||||
// by a dash.
|
||||
// E.g.:
|
||||
// 0
|
||||
// 0,1,2,3
|
||||
// 0-3
|
||||
// 1,10-23
|
||||
const char* p = buffer;
|
||||
const char* p_end = p + ret;
|
||||
while (p < p_end) {
|
||||
// Skip leading space, if any
|
||||
while (p < p_end && my_isspace(*p))
|
||||
p++;
|
||||
|
||||
// Find start and size of current item.
|
||||
const char* item = p;
|
||||
size_t item_len = static_cast<size_t>(p_end - p);
|
||||
const char* item_next =
|
||||
static_cast<const char*>(my_memchr(p, ',', item_len));
|
||||
if (item_next != NULL) {
|
||||
p = item_next + 1;
|
||||
item_len = static_cast<size_t>(item_next - item);
|
||||
} else {
|
||||
p = p_end;
|
||||
item_next = p_end;
|
||||
}
|
||||
|
||||
// Ignore trailing spaces.
|
||||
while (item_next > item && my_isspace(item_next[-1]))
|
||||
item_next--;
|
||||
|
||||
// skip empty items.
|
||||
if (item_next == item)
|
||||
continue;
|
||||
|
||||
// read first decimal value.
|
||||
uintptr_t start = 0;
|
||||
const char* next = my_read_decimal_ptr(&start, item);
|
||||
uintptr_t end = start;
|
||||
if (*next == '-')
|
||||
my_read_decimal_ptr(&end, next+1);
|
||||
|
||||
while (start <= end)
|
||||
SetBit(start++);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Intersect this CPU set with another one.
|
||||
void IntersectWith(const CpuSet& other) {
|
||||
for (size_t nn = 0; nn < kMaskWordCount; ++nn)
|
||||
mask_[nn] &= other.mask_[nn];
|
||||
}
|
||||
|
||||
// Return the number of CPUs in this set.
|
||||
int GetCount() {
|
||||
int result = 0;
|
||||
for (size_t nn = 0; nn < kMaskWordCount; ++nn) {
|
||||
result += __builtin_popcount(mask_[nn]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void SetBit(uintptr_t index) {
|
||||
size_t nn = static_cast<size_t>(index);
|
||||
if (nn < kMaxCpus)
|
||||
mask_[nn / kMaskWordBits] |= (1U << (nn % kMaskWordBits));
|
||||
}
|
||||
|
||||
typedef uint32_t MaskWordType;
|
||||
static const size_t kMaskWordBits = 8*sizeof(MaskWordType);
|
||||
static const size_t kMaskWordCount =
|
||||
(kMaxCpus + kMaskWordBits - 1) / kMaskWordBits;
|
||||
|
||||
MaskWordType mask_[kMaskWordCount];
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_
|
164
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc
vendored
Normal file
164
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
// Copyright (c) 2013, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/linux/minidump_writer/cpu_set.h"
|
||||
#include "common/linux/tests/auto_testfile.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef testing::Test CpuSetTest;
|
||||
|
||||
// Helper class to write test text file to a temporary file and return
|
||||
// its file descriptor.
|
||||
class ScopedTestFile : public AutoTestFile {
|
||||
public:
|
||||
explicit ScopedTestFile(const char* text)
|
||||
: AutoTestFile("cpu_set", text) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, EmptyCount) {
|
||||
CpuSet set;
|
||||
ASSERT_EQ(0, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, OneCpu) {
|
||||
ScopedTestFile file("10");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
|
||||
CpuSet set;
|
||||
ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
|
||||
ASSERT_EQ(1, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, OneCpuTerminated) {
|
||||
ScopedTestFile file("10\n");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
|
||||
CpuSet set;
|
||||
ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
|
||||
ASSERT_EQ(1, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, TwoCpusWithComma) {
|
||||
ScopedTestFile file("1,10");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
|
||||
CpuSet set;
|
||||
ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
|
||||
ASSERT_EQ(2, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, TwoCpusWithRange) {
|
||||
ScopedTestFile file("1-2");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
|
||||
CpuSet set;
|
||||
ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
|
||||
ASSERT_EQ(2, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, TenCpusWithRange) {
|
||||
ScopedTestFile file("9-18");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
|
||||
CpuSet set;
|
||||
ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
|
||||
ASSERT_EQ(10, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, MultiItems) {
|
||||
ScopedTestFile file("0, 2-4, 128");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
|
||||
CpuSet set;
|
||||
ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
|
||||
ASSERT_EQ(5, set.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, IntersectWith) {
|
||||
ScopedTestFile file1("9-19");
|
||||
ASSERT_TRUE(file1.IsOk());
|
||||
CpuSet set1;
|
||||
ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
|
||||
ASSERT_EQ(11, set1.GetCount());
|
||||
|
||||
ScopedTestFile file2("16-24");
|
||||
ASSERT_TRUE(file2.IsOk());
|
||||
CpuSet set2;
|
||||
ASSERT_TRUE(set2.ParseSysFile(file2.GetFd()));
|
||||
ASSERT_EQ(9, set2.GetCount());
|
||||
|
||||
set1.IntersectWith(set2);
|
||||
ASSERT_EQ(4, set1.GetCount());
|
||||
ASSERT_EQ(9, set2.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, SelfIntersection) {
|
||||
ScopedTestFile file1("9-19");
|
||||
ASSERT_TRUE(file1.IsOk());
|
||||
CpuSet set1;
|
||||
ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
|
||||
ASSERT_EQ(11, set1.GetCount());
|
||||
|
||||
set1.IntersectWith(set1);
|
||||
ASSERT_EQ(11, set1.GetCount());
|
||||
}
|
||||
|
||||
TEST(CpuSetTest, EmptyIntersection) {
|
||||
ScopedTestFile file1("0-19");
|
||||
ASSERT_TRUE(file1.IsOk());
|
||||
CpuSet set1;
|
||||
ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
|
||||
ASSERT_EQ(20, set1.GetCount());
|
||||
|
||||
ScopedTestFile file2("20-39");
|
||||
ASSERT_TRUE(file2.IsOk());
|
||||
CpuSet set2;
|
||||
ASSERT_TRUE(set2.ParseSysFile(file2.GetFd()));
|
||||
ASSERT_EQ(20, set2.GetCount());
|
||||
|
||||
set1.IntersectWith(set2);
|
||||
ASSERT_EQ(0, set1.GetCount());
|
||||
|
||||
ASSERT_EQ(20, set2.GetCount());
|
||||
}
|
||||
|
106
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/directory_reader.h
vendored
Normal file
106
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/directory_reader.h
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
|
||||
#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class for enumerating a directory without using diropen/readdir or other
|
||||
// functions which may allocate memory.
|
||||
class DirectoryReader {
|
||||
public:
|
||||
DirectoryReader(int fd)
|
||||
: fd_(fd),
|
||||
buf_used_(0) {
|
||||
}
|
||||
|
||||
// Return the next entry from the directory
|
||||
// name: (output) the NUL terminated entry name
|
||||
//
|
||||
// Returns true iff successful (false on EOF).
|
||||
//
|
||||
// After calling this, one must call |PopEntry| otherwise you'll get the same
|
||||
// entry over and over.
|
||||
bool GetNextEntry(const char** name) {
|
||||
struct kernel_dirent* const dent =
|
||||
reinterpret_cast<kernel_dirent*>(buf_);
|
||||
|
||||
if (buf_used_ == 0) {
|
||||
// need to read more entries.
|
||||
const int n = sys_getdents(fd_, dent, sizeof(buf_));
|
||||
if (n < 0) {
|
||||
return false;
|
||||
} else if (n == 0) {
|
||||
hit_eof_ = true;
|
||||
} else {
|
||||
buf_used_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_used_ == 0 && hit_eof_)
|
||||
return false;
|
||||
|
||||
assert(buf_used_ > 0);
|
||||
|
||||
*name = dent->d_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PopEntry() {
|
||||
if (!buf_used_)
|
||||
return;
|
||||
|
||||
const struct kernel_dirent* const dent =
|
||||
reinterpret_cast<kernel_dirent*>(buf_);
|
||||
|
||||
buf_used_ -= dent->d_reclen;
|
||||
my_memmove(buf_, buf_ + dent->d_reclen, buf_used_);
|
||||
}
|
||||
|
||||
private:
|
||||
const int fd_;
|
||||
bool hit_eof_;
|
||||
unsigned buf_used_;
|
||||
uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1];
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "client/linux/minidump_writer/directory_reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
typedef testing::Test DirectoryReaderTest;
|
||||
}
|
||||
|
||||
TEST(DirectoryReaderTest, CompareResults) {
|
||||
std::set<string> dent_set;
|
||||
|
||||
DIR *const dir = opendir("/proc/self");
|
||||
ASSERT_TRUE(dir != NULL);
|
||||
|
||||
struct dirent* dent;
|
||||
while ((dent = readdir(dir)))
|
||||
dent_set.insert(dent->d_name);
|
||||
|
||||
closedir(dir);
|
||||
|
||||
const int fd = open("/proc/self", O_DIRECTORY | O_RDONLY);
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
DirectoryReader dir_reader(fd);
|
||||
unsigned seen = 0;
|
||||
|
||||
const char* name;
|
||||
while (dir_reader.GetNextEntry(&name)) {
|
||||
ASSERT_TRUE(dent_set.find(name) != dent_set.end());
|
||||
seen++;
|
||||
dir_reader.PopEntry();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(dent_set.find("status") != dent_set.end());
|
||||
ASSERT_TRUE(dent_set.find("stat") != dent_set.end());
|
||||
ASSERT_TRUE(dent_set.find("cmdline") != dent_set.end());
|
||||
|
||||
ASSERT_EQ(dent_set.size(), seen);
|
||||
close(fd);
|
||||
}
|
131
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/line_reader.h
vendored
Normal file
131
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/line_reader.h
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
|
||||
#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class for reading a file, line by line, without using fopen/fgets or other
|
||||
// functions which may allocate memory.
|
||||
class LineReader {
|
||||
public:
|
||||
LineReader(int fd)
|
||||
: fd_(fd),
|
||||
hit_eof_(false),
|
||||
buf_used_(0) {
|
||||
}
|
||||
|
||||
// The maximum length of a line.
|
||||
static const size_t kMaxLineLen = 512;
|
||||
|
||||
// Return the next line from the file.
|
||||
// line: (output) a pointer to the start of the line. The line is NUL
|
||||
// terminated.
|
||||
// len: (output) the length of the line (not inc the NUL byte)
|
||||
//
|
||||
// Returns true iff successful (false on EOF).
|
||||
//
|
||||
// One must call |PopLine| after this function, otherwise you'll continue to
|
||||
// get the same line over and over.
|
||||
bool GetNextLine(const char **line, unsigned *len) {
|
||||
for (;;) {
|
||||
if (buf_used_ == 0 && hit_eof_)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < buf_used_; ++i) {
|
||||
if (buf_[i] == '\n' || buf_[i] == 0) {
|
||||
buf_[i] = 0;
|
||||
*len = i;
|
||||
*line = buf_;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_used_ == sizeof(buf_)) {
|
||||
// we scanned the whole buffer and didn't find an end-of-line marker.
|
||||
// This line is too long to process.
|
||||
return false;
|
||||
}
|
||||
|
||||
// We didn't find any end-of-line terminators in the buffer. However, if
|
||||
// this is the last line in the file it might not have one:
|
||||
if (hit_eof_) {
|
||||
assert(buf_used_);
|
||||
// There's room for the NUL because of the buf_used_ == sizeof(buf_)
|
||||
// check above.
|
||||
buf_[buf_used_] = 0;
|
||||
*len = buf_used_;
|
||||
buf_used_ += 1; // since we appended the NUL.
|
||||
*line = buf_;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we should pull in more data from the file
|
||||
const ssize_t n = sys_read(fd_, buf_ + buf_used_,
|
||||
sizeof(buf_) - buf_used_);
|
||||
if (n < 0) {
|
||||
return false;
|
||||
} else if (n == 0) {
|
||||
hit_eof_ = true;
|
||||
} else {
|
||||
buf_used_ += n;
|
||||
}
|
||||
|
||||
// At this point, we have either set the hit_eof_ flag, or we have more
|
||||
// data to process...
|
||||
}
|
||||
}
|
||||
|
||||
void PopLine(unsigned len) {
|
||||
// len doesn't include the NUL byte at the end.
|
||||
|
||||
assert(buf_used_ >= len + 1);
|
||||
buf_used_ -= len + 1;
|
||||
my_memmove(buf_, buf_ + len + 1, buf_used_);
|
||||
}
|
||||
|
||||
private:
|
||||
const int fd_;
|
||||
|
||||
bool hit_eof_;
|
||||
unsigned buf_used_;
|
||||
char buf_[kMaxLineLen];
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
|
169
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc
vendored
Normal file
169
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
// Copyright (c) 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "client/linux/minidump_writer/line_reader.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/tests/auto_testfile.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef testing::Test LineReaderTest;
|
||||
|
||||
class ScopedTestFile : public AutoTestFile {
|
||||
public:
|
||||
explicit ScopedTestFile(const char* text)
|
||||
: AutoTestFile("line_reader", text) {
|
||||
}
|
||||
|
||||
ScopedTestFile(const char* text, size_t text_len)
|
||||
: AutoTestFile("line_reader", text, text_len) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, EmptyFile) {
|
||||
ScopedTestFile file("");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned len;
|
||||
ASSERT_FALSE(reader.GetNextLine(&line, &len));
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, OneLineTerminated) {
|
||||
ScopedTestFile file("a\n");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned int len;
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ((unsigned int)1, len);
|
||||
ASSERT_EQ('a', line[0]);
|
||||
ASSERT_EQ('\0', line[1]);
|
||||
reader.PopLine(len);
|
||||
|
||||
ASSERT_FALSE(reader.GetNextLine(&line, &len));
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, OneLine) {
|
||||
ScopedTestFile file("a");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned len;
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ((unsigned)1, len);
|
||||
ASSERT_EQ('a', line[0]);
|
||||
ASSERT_EQ('\0', line[1]);
|
||||
reader.PopLine(len);
|
||||
|
||||
ASSERT_FALSE(reader.GetNextLine(&line, &len));
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, TwoLinesTerminated) {
|
||||
ScopedTestFile file("a\nb\n");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned len;
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ((unsigned)1, len);
|
||||
ASSERT_EQ('a', line[0]);
|
||||
ASSERT_EQ('\0', line[1]);
|
||||
reader.PopLine(len);
|
||||
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ((unsigned)1, len);
|
||||
ASSERT_EQ('b', line[0]);
|
||||
ASSERT_EQ('\0', line[1]);
|
||||
reader.PopLine(len);
|
||||
|
||||
ASSERT_FALSE(reader.GetNextLine(&line, &len));
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, TwoLines) {
|
||||
ScopedTestFile file("a\nb");
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned len;
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ((unsigned)1, len);
|
||||
ASSERT_EQ('a', line[0]);
|
||||
ASSERT_EQ('\0', line[1]);
|
||||
reader.PopLine(len);
|
||||
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ((unsigned)1, len);
|
||||
ASSERT_EQ('b', line[0]);
|
||||
ASSERT_EQ('\0', line[1]);
|
||||
reader.PopLine(len);
|
||||
|
||||
ASSERT_FALSE(reader.GetNextLine(&line, &len));
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, MaxLength) {
|
||||
char l[LineReader::kMaxLineLen-1];
|
||||
memset(l, 'a', sizeof(l));
|
||||
ScopedTestFile file(l, sizeof(l));
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned len;
|
||||
ASSERT_TRUE(reader.GetNextLine(&line, &len));
|
||||
ASSERT_EQ(sizeof(l), len);
|
||||
ASSERT_TRUE(memcmp(l, line, sizeof(l)) == 0);
|
||||
ASSERT_EQ('\0', line[len]);
|
||||
}
|
||||
|
||||
TEST(LineReaderTest, TooLong) {
|
||||
// Note: this writes kMaxLineLen 'a' chars in the test file.
|
||||
char l[LineReader::kMaxLineLen];
|
||||
memset(l, 'a', sizeof(l));
|
||||
ScopedTestFile file(l, sizeof(l));
|
||||
ASSERT_TRUE(file.IsOk());
|
||||
LineReader reader(file.GetFd());
|
||||
|
||||
const char *line;
|
||||
unsigned len;
|
||||
ASSERT_FALSE(reader.GetNextLine(&line, &len));
|
||||
}
|
257
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc
vendored
Normal file
257
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc
vendored
Normal file
|
@ -0,0 +1,257 @@
|
|||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper.
|
||||
// See linux_core_dumper.h for details.
|
||||
|
||||
#include "client/linux/minidump_writer/linux_core_dumper.h"
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/procfs.h>
|
||||
#if defined(__mips__) && defined(__ANDROID__)
|
||||
// To get register definitions.
|
||||
#include <asm/reg.h>
|
||||
#endif
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
LinuxCoreDumper::LinuxCoreDumper(pid_t pid,
|
||||
const char* core_path,
|
||||
const char* procfs_path)
|
||||
: LinuxDumper(pid),
|
||||
core_path_(core_path),
|
||||
procfs_path_(procfs_path),
|
||||
thread_infos_(&allocator_, 8) {
|
||||
assert(core_path_);
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::BuildProcPath(char* path, pid_t pid,
|
||||
const char* node) const {
|
||||
if (!path || !node)
|
||||
return false;
|
||||
|
||||
size_t node_len = my_strlen(node);
|
||||
if (node_len == 0)
|
||||
return false;
|
||||
|
||||
size_t procfs_path_len = my_strlen(procfs_path_);
|
||||
size_t total_length = procfs_path_len + 1 + node_len;
|
||||
if (total_length >= NAME_MAX)
|
||||
return false;
|
||||
|
||||
memcpy(path, procfs_path_, procfs_path_len);
|
||||
path[procfs_path_len] = '/';
|
||||
memcpy(path + procfs_path_len + 1, node, node_len);
|
||||
path[total_length] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
const void* src, size_t length) {
|
||||
ElfCoreDump::Addr virtual_address = reinterpret_cast<ElfCoreDump::Addr>(src);
|
||||
// TODO(benchan): Investigate whether the data to be copied could span
|
||||
// across multiple segments in the core dump file. ElfCoreDump::CopyData
|
||||
// and this method do not handle that case yet.
|
||||
if (!core_.CopyData(dest, virtual_address, length)) {
|
||||
// If the data segment is not found in the core dump, fill the result
|
||||
// with marker characters.
|
||||
memset(dest, 0xab, length);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
|
||||
if (index >= thread_infos_.size())
|
||||
return false;
|
||||
|
||||
*info = thread_infos_[index];
|
||||
const uint8_t* stack_pointer;
|
||||
#if defined(__i386)
|
||||
memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
|
||||
#elif defined(__x86_64)
|
||||
memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
|
||||
#elif defined(__ARM_EABI__)
|
||||
memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
|
||||
#elif defined(__aarch64__)
|
||||
memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
|
||||
#elif defined(__mips__)
|
||||
stack_pointer =
|
||||
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
|
||||
#else
|
||||
#error "This code hasn't been ported to your platform yet."
|
||||
#endif
|
||||
info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::IsPostMortem() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::ThreadsSuspend() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::ThreadsResume() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::EnumerateThreads() {
|
||||
if (!mapped_core_file_.Map(core_path_, 0)) {
|
||||
fprintf(stderr, "Could not map core dump file into memory\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
core_.SetContent(mapped_core_file_.content());
|
||||
if (!core_.IsValid()) {
|
||||
fprintf(stderr, "Invalid core dump file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ElfCoreDump::Note note = core_.GetFirstNote();
|
||||
if (!note.IsValid()) {
|
||||
fprintf(stderr, "PT_NOTE section not found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first_thread = true;
|
||||
do {
|
||||
ElfCoreDump::Word type = note.GetType();
|
||||
MemoryRange name = note.GetName();
|
||||
MemoryRange description = note.GetDescription();
|
||||
|
||||
if (type == 0 || name.IsEmpty() || description.IsEmpty()) {
|
||||
fprintf(stderr, "Could not found a valid PT_NOTE.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are
|
||||
// ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific):
|
||||
// Thread Name Type
|
||||
// -------------------------------------------------------------------
|
||||
// 1st thread CORE NT_PRSTATUS
|
||||
// process-wide CORE NT_PRPSINFO
|
||||
// process-wide CORE NT_AUXV
|
||||
// 1st thread CORE NT_FPREGSET
|
||||
// 1st thread LINUX NT_PRXFPREG
|
||||
// 1st thread LINUX NT_386_TLS
|
||||
//
|
||||
// 2nd thread CORE NT_PRSTATUS
|
||||
// 2nd thread CORE NT_FPREGSET
|
||||
// 2nd thread LINUX NT_PRXFPREG
|
||||
// 2nd thread LINUX NT_386_TLS
|
||||
//
|
||||
// 3rd thread CORE NT_PRSTATUS
|
||||
// 3rd thread CORE NT_FPREGSET
|
||||
// 3rd thread LINUX NT_PRXFPREG
|
||||
// 3rd thread LINUX NT_386_TLS
|
||||
//
|
||||
// The following code only works if notes are ordered as expected.
|
||||
switch (type) {
|
||||
case NT_PRSTATUS: {
|
||||
if (description.length() != sizeof(elf_prstatus)) {
|
||||
fprintf(stderr, "Found NT_PRSTATUS descriptor of unexpected size\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const elf_prstatus* status =
|
||||
reinterpret_cast<const elf_prstatus*>(description.data());
|
||||
pid_t pid = status->pr_pid;
|
||||
ThreadInfo info;
|
||||
memset(&info, 0, sizeof(ThreadInfo));
|
||||
info.tgid = status->pr_pgrp;
|
||||
info.ppid = status->pr_ppid;
|
||||
#if defined(__mips__)
|
||||
#if defined(__ANDROID__)
|
||||
for (int i = EF_R0; i <= EF_R31; i++)
|
||||
info.mcontext.gregs[i - EF_R0] = status->pr_reg[i];
|
||||
#else // __ANDROID__
|
||||
for (int i = EF_REG0; i <= EF_REG31; i++)
|
||||
info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i];
|
||||
#endif // __ANDROID__
|
||||
info.mcontext.mdlo = status->pr_reg[EF_LO];
|
||||
info.mcontext.mdhi = status->pr_reg[EF_HI];
|
||||
info.mcontext.pc = status->pr_reg[EF_CP0_EPC];
|
||||
#else // __mips__
|
||||
memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
|
||||
#endif // __mips__
|
||||
if (first_thread) {
|
||||
crash_thread_ = pid;
|
||||
crash_signal_ = status->pr_info.si_signo;
|
||||
}
|
||||
first_thread = false;
|
||||
threads_.push_back(pid);
|
||||
thread_infos_.push_back(info);
|
||||
break;
|
||||
}
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
case NT_FPREGSET: {
|
||||
if (thread_infos_.empty())
|
||||
return false;
|
||||
|
||||
ThreadInfo* info = &thread_infos_.back();
|
||||
if (description.length() != sizeof(info->fpregs)) {
|
||||
fprintf(stderr, "Found NT_FPREGSET descriptor of unexpected size\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&info->fpregs, description.data(), sizeof(info->fpregs));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(__i386)
|
||||
case NT_PRXFPREG: {
|
||||
if (thread_infos_.empty())
|
||||
return false;
|
||||
|
||||
ThreadInfo* info = &thread_infos_.back();
|
||||
if (description.length() != sizeof(info->fpxregs)) {
|
||||
fprintf(stderr, "Found NT_PRXFPREG descriptor of unexpected size\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&info->fpxregs, description.data(), sizeof(info->fpxregs));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
note = note.GetNextNote();
|
||||
} while (note.IsValid());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
123
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_core_dumper.h
vendored
Normal file
123
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_core_dumper.h
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// linux_core_dumper.h: Define the google_breakpad::LinuxCoreDumper
|
||||
// class, which is derived from google_breakpad::LinuxDumper to extract
|
||||
// information from a crashed process via its core dump and proc files.
|
||||
|
||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_
|
||||
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_
|
||||
|
||||
#include "client/linux/minidump_writer/linux_dumper.h"
|
||||
#include "common/linux/elf_core_dump.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class LinuxCoreDumper : public LinuxDumper {
|
||||
public:
|
||||
// Constructs a dumper for extracting information of a given process
|
||||
// with a process ID of |pid| via its core dump file at |core_path| and
|
||||
// its proc files at |procfs_path|. If |procfs_path| is a copy of
|
||||
// /proc/<pid>, it should contain the following files:
|
||||
// auxv, cmdline, environ, exe, maps, status
|
||||
LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path);
|
||||
|
||||
// Implements LinuxDumper::BuildProcPath().
|
||||
// Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
|
||||
// |path| is a character array of at least NAME_MAX bytes to return the
|
||||
// result.|node| is the final node without any slashes. Return true on
|
||||
// success.
|
||||
//
|
||||
// As this dumper performs a post-mortem dump and makes use of a copy
|
||||
// of the proc files of the crashed process, this derived method does
|
||||
// not actually make use of |pid| and always returns a subpath of
|
||||
// |procfs_path_| regardless of whether |pid| corresponds to the main
|
||||
// process or a thread of the process, i.e. assuming both the main process
|
||||
// and its threads have the following proc files with the same content:
|
||||
// auxv, cmdline, environ, exe, maps, status
|
||||
virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const;
|
||||
|
||||
// Implements LinuxDumper::CopyFromProcess().
|
||||
// Copies content of |length| bytes from a given process |child|,
|
||||
// starting from |src|, into |dest|. This method extracts the content
|
||||
// the core dump and fills |dest| with a sequence of marker bytes
|
||||
// if the expected data is not found in the core dump. Returns true if
|
||||
// the expected data is found in the core dump.
|
||||
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
size_t length);
|
||||
|
||||
// Implements LinuxDumper::GetThreadInfoByIndex().
|
||||
// Reads information about the |index|-th thread of |threads_|.
|
||||
// Returns true on success. One must have called |ThreadsSuspend| first.
|
||||
virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info);
|
||||
|
||||
// Implements LinuxDumper::IsPostMortem().
|
||||
// Always returns true to indicate that this dumper performs a
|
||||
// post-mortem dump of a crashed process via a core dump file.
|
||||
virtual bool IsPostMortem() const;
|
||||
|
||||
// Implements LinuxDumper::ThreadsSuspend().
|
||||
// As the dumper performs a post-mortem dump via a core dump file,
|
||||
// there is no threads to suspend. This method does nothing and
|
||||
// always returns true.
|
||||
virtual bool ThreadsSuspend();
|
||||
|
||||
// Implements LinuxDumper::ThreadsResume().
|
||||
// As the dumper performs a post-mortem dump via a core dump file,
|
||||
// there is no threads to resume. This method does nothing and
|
||||
// always returns true.
|
||||
virtual bool ThreadsResume();
|
||||
|
||||
protected:
|
||||
// Implements LinuxDumper::EnumerateThreads().
|
||||
// Enumerates all threads of the given process into |threads_|.
|
||||
virtual bool EnumerateThreads();
|
||||
|
||||
private:
|
||||
// Path of the core dump file.
|
||||
const char* core_path_;
|
||||
|
||||
// Path of the directory containing the proc files of the given process,
|
||||
// which is usually a copy of /proc/<pid>.
|
||||
const char* procfs_path_;
|
||||
|
||||
// Memory-mapped core dump file at |core_path_|.
|
||||
MemoryMappedFile mapped_core_file_;
|
||||
|
||||
// Content of the core dump file.
|
||||
ElfCoreDump core_;
|
||||
|
||||
// Thread info found in the core dump file.
|
||||
wasteful_vector<ThreadInfo> thread_infos_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_LINUX_CORE_DUMPER_H_
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// linux_core_dumper_unittest.cc:
|
||||
// Unit tests for google_breakpad::LinuxCoreDumoer.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/linux/minidump_writer/linux_core_dumper.h"
|
||||
#include "common/linux/tests/crash_generator.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
TEST(LinuxCoreDumperTest, BuildProcPath) {
|
||||
const pid_t pid = getpid();
|
||||
const char procfs_path[] = "/procfs_copy";
|
||||
LinuxCoreDumper dumper(getpid(), "core_file", procfs_path);
|
||||
|
||||
char maps_path[NAME_MAX] = "";
|
||||
char maps_path_expected[NAME_MAX];
|
||||
snprintf(maps_path_expected, sizeof(maps_path_expected),
|
||||
"%s/maps", procfs_path);
|
||||
EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps"));
|
||||
EXPECT_STREQ(maps_path_expected, maps_path);
|
||||
|
||||
EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps"));
|
||||
EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, ""));
|
||||
EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL));
|
||||
|
||||
char long_node[NAME_MAX];
|
||||
size_t long_node_len = NAME_MAX - strlen(procfs_path) - 1;
|
||||
memset(long_node, 'a', long_node_len);
|
||||
long_node[long_node_len] = '\0';
|
||||
EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, long_node));
|
||||
}
|
||||
|
||||
TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) {
|
||||
CrashGenerator crash_generator;
|
||||
if (!crash_generator.HasDefaultCorePattern()) {
|
||||
fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test "
|
||||
"is skipped due to non-default core pattern\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned kNumOfThreads = 3;
|
||||
const unsigned kCrashThread = 1;
|
||||
const int kCrashSignal = SIGABRT;
|
||||
pid_t child_pid;
|
||||
ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
|
||||
kCrashSignal, &child_pid));
|
||||
|
||||
const string core_file = crash_generator.GetCoreFilePath();
|
||||
const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
struct stat st;
|
||||
if (stat(core_file.c_str(), &st) != 0) {
|
||||
fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test is "
|
||||
"skipped due to no core file being generated");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str());
|
||||
|
||||
EXPECT_TRUE(dumper.Init());
|
||||
|
||||
EXPECT_TRUE(dumper.IsPostMortem());
|
||||
|
||||
// These are no-ops and should always return true.
|
||||
EXPECT_TRUE(dumper.ThreadsSuspend());
|
||||
EXPECT_TRUE(dumper.ThreadsResume());
|
||||
|
||||
// LinuxCoreDumper cannot determine the crash address and thus it always
|
||||
// sets the crash address to 0.
|
||||
EXPECT_EQ(0U, dumper.crash_address());
|
||||
EXPECT_EQ(kCrashSignal, dumper.crash_signal());
|
||||
EXPECT_EQ(crash_generator.GetThreadId(kCrashThread),
|
||||
dumper.crash_thread());
|
||||
|
||||
EXPECT_EQ(kNumOfThreads, dumper.threads().size());
|
||||
for (unsigned i = 0; i < kNumOfThreads; ++i) {
|
||||
ThreadInfo info;
|
||||
EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &info));
|
||||
const void* stack;
|
||||
size_t stack_len;
|
||||
EXPECT_TRUE(dumper.GetStackInfo(&stack, &stack_len, info.stack_pointer));
|
||||
EXPECT_EQ(getpid(), info.ppid);
|
||||
}
|
||||
}
|
475
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_dumper.cc
vendored
Normal file
475
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_dumper.cc
vendored
Normal file
|
@ -0,0 +1,475 @@
|
|||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// linux_dumper.cc: Implement google_breakpad::LinuxDumper.
|
||||
// See linux_dumper.h for details.
|
||||
|
||||
// This code deals with the mechanics of getting information about a crashed
|
||||
// process. Since this code may run in a compromised address space, the same
|
||||
// rules apply as detailed at the top of minidump_writer.h: no libc calls and
|
||||
// use the alternative allocator.
|
||||
|
||||
#include "client/linux/minidump_writer/linux_dumper.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "client/linux/minidump_writer/line_reader.h"
|
||||
#include "common/linux/elfutils.h"
|
||||
#include "common/linux/file_id.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
static const char kMappedFileUnsafePrefix[] = "/dev/";
|
||||
static const char kDeletedSuffix[] = " (deleted)";
|
||||
static const char kReservedFlags[] = " ---p";
|
||||
|
||||
inline static bool IsMappedFileOpenUnsafe(
|
||||
const google_breakpad::MappingInfo& mapping) {
|
||||
// It is unsafe to attempt to open a mapped file that lives under /dev,
|
||||
// because the semantics of the open may be driver-specific so we'd risk
|
||||
// hanging the crash dumper. And a file in /dev/ almost certainly has no
|
||||
// ELF file identifier anyways.
|
||||
return my_strncmp(mapping.name,
|
||||
kMappedFileUnsafePrefix,
|
||||
sizeof(kMappedFileUnsafePrefix) - 1) == 0;
|
||||
}
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// All interesting auvx entry types are below AT_SYSINFO_EHDR
|
||||
#define AT_MAX AT_SYSINFO_EHDR
|
||||
|
||||
LinuxDumper::LinuxDumper(pid_t pid)
|
||||
: pid_(pid),
|
||||
crash_address_(0),
|
||||
crash_signal_(0),
|
||||
crash_thread_(pid),
|
||||
threads_(&allocator_, 8),
|
||||
mappings_(&allocator_),
|
||||
auxv_(&allocator_, AT_MAX + 1) {
|
||||
// The passed-in size to the constructor (above) is only a hint.
|
||||
// Must call .resize() to do actual initialization of the elements.
|
||||
auxv_.resize(AT_MAX + 1);
|
||||
}
|
||||
|
||||
LinuxDumper::~LinuxDumper() {
|
||||
}
|
||||
|
||||
bool LinuxDumper::Init() {
|
||||
return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
|
||||
}
|
||||
|
||||
bool
|
||||
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
|
||||
bool member,
|
||||
unsigned int mapping_id,
|
||||
uint8_t identifier[sizeof(MDGUID)]) {
|
||||
assert(!member || mapping_id < mappings_.size());
|
||||
my_memset(identifier, 0, sizeof(MDGUID));
|
||||
if (IsMappedFileOpenUnsafe(mapping))
|
||||
return false;
|
||||
|
||||
// Special-case linux-gate because it's not a real file.
|
||||
if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
|
||||
void* linux_gate = NULL;
|
||||
if (pid_ == sys_getpid()) {
|
||||
linux_gate = reinterpret_cast<void*>(mapping.start_addr);
|
||||
} else {
|
||||
linux_gate = allocator_.Alloc(mapping.size);
|
||||
CopyFromProcess(linux_gate, pid_,
|
||||
reinterpret_cast<const void*>(mapping.start_addr),
|
||||
mapping.size);
|
||||
}
|
||||
return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
|
||||
}
|
||||
|
||||
char filename[NAME_MAX];
|
||||
size_t filename_len = my_strlen(mapping.name);
|
||||
if (filename_len >= NAME_MAX) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
my_memcpy(filename, mapping.name, filename_len);
|
||||
filename[filename_len] = '\0';
|
||||
bool filename_modified = HandleDeletedFileInMapping(filename);
|
||||
|
||||
MemoryMappedFile mapped_file(filename, mapping.offset);
|
||||
if (!mapped_file.data() || mapped_file.size() < SELFMAG)
|
||||
return false;
|
||||
|
||||
bool success =
|
||||
FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
|
||||
if (success && member && filename_modified) {
|
||||
mappings_[mapping_id]->name[filename_len -
|
||||
sizeof(kDeletedSuffix) + 1] = '\0';
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool ElfFileSoNameFromMappedFile(
|
||||
const void* elf_base, char* soname, size_t soname_size) {
|
||||
if (!IsValidElf(elf_base)) {
|
||||
// Not ELF
|
||||
return false;
|
||||
}
|
||||
|
||||
const void* segment_start;
|
||||
size_t segment_size;
|
||||
int elf_class;
|
||||
if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC,
|
||||
&segment_start, &segment_size, &elf_class)) {
|
||||
// No dynamic section
|
||||
return false;
|
||||
}
|
||||
|
||||
const void* dynstr_start;
|
||||
size_t dynstr_size;
|
||||
if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB,
|
||||
&dynstr_start, &dynstr_size, &elf_class)) {
|
||||
// No dynstr section
|
||||
return false;
|
||||
}
|
||||
|
||||
const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start);
|
||||
size_t dcount = segment_size / sizeof(ElfW(Dyn));
|
||||
for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
|
||||
if (dyn->d_tag == DT_SONAME) {
|
||||
const char* dynstr = static_cast<const char*>(dynstr_start);
|
||||
if (dyn->d_un.d_val >= dynstr_size) {
|
||||
// Beyond the end of the dynstr section
|
||||
return false;
|
||||
}
|
||||
const char* str = dynstr + dyn->d_un.d_val;
|
||||
const size_t maxsize = dynstr_size - dyn->d_un.d_val;
|
||||
my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Did not find SONAME
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the shared object name (SONAME) by examining the ELF information
|
||||
// for |mapping|. If the SONAME is found copy it into the passed buffer
|
||||
// |soname| and return true. The size of the buffer is |soname_size|.
|
||||
// The SONAME will be truncated if it is too long to fit in the buffer.
|
||||
bool ElfFileSoName(
|
||||
const MappingInfo& mapping, char* soname, size_t soname_size) {
|
||||
if (IsMappedFileOpenUnsafe(mapping)) {
|
||||
// Not safe
|
||||
return false;
|
||||
}
|
||||
|
||||
char filename[NAME_MAX];
|
||||
size_t filename_len = my_strlen(mapping.name);
|
||||
if (filename_len >= NAME_MAX) {
|
||||
assert(false);
|
||||
// name too long
|
||||
return false;
|
||||
}
|
||||
|
||||
my_memcpy(filename, mapping.name, filename_len);
|
||||
filename[filename_len] = '\0';
|
||||
|
||||
MemoryMappedFile mapped_file(filename, mapping.offset);
|
||||
if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
|
||||
// mmap failed
|
||||
return false;
|
||||
}
|
||||
|
||||
return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// static
|
||||
void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
|
||||
char* file_path,
|
||||
size_t file_path_size,
|
||||
char* file_name,
|
||||
size_t file_name_size) {
|
||||
my_strlcpy(file_path, mapping.name, file_path_size);
|
||||
|
||||
// If an executable is mapped from a non-zero offset, this is likely because
|
||||
// the executable was loaded directly from inside an archive file (e.g., an
|
||||
// apk on Android). We try to find the name of the shared object (SONAME) by
|
||||
// looking in the file for ELF sections.
|
||||
bool mapped_from_archive = false;
|
||||
if (mapping.exec && mapping.offset != 0)
|
||||
mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size);
|
||||
|
||||
if (mapped_from_archive) {
|
||||
// Some tools (e.g., stackwalk) extract the basename from the pathname. In
|
||||
// this case, we append the file_name to the mapped archive path as follows:
|
||||
// file_name := libname.so
|
||||
// file_path := /path/to/ARCHIVE.APK/libname.so
|
||||
if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
|
||||
my_strlcat(file_path, "/", file_path_size);
|
||||
my_strlcat(file_path, file_name, file_path_size);
|
||||
}
|
||||
} else {
|
||||
// Common case:
|
||||
// file_path := /path/to/libname.so
|
||||
// file_name := libname.so
|
||||
const char* basename = my_strrchr(file_path, '/');
|
||||
basename = basename == NULL ? file_path : (basename + 1);
|
||||
my_strlcpy(file_name, basename, file_name_size);
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxDumper::ReadAuxv() {
|
||||
char auxv_path[NAME_MAX];
|
||||
if (!BuildProcPath(auxv_path, pid_, "auxv")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd = sys_open(auxv_path, O_RDONLY, 0);
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
elf_aux_entry one_aux_entry;
|
||||
bool res = false;
|
||||
while (sys_read(fd,
|
||||
&one_aux_entry,
|
||||
sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
|
||||
one_aux_entry.a_type != AT_NULL) {
|
||||
if (one_aux_entry.a_type <= AT_MAX) {
|
||||
auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val;
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
sys_close(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LinuxDumper::EnumerateMappings() {
|
||||
char maps_path[NAME_MAX];
|
||||
if (!BuildProcPath(maps_path, pid_, "maps"))
|
||||
return false;
|
||||
|
||||
// linux_gate_loc is the beginning of the kernel's mapping of
|
||||
// linux-gate.so in the process. It doesn't actually show up in the
|
||||
// maps list as a filename, but it can be found using the AT_SYSINFO_EHDR
|
||||
// aux vector entry, which gives the information necessary to special
|
||||
// case its entry when creating the list of mappings.
|
||||
// See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
|
||||
// information.
|
||||
const void* linux_gate_loc =
|
||||
reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]);
|
||||
// Although the initial executable is usually the first mapping, it's not
|
||||
// guaranteed (see http://crosbug.com/25355); therefore, try to use the
|
||||
// actual entry point to find the mapping.
|
||||
const void* entry_point_loc = reinterpret_cast<void *>(auxv_[AT_ENTRY]);
|
||||
|
||||
const int fd = sys_open(maps_path, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
LineReader* const line_reader = new(allocator_) LineReader(fd);
|
||||
|
||||
const char* line;
|
||||
unsigned line_len;
|
||||
while (line_reader->GetNextLine(&line, &line_len)) {
|
||||
uintptr_t start_addr, end_addr, offset;
|
||||
|
||||
const char* i1 = my_read_hex_ptr(&start_addr, line);
|
||||
if (*i1 == '-') {
|
||||
const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
|
||||
if (*i2 == ' ') {
|
||||
bool exec = (*(i2 + 3) == 'x');
|
||||
const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
|
||||
if (*i3 == ' ') {
|
||||
const char* name = NULL;
|
||||
// Only copy name if the name is a valid path name, or if
|
||||
// it's the VDSO image.
|
||||
if (((name = my_strchr(line, '/')) == NULL) &&
|
||||
linux_gate_loc &&
|
||||
reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
|
||||
name = kLinuxGateLibraryName;
|
||||
offset = 0;
|
||||
}
|
||||
// Merge adjacent mappings with the same name into one module,
|
||||
// assuming they're a single library mapped by the dynamic linker
|
||||
if (name && !mappings_.empty()) {
|
||||
MappingInfo* module = mappings_.back();
|
||||
if ((start_addr == module->start_addr + module->size) &&
|
||||
(my_strlen(name) == my_strlen(module->name)) &&
|
||||
(my_strncmp(name, module->name, my_strlen(name)) == 0)) {
|
||||
module->size = end_addr - module->start_addr;
|
||||
line_reader->PopLine(line_len);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Also merge mappings that result from address ranges that the
|
||||
// linker reserved but which a loaded library did not use. These
|
||||
// appear as an anonymous private mapping with no access flags set
|
||||
// and which directly follow an executable mapping.
|
||||
if (!name && !mappings_.empty()) {
|
||||
MappingInfo* module = mappings_.back();
|
||||
if ((start_addr == module->start_addr + module->size) &&
|
||||
module->exec &&
|
||||
module->name[0] == '/' &&
|
||||
offset == 0 && my_strncmp(i2,
|
||||
kReservedFlags,
|
||||
sizeof(kReservedFlags) - 1) == 0) {
|
||||
module->size = end_addr - module->start_addr;
|
||||
line_reader->PopLine(line_len);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
MappingInfo* const module = new(allocator_) MappingInfo;
|
||||
my_memset(module, 0, sizeof(MappingInfo));
|
||||
module->start_addr = start_addr;
|
||||
module->size = end_addr - start_addr;
|
||||
module->offset = offset;
|
||||
module->exec = exec;
|
||||
if (name != NULL) {
|
||||
const unsigned l = my_strlen(name);
|
||||
if (l < sizeof(module->name))
|
||||
my_memcpy(module->name, name, l);
|
||||
}
|
||||
// If this is the entry-point mapping, and it's not already the
|
||||
// first one, then we need to make it be first. This is because
|
||||
// the minidump format assumes the first module is the one that
|
||||
// corresponds to the main executable (as codified in
|
||||
// processor/minidump.cc:MinidumpModuleList::GetMainModule()).
|
||||
if (entry_point_loc &&
|
||||
(entry_point_loc >=
|
||||
reinterpret_cast<void*>(module->start_addr)) &&
|
||||
(entry_point_loc <
|
||||
reinterpret_cast<void*>(module->start_addr+module->size)) &&
|
||||
!mappings_.empty()) {
|
||||
// push the module onto the front of the list.
|
||||
mappings_.resize(mappings_.size() + 1);
|
||||
for (size_t idx = mappings_.size() - 1; idx > 0; idx--)
|
||||
mappings_[idx] = mappings_[idx - 1];
|
||||
mappings_[0] = module;
|
||||
} else {
|
||||
mappings_.push_back(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
line_reader->PopLine(line_len);
|
||||
}
|
||||
|
||||
sys_close(fd);
|
||||
|
||||
return !mappings_.empty();
|
||||
}
|
||||
|
||||
// Get information about the stack, given the stack pointer. We don't try to
|
||||
// walk the stack since we might not have all the information needed to do
|
||||
// unwind. So we just grab, up to, 32k of stack.
|
||||
bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
|
||||
uintptr_t int_stack_pointer) {
|
||||
// Move the stack pointer to the bottom of the page that it's in.
|
||||
const uintptr_t page_size = getpagesize();
|
||||
|
||||
uint8_t* const stack_pointer =
|
||||
reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
|
||||
|
||||
// The number of bytes of stack which we try to capture.
|
||||
static const ptrdiff_t kStackToCapture = 32 * 1024;
|
||||
|
||||
const MappingInfo* mapping = FindMapping(stack_pointer);
|
||||
if (!mapping)
|
||||
return false;
|
||||
const ptrdiff_t offset = stack_pointer -
|
||||
reinterpret_cast<uint8_t*>(mapping->start_addr);
|
||||
const ptrdiff_t distance_to_end =
|
||||
static_cast<ptrdiff_t>(mapping->size) - offset;
|
||||
*stack_len = distance_to_end > kStackToCapture ?
|
||||
kStackToCapture : distance_to_end;
|
||||
*stack = stack_pointer;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find the mapping which the given memory address falls in.
|
||||
const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
|
||||
const uintptr_t addr = (uintptr_t) address;
|
||||
|
||||
for (size_t i = 0; i < mappings_.size(); ++i) {
|
||||
const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
|
||||
if (addr >= start && addr - start < mappings_[i]->size)
|
||||
return mappings_[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
|
||||
static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
|
||||
|
||||
// Check for ' (deleted)' in |path|.
|
||||
// |path| has to be at least as long as "/x (deleted)".
|
||||
const size_t path_len = my_strlen(path);
|
||||
if (path_len < kDeletedSuffixLen + 2)
|
||||
return false;
|
||||
if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
|
||||
kDeletedSuffixLen) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check |path| against the /proc/pid/exe 'symlink'.
|
||||
char exe_link[NAME_MAX];
|
||||
char new_path[NAME_MAX];
|
||||
if (!BuildProcPath(exe_link, pid_, "exe"))
|
||||
return false;
|
||||
if (!SafeReadLink(exe_link, new_path))
|
||||
return false;
|
||||
if (my_strcmp(path, new_path) != 0)
|
||||
return false;
|
||||
|
||||
// Check to see if someone actually named their executable 'foo (deleted)'.
|
||||
struct kernel_stat exe_stat;
|
||||
struct kernel_stat new_path_stat;
|
||||
if (sys_stat(exe_link, &exe_stat) == 0 &&
|
||||
sys_stat(new_path, &new_path_stat) == 0 &&
|
||||
exe_stat.st_dev == new_path_stat.st_dev &&
|
||||
exe_stat.st_ino == new_path_stat.st_ino) {
|
||||
return false;
|
||||
}
|
||||
|
||||
my_memcpy(path, exe_link, NAME_MAX);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
189
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_dumper.h
vendored
Normal file
189
TMessagesProj/jni/third_party/breakpad/src/client/linux/minidump_writer/linux_dumper.h
vendored
Normal file
|
@ -0,0 +1,189 @@
|
|||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// linux_dumper.h: Define the google_breakpad::LinuxDumper class, which
|
||||
// is a base class for extracting information of a crashed process. It
|
||||
// was originally a complete implementation using the ptrace API, but
|
||||
// has been refactored to allow derived implementations supporting both
|
||||
// ptrace and core dump. A portion of the original implementation is now
|
||||
// in google_breakpad::LinuxPtraceDumper (see linux_ptrace_dumper.h for
|
||||
// details).
|
||||
|
||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
|
||||
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
|
||||
|
||||
#include <elf.h>
|
||||
#include <linux/limits.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "client/linux/dump_writer_common/mapping_info.h"
|
||||
#include "client/linux/dump_writer_common/thread_info.h"
|
||||
#include "common/memory.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
|
||||
#if defined(__i386) || defined(__ARM_EABI__) || \
|
||||
(defined(__mips__) && _MIPS_SIM == _ABIO32)
|
||||
typedef Elf32_auxv_t elf_aux_entry;
|
||||
#elif defined(__x86_64) || defined(__aarch64__) || \
|
||||
(defined(__mips__) && _MIPS_SIM != _ABIO32)
|
||||
typedef Elf64_auxv_t elf_aux_entry;
|
||||
#endif
|
||||
|
||||
typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t;
|
||||
|
||||
// When we find the VDSO mapping in the process's address space, this
|
||||
// is the name we use for it when writing it to the minidump.
|
||||
// This should always be less than NAME_MAX!
|
||||
const char kLinuxGateLibraryName[] = "linux-gate.so";
|
||||
|
||||
class LinuxDumper {
|
||||
public:
|
||||
explicit LinuxDumper(pid_t pid);
|
||||
|
||||
virtual ~LinuxDumper();
|
||||
|
||||
// Parse the data for |threads| and |mappings|.
|
||||
virtual bool Init();
|
||||
|
||||
// Return true if the dumper performs a post-mortem dump.
|
||||
virtual bool IsPostMortem() const = 0;
|
||||
|
||||
// Suspend/resume all threads in the given process.
|
||||
virtual bool ThreadsSuspend() = 0;
|
||||
virtual bool ThreadsResume() = 0;
|
||||
|
||||
// Read information about the |index|-th thread of |threads_|.
|
||||
// Returns true on success. One must have called |ThreadsSuspend| first.
|
||||
virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info) = 0;
|
||||
|
||||
// These are only valid after a call to |Init|.
|
||||
const wasteful_vector<pid_t> &threads() { return threads_; }
|
||||
const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
|
||||
const MappingInfo* FindMapping(const void* address) const;
|
||||
const wasteful_vector<elf_aux_val_t>& auxv() { return auxv_; }
|
||||
|
||||
// Find a block of memory to take as the stack given the top of stack pointer.
|
||||
// stack: (output) the lowest address in the memory area
|
||||
// stack_len: (output) the length of the memory area
|
||||
// stack_top: the current top of the stack
|
||||
bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
|
||||
|
||||
PageAllocator* allocator() { return &allocator_; }
|
||||
|
||||
// Copy content of |length| bytes from a given process |child|,
|
||||
// starting from |src|, into |dest|. Returns true on success.
|
||||
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
size_t length) = 0;
|
||||
|
||||
// Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
|
||||
// |path| is a character array of at least NAME_MAX bytes to return the
|
||||
// result.|node| is the final node without any slashes. Returns true on
|
||||
// success.
|
||||
virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0;
|
||||
|
||||
// Generate a File ID from the .text section of a mapped entry.
|
||||
// If not a member, mapping_id is ignored. This method can also manipulate the
|
||||
// |mapping|.name to truncate "(deleted)" from the file name if necessary.
|
||||
bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
|
||||
bool member,
|
||||
unsigned int mapping_id,
|
||||
uint8_t identifier[sizeof(MDGUID)]);
|
||||
|
||||
uintptr_t crash_address() const { return crash_address_; }
|
||||
void set_crash_address(uintptr_t crash_address) {
|
||||
crash_address_ = crash_address;
|
||||
}
|
||||
|
||||
int crash_signal() const { return crash_signal_; }
|
||||
void set_crash_signal(int crash_signal) { crash_signal_ = crash_signal; }
|
||||
|
||||
pid_t crash_thread() const { return crash_thread_; }
|
||||
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
|
||||
|
||||
// Extracts the effective path and file name of from |mapping|. In most cases
|
||||
// the effective name/path are just the mapping's path and basename. In some
|
||||
// other cases, however, a library can be mapped from an archive (e.g., when
|
||||
// loading .so libs from an apk on Android) and this method is able to
|
||||
// reconstruct the original file name.
|
||||
static void GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
|
||||
char* file_path,
|
||||
size_t file_path_size,
|
||||
char* file_name,
|
||||
size_t file_name_size);
|
||||
|
||||
protected:
|
||||
bool ReadAuxv();
|
||||
|
||||
virtual bool EnumerateMappings();
|
||||
|
||||
virtual bool EnumerateThreads() = 0;
|
||||
|
||||
// For the case where a running program has been deleted, it'll show up in
|
||||
// /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then
|
||||
// see if '/path/to/program (deleted)' matches /proc/pid/exe and return
|
||||
// /proc/pid/exe in |path| so ELF identifier generation works correctly. This
|
||||
// also checks to see if '/path/to/program (deleted)' exists, so it does not
|
||||
// get fooled by a poorly named binary.
|
||||
// For programs that don't end with ' (deleted)', this is a no-op.
|
||||
// This assumes |path| is a buffer with length NAME_MAX.
|
||||
// Returns true if |path| is modified.
|
||||
bool HandleDeletedFileInMapping(char* path) const;
|
||||
|
||||
// ID of the crashed process.
|
||||
const pid_t pid_;
|
||||
|
||||
// Virtual address at which the process crashed.
|
||||
uintptr_t crash_address_;
|
||||
|
||||
// Signal that terminated the crashed process.
|
||||
int crash_signal_;
|
||||
|
||||
// ID of the crashed thread.
|
||||
pid_t crash_thread_;
|
||||
|
||||
mutable PageAllocator allocator_;
|
||||
|
||||
// IDs of all the threads.
|
||||
wasteful_vector<pid_t> threads_;
|
||||
|
||||
// Info from /proc/<pid>/maps.
|
||||
wasteful_vector<MappingInfo*> mappings_;
|
||||
|
||||
// Info from /proc/<pid>/auxv
|
||||
wasteful_vector<elf_aux_val_t> auxv_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue