├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── github │ └── kr328 │ └── plugin │ └── riru │ ├── CMakePlugin.java │ ├── MagiskPlugin.java │ ├── SignaturePlugin.java │ ├── TransformDexPlugin.java │ ├── conf │ ├── AndroidConfig.java │ ├── CMakeConfig.java │ └── LocalProperties.java │ ├── exts │ ├── CMakeExtension.java │ ├── MagiskExtension.java │ ├── SignatureExtension.java │ └── TransformDexExtension.java │ ├── tasks │ ├── CMakeBuildTask.java │ ├── CMakeConfigTask.java │ ├── MagiskBuildTask.java │ ├── SignatureTask.java │ └── TransformDexTask.java │ └── utils │ ├── AndroidUtils.java │ └── PathUtils.java ├── classpath ├── build.gradle └── src │ └── main │ └── java │ └── android │ ├── app │ └── IActivityManager.java │ ├── content │ └── IContentProvider.java │ └── os │ ├── IServiceManager.java │ ├── ServiceManager.java │ └── ServiceManagerNative.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── settings.gradle └── src └── main ├── cpp ├── CMakeLists.txt ├── hook.c ├── hook.h ├── libriru_utils │ ├── CMakeLists.txt │ ├── libriru │ │ ├── CMakeLists.txt │ │ ├── README.txt │ │ ├── riru.c │ │ └── riru.h │ ├── libxhook │ │ ├── CMakeLists.txt │ │ ├── README.txt │ │ ├── queue.h │ │ ├── tree.h │ │ ├── xh_core.c │ │ ├── xh_core.h │ │ ├── xh_elf.c │ │ ├── xh_elf.h │ │ ├── xh_errno.h │ │ ├── xh_jni.c │ │ ├── xh_log.c │ │ ├── xh_log.h │ │ ├── xh_util.c │ │ ├── xh_util.h │ │ ├── xh_version.c │ │ ├── xh_version.h │ │ ├── xhook.c │ │ └── xhook.h │ ├── riru_utils.c │ └── riru_utils.h ├── log.h └── main.c ├── java └── com │ └── github │ └── kr328 │ └── srsf │ ├── Global.java │ ├── Injector.java │ └── LocalInterfaceProxy.java └── raw └── magisk ├── META-INF └── com │ └── google │ └── android │ ├── update-binary │ └── updater-script ├── common ├── post-fs-data.sh ├── service.sh └── system.prop ├── config.sh └── module.prop /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | 4 | # Ignore Gradle GUI config 5 | gradle-app.setting 6 | 7 | # Avoid ignoring Gradle wrapper jar targetFile (.jar files are usually ignored) 8 | !gradle-wrapper.jar 9 | 10 | # Cache of project 11 | .gradletasknamecache 12 | 13 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 14 | # gradle/wrapper/gradle-wrapper.properties 15 | 16 | # Ignore IDEA config 17 | /.idea 18 | *.iml 19 | 20 | # KeyStore 21 | *.keystore 22 | *.jks 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source targetFile to most effectively 631 | state the exclusion of warranty; and each targetFile should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Riru - SRSharedFix (Deprecated) 2 | 3 | A module of [Riru](https://github.com/RikkaApps/Riru). Fix [StorageRedirect](https://play.google.com/store/apps/details?id=moe.shizuku.redirectstorage) open/share file to other apps cause file not found problem. 4 | 5 | ## Requirements 6 | 7 | * [Riru](https://github.com/RikkaApps/Riru) > 7 installed. 8 | * Android 9.0 (8.0/8.1 not tested) 9 | 10 | ## Build 11 | 12 | 1.Install JDK ,Gradle ,Android SDK ,Android NDK 13 | 14 | 2.Configure with your environment [local.properties](https://github.com/Kr328/Riru-InternalBrowserRedirect/blob/master/local.properties) 15 | 16 | 3.Run command 17 | 18 | ``` Gradle 19 | ./gradlew build 20 | ``` 21 | 4.Pick magisk-module.zip from build/outputs 22 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import com.github.kr328.plugin.riru.CMakePlugin 2 | import com.github.kr328.plugin.riru.MagiskPlugin 3 | import com.github.kr328.plugin.riru.SignaturePlugin 4 | import com.github.kr328.plugin.riru.TransformDexPlugin 5 | import com.github.kr328.plugin.riru.utils.AndroidUtils 6 | import com.github.kr328.plugin.riru.utils.PathUtils 7 | 8 | apply plugin: 'java' 9 | apply plugin: 'idea' 10 | apply plugin: CMakePlugin 11 | apply plugin: TransformDexPlugin 12 | apply plugin: MagiskPlugin 13 | apply plugin: SignaturePlugin; 14 | 15 | sourceCompatibility = 1.8 16 | targetCompatibility = 1.8 17 | 18 | repositories { 19 | mavenCentral() 20 | jcenter() 21 | } 22 | 23 | sourceSets { 24 | main.compileClasspath += project(":classpath").files("src/main/java") // for hidden api 25 | main.compileClasspath += files(AndroidUtils.androidJarPath("android-28")) //android.jar 26 | } 27 | 28 | compileJava { 29 | destinationDir file(PathUtils.toLocalSeparator("$buildDir/intermediate/classes")) 30 | } 31 | 32 | cmake { 33 | source 'src/main/cpp' 34 | abiFilter "armeabi-v7a" ,"arm64-v8a" 35 | platform "android-21" 36 | } 37 | 38 | dex { 39 | buildToolsVersion "28.0.3" 40 | compilePlatform "android-28" 41 | output "boot-srsf.jar" 42 | } 43 | 44 | magisk { 45 | output file("$buildDir/outputs/magisk-module.zip") 46 | 47 | map file("$buildDir/outputs/dex/") ,"system/framework/" 48 | map file("$buildDir/outputs/cmake/armeabi-v7a/shared") ,"system/lib" 49 | map file("$buildDir/outputs/cmake/arm64-v8a/shared") ,"system/lib64" 50 | map file("src/main/raw/magisk") ,"" 51 | } 52 | 53 | signature { 54 | targetFile file("$buildDir/outputs/magisk-module.zip") 55 | buildToolsVersion "28.0.3" 56 | 57 | keyStore file("release.keystore") 58 | keyStorePassword "android" 59 | alias "androiddebugkey" 60 | aliasPassword "android" 61 | } 62 | 63 | task cleanAll(type: Delete) { 64 | delete "build" ,"out" 65 | delete PathUtils.toLocalSeparator("buildSrc/build") ,PathUtils.toLocalSeparator("buildSrc/out") 66 | } 67 | 68 | dependencies { 69 | compileOnly project("classpath") 70 | } 71 | 72 | signatureOutput.dependsOn(buildMagiskModule) 73 | assemble.dependsOn.clear() 74 | build.dependsOn.clear() 75 | assemble.dependsOn(cmakeBuild ,transformDex ,buildMagiskModule ,signatureOutput) 76 | build.dependsOn(assemble) 77 | clean.dependsOn(cleanAll) -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'groovy' 2 | apply plugin: 'java' 3 | 4 | dependencies { 5 | compile gradleApi() 6 | compile localGroovy() 7 | } -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/CMakePlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru; 2 | 3 | import com.github.kr328.plugin.riru.conf.CMakeConfig; 4 | import com.github.kr328.plugin.riru.exts.CMakeExtension; 5 | import com.github.kr328.plugin.riru.tasks.CMakeBuildTask; 6 | import com.github.kr328.plugin.riru.tasks.CMakeConfigTask; 7 | import org.gradle.api.Plugin; 8 | import org.gradle.api.Project; 9 | 10 | public class CMakePlugin implements Plugin { 11 | @Override 12 | public void apply(Project target) { 13 | CMakeExtension cMakeExtension = target.getExtensions().create("cmake" , CMakeExtension.class); 14 | CMakeConfig cMakeConfig = CMakeConfig.read(); 15 | 16 | CMakeConfigTask cMakeConfigTask = target.getTasks().create("cmakeConfig" , CMakeConfigTask.class); 17 | CMakeBuildTask cMakeBuildTask = target.getTasks().create("cmakeBuild" ,CMakeBuildTask.class); 18 | 19 | cMakeConfigTask.config = cMakeConfig; 20 | cMakeConfigTask.extension = cMakeExtension; 21 | cMakeBuildTask.config = cMakeConfig; 22 | cMakeBuildTask.extension = cMakeExtension; 23 | 24 | cMakeBuildTask.dependsOn(cMakeConfigTask); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/MagiskPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru; 2 | 3 | import com.github.kr328.plugin.riru.exts.MagiskExtension; 4 | import com.github.kr328.plugin.riru.tasks.MagiskBuildTask; 5 | import org.gradle.api.Plugin; 6 | import org.gradle.api.Project; 7 | 8 | public class MagiskPlugin implements Plugin { 9 | @Override 10 | public void apply(Project target) { 11 | MagiskExtension extension = target.getExtensions().create("magisk" , MagiskExtension.class); 12 | MagiskBuildTask task = target.getTasks().create("buildMagiskModule" , MagiskBuildTask.class); 13 | 14 | //task.mustRunAfter(TransformDexTask.class , CMakeBuildTask.class); 15 | task.mustRunAfter("transformDex" ,"cmakeBuild"); 16 | 17 | task.extension = extension; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/SignaturePlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru; 2 | 3 | import com.github.kr328.plugin.riru.conf.AndroidConfig; 4 | import com.github.kr328.plugin.riru.exts.SignatureExtension; 5 | import com.github.kr328.plugin.riru.tasks.SignatureTask; 6 | import org.gradle.api.Plugin; 7 | import org.gradle.api.Project; 8 | 9 | public class SignaturePlugin implements Plugin { 10 | @Override 11 | public void apply(Project project) { 12 | SignatureExtension extension = project.getExtensions().create("signature" , SignatureExtension.class); 13 | SignatureTask task = project.getTasks().create("signatureOutput" ,SignatureTask.class); 14 | 15 | task.extension = extension; 16 | task.config = AndroidConfig.read(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/TransformDexPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru; 2 | 3 | import com.github.kr328.plugin.riru.conf.AndroidConfig; 4 | import com.github.kr328.plugin.riru.exts.TransformDexExtension; 5 | import com.github.kr328.plugin.riru.tasks.TransformDexTask; 6 | import org.gradle.api.Plugin; 7 | import org.gradle.api.Project; 8 | import org.gradle.api.plugins.JavaPlugin; 9 | import org.gradle.api.tasks.compile.JavaCompile; 10 | 11 | public class TransformDexPlugin implements Plugin { 12 | @Override 13 | public void apply(Project target) { 14 | target.getPluginManager().apply(JavaPlugin.class); 15 | 16 | TransformDexExtension extension = target.getExtensions().create("dex" , TransformDexExtension.class); 17 | AndroidConfig config = AndroidConfig.read(); 18 | 19 | JavaCompile javaCompile = (JavaCompile)target.getTasks().getByName("compileJava"); 20 | TransformDexTask transformDexTask = target.getTasks().create("transformDex" , TransformDexTask.class); 21 | 22 | transformDexTask.dependsOn(javaCompile); 23 | 24 | transformDexTask.extension = extension; 25 | transformDexTask.config = config; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/conf/AndroidConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.conf; 2 | 3 | import org.gradle.api.GradleScriptException; 4 | 5 | import java.util.Properties; 6 | 7 | public class AndroidConfig { 8 | public String androidSdkPath; 9 | 10 | public static AndroidConfig read() { 11 | Properties properties = LocalProperties.get(); 12 | AndroidConfig result = new AndroidConfig(); 13 | 14 | result.androidSdkPath = properties.getProperty("android.sdk"); 15 | 16 | if ( result.androidSdkPath == null ) 17 | throw new GradleScriptException("android.sdk must set in local.properies" ,new NullPointerException()); 18 | 19 | return result; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/conf/CMakeConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.conf; 2 | 3 | import org.gradle.api.GradleScriptException; 4 | 5 | import java.util.Properties; 6 | 7 | public class CMakeConfig { 8 | public String cmakeDirectory; 9 | public String androidNdkPath; 10 | 11 | public static CMakeConfig read() { 12 | Properties properties = LocalProperties.get(); 13 | CMakeConfig result = new CMakeConfig(); 14 | 15 | result.cmakeDirectory = properties.getProperty("android.cmake"); 16 | result.androidNdkPath = properties.getProperty("android.ndk"); 17 | 18 | if ( result.cmakeDirectory == null ) 19 | throw new GradleScriptException("android.cmake must set in local.properties" ,new Exception()); 20 | 21 | if ( result.androidNdkPath == null ) 22 | throw new GradleScriptException("android.ndk must set in local.properties" ,new Exception()); 23 | 24 | return result; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/conf/LocalProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.conf; 2 | 3 | import org.gradle.api.GradleScriptException; 4 | 5 | import java.io.FileInputStream; 6 | import java.util.Properties; 7 | 8 | public class LocalProperties { 9 | private static Properties properties; 10 | 11 | public static synchronized Properties get() { 12 | if ( properties == null ) { 13 | properties = new Properties(); 14 | FileInputStream fileInputStream; 15 | 16 | try { 17 | fileInputStream = new FileInputStream("local.properties"); 18 | properties.load(fileInputStream); 19 | } catch (Exception e) { 20 | throw new GradleScriptException("local.properties load failure" ,e); 21 | } 22 | } 23 | 24 | return properties; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/exts/CMakeExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.exts; 2 | 3 | public class CMakeExtension { 4 | private String source = ""; 5 | private String platform = "android-24"; 6 | private String[] abiFilter = new String[]{"armeabi-v7a" ,"arm64-v8a"}; 7 | private String stl = "c++_static"; 8 | 9 | public String getSource() { 10 | return source; 11 | } 12 | 13 | public void setSource(String source) { 14 | this.source = source; 15 | } 16 | 17 | public String getPlatform() { 18 | return platform; 19 | } 20 | 21 | public void setPlatform(String platform) { 22 | this.platform = platform; 23 | } 24 | 25 | public String[] getAbiFilter() { 26 | return abiFilter; 27 | } 28 | 29 | public void setAbiFilter(String[] abiFilter) { 30 | this.abiFilter = abiFilter; 31 | } 32 | 33 | public String getStl() { 34 | return stl; 35 | } 36 | 37 | public void setStl(String stl) { 38 | this.stl = stl; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/exts/MagiskExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.exts; 2 | 3 | import com.github.kr328.plugin.riru.utils.PathUtils; 4 | import groovy.lang.Closure; 5 | import org.gradle.api.NamedDomainObjectCollection; 6 | import org.gradle.api.Project; 7 | 8 | import java.io.File; 9 | import java.util.HashMap; 10 | 11 | public class MagiskExtension { 12 | private HashMap zipMap = new HashMap<>(); 13 | private File output; 14 | 15 | public MagiskExtension map(File source ,String target) { 16 | zipMap.put(source ,target); 17 | return this; 18 | } 19 | 20 | public HashMap getZipMap() { 21 | return zipMap; 22 | } 23 | 24 | public File getOutput() { 25 | return output; 26 | } 27 | 28 | public void setOutput(File output) { 29 | this.output = output; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/exts/SignatureExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.exts; 2 | 3 | import java.io.File; 4 | 5 | public class SignatureExtension { 6 | private File targetFile; 7 | private String buildToolsVersion; 8 | 9 | private File keyStore; 10 | private String keyStorePassword; 11 | private String alias; 12 | private String aliasPassword; 13 | 14 | public File getKeyStore() { 15 | return keyStore; 16 | } 17 | 18 | public void setKeyStore(File keyStore) { 19 | this.keyStore = keyStore; 20 | } 21 | 22 | public String getKeyStorePassword() { 23 | return keyStorePassword; 24 | } 25 | 26 | public void setKeyStorePassword(String keyStorePassword) { 27 | this.keyStorePassword = keyStorePassword; 28 | } 29 | 30 | public String getAlias() { 31 | return alias; 32 | } 33 | 34 | public void setAlias(String alias) { 35 | this.alias = alias; 36 | } 37 | 38 | public String getAliasPassword() { 39 | return aliasPassword; 40 | } 41 | 42 | public void setAliasPassword(String aliasPassword) { 43 | this.aliasPassword = aliasPassword; 44 | } 45 | 46 | public File getTargetFile() { 47 | return targetFile; 48 | } 49 | 50 | public void setTargetFile(File targetFile) { 51 | this.targetFile = targetFile; 52 | } 53 | 54 | public String getBuildToolsVersion() { 55 | return buildToolsVersion; 56 | } 57 | 58 | public void setBuildToolsVersion(String buildToolsVersion) { 59 | this.buildToolsVersion = buildToolsVersion; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/exts/TransformDexExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.exts; 2 | 3 | import com.github.kr328.plugin.riru.utils.PathUtils; 4 | 5 | public class TransformDexExtension { 6 | private String buildToolsVersion = ""; 7 | private String compilePlatform = ""; 8 | private String output = "classes.dex"; 9 | 10 | public String getBuildToolsVersion() { 11 | return buildToolsVersion; 12 | } 13 | 14 | public void setBuildToolsVersion(String buildToolsVersion) { 15 | this.buildToolsVersion = buildToolsVersion; 16 | } 17 | 18 | public String getCompilePlatform() { 19 | return compilePlatform; 20 | } 21 | 22 | public void setCompilePlatform(String compilePlatform) { 23 | this.compilePlatform = compilePlatform; 24 | } 25 | 26 | public String getOutput() { 27 | return output; 28 | } 29 | 30 | public void setOutput(String output) { 31 | this.output = output; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/tasks/CMakeBuildTask.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.tasks; 2 | 3 | import com.github.kr328.plugin.riru.conf.CMakeConfig; 4 | import com.github.kr328.plugin.riru.exts.CMakeExtension; 5 | import com.github.kr328.plugin.riru.utils.PathUtils; 6 | import org.gradle.api.DefaultTask; 7 | import org.gradle.api.GradleScriptException; 8 | import org.gradle.api.tasks.TaskAction; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.File; 12 | import java.io.InputStreamReader; 13 | 14 | public class CMakeBuildTask extends DefaultTask { 15 | public CMakeExtension extension; 16 | public CMakeConfig config; 17 | 18 | @TaskAction 19 | @SuppressWarnings("unused") 20 | public void executeBuild() { 21 | for ( String abi : extension.getAbiFilter() ) { 22 | try { 23 | executeAbi(abi); 24 | } catch (Exception e) { 25 | throw new GradleScriptException("CMake build failure." ,e); 26 | } 27 | } 28 | } 29 | 30 | private void executeAbi(String abi) throws Exception { 31 | ProcessBuilder builder = new ProcessBuilder(); 32 | StringBuilder outputs = new StringBuilder(); 33 | 34 | builder.command(PathUtils.toLocalSeparator(config.cmakeDirectory + "/bin/cmake" + PathUtils.executableSuffix(".exe")) , "--build" ,"."); 35 | 36 | File cmakeConfigDirectory = getProject().file(PathUtils.toLocalSeparator(getProject().getBuildDir().getAbsolutePath() + "/intermediate/cmake/" + abi)).getAbsoluteFile(); 37 | 38 | builder.directory(cmakeConfigDirectory); 39 | 40 | Process process = builder.start(); 41 | BufferedReader reader; 42 | String line; 43 | 44 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 45 | while (( line = reader.readLine()) != null ) 46 | outputs.append(line).append('\n'); 47 | reader.close(); 48 | 49 | reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 50 | while (( line = reader.readLine()) != null ) 51 | outputs.append(line).append('\n'); 52 | reader.close(); 53 | 54 | int result = process.waitFor(); 55 | 56 | if ( result != 0 ) 57 | throw new Exception("CMake build failure: \n" + outputs.toString()); 58 | 59 | process.destroy(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/tasks/CMakeConfigTask.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.tasks; 2 | 3 | import com.github.kr328.plugin.riru.conf.CMakeConfig; 4 | import com.github.kr328.plugin.riru.exts.CMakeExtension; 5 | import com.github.kr328.plugin.riru.utils.PathUtils; 6 | import org.gradle.api.DefaultTask; 7 | import org.gradle.api.GradleScriptException; 8 | import org.gradle.api.tasks.TaskAction; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.File; 12 | import java.io.InputStreamReader; 13 | 14 | public class CMakeConfigTask extends DefaultTask { 15 | public CMakeExtension extension; 16 | public CMakeConfig config; 17 | 18 | @TaskAction @SuppressWarnings("unused") 19 | public void execCMake() { 20 | for ( String abi : extension.getAbiFilter()) { 21 | try { 22 | execCMakeAbi(abi); 23 | } catch (Exception e) { 24 | throw new GradleScriptException("CMake build failure" ,e); 25 | } 26 | } 27 | } 28 | 29 | @SuppressWarnings("ResultOfMethodCallIgnored") 30 | private void execCMakeAbi(String abi) throws Exception { 31 | ProcessBuilder builder = new ProcessBuilder(); 32 | StringBuilder outputs = new StringBuilder(); 33 | 34 | builder.command(PathUtils.toLocalSeparator(config.cmakeDirectory + "/bin/cmake" + PathUtils.executableSuffix(".exe")) , 35 | "-G" ,"Ninja" , 36 | "-DCMAKE_MAKE_PROGRAM=" + PathUtils.toLocalSeparator(config.cmakeDirectory + "/bin/ninja" + PathUtils.executableSuffix(".exe")), 37 | "-DCMAKE_TOOLCHAIN_FILE=" + PathUtils.toLocalSeparator(config.androidNdkPath + "/build/cmake/android.toolchain.cmake") , 38 | "-DANDROID_PLATFORM=" + extension.getPlatform(), 39 | "-DANDROID_STL=" + extension.getStl(), 40 | "-DANDROID_ABI=" + abi , 41 | "-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=" + PathUtils.toLocalSeparator(getProject().getBuildDir().getAbsolutePath() + "/outputs/cmake/" + abi + "/static") , 42 | "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=" + PathUtils.toLocalSeparator(getProject().getBuildDir().getAbsolutePath() + "/outputs/cmake/" + abi + "/shared") , 43 | "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=" + PathUtils.toLocalSeparator(getProject().getBuildDir().getAbsolutePath() + "/outputs/cmake/" + abi + "/executable") , 44 | getProject().file(PathUtils.toLocalSeparator(extension.getSource())).getAbsolutePath()); 45 | 46 | File cmakeConfigDirectory = getProject().file(PathUtils.toLocalSeparator(getProject().getBuildDir().getAbsolutePath() + "/intermediate/cmake/" + abi)).getAbsoluteFile(); 47 | cmakeConfigDirectory.mkdirs(); 48 | 49 | builder.directory(cmakeConfigDirectory); 50 | 51 | Process process = builder.start(); 52 | BufferedReader reader; 53 | String line; 54 | 55 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 56 | while (( line = reader.readLine()) != null ) 57 | outputs.append(line).append('\n'); 58 | reader.close(); 59 | 60 | reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 61 | while (( line = reader.readLine()) != null ) 62 | outputs.append(line).append('\n'); 63 | reader.close(); 64 | 65 | int result = process.waitFor(); 66 | 67 | if ( result != 0 ) 68 | throw new Exception("CMake config failure: \n" + outputs.toString()); 69 | 70 | process.destroy(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/tasks/MagiskBuildTask.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.tasks; 2 | 3 | import com.github.kr328.plugin.riru.exts.MagiskExtension; 4 | import com.github.kr328.plugin.riru.utils.PathUtils; 5 | import org.gradle.api.DefaultTask; 6 | import org.gradle.api.GradleScriptException; 7 | import org.gradle.api.tasks.TaskAction; 8 | 9 | import java.io.*; 10 | import java.util.Map; 11 | import java.util.Objects; 12 | import java.util.zip.ZipEntry; 13 | import java.util.zip.ZipOutputStream; 14 | 15 | public class MagiskBuildTask extends DefaultTask { 16 | public MagiskExtension extension; 17 | 18 | @TaskAction 19 | @SuppressWarnings({"unused", "ResultOfMethodCallIgnored"}) 20 | public void run() throws IOException { 21 | File outputFile = new File(extension.getOutput().getAbsolutePath()); 22 | outputFile.getParentFile().mkdirs(); 23 | 24 | ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile)); 25 | 26 | for ( Map.Entry entry : extension.getZipMap().entrySet() ) { 27 | archiveEntry(entry.getKey() ,entry.getValue() ,outputStream); 28 | } 29 | 30 | outputStream.close(); 31 | } 32 | 33 | private void archiveEntry(File source ,String target ,ZipOutputStream stream) throws IOException { 34 | if ( source.isDirectory() ) { 35 | for ( File f : Objects.requireNonNull(source.listFiles())) 36 | archiveEntry(f ,target + "/" + f.getName() ,stream); 37 | } 38 | else if ( source.isFile() ) { 39 | ZipEntry entry = new ZipEntry(PathUtils.zipEntry(target)); 40 | stream.putNextEntry(entry); 41 | readFileToStream(source ,stream); 42 | } 43 | else 44 | throw new GradleScriptException("Magisk file not found." ,new FileNotFoundException(source.getAbsolutePath())); 45 | } 46 | 47 | @SuppressWarnings("ResultOfMethodCallIgnored") 48 | private void readFileToStream(File file , OutputStream stream) throws IOException { 49 | FileInputStream inputStream = new FileInputStream(file); 50 | byte[] buffer = new byte[inputStream.available()]; 51 | inputStream.read(buffer); 52 | stream.write(buffer); 53 | inputStream.close(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/tasks/SignatureTask.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.tasks; 2 | 3 | import com.github.kr328.plugin.riru.conf.AndroidConfig; 4 | import com.github.kr328.plugin.riru.exts.SignatureExtension; 5 | import com.github.kr328.plugin.riru.utils.PathUtils; 6 | import org.gradle.api.DefaultTask; 7 | import org.gradle.api.GradleScriptException; 8 | import org.gradle.api.tasks.TaskAction; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.InputStreamReader; 12 | 13 | public class SignatureTask extends DefaultTask { 14 | public SignatureExtension extension; 15 | public AndroidConfig config; 16 | 17 | @TaskAction 18 | @SuppressWarnings("unused") 19 | public void exec() { 20 | if ( extension.getTargetFile() == null || extension.getKeyStore() == null || extension.getBuildToolsVersion() == null ) { 21 | setDidWork(false); 22 | return; 23 | } 24 | 25 | try { 26 | doSignature(); 27 | } catch (Exception e) { 28 | throw new GradleScriptException("Signature failure" ,e); 29 | } 30 | } 31 | 32 | private void doSignature() throws Exception { 33 | ProcessBuilder builder = new ProcessBuilder(); 34 | StringBuilder outputs = new StringBuilder(); 35 | 36 | builder.command(PathUtils.toLocalSeparator(config.androidSdkPath + "/build-tools/" + extension.getBuildToolsVersion() + "/apksigner" + PathUtils.executableSuffix(".bat")), 37 | "sign" , 38 | "--min-sdk-version" ,"24" , 39 | "--max-sdk-version" ,"28" , 40 | "--ks" ,extension.getKeyStore().getAbsolutePath() , 41 | "--ks-pass" ,"pass:" + extension.getKeyStorePassword() , 42 | "--ks-key-alias" ,extension.getAlias() , 43 | "--key-pass" ,"pass:" + extension.getAliasPassword() , 44 | extension.getTargetFile().getAbsolutePath()); 45 | 46 | Process process = builder.start(); 47 | BufferedReader reader; 48 | String line; 49 | 50 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 51 | while (( line = reader.readLine()) != null ) 52 | outputs.append(line).append('\n'); 53 | reader.close(); 54 | 55 | reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 56 | while (( line = reader.readLine()) != null ) 57 | outputs.append(line).append('\n'); 58 | reader.close(); 59 | 60 | int result = process.waitFor(); 61 | 62 | if ( result != 0 ) 63 | throw new Exception("Signature build failure: \n" + outputs.toString()); 64 | 65 | process.destroy(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/tasks/TransformDexTask.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.tasks; 2 | 3 | import com.github.kr328.plugin.riru.conf.AndroidConfig; 4 | import com.github.kr328.plugin.riru.exts.TransformDexExtension; 5 | import com.github.kr328.plugin.riru.utils.PathUtils; 6 | import org.gradle.api.DefaultTask; 7 | import org.gradle.api.GradleScriptException; 8 | import org.gradle.api.tasks.TaskAction; 9 | import org.gradle.api.tasks.compile.JavaCompile; 10 | 11 | import java.io.BufferedReader; 12 | import java.io.File; 13 | import java.io.InputStreamReader; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.nio.file.Paths; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | 21 | public class TransformDexTask extends DefaultTask { 22 | public TransformDexExtension extension; 23 | public AndroidConfig config; 24 | 25 | @TaskAction 26 | @SuppressWarnings("unused") 27 | public void exec() { 28 | JavaCompile task = (JavaCompile) getProject().getTasks().getByName("compileJava"); 29 | File source = task.getDestinationDir(); 30 | 31 | if ( task.getState().getNoSource() || task.getState().getUpToDate() ) { 32 | setDidWork(false); 33 | return; 34 | } 35 | 36 | try { 37 | ProcessBuilder builder = new ProcessBuilder(); 38 | StringBuilder outputs = new StringBuilder(); 39 | 40 | String executable = PathUtils.toLocalSeparator(config.androidSdkPath + 41 | "/build-tools/" + extension.getBuildToolsVersion() + 42 | "/d8" + (System.getProperty("os.name").toLowerCase().contains("win") ? ".bat" : "")); 43 | String outputPath = PathUtils.toLocalSeparator(getProject().getBuildDir().getAbsolutePath().concat("/outputs/dex/").concat(extension.getOutput())); 44 | String libraryPath = PathUtils.toLocalSeparator(config.androidSdkPath + "/platforms/" + extension.getCompilePlatform() + "/android.jar"); 45 | 46 | //noinspection ResultOfMethodCallIgnored 47 | new File(outputPath).getParentFile().mkdirs(); 48 | 49 | ArrayList command = new ArrayList<>(); 50 | 51 | command.add(executable); 52 | command.add("--output"); 53 | command.add(outputPath); 54 | command.add("--lib"); 55 | command.add(libraryPath); 56 | 57 | List classes = Files.walk(Paths.get(source.getAbsolutePath())) 58 | .map(Path::toAbsolutePath) 59 | .map(Path::toString) 60 | .filter(s -> s.endsWith(".class")) 61 | .collect(Collectors.toList()); 62 | 63 | command.addAll(classes); 64 | 65 | builder.command(command.toArray(new String[0])); 66 | 67 | Process process = builder.start(); 68 | BufferedReader reader; 69 | String line; 70 | 71 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 72 | while (( line = reader.readLine()) != null ) 73 | outputs.append(line).append('\n'); 74 | reader.close(); 75 | 76 | reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 77 | while (( line = reader.readLine()) != null ) 78 | outputs.append(line).append('\n'); 79 | reader.close(); 80 | 81 | int result = process.waitFor(); 82 | 83 | if ( result != 0 ) 84 | throw new Exception("Exec d8: " + command + "\n" + outputs.toString()); 85 | 86 | if ( !new File(outputPath).exists() ) 87 | throw new Exception("Exec d8: " + command + "\n" + outputs.toString()); 88 | 89 | process.destroy(); 90 | } 91 | catch (Exception e) { 92 | throw new GradleScriptException("Exec d8: " + e.toString(),e); 93 | } 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/utils/AndroidUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.utils; 2 | 3 | import com.github.kr328.plugin.riru.TransformDexPlugin; 4 | import com.github.kr328.plugin.riru.conf.AndroidConfig; 5 | import com.github.kr328.plugin.riru.conf.LocalProperties; 6 | import com.github.kr328.plugin.riru.exts.TransformDexExtension; 7 | import org.gradle.api.GradleScriptException; 8 | 9 | import java.io.File; 10 | import java.io.FileNotFoundException; 11 | 12 | public class AndroidUtils { 13 | public static String androidJarPath(String platform) { 14 | String path = PathUtils.toLocalSeparator(AndroidConfig.read().androidSdkPath + "/platforms/" + platform + "/android.jar"); 15 | if ( !new File(path).exists() ) 16 | throw new GradleScriptException("android.jar not found" ,new FileNotFoundException("android.jar not found")); 17 | return path; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/github/kr328/plugin/riru/utils/PathUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.plugin.riru.utils; 2 | 3 | import java.io.File; 4 | 5 | public class PathUtils { 6 | public static String toLocalSeparator(String p) { 7 | return p.replace('/' , File.separatorChar).replace('\\' ,File.separatorChar); 8 | } 9 | 10 | public static String zipEntry(String p) { 11 | String result = p.replaceAll("/+" ,"/"); 12 | if ( result.indexOf('/') == 0 ) 13 | return result.substring(1); 14 | return result; 15 | } 16 | 17 | public static String executableSuffix(String suffix) { 18 | if ( System.getProperty("os.name").toLowerCase().contains("win") ) 19 | return suffix; 20 | return ""; 21 | } 22 | 23 | private static String exe; 24 | } 25 | -------------------------------------------------------------------------------- /classpath/build.gradle: -------------------------------------------------------------------------------- 1 | import com.github.kr328.plugin.riru.utils.AndroidUtils 2 | import com.github.kr328.plugin.riru.utils.PathUtils 3 | 4 | apply plugin: 'java' 5 | 6 | repositories { 7 | mavenCentral() 8 | jcenter() 9 | } 10 | 11 | sourceSets { 12 | main.compileClasspath += files(AndroidUtils.androidJarPath("android-28")) //android.jar 13 | } 14 | 15 | compileJava { 16 | //destinationDir targetFile(PathUtils.toLocalSeparator("$buildDir/intermediate/classes")) 17 | } -------------------------------------------------------------------------------- /classpath/src/main/java/android/app/IActivityManager.java: -------------------------------------------------------------------------------- 1 | package android.app; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | 7 | public abstract interface IActivityManager extends IInterface { 8 | public static class Stub extends Binder implements IActivityManager { 9 | public static IActivityManager asInterface(IBinder binder) { 10 | throw new IllegalArgumentException("Unsupported"); 11 | } 12 | 13 | @Override 14 | public IBinder asBinder() { 15 | throw new IllegalArgumentException("Unsupported"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /classpath/src/main/java/android/content/IContentProvider.java: -------------------------------------------------------------------------------- 1 | package android.content; 2 | 3 | public interface IContentProvider { 4 | } 5 | -------------------------------------------------------------------------------- /classpath/src/main/java/android/os/IServiceManager.java: -------------------------------------------------------------------------------- 1 | package android.os; 2 | 3 | public interface IServiceManager extends IInterface { 4 | public abstract IBinder getService(String paramString) throws RemoteException; 5 | } 6 | -------------------------------------------------------------------------------- /classpath/src/main/java/android/os/ServiceManager.java: -------------------------------------------------------------------------------- 1 | package android.os; 2 | 3 | public final class ServiceManager { 4 | public static IBinder getService(String name) { 5 | throw new IllegalArgumentException("Unsupported"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /classpath/src/main/java/android/os/ServiceManagerNative.java: -------------------------------------------------------------------------------- 1 | package android.os; 2 | 3 | public class ServiceManagerNative extends Binder implements IServiceManager { 4 | public static IServiceManager asInterface(IBinder binder) { 5 | throw new IllegalArgumentException("Unsupported"); 6 | } 7 | 8 | @Override 9 | public IBinder getService(String paramString) throws RemoteException { 10 | throw new IllegalArgumentException("Unsupported"); 11 | } 12 | 13 | @Override 14 | public IBinder asBinder() { 15 | throw new IllegalArgumentException("Unsupported"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr328/Riru-SRSharedFix/6811ce4e9321170bd8b02b073166114db02241e2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Aug 30 11:15:55 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | # Android Sdk Directory 2 | android.sdk= 3 | 4 | # Android Ndk Directory 5 | android.ndk= 6 | 7 | # Android CMake Directory 8 | android.cmake= 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'SRSharedFix' 2 | 3 | include ":classpath" -------------------------------------------------------------------------------- /src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(riru_template) 3 | 4 | include_directories(libriru_utils) 5 | include_directories(libriru_utils/libriru) 6 | include_directories(libriru_utils/libxhook) 7 | 8 | add_subdirectory(libriru_utils) 9 | 10 | add_library(riru_srsf SHARED main.c hook.c) 11 | target_link_libraries(riru_srsf riru_utils log) 12 | 13 | -------------------------------------------------------------------------------- /src/main/cpp/hook.c: -------------------------------------------------------------------------------- 1 | #include "hook.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define ELMLEN(a) (sizeof(a)/sizeof(*a)) 9 | 10 | // Patch Android Framework 11 | static int android_runtime_start_reg_replaced(JNIEnv *env); 12 | static int (*android_runtime_start_reg_original)(JNIEnv *env); 13 | 14 | static jobject get_context_object_replaced(JNIEnv* env, jobject clazz); 15 | static jobject (*get_context_object_original)(JNIEnv* env, jobject clazz); 16 | 17 | static riru_utils_native_replace_t native_replace_list[] = { 18 | {".*android_runtime.*" ,"_ZN7android14AndroidRuntime8startRegEP7_JNIEnv" ,(void*)&android_runtime_start_reg_replaced ,(void**)&android_runtime_start_reg_original} 19 | }; 20 | 21 | static riru_utils_jni_replace_method_t jni_replace_method_list[] = { 22 | {"com/android/internal/os/BinderInternal" ,"getContextObject" ,"()Landroid/os/IBinder;" ,(void*)&get_context_object_replaced ,(void**)&get_context_object_original} 23 | }; 24 | 25 | int hook_install() { 26 | riru_utils_init_module("srsf"); 27 | riru_utils_replace_native_functions(native_replace_list ,ELMLEN(native_replace_list)); 28 | 29 | return 0; 30 | } 31 | 32 | // Logic Implemention 33 | static int class_loaded = 0; 34 | static jmethodID java_get_context_object_method = NULL; 35 | static jclass java_inject_class = NULL; 36 | 37 | static jobject utils_get_context_object(JNIEnv* env, jobject clazz); 38 | static jstring utils_get_current_config(JNIEnv *env ,jobject clazz); 39 | 40 | static const JNINativeMethod java_inject_methods[] = { 41 | /* name, signature, funcPtr */ 42 | {"getContextObjectOriginal","()Landroid/os/IBinder;", (void*)&utils_get_context_object} 43 | }; 44 | 45 | static jobject utils_get_context_object(JNIEnv* env, jobject clazz) { 46 | return get_context_object_original(env ,clazz); 47 | } 48 | 49 | static int is_app_uid(int uid) { 50 | int appId = uid % 100000; 51 | 52 | // limit only regular app, or strange situation will happen, such as zygote process not start (dead for no reason and leave no clues?) 53 | // https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r8/core/java/android/os/UserHandle.java#151 54 | return appId >= 10000 && appId <= 19999; 55 | } 56 | 57 | static int android_runtime_start_reg_replaced(JNIEnv *env) { 58 | int result = android_runtime_start_reg_original(env); 59 | 60 | if ( !class_loaded ) { 61 | riru_utils_replace_jni_methods(jni_replace_method_list ,ELMLEN(jni_replace_method_list) ,env); 62 | 63 | if ((java_inject_class = (*env)->FindClass(env,"com/github/kr328/srsf/Injector")) != NULL ) { 64 | java_get_context_object_method = (*env)->GetStaticMethodID(env ,java_inject_class ,"getContextObjectReplaced" ,"()Landroid/os/IBinder;"); 65 | (*env)->RegisterNatives(env ,java_inject_class ,java_inject_methods ,ELMLEN(java_inject_methods)); 66 | } 67 | else 68 | LOGE("Find Class failure."); 69 | 70 | class_loaded = 1; 71 | } 72 | 73 | return result; 74 | } 75 | 76 | static jobject get_context_object_replaced(JNIEnv* env, jobject clazz) { 77 | if ( is_app_uid(getuid()) && java_get_context_object_method ) { 78 | //LOGI("Calling javaHookedGetContextObjectId"); 79 | 80 | jobject result = (*env)->CallStaticObjectMethod(env ,java_inject_class ,java_get_context_object_method); 81 | 82 | if ( (*env)->ExceptionCheck(env) ) { 83 | (*env)->ExceptionDescribe(env); 84 | (*env)->ExceptionClear(env); 85 | LOGE("Call method failure"); 86 | } else 87 | return result; 88 | } 89 | 90 | return get_context_object_original(env,clazz); 91 | } 92 | -------------------------------------------------------------------------------- /src/main/cpp/hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "riru_utils.h" 11 | 12 | #include "log.h" 13 | 14 | int hook_install(); -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(riru_utils) 3 | 4 | add_subdirectory(libxhook) 5 | add_subdirectory(libriru) 6 | 7 | set(CMAKE_CXX_STANDARD 14) 8 | 9 | add_library(riru_utils STATIC riru_utils.h riru_utils.c) 10 | target_link_libraries(riru_utils riru xhook) 11 | target_include_directories(riru_utils PRIVATE libxhook libriru) 12 | 13 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libriru/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(libriru) 3 | 4 | add_library(riru STATIC riru.c) -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libriru/README.txt: -------------------------------------------------------------------------------- 1 | # RikkaApps Project 2 | https://github.com/RikkaApps/Riru/tree/master/riru-module-template/jni/main 3 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libriru/riru.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef __LP64__ 5 | #define LIB "/system/lib64/libmemtrack.so" 6 | #else 7 | #define LIB "/system/lib/libmemtrack.so" 8 | #endif 9 | 10 | static void *riru_handle; 11 | static char *riru_module_name; 12 | 13 | static void *get_handle() { 14 | if (riru_handle == NULL) 15 | riru_handle = dlopen(LIB, RTLD_NOW | RTLD_GLOBAL); 16 | 17 | return riru_handle; 18 | } 19 | 20 | const char *riru_get_module_name() { 21 | return riru_module_name; 22 | } 23 | 24 | void riru_set_module_name(const char *name) { 25 | riru_module_name = strdup(name); 26 | } 27 | 28 | int riru_get_version() { 29 | static void **sym; 30 | void *handle; 31 | if ((handle = get_handle()) == NULL) return -1; 32 | if (sym == NULL) sym = dlsym(handle, "riru_get_version"); 33 | if (sym) return ((int (*)()) sym)(); 34 | return -1; 35 | } 36 | 37 | void *riru_get_func(const char *name) { 38 | static void **sym; 39 | void *handle; 40 | if ((handle = get_handle()) == NULL) return NULL; 41 | if (sym == NULL) sym = dlsym(handle, "riru_get_func"); 42 | if (sym) return ((void *(*)(const char *, const char *)) sym)(riru_get_module_name(), name); 43 | return NULL; 44 | } 45 | 46 | void *riru_get_native_method_func(const char *className, const char *name, const char *signature) { 47 | static void **sym; 48 | void *handle; 49 | if ((handle = get_handle()) == NULL) return NULL; 50 | if (sym == NULL) sym = dlsym(handle, "riru_get_native_method_func"); 51 | if (sym) 52 | return ((void *(*)(const char *, const char *, const char *, const char *)) sym)( 53 | riru_get_module_name(), className, name, signature); 54 | return NULL; 55 | } 56 | 57 | void riru_set_func(const char *name, void *func) { 58 | static void **sym; 59 | void *handle; 60 | if ((handle = get_handle()) == NULL) return; 61 | if (sym == NULL) sym = dlsym(handle, "riru_set_func"); 62 | if (sym) 63 | ((void *(*)(const char *, const char *, void *)) sym)(riru_get_module_name(), name, func); 64 | } 65 | 66 | void riru_set_native_method_func(const char *className, const char *name, const char *signature, 67 | void *func) { 68 | static void **sym; 69 | void *handle; 70 | if ((handle = get_handle()) == NULL) return; 71 | if (sym == NULL) sym = dlsym(handle, "riru_set_native_method_func"); 72 | if (sym) 73 | ((void *(*)(const char *, const char *, const char *, const char *, void *)) sym)( 74 | riru_get_module_name(), className, name, signature, func); 75 | } -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libriru/riru.h: -------------------------------------------------------------------------------- 1 | #ifndef RIRU_H 2 | #define RIRU_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | __attribute__((visibility("default"))) void riru_set_module_name(const char *name); 8 | 9 | /** 10 | * Get Riru version. 11 | * 12 | * @return Riru version 13 | */ 14 | int riru_get_version(); 15 | 16 | /* 17 | * Get new_func address from last module which hook func. 18 | * Use this as your old_func if you want to hook func. 19 | * 20 | * @param name a unique name 21 | * @return new_func from last module or null 22 | */ 23 | void *riru_get_func(const char *name); 24 | 25 | /* 26 | * Java native version of riru_get_func. 27 | * 28 | * @param className class name 29 | * @param name method name 30 | * @param signature method signature 31 | * @return new_func address from last module or original address 32 | */ 33 | void *riru_get_native_method_func(const char *className, const char *name, const char *signature); 34 | 35 | /* 36 | * Set new_func address for next module which wants to hook func. 37 | * 38 | * @param name a unique name 39 | * @param func your new_func address 40 | */ 41 | void riru_set_func(const char *name, void *func); 42 | 43 | /* 44 | * Java native method version of riru_set_func. 45 | * 46 | * @param className class name 47 | * @param name method name 48 | * @param signature method signature 49 | * @param func your new_func address 50 | */ 51 | void riru_set_native_method_func(const char *className, const char *name, const char *signature, 52 | void *func); 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(xhook) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_C_STANDARD 11) 6 | 7 | add_library(xhook STATIC xhook.c xh_core.c xh_elf.c xh_jni.c xh_log.c xh_util.c xh_version.c) 8 | target_link_libraries(xhook log dl) 9 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/README.txt: -------------------------------------------------------------------------------- 1 | # iqiyi project 2 | https://github.com/iqiyi/xHook 3 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/queue.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1991, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 30 | * $FreeBSD: stable/9/sys/sys/queue.h 252365 2013-06-29 04:25:40Z lstewart $ 31 | */ 32 | 33 | #ifndef QUEUE_H 34 | #define QUEUE_H 35 | 36 | /* #include */ 37 | #define __containerof(ptr, type, field) ((type *)((char *)(ptr) - ((char *)&((type *)0)->field))) 38 | 39 | /* 40 | * This file defines four types of data structures: singly-linked lists, 41 | * singly-linked tail queues, lists and tail queues. 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A singly-linked tail queue is headed by a pair of pointers, one to the 54 | * head of the list and the other to the tail of the list. The elements are 55 | * singly linked for minimum space and pointer manipulation overhead at the 56 | * expense of O(n) removal for arbitrary elements. New elements can be added 57 | * to the list after an existing element, at the head of the list, or at the 58 | * end of the list. Elements being removed from the head of the tail queue 59 | * should use the explicit macro for this purpose for optimum efficiency. 60 | * A singly-linked tail queue may only be traversed in the forward direction. 61 | * Singly-linked tail queues are ideal for applications with large datasets 62 | * and few or no removals or for implementing a FIFO queue. 63 | * 64 | * A list is headed by a single forward pointer (or an array of forward 65 | * pointers for a hash table header). The elements are doubly linked 66 | * so that an arbitrary element can be removed without a need to 67 | * traverse the list. New elements can be added to the list before 68 | * or after an existing element or at the head of the list. A list 69 | * may be traversed in either direction. 70 | * 71 | * A tail queue is headed by a pair of pointers, one to the head of the 72 | * list and the other to the tail of the list. The elements are doubly 73 | * linked so that an arbitrary element can be removed without a need to 74 | * traverse the list. New elements can be added to the list before or 75 | * after an existing element, at the head of the list, or at the end of 76 | * the list. A tail queue may be traversed in either direction. 77 | * 78 | * For details on the use of these macros, see the queue(3) manual page. 79 | * 80 | * SLIST LIST STAILQ TAILQ 81 | * _HEAD + + + + 82 | * _HEAD_INITIALIZER + + + + 83 | * _ENTRY + + + + 84 | * _INIT + + + + 85 | * _EMPTY + + + + 86 | * _FIRST + + + + 87 | * _NEXT + + + + 88 | * _PREV - + - + 89 | * _LAST - - + + 90 | * _FOREACH + + + + 91 | * _FOREACH_FROM + + + + 92 | * _FOREACH_SAFE + + + + 93 | * _FOREACH_FROM_SAFE + + + + 94 | * _FOREACH_REVERSE - - - + 95 | * _FOREACH_REVERSE_FROM - - - + 96 | * _FOREACH_REVERSE_SAFE - - - + 97 | * _FOREACH_REVERSE_FROM_SAFE - - - + 98 | * _INSERT_HEAD + + + + 99 | * _INSERT_BEFORE - + - + 100 | * _INSERT_AFTER + + + + 101 | * _INSERT_TAIL - - + + 102 | * _CONCAT - - + + 103 | * _REMOVE_AFTER + - + - 104 | * _REMOVE_HEAD + - + - 105 | * _REMOVE + + + + 106 | * _SWAP + + + + 107 | * 108 | */ 109 | 110 | /* 111 | * Singly-linked List declarations. 112 | */ 113 | #define SLIST_HEAD(name, type, qual) \ 114 | struct name { \ 115 | struct type *qual slh_first; /* first element */ \ 116 | } 117 | 118 | #define SLIST_HEAD_INITIALIZER(head) \ 119 | { NULL } 120 | 121 | #define SLIST_ENTRY(type, qual) \ 122 | struct { \ 123 | struct type *qual sle_next; /* next element */ \ 124 | } 125 | 126 | /* 127 | * Singly-linked List functions. 128 | */ 129 | #define SLIST_INIT(head) do { \ 130 | SLIST_FIRST((head)) = NULL; \ 131 | } while (0) 132 | 133 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 134 | 135 | #define SLIST_FIRST(head) ((head)->slh_first) 136 | 137 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 138 | 139 | #define SLIST_FOREACH(var, head, field) \ 140 | for ((var) = SLIST_FIRST((head)); \ 141 | (var); \ 142 | (var) = SLIST_NEXT((var), field)) 143 | 144 | #define SLIST_FOREACH_FROM(var, head, field) \ 145 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ 146 | (var); \ 147 | (var) = SLIST_NEXT((var), field)) 148 | 149 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 150 | for ((var) = SLIST_FIRST((head)); \ 151 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 152 | (var) = (tvar)) 153 | 154 | #define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ 155 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ 156 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 157 | (var) = (tvar)) 158 | 159 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 160 | SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 161 | SLIST_FIRST((head)) = (elm); \ 162 | } while (0) 163 | 164 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 165 | SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 166 | SLIST_NEXT((slistelm), field) = (elm); \ 167 | } while (0) 168 | 169 | #define SLIST_REMOVE_AFTER(elm, field) do { \ 170 | SLIST_NEXT(elm, field) = \ 171 | SLIST_NEXT(SLIST_NEXT(elm, field), field); \ 172 | } while (0) 173 | 174 | #define SLIST_REMOVE_HEAD(head, field) do { \ 175 | SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 176 | } while (0) 177 | 178 | #define SLIST_REMOVE(head, elm, type, field) do { \ 179 | if (SLIST_FIRST((head)) == (elm)) { \ 180 | SLIST_REMOVE_HEAD((head), field); \ 181 | } \ 182 | else { \ 183 | struct type *curelm = SLIST_FIRST((head)); \ 184 | while (SLIST_NEXT(curelm, field) != (elm)) \ 185 | curelm = SLIST_NEXT(curelm, field); \ 186 | SLIST_REMOVE_AFTER(curelm, field); \ 187 | } \ 188 | } while (0) 189 | 190 | #define SLIST_SWAP(head1, head2, type) do { \ 191 | struct type *swap_first = SLIST_FIRST(head1); \ 192 | SLIST_FIRST(head1) = SLIST_FIRST(head2); \ 193 | SLIST_FIRST(head2) = swap_first; \ 194 | } while (0) 195 | 196 | /* 197 | * List declarations. 198 | */ 199 | #define LIST_HEAD(name, type, qual) \ 200 | struct name { \ 201 | struct type *qual lh_first; /* first element */ \ 202 | } 203 | 204 | #define LIST_HEAD_INITIALIZER(head) \ 205 | { NULL } 206 | 207 | #define LIST_ENTRY(type, qual) \ 208 | struct { \ 209 | struct type *qual le_next; /* next element */ \ 210 | struct type *qual *le_prev; /* address of previous next element */ \ 211 | } 212 | 213 | /* 214 | * List functions. 215 | */ 216 | #define LIST_INIT(head) do { \ 217 | LIST_FIRST((head)) = NULL; \ 218 | } while (0) 219 | 220 | #define LIST_EMPTY(head) ((head)->lh_first == NULL) 221 | 222 | #define LIST_FIRST(head) ((head)->lh_first) 223 | 224 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 225 | 226 | #define LIST_PREV(elm, head, type, field) \ 227 | ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ 228 | __containerof((elm)->field.le_prev, struct type, field.le_next)) 229 | 230 | #define LIST_FOREACH(var, head, field) \ 231 | for ((var) = LIST_FIRST((head)); \ 232 | (var); \ 233 | (var) = LIST_NEXT((var), field)) 234 | 235 | #define LIST_FOREACH_FROM(var, head, field) \ 236 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ 237 | (var); \ 238 | (var) = LIST_NEXT((var), field)) 239 | 240 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 241 | for ((var) = LIST_FIRST((head)); \ 242 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 243 | (var) = (tvar)) 244 | 245 | #define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ 246 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ 247 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 248 | (var) = (tvar)) 249 | 250 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 251 | if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 252 | LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ 253 | LIST_FIRST((head)) = (elm); \ 254 | (elm)->field.le_prev = &LIST_FIRST((head)); \ 255 | } while (0) 256 | 257 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 258 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 259 | LIST_NEXT((elm), field) = (listelm); \ 260 | *(listelm)->field.le_prev = (elm); \ 261 | (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 262 | } while (0) 263 | 264 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 265 | if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ 266 | LIST_NEXT((listelm), field)->field.le_prev = \ 267 | &LIST_NEXT((elm), field); \ 268 | LIST_NEXT((listelm), field) = (elm); \ 269 | (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 270 | } while (0) 271 | 272 | #define LIST_REMOVE(elm, field) do { \ 273 | if (LIST_NEXT((elm), field) != NULL) \ 274 | LIST_NEXT((elm), field)->field.le_prev = \ 275 | (elm)->field.le_prev; \ 276 | *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 277 | } while (0) 278 | 279 | #define LIST_SWAP(head1, head2, type, field) do { \ 280 | struct type *swap_tmp = LIST_FIRST((head1)); \ 281 | LIST_FIRST((head1)) = LIST_FIRST((head2)); \ 282 | LIST_FIRST((head2)) = swap_tmp; \ 283 | if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ 284 | swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ 285 | if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ 286 | swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ 287 | } while (0) 288 | 289 | /* 290 | * Singly-linked Tail queue declarations. 291 | */ 292 | #define STAILQ_HEAD(name, type, qual) \ 293 | struct name { \ 294 | struct type *qual stqh_first;/* first element */ \ 295 | struct type *qual *stqh_last;/* addr of last next element */ \ 296 | } 297 | 298 | #define STAILQ_HEAD_INITIALIZER(head) \ 299 | { NULL, &(head).stqh_first } 300 | 301 | #define STAILQ_ENTRY(type, qual) \ 302 | struct { \ 303 | struct type *qual stqe_next; /* next element */ \ 304 | } 305 | 306 | /* 307 | * Singly-linked Tail queue functions. 308 | */ 309 | #define STAILQ_INIT(head) do { \ 310 | STAILQ_FIRST((head)) = NULL; \ 311 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 312 | } while (0) 313 | 314 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 315 | 316 | #define STAILQ_FIRST(head) ((head)->stqh_first) 317 | 318 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 319 | 320 | #define STAILQ_LAST(head, type, field) \ 321 | (STAILQ_EMPTY((head)) ? NULL : \ 322 | __containerof((head)->stqh_last, struct type, field.stqe_next)) 323 | 324 | #define STAILQ_FOREACH(var, head, field) \ 325 | for((var) = STAILQ_FIRST((head)); \ 326 | (var); \ 327 | (var) = STAILQ_NEXT((var), field)) 328 | 329 | #define STAILQ_FOREACH_FROM(var, head, field) \ 330 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ 331 | (var); \ 332 | (var) = STAILQ_NEXT((var), field)) 333 | 334 | #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ 335 | for ((var) = STAILQ_FIRST((head)); \ 336 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 337 | (var) = (tvar)) 338 | 339 | #define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ 340 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ 341 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 342 | (var) = (tvar)) 343 | 344 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 345 | if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 346 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 347 | STAILQ_FIRST((head)) = (elm); \ 348 | } while (0) 349 | 350 | #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 351 | if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \ 352 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 353 | STAILQ_NEXT((tqelm), field) = (elm); \ 354 | } while (0) 355 | 356 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 357 | STAILQ_NEXT((elm), field) = NULL; \ 358 | *(head)->stqh_last = (elm); \ 359 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 360 | } while (0) 361 | 362 | #define STAILQ_CONCAT(head1, head2) do { \ 363 | if (!STAILQ_EMPTY((head2))) { \ 364 | *(head1)->stqh_last = (head2)->stqh_first; \ 365 | (head1)->stqh_last = (head2)->stqh_last; \ 366 | STAILQ_INIT((head2)); \ 367 | } \ 368 | } while (0) 369 | 370 | #define STAILQ_REMOVE_AFTER(head, elm, field) do { \ 371 | if ((STAILQ_NEXT(elm, field) = \ 372 | STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ 373 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 374 | } while (0) 375 | 376 | #define STAILQ_REMOVE_HEAD(head, field) do { \ 377 | if ((STAILQ_FIRST((head)) = \ 378 | STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 379 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 380 | } while (0) 381 | 382 | #define STAILQ_REMOVE(head, elm, type, field) do { \ 383 | if (STAILQ_FIRST((head)) == (elm)) { \ 384 | STAILQ_REMOVE_HEAD((head), field); \ 385 | } \ 386 | else { \ 387 | struct type *curelm = STAILQ_FIRST((head)); \ 388 | while (STAILQ_NEXT(curelm, field) != (elm)) \ 389 | curelm = STAILQ_NEXT(curelm, field); \ 390 | STAILQ_REMOVE_AFTER(head, curelm, field); \ 391 | } \ 392 | } while (0) 393 | 394 | #define STAILQ_SWAP(head1, head2, type) do { \ 395 | struct type *swap_first = STAILQ_FIRST(head1); \ 396 | struct type **swap_last = (head1)->stqh_last; \ 397 | STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ 398 | (head1)->stqh_last = (head2)->stqh_last; \ 399 | STAILQ_FIRST(head2) = swap_first; \ 400 | (head2)->stqh_last = swap_last; \ 401 | if (STAILQ_EMPTY(head1)) \ 402 | (head1)->stqh_last = &STAILQ_FIRST(head1); \ 403 | if (STAILQ_EMPTY(head2)) \ 404 | (head2)->stqh_last = &STAILQ_FIRST(head2); \ 405 | } while (0) 406 | 407 | /* 408 | * Tail queue declarations. 409 | */ 410 | #define TAILQ_HEAD(name, type, qual) \ 411 | struct name { \ 412 | struct type *qual tqh_first; /* first element */ \ 413 | struct type *qual *tqh_last; /* addr of last next element */ \ 414 | } 415 | 416 | #define TAILQ_HEAD_INITIALIZER(head) \ 417 | { NULL, &(head).tqh_first } 418 | 419 | #define TAILQ_ENTRY(type, qual) \ 420 | struct { \ 421 | struct type *qual tqe_next; /* next element */ \ 422 | struct type *qual *tqe_prev; /* address of previous next element */ \ 423 | } 424 | 425 | /* 426 | * Tail queue functions. 427 | */ 428 | #define TAILQ_INIT(head) do { \ 429 | TAILQ_FIRST((head)) = NULL; \ 430 | (head)->tqh_last = &TAILQ_FIRST((head)); \ 431 | } while (0) 432 | 433 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 434 | 435 | #define TAILQ_FIRST(head) ((head)->tqh_first) 436 | 437 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 438 | 439 | #define TAILQ_PREV(elm, headname, field) \ 440 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 441 | 442 | #define TAILQ_LAST(head, headname) \ 443 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 444 | 445 | #define TAILQ_FOREACH(var, head, field) \ 446 | for ((var) = TAILQ_FIRST((head)); \ 447 | (var); \ 448 | (var) = TAILQ_NEXT((var), field)) 449 | 450 | #define TAILQ_FOREACH_FROM(var, head, field) \ 451 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ 452 | (var); \ 453 | (var) = TAILQ_NEXT((var), field)) 454 | 455 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 456 | for ((var) = TAILQ_FIRST((head)); \ 457 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 458 | (var) = (tvar)) 459 | 460 | #define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ 461 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ 462 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 463 | (var) = (tvar)) 464 | 465 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 466 | for ((var) = TAILQ_LAST((head), headname); \ 467 | (var); \ 468 | (var) = TAILQ_PREV((var), headname, field)) 469 | 470 | #define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ 471 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ 472 | (var); \ 473 | (var) = TAILQ_PREV((var), headname, field)) 474 | 475 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 476 | for ((var) = TAILQ_LAST((head), headname); \ 477 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 478 | (var) = (tvar)) 479 | 480 | #define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ 481 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ 482 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 483 | (var) = (tvar)) 484 | 485 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 486 | if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 487 | TAILQ_FIRST((head))->field.tqe_prev = \ 488 | &TAILQ_NEXT((elm), field); \ 489 | else \ 490 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 491 | TAILQ_FIRST((head)) = (elm); \ 492 | (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 493 | } while (0) 494 | 495 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 496 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 497 | TAILQ_NEXT((elm), field) = (listelm); \ 498 | *(listelm)->field.tqe_prev = (elm); \ 499 | (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 500 | } while (0) 501 | 502 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 503 | if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \ 504 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 505 | &TAILQ_NEXT((elm), field); \ 506 | else \ 507 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 508 | TAILQ_NEXT((listelm), field) = (elm); \ 509 | (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 510 | } while (0) 511 | 512 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 513 | TAILQ_NEXT((elm), field) = NULL; \ 514 | (elm)->field.tqe_prev = (head)->tqh_last; \ 515 | *(head)->tqh_last = (elm); \ 516 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 517 | } while (0) 518 | 519 | #define TAILQ_CONCAT(head1, head2, field) do { \ 520 | if (!TAILQ_EMPTY(head2)) { \ 521 | *(head1)->tqh_last = (head2)->tqh_first; \ 522 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 523 | (head1)->tqh_last = (head2)->tqh_last; \ 524 | TAILQ_INIT((head2)); \ 525 | } \ 526 | } while (0) 527 | 528 | #define TAILQ_REMOVE(head, elm, field) do { \ 529 | if ((TAILQ_NEXT((elm), field)) != NULL) \ 530 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 531 | (elm)->field.tqe_prev; \ 532 | else \ 533 | (head)->tqh_last = (elm)->field.tqe_prev; \ 534 | *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 535 | } while (0) 536 | 537 | #define TAILQ_SWAP(head1, head2, type, field) do { \ 538 | struct type *swap_first = (head1)->tqh_first; \ 539 | struct type **swap_last = (head1)->tqh_last; \ 540 | (head1)->tqh_first = (head2)->tqh_first; \ 541 | (head1)->tqh_last = (head2)->tqh_last; \ 542 | (head2)->tqh_first = swap_first; \ 543 | (head2)->tqh_last = swap_last; \ 544 | if ((swap_first = (head1)->tqh_first) != NULL) \ 545 | swap_first->field.tqe_prev = &(head1)->tqh_first; \ 546 | else \ 547 | (head1)->tqh_last = &(head1)->tqh_first; \ 548 | if ((swap_first = (head2)->tqh_first) != NULL) \ 549 | swap_first->field.tqe_prev = &(head2)->tqh_first; \ 550 | else \ 551 | (head2)->tqh_last = &(head2)->tqh_first; \ 552 | } while (0) 553 | 554 | #endif 555 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_core.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "queue.h" 35 | #include "tree.h" 36 | #include "xh_errno.h" 37 | #include "xh_log.h" 38 | #include "xh_elf.h" 39 | #include "xh_version.h" 40 | #include "xh_core.h" 41 | 42 | #define XH_CORE_DEBUG 0 43 | 44 | //registered hook info collection 45 | typedef struct xh_core_hook_info 46 | { 47 | #if XH_CORE_DEBUG 48 | char *pathname_regex_str; 49 | #endif 50 | regex_t pathname_regex; 51 | char *symbol; 52 | void *new_func; 53 | void **old_func; 54 | TAILQ_ENTRY(xh_core_hook_info,) link; 55 | } xh_core_hook_info_t; 56 | typedef TAILQ_HEAD(xh_core_hook_info_queue, xh_core_hook_info,) xh_core_hook_info_queue_t; 57 | 58 | //ignored hook info collection 59 | typedef struct xh_core_ignore_info 60 | { 61 | #if XH_CORE_DEBUG 62 | char *pathname_regex_str; 63 | #endif 64 | regex_t pathname_regex; 65 | char *symbol; //NULL meaning for all symbols 66 | TAILQ_ENTRY(xh_core_ignore_info,) link; 67 | } xh_core_ignore_info_t; 68 | typedef TAILQ_HEAD(xh_core_ignore_info_queue, xh_core_ignore_info,) xh_core_ignore_info_queue_t; 69 | 70 | //required info from /proc/self/maps 71 | typedef struct xh_core_map_info 72 | { 73 | char *pathname; 74 | uintptr_t base_addr; 75 | xh_elf_t elf; 76 | RB_ENTRY(xh_core_map_info) link; 77 | } xh_core_map_info_t; 78 | static __inline__ int xh_core_map_info_cmp(xh_core_map_info_t *a, xh_core_map_info_t *b) 79 | { 80 | return strcmp(a->pathname, b->pathname); 81 | } 82 | typedef RB_HEAD(xh_core_map_info_tree, xh_core_map_info) xh_core_map_info_tree_t; 83 | RB_GENERATE_STATIC(xh_core_map_info_tree, xh_core_map_info, link, xh_core_map_info_cmp) 84 | 85 | //signal handler for SIGSEGV 86 | //for xh_elf_init(), xh_elf_hook(), xh_elf_check_elfheader() 87 | static int xh_core_sigsegv_enable = 1; //enable by default 88 | static struct sigaction xh_core_sigsegv_act_old; 89 | static volatile int xh_core_sigsegv_flag = 0; 90 | static sigjmp_buf xh_core_sigsegv_env; 91 | static void xh_core_sigsegv_handler(int sig) 92 | { 93 | (void)sig; 94 | 95 | if(xh_core_sigsegv_flag) 96 | siglongjmp(xh_core_sigsegv_env, 1); 97 | else 98 | sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL); 99 | } 100 | static int xh_core_add_sigsegv_handler() 101 | { 102 | struct sigaction act; 103 | 104 | if(!xh_core_sigsegv_enable) return 0; 105 | 106 | if(0 != sigemptyset(&act.sa_mask)) return (0 == errno ? XH_ERRNO_UNKNOWN : errno); 107 | act.sa_handler = xh_core_sigsegv_handler; 108 | 109 | if(0 != sigaction(SIGSEGV, &act, &xh_core_sigsegv_act_old)) 110 | return (0 == errno ? XH_ERRNO_UNKNOWN : errno); 111 | 112 | return 0; 113 | } 114 | static void xh_core_del_sigsegv_handler() 115 | { 116 | if(!xh_core_sigsegv_enable) return; 117 | 118 | sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL); 119 | } 120 | 121 | 122 | static xh_core_hook_info_queue_t xh_core_hook_info = TAILQ_HEAD_INITIALIZER(xh_core_hook_info); 123 | static xh_core_ignore_info_queue_t xh_core_ignore_info = TAILQ_HEAD_INITIALIZER(xh_core_ignore_info); 124 | static xh_core_map_info_tree_t xh_core_map_info = RB_INITIALIZER(&xh_core_map_info); 125 | static pthread_mutex_t xh_core_mutex = PTHREAD_MUTEX_INITIALIZER; 126 | static pthread_cond_t xh_core_cond = PTHREAD_COND_INITIALIZER; 127 | static volatile int xh_core_inited = 0; 128 | static volatile int xh_core_init_ok = 0; 129 | static volatile int xh_core_async_inited = 0; 130 | static volatile int xh_core_async_init_ok = 0; 131 | static pthread_mutex_t xh_core_refresh_mutex = PTHREAD_MUTEX_INITIALIZER; 132 | static pthread_t xh_core_refresh_thread_tid; 133 | static volatile int xh_core_refresh_thread_running = 0; 134 | static volatile int xh_core_refresh_thread_do = 0; 135 | 136 | 137 | int xh_core_register(const char *pathname_regex_str, const char *symbol, 138 | void *new_func, void **old_func) 139 | { 140 | xh_core_hook_info_t *hi; 141 | regex_t regex; 142 | 143 | if(NULL == pathname_regex_str || NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL; 144 | 145 | if(xh_core_inited) 146 | { 147 | XH_LOG_ERROR("do not register hook after refresh(): %s, %s", pathname_regex_str, symbol); 148 | return XH_ERRNO_INVAL; 149 | } 150 | 151 | if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL; 152 | 153 | if(NULL == (hi = malloc(sizeof(xh_core_hook_info_t)))) return XH_ERRNO_NOMEM; 154 | if(NULL == (hi->symbol = strdup(symbol))) 155 | { 156 | free(hi); 157 | return XH_ERRNO_NOMEM; 158 | } 159 | #if XH_CORE_DEBUG 160 | if(NULL == (hi->pathname_regex_str = strdup(pathname_regex_str))) 161 | { 162 | free(hi->symbol); 163 | free(hi); 164 | return XH_ERRNO_NOMEM; 165 | } 166 | #endif 167 | hi->pathname_regex = regex; 168 | hi->new_func = new_func; 169 | hi->old_func = old_func; 170 | 171 | pthread_mutex_lock(&xh_core_mutex); 172 | TAILQ_INSERT_TAIL(&xh_core_hook_info, hi, link); 173 | pthread_mutex_unlock(&xh_core_mutex); 174 | 175 | return 0; 176 | } 177 | 178 | int xh_core_ignore(const char *pathname_regex_str, const char *symbol) 179 | { 180 | xh_core_ignore_info_t *ii; 181 | regex_t regex; 182 | 183 | if(NULL == pathname_regex_str) return XH_ERRNO_INVAL; 184 | 185 | if(xh_core_inited) 186 | { 187 | XH_LOG_ERROR("do not ignore hook after refresh(): %s, %s", pathname_regex_str, symbol ? symbol : "ALL"); 188 | return XH_ERRNO_INVAL; 189 | } 190 | 191 | if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL; 192 | 193 | if(NULL == (ii = malloc(sizeof(xh_core_ignore_info_t)))) return XH_ERRNO_NOMEM; 194 | if(NULL != symbol) 195 | { 196 | if(NULL == (ii->symbol = strdup(symbol))) 197 | { 198 | free(ii); 199 | return XH_ERRNO_NOMEM; 200 | } 201 | } 202 | else 203 | { 204 | ii->symbol = NULL; //ignore all symbols 205 | } 206 | #if XH_CORE_DEBUG 207 | if(NULL == (ii->pathname_regex_str = strdup(pathname_regex_str))) 208 | { 209 | free(ii->symbol); 210 | free(ii); 211 | return XH_ERRNO_NOMEM; 212 | } 213 | #endif 214 | ii->pathname_regex = regex; 215 | 216 | pthread_mutex_lock(&xh_core_mutex); 217 | TAILQ_INSERT_TAIL(&xh_core_ignore_info, ii, link); 218 | pthread_mutex_unlock(&xh_core_mutex); 219 | 220 | return 0; 221 | } 222 | 223 | static int xh_core_check_elf_header(uintptr_t base_addr, const char *pathname) 224 | { 225 | if(!xh_core_sigsegv_enable) 226 | { 227 | return xh_elf_check_elfheader(base_addr); 228 | } 229 | else 230 | { 231 | int ret = XH_ERRNO_UNKNOWN; 232 | 233 | xh_core_sigsegv_flag = 1; 234 | if(0 == sigsetjmp(xh_core_sigsegv_env, 1)) 235 | { 236 | ret = xh_elf_check_elfheader(base_addr); 237 | } 238 | else 239 | { 240 | ret = XH_ERRNO_SEGVERR; 241 | XH_LOG_WARN("catch SIGSEGV when check_elfheader: %s", pathname); 242 | } 243 | xh_core_sigsegv_flag = 0; 244 | return ret; 245 | } 246 | } 247 | 248 | static void xh_core_hook_impl(xh_core_map_info_t *mi) 249 | { 250 | //init 251 | if(0 != xh_elf_init(&(mi->elf), mi->base_addr, mi->pathname)) return; 252 | 253 | //hook 254 | xh_core_hook_info_t *hi; 255 | xh_core_ignore_info_t *ii; 256 | int ignore; 257 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info 258 | { 259 | if(0 == regexec(&(hi->pathname_regex), mi->pathname, 0, NULL, 0)) 260 | { 261 | ignore = 0; 262 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info 263 | { 264 | if(0 == regexec(&(ii->pathname_regex), mi->pathname, 0, NULL, 0)) 265 | { 266 | if(NULL == ii->symbol) //ignore all symbols 267 | return; 268 | 269 | if(0 == strcmp(ii->symbol, hi->symbol)) //ignore the current symbol 270 | { 271 | ignore = 1; 272 | break; 273 | } 274 | } 275 | } 276 | 277 | if(0 == ignore) 278 | xh_elf_hook(&(mi->elf), hi->symbol, hi->new_func, hi->old_func); 279 | } 280 | } 281 | } 282 | 283 | static void xh_core_hook(xh_core_map_info_t *mi) 284 | { 285 | if(!xh_core_sigsegv_enable) 286 | { 287 | xh_core_hook_impl(mi); 288 | } 289 | else 290 | { 291 | xh_core_sigsegv_flag = 1; 292 | if(0 == sigsetjmp(xh_core_sigsegv_env, 1)) 293 | { 294 | xh_core_hook_impl(mi); 295 | } 296 | else 297 | { 298 | XH_LOG_WARN("catch SIGSEGV when init or hook: %s", mi->pathname); 299 | } 300 | xh_core_sigsegv_flag = 0; 301 | } 302 | } 303 | 304 | static void xh_core_refresh_impl() 305 | { 306 | char line[512]; 307 | FILE *fp; 308 | uintptr_t base_addr; 309 | char perm[5]; 310 | unsigned long offset; 311 | int pathname_pos; 312 | char *pathname; 313 | size_t pathname_len; 314 | xh_core_map_info_t *mi, *mi_tmp; 315 | xh_core_map_info_t mi_key; 316 | xh_core_hook_info_t *hi; 317 | xh_core_ignore_info_t *ii; 318 | int match; 319 | xh_core_map_info_tree_t map_info_refreshed = RB_INITIALIZER(&map_info_refreshed); 320 | 321 | if(NULL == (fp = fopen("/proc/self/maps", "r"))) 322 | { 323 | XH_LOG_ERROR("fopen /proc/self/maps failed"); 324 | return; 325 | } 326 | 327 | while(fgets(line, sizeof(line), fp)) 328 | { 329 | if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; 330 | 331 | //check permission 332 | if(perm[0] != 'r') continue; 333 | if(perm[3] != 'p') continue; //do not touch the shared memory 334 | 335 | //check offset 336 | // 337 | //We are trying to find ELF header in memory. 338 | //It can only be found at the beginning of a mapped memory regions 339 | //whose offset is 0. 340 | if(0 != offset) continue; 341 | 342 | //get pathname 343 | while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) 344 | pathname_pos += 1; 345 | if(pathname_pos >= (int)(sizeof(line) - 1)) continue; 346 | pathname = line + pathname_pos; 347 | pathname_len = strlen(pathname); 348 | if(0 == pathname_len) continue; 349 | if(pathname[pathname_len - 1] == '\n') 350 | { 351 | pathname[pathname_len - 1] = '\0'; 352 | pathname_len -= 1; 353 | } 354 | if(0 == pathname_len) continue; 355 | if('[' == pathname[0]) continue; 356 | 357 | //check pathname 358 | //if we need to hook this elf? 359 | match = 0; 360 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info 361 | { 362 | if(0 == regexec(&(hi->pathname_regex), pathname, 0, NULL, 0)) 363 | { 364 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info 365 | { 366 | if(0 == regexec(&(ii->pathname_regex), pathname, 0, NULL, 0)) 367 | { 368 | if(NULL == ii->symbol) 369 | goto check_finished; 370 | 371 | if(0 == strcmp(ii->symbol, hi->symbol)) 372 | goto check_continue; 373 | } 374 | } 375 | 376 | match = 1; 377 | check_continue: 378 | break; 379 | } 380 | } 381 | check_finished: 382 | if(0 == match) continue; 383 | 384 | //check elf header format 385 | //We are trying to do ELF header checking as late as possible. 386 | if(0 != xh_core_check_elf_header(base_addr, pathname)) continue; 387 | 388 | //check existed map item 389 | mi_key.pathname = pathname; 390 | if(NULL != (mi = RB_FIND(xh_core_map_info_tree, &xh_core_map_info, &mi_key))) 391 | { 392 | //exist 393 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); 394 | 395 | //repeated? 396 | //We only keep the first one, that is the real base address 397 | if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi)) 398 | { 399 | #if XH_CORE_DEBUG 400 | XH_LOG_DEBUG("repeated map info when update: %s", line); 401 | #endif 402 | free(mi->pathname); 403 | free(mi); 404 | continue; 405 | } 406 | 407 | //re-hook if base_addr changed 408 | if(mi->base_addr != base_addr) 409 | { 410 | mi->base_addr = base_addr; 411 | xh_core_hook(mi); 412 | } 413 | } 414 | else 415 | { 416 | //not exist, create a new map info 417 | if(NULL == (mi = (xh_core_map_info_t *)malloc(sizeof(xh_core_map_info_t)))) continue; 418 | if(NULL == (mi->pathname = strdup(pathname))) 419 | { 420 | free(mi); 421 | continue; 422 | } 423 | mi->base_addr = base_addr; 424 | 425 | //repeated? 426 | //We only keep the first one, that is the real base address 427 | if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi)) 428 | { 429 | #if XH_CORE_DEBUG 430 | XH_LOG_DEBUG("repeated map info when create: %s", line); 431 | #endif 432 | free(mi->pathname); 433 | free(mi); 434 | continue; 435 | } 436 | 437 | //hook 438 | xh_core_hook(mi); //hook 439 | } 440 | } 441 | fclose(fp); 442 | 443 | //free all missing map item, maybe dlclosed? 444 | RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp) 445 | { 446 | #if XH_CORE_DEBUG 447 | XH_LOG_DEBUG("remove missing map info: %s", mi->pathname); 448 | #endif 449 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); 450 | if(mi->pathname) free(mi->pathname); 451 | free(mi); 452 | } 453 | 454 | //save the new refreshed map info tree 455 | xh_core_map_info = map_info_refreshed; 456 | 457 | XH_LOG_INFO("map refreshed"); 458 | 459 | #if XH_CORE_DEBUG 460 | RB_FOREACH(mi, xh_core_map_info_tree, &xh_core_map_info) 461 | XH_LOG_DEBUG(" %"PRIxPTR" %s\n", mi->base_addr, mi->pathname); 462 | #endif 463 | } 464 | 465 | static void *xh_core_refresh_thread_func(void *arg) 466 | { 467 | (void)arg; 468 | 469 | pthread_setname_np(pthread_self(), "xh_refresh_loop"); 470 | 471 | while(xh_core_refresh_thread_running) 472 | { 473 | //waiting for a refresh task or exit 474 | pthread_mutex_lock(&xh_core_mutex); 475 | while(!xh_core_refresh_thread_do && xh_core_refresh_thread_running) 476 | { 477 | pthread_cond_wait(&xh_core_cond, &xh_core_mutex); 478 | } 479 | if(!xh_core_refresh_thread_running) 480 | { 481 | pthread_mutex_unlock(&xh_core_mutex); 482 | break; 483 | } 484 | xh_core_refresh_thread_do = 0; 485 | pthread_mutex_unlock(&xh_core_mutex); 486 | 487 | //refresh 488 | pthread_mutex_lock(&xh_core_refresh_mutex); 489 | xh_core_refresh_impl(); 490 | pthread_mutex_unlock(&xh_core_refresh_mutex); 491 | } 492 | 493 | return NULL; 494 | } 495 | 496 | static void xh_core_init_once() 497 | { 498 | if(xh_core_inited) return; 499 | 500 | pthread_mutex_lock(&xh_core_mutex); 501 | 502 | if(xh_core_inited) goto end; 503 | 504 | xh_core_inited = 1; 505 | 506 | //dump debug info 507 | XH_LOG_INFO("%s\n", xh_version_str_full()); 508 | #if XH_CORE_DEBUG 509 | xh_core_hook_info_t *hi; 510 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) 511 | XH_LOG_INFO(" hook: %s @ %s, (%p, %p)\n", hi->symbol, hi->pathname_regex_str, 512 | hi->new_func, hi->old_func); 513 | xh_core_ignore_info_t *ii; 514 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) 515 | XH_LOG_INFO(" ignore: %s @ %s\n", ii->symbol ? ii->symbol : "ALL ", 516 | ii->pathname_regex_str); 517 | #endif 518 | 519 | //register signal handler 520 | if(0 != xh_core_add_sigsegv_handler()) goto end; 521 | 522 | //OK 523 | xh_core_init_ok = 1; 524 | 525 | end: 526 | pthread_mutex_unlock(&xh_core_mutex); 527 | } 528 | 529 | static void xh_core_init_async_once() 530 | { 531 | if(xh_core_async_inited) return; 532 | 533 | pthread_mutex_lock(&xh_core_mutex); 534 | 535 | if(xh_core_async_inited) goto end; 536 | 537 | xh_core_async_inited = 1; 538 | 539 | //create async refresh thread 540 | xh_core_refresh_thread_running = 1; 541 | if(0 != pthread_create(&xh_core_refresh_thread_tid, NULL, &xh_core_refresh_thread_func, NULL)) 542 | { 543 | xh_core_refresh_thread_running = 0; 544 | goto end; 545 | } 546 | 547 | //OK 548 | xh_core_async_init_ok = 1; 549 | 550 | end: 551 | pthread_mutex_unlock(&xh_core_mutex); 552 | } 553 | 554 | int xh_core_refresh(int async) 555 | { 556 | //init 557 | xh_core_init_once(); 558 | if(!xh_core_init_ok) return XH_ERRNO_UNKNOWN; 559 | 560 | if(async) 561 | { 562 | //init for async 563 | xh_core_init_async_once(); 564 | if(!xh_core_async_init_ok) return XH_ERRNO_UNKNOWN; 565 | 566 | //refresh async 567 | pthread_mutex_lock(&xh_core_mutex); 568 | xh_core_refresh_thread_do = 1; 569 | pthread_cond_signal(&xh_core_cond); 570 | pthread_mutex_unlock(&xh_core_mutex); 571 | } 572 | else 573 | { 574 | //refresh sync 575 | pthread_mutex_lock(&xh_core_refresh_mutex); 576 | xh_core_refresh_impl(); 577 | pthread_mutex_unlock(&xh_core_refresh_mutex); 578 | } 579 | 580 | return 0; 581 | } 582 | 583 | void xh_core_clear() 584 | { 585 | //stop the async refresh thread 586 | if(xh_core_async_init_ok) 587 | { 588 | pthread_mutex_lock(&xh_core_mutex); 589 | xh_core_refresh_thread_running = 0; 590 | pthread_cond_signal(&xh_core_cond); 591 | pthread_mutex_unlock(&xh_core_mutex); 592 | 593 | pthread_join(xh_core_refresh_thread_tid, NULL); 594 | xh_core_async_init_ok = 0; 595 | } 596 | xh_core_async_inited = 0; 597 | 598 | //unregister the sig handler 599 | if(xh_core_init_ok) 600 | { 601 | xh_core_del_sigsegv_handler(); 602 | xh_core_init_ok = 0; 603 | } 604 | xh_core_inited = 0; 605 | 606 | pthread_mutex_lock(&xh_core_mutex); 607 | pthread_mutex_lock(&xh_core_refresh_mutex); 608 | 609 | //free all map info 610 | xh_core_map_info_t *mi, *mi_tmp; 611 | RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp) 612 | { 613 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi); 614 | if(mi->pathname) free(mi->pathname); 615 | free(mi); 616 | } 617 | 618 | //free all hook info 619 | xh_core_hook_info_t *hi, *hi_tmp; 620 | TAILQ_FOREACH_SAFE(hi, &xh_core_hook_info, link, hi_tmp) 621 | { 622 | TAILQ_REMOVE(&xh_core_hook_info, hi, link); 623 | #if XH_CORE_DEBUG 624 | free(hi->pathname_regex_str); 625 | #endif 626 | regfree(&(hi->pathname_regex)); 627 | free(hi->symbol); 628 | free(hi); 629 | } 630 | 631 | //free all ignore info 632 | xh_core_ignore_info_t *ii, *ii_tmp; 633 | TAILQ_FOREACH_SAFE(ii, &xh_core_ignore_info, link, ii_tmp) 634 | { 635 | TAILQ_REMOVE(&xh_core_ignore_info, ii, link); 636 | #if XH_CORE_DEBUG 637 | free(ii->pathname_regex_str); 638 | #endif 639 | regfree(&(ii->pathname_regex)); 640 | free(ii->symbol); 641 | free(ii); 642 | } 643 | 644 | pthread_mutex_unlock(&xh_core_refresh_mutex); 645 | pthread_mutex_unlock(&xh_core_mutex); 646 | } 647 | 648 | void xh_core_enable_debug(int flag) 649 | { 650 | xh_log_priority = (flag ? ANDROID_LOG_DEBUG : ANDROID_LOG_WARN); 651 | } 652 | 653 | void xh_core_enable_sigsegv_protection(int flag) 654 | { 655 | xh_core_sigsegv_enable = (flag ? 1 : 0); 656 | } 657 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_core.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_CORE_H 25 | #define XH_CORE_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | int xh_core_register(const char *pathname_regex_str, const char *symbol, 32 | void *new_func, void **old_func); 33 | 34 | int xh_core_ignore(const char *pathname_regex_str, const char *symbol); 35 | 36 | int xh_core_refresh(int async); 37 | 38 | void xh_core_clear(); 39 | 40 | void xh_core_enable_debug(int flag); 41 | 42 | void xh_core_enable_sigsegv_protection(int flag); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_elf.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_ELF_H 25 | #define XH_ELF_H 1 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef struct 36 | { 37 | const char *pathname; 38 | 39 | ElfW(Addr) base_addr; 40 | ElfW(Addr) bias_addr; 41 | 42 | ElfW(Ehdr) *ehdr; 43 | ElfW(Phdr) *phdr; 44 | 45 | ElfW(Dyn) *dyn; //.dynamic 46 | ElfW(Word) dyn_sz; 47 | 48 | const char *strtab; //.dynstr (string-table) 49 | ElfW(Sym) *symtab; //.dynsym (symbol-index to string-table's offset) 50 | 51 | ElfW(Addr) relplt; //.rel.plt or .rela.plt 52 | ElfW(Word) relplt_sz; 53 | 54 | ElfW(Addr) reldyn; //.rel.dyn or .rela.dyn 55 | ElfW(Word) reldyn_sz; 56 | 57 | ElfW(Addr) relandroid; //android compressed rel or rela 58 | ElfW(Word) relandroid_sz; 59 | 60 | //for ELF hash 61 | uint32_t *bucket; 62 | uint32_t bucket_cnt; 63 | uint32_t *chain; 64 | uint32_t chain_cnt; //invalid for GNU hash 65 | 66 | //append for GNU hash 67 | uint32_t symoffset; 68 | ElfW(Addr) *bloom; 69 | uint32_t bloom_sz; 70 | uint32_t bloom_shift; 71 | 72 | int is_use_rela; 73 | int is_use_gnu_hash; 74 | } xh_elf_t; 75 | 76 | int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname); 77 | int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func); 78 | 79 | int xh_elf_check_elfheader(uintptr_t base_addr); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_errno.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_ERRNO_H 25 | #define XH_ERRNO_H 1 26 | 27 | #define XH_ERRNO_UNKNOWN 1001 28 | #define XH_ERRNO_INVAL 1002 29 | #define XH_ERRNO_NOMEM 1003 30 | #define XH_ERRNO_REPEAT 1004 31 | #define XH_ERRNO_NOTFND 1005 32 | #define XH_ERRNO_BADMAPS 1006 33 | #define XH_ERRNO_FORMAT 1007 34 | #define XH_ERRNO_ELFINIT 1008 35 | #define XH_ERRNO_SEGVERR 1009 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_jni.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include "xhook.h" 26 | 27 | #define JNI_API_DEF(f) Java_com_qiyi_xhook_NativeHandler_##f 28 | 29 | JNIEXPORT jint JNI_API_DEF(refresh)(JNIEnv *env, jobject obj, jboolean async) 30 | { 31 | (void)env; 32 | (void)obj; 33 | 34 | return xhook_refresh(async ? 1 : 0); 35 | } 36 | 37 | JNIEXPORT void JNI_API_DEF(clear)(JNIEnv *env, jobject obj) 38 | { 39 | (void)env; 40 | (void)obj; 41 | 42 | xhook_clear(); 43 | } 44 | 45 | JNIEXPORT void JNI_API_DEF(enableDebug)(JNIEnv *env, jobject obj, jboolean flag) 46 | { 47 | (void)env; 48 | (void)obj; 49 | 50 | xhook_enable_debug(flag ? 1 : 0); 51 | } 52 | 53 | JNIEXPORT void JNI_API_DEF(enableSigSegvProtection)(JNIEnv *env, jobject obj, jboolean flag) 54 | { 55 | (void)env; 56 | (void)obj; 57 | 58 | xhook_enable_sigsegv_protection(flag ? 1 : 0); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_log.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include "xh_log.h" 26 | 27 | android_LogPriority xh_log_priority = ANDROID_LOG_WARN; 28 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_log.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_LOG_H 25 | #define XH_LOG_H 1 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | extern android_LogPriority xh_log_priority; 34 | 35 | #define XH_LOG_TAG "xhook" 36 | #define XH_LOG_DEBUG(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_DEBUG) __android_log_print(ANDROID_LOG_DEBUG, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) 37 | #define XH_LOG_INFO(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_INFO) __android_log_print(ANDROID_LOG_INFO, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) 38 | #define XH_LOG_WARN(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_WARN) __android_log_print(ANDROID_LOG_WARN, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) 39 | #define XH_LOG_ERROR(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_ERROR) __android_log_print(ANDROID_LOG_ERROR, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0) 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_util.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "xh_util.h" 37 | #include "xh_errno.h" 38 | #include "xh_log.h" 39 | 40 | #define PAGE_START(addr) ((addr) & PAGE_MASK) 41 | #define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE) 42 | #define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr)) 43 | 44 | int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot) 45 | { 46 | uintptr_t start_addr = addr; 47 | uintptr_t end_addr = addr + len; 48 | FILE *fp; 49 | char line[512]; 50 | uintptr_t start, end; 51 | char perm[5]; 52 | int load0 = 1; 53 | int found_all = 0; 54 | 55 | *prot = 0; 56 | 57 | if(NULL == (fp = fopen("/proc/self/maps", "r"))) return XH_ERRNO_BADMAPS; 58 | 59 | while(fgets(line, sizeof(line), fp)) 60 | { 61 | if(NULL != pathname) 62 | if(NULL == strstr(line, pathname)) continue; 63 | 64 | if(sscanf(line, "%"PRIxPTR"-%"PRIxPTR" %4s ", &start, &end, perm) != 3) continue; 65 | 66 | if(perm[3] != 'p') continue; 67 | 68 | if(start_addr >= start && start_addr < end) 69 | { 70 | if(load0) 71 | { 72 | //first load segment 73 | if(perm[0] == 'r') *prot |= PROT_READ; 74 | if(perm[1] == 'w') *prot |= PROT_WRITE; 75 | if(perm[2] == 'x') *prot |= PROT_EXEC; 76 | load0 = 0; 77 | } 78 | else 79 | { 80 | //others 81 | if(perm[0] != 'r') *prot &= ~PROT_READ; 82 | if(perm[1] != 'w') *prot &= ~PROT_WRITE; 83 | if(perm[2] != 'x') *prot &= ~PROT_EXEC; 84 | } 85 | 86 | if(end_addr <= end) 87 | { 88 | found_all = 1; 89 | break; //finished 90 | } 91 | else 92 | { 93 | start_addr = end; //try to find the next load segment 94 | } 95 | } 96 | } 97 | 98 | fclose(fp); 99 | 100 | if(!found_all) return XH_ERRNO_SEGVERR; 101 | 102 | return 0; 103 | } 104 | 105 | int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot) 106 | { 107 | return xh_util_get_mem_protect(addr, sizeof(addr), pathname, prot); 108 | } 109 | 110 | int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot) 111 | { 112 | if(0 != mprotect((void *)PAGE_START(addr), PAGE_COVER(addr), (int)prot)) 113 | return 0 == errno ? XH_ERRNO_UNKNOWN : errno; 114 | 115 | return 0; 116 | } 117 | 118 | void xh_util_flush_instruction_cache(uintptr_t addr) 119 | { 120 | __builtin___clear_cache((void *)PAGE_START(addr), (void *)PAGE_END(addr)); 121 | } 122 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_UTILS_H 25 | #define XH_UTILS_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #if defined(__LP64__) 32 | #define XH_UTIL_FMT_LEN "16" 33 | #define XH_UTIL_FMT_X "llx" 34 | #else 35 | #define XH_UTIL_FMT_LEN "8" 36 | #define XH_UTIL_FMT_X "x" 37 | #endif 38 | 39 | #define XH_UTIL_FMT_FIXED_X XH_UTIL_FMT_LEN XH_UTIL_FMT_X 40 | #define XH_UTIL_FMT_FIXED_S XH_UTIL_FMT_LEN "s" 41 | 42 | int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot); 43 | int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot); 44 | int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot); 45 | void xh_util_flush_instruction_cache(uintptr_t addr); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_version.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include "xh_version.h" 25 | 26 | #define XH_VERSION_MAJOR 1 27 | #define XH_VERSION_MINOR 1 28 | #define XH_VERSION_EXTRA 9 29 | 30 | #define XH_VERSION ((XH_VERSION_MAJOR << 16) | (XH_VERSION_MINOR << 8) | (XH_VERSION_EXTRA)) 31 | 32 | #define XH_VERSION_TO_STR_HELPER(x) #x 33 | #define XH_VERSION_TO_STR(x) XH_VERSION_TO_STR_HELPER(x) 34 | 35 | #define XH_VERSION_STR XH_VERSION_TO_STR(XH_VERSION_MAJOR) "." \ 36 | XH_VERSION_TO_STR(XH_VERSION_MINOR) "." \ 37 | XH_VERSION_TO_STR(XH_VERSION_EXTRA) 38 | 39 | #if defined(__arm__) 40 | #define XH_VERSION_ARCH "arm" 41 | #elif defined(__aarch64__) 42 | #define XH_VERSION_ARCH "aarch64" 43 | #elif defined(__i386__) 44 | #define XH_VERSION_ARCH "x86" 45 | #elif defined(__x86_64__) 46 | #define XH_VERSION_ARCH "x86_64" 47 | #else 48 | #define XH_VERSION_ARCH "unknown" 49 | #endif 50 | 51 | #define XH_VERSION_STR_FULL "libxhook "XH_VERSION_STR" ("XH_VERSION_ARCH")" 52 | 53 | unsigned int xh_version() 54 | { 55 | return XH_VERSION; 56 | } 57 | 58 | const char *xh_version_str() 59 | { 60 | return XH_VERSION_STR; 61 | } 62 | 63 | const char *xh_version_str_full() 64 | { 65 | return XH_VERSION_STR_FULL; 66 | } 67 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xh_version.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XH_VERSION_H 25 | #define XH_VERSION_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | unsigned int xh_version(); 32 | 33 | const char *xh_version_str(); 34 | 35 | const char *xh_version_str_full(); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #include "xh_core.h" 25 | #include "xhook.h" 26 | 27 | int xhook_register(const char *pathname_regex_str, const char *symbol, 28 | void *new_func, void **old_func) 29 | { 30 | return xh_core_register(pathname_regex_str, symbol, new_func, old_func); 31 | } 32 | 33 | int xhook_ignore(const char *pathname_regex_str, const char *symbol) 34 | { 35 | return xh_core_ignore(pathname_regex_str, symbol); 36 | } 37 | 38 | int xhook_refresh(int async) 39 | { 40 | return xh_core_refresh(async); 41 | } 42 | 43 | void xhook_clear() 44 | { 45 | return xh_core_clear(); 46 | } 47 | 48 | void xhook_enable_debug(int flag) 49 | { 50 | return xh_core_enable_debug(flag); 51 | } 52 | 53 | void xhook_enable_sigsegv_protection(int flag) 54 | { 55 | return xh_core_enable_sigsegv_protection(flag); 56 | } 57 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/libxhook/xhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2018-04-11. 23 | 24 | #ifndef XHOOK_H 25 | #define XHOOK_H 1 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #define XHOOK_EXPORT __attribute__((visibility("default"))) 32 | 33 | int xhook_register(const char *pathname_regex_str, const char *symbol, 34 | void *new_func, void **old_func) XHOOK_EXPORT; 35 | 36 | int xhook_ignore(const char *pathname_regex_str, const char *symbol) XHOOK_EXPORT; 37 | 38 | int xhook_refresh(int async) XHOOK_EXPORT; 39 | 40 | void xhook_clear() XHOOK_EXPORT; 41 | 42 | void xhook_enable_debug(int flag) XHOOK_EXPORT; 43 | 44 | void xhook_enable_sigsegv_protection(int flag) XHOOK_EXPORT; 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/riru_utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Kr328 on 18-11-26. 3 | // 4 | 5 | #include "riru_utils.h" 6 | 7 | #include "xhook.h" 8 | #include "riru.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | //Public Export 15 | int riru_utils_replace_native_functions(riru_utils_native_replace_t *functions, int length) { 16 | for ( int i = 0 ; i < length ; i++ ) { 17 | riru_utils_native_replace_t *current = functions + i; 18 | xhook_register(current->library_pattern ,current->symbol ,current->replace_function ,current->original_function); 19 | } 20 | 21 | if ( xhook_refresh(0) == 0 ) 22 | xhook_clear(); 23 | else 24 | return -1; 25 | 26 | for ( int i = 0 ; i < length ; i++ ) { 27 | riru_utils_native_replace_t *current = functions + i; 28 | 29 | void *replaced_original = riru_get_func(current->symbol); 30 | if ( replaced_original && replaced_original != *current->original_function ) { 31 | *current->original_function = replaced_original; 32 | riru_set_func(current->symbol ,current->replace_function); 33 | } 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | //Public Export 40 | int riru_utils_replace_jni_methods(riru_utils_jni_replace_method_t *classes ,int length ,JNIEnv *env) { 41 | for ( int i = 0 ; i < length ; i++ ) { 42 | riru_utils_jni_replace_method_t *current = classes + i; 43 | 44 | void *original_function = riru_get_native_method_func(current->class_name ,current->method_name ,current->signature); 45 | *current->original_function = original_function; 46 | riru_set_native_method_func(current->class_name ,current->method_name ,current->signature ,current->replace_function); 47 | 48 | JNINativeMethod method = {current->method_name ,current->signature ,current->replace_function}; 49 | 50 | (*env)->RegisterNatives(env ,(*env)->FindClass(env ,current->class_name) ,&method ,1); 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | int riru_utils_init_module(const char *module_name) { 57 | riru_set_module_name(module_name); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /src/main/cpp/libriru_utils/riru_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // 3 | // Created by Kr328 on 18-11-26. 4 | // 5 | 6 | #include 7 | 8 | typedef struct riru_utils_native_replace_s { 9 | const char *library_pattern; 10 | const char *symbol; 11 | void *replace_function; 12 | void **original_function; 13 | } riru_utils_native_replace_t; 14 | 15 | typedef struct riru_utils_jni_replace_method_s { 16 | const char *class_name; 17 | const char *method_name; 18 | const char *signature; 19 | void *replace_function; 20 | void **original_function; 21 | } riru_utils_jni_replace_method_t; 22 | 23 | int riru_utils_replace_native_functions(riru_utils_native_replace_t *functions, int length); 24 | int riru_utils_replace_jni_methods(riru_utils_jni_replace_method_t *classes ,int length ,JNIEnv *env); 25 | 26 | //Return Riru version 27 | int riru_utils_init_module(const char *module_name); 28 | -------------------------------------------------------------------------------- /src/main/cpp/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define TAG "InternalBrowserRedirect" 6 | 7 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO ,TAG ,__VA_ARGS__) 8 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG ,TAG ,__VA_ARGS__) 9 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR ,TAG ,__VA_ARGS__) 10 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN ,TAG ,__VA_ARGS__) -------------------------------------------------------------------------------- /src/main/cpp/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "hook.h" 10 | #include "log.h" 11 | 12 | //#define DEX_PATH "/data/local/tmp/injector.jar" 13 | #define DEX_PATH "/system/framework/boot-srsf.jar" 14 | 15 | __attribute__((visibility("default"))) 16 | void onModuleLoaded() { 17 | char buffer[4096]; 18 | char *p = NULL; 19 | 20 | strcpy(buffer,(p = getenv("CLASSPATH")) ? p : ""); 21 | strcat(buffer,":" DEX_PATH); 22 | setenv("CLASSPATH",buffer,1); 23 | 24 | hook_install(); 25 | } 26 | 27 | __attribute__((constructor)) 28 | void onLibraryLoaded() { 29 | 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/kr328/srsf/Global.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.srsf; 2 | 3 | public class Global { 4 | public static final String TAG = "SRSharedFix"; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/github/kr328/srsf/Injector.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.srsf; 2 | 3 | import android.app.IActivityManager; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.*; 8 | import android.util.Log; 9 | 10 | import java.io.File; 11 | import java.lang.reflect.Method; 12 | import java.util.ArrayList; 13 | 14 | @SuppressWarnings("unused") 15 | public class Injector { 16 | public static IBinder getContextObjectReplaced() { 17 | //Log.i(Global.TAG ,"Java getContextObject called"); 18 | 19 | return LocalInterfaceProxy.createInterfaceProxyBinder(ServiceManagerNative.asInterface(getContextObjectOriginal()) ,IServiceManager.class.getName() ,(original , replaced , method , args) -> { 20 | if ( "getService".equals(method.getName()) ) { 21 | switch ( args[0].toString() ) { 22 | case Context.ACTIVITY_SERVICE : 23 | return LocalInterfaceProxy.createInterfaceProxyBinder(IActivityManager.Stub.asInterface(original.getService(Context.ACTIVITY_SERVICE)) ,IActivityManager.class.getName() ,Injector::onActivityServiceCalled); 24 | } 25 | } 26 | return method.invoke(original ,args); 27 | }); 28 | } 29 | 30 | private static Object onActivityServiceCalled(IActivityManager original ,IActivityManager replaced ,Method method ,Object[] args) throws Throwable { 31 | switch ( method.getName() ) { 32 | case "startActivity" : 33 | Intent intent = (Intent) args[2]; 34 | args[2] = onStartActivity((String) args[1] ,intent); 35 | break; 36 | } 37 | 38 | return method.invoke(original ,args); 39 | } 40 | 41 | private static Intent onStartActivity(String sourcePackage ,Intent intent) { 42 | Uri uri; 43 | 44 | if ( intent.getAction() == null || sourcePackage == null ) 45 | return intent; 46 | 47 | switch ( intent.getAction() ) { 48 | case Intent.ACTION_VIEW : 49 | uri = intent.getData(); 50 | if ( uri != null && uri.getScheme().equals("file") ) 51 | intent.setData(uri = Uri.fromFile(new File(toRedirectedPath(sourcePackage ,uri.getPath())))); 52 | Log.i(Global.TAG ,"Try fix " + (uri == null ? "null" : uri)); 53 | break; 54 | case Intent.ACTION_SEND : 55 | uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); 56 | if ( uri != null && uri.getScheme().equals("file") ) 57 | intent.putExtra(Intent.EXTRA_STREAM ,uri = Uri.fromFile(new File(toRedirectedPath(sourcePackage ,uri.getPath())))); 58 | Log.i(Global.TAG ,"Try fix " + (uri == null ? "null" : uri)); 59 | break; 60 | case Intent.ACTION_SEND_MULTIPLE : 61 | ArrayList listExtra = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); 62 | if ( listExtra == null ) 63 | break; 64 | ArrayList ouputListExtra = new ArrayList<>(); 65 | for ( Parcelable p : listExtra ) { 66 | if ( p instanceof Uri && ((Uri)p).getScheme().equals("file")) 67 | ouputListExtra.add(Uri.fromFile(new File(toRedirectedPath(sourcePackage ,((Uri)p).getPath())))); 68 | else 69 | ouputListExtra.add(p); 70 | } 71 | intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM ,ouputListExtra); 72 | Log.i(Global.TAG ,"Try fix " + ouputListExtra); 73 | break; 74 | } 75 | 76 | return intent; 77 | } 78 | 79 | private static String toRedirectedPath(String packageName ,String path) { 80 | File sourceFile = new File(path); 81 | String externalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 82 | String sourcePath = sourceFile.getAbsolutePath(); 83 | String result = path; 84 | 85 | if ( sourcePath.startsWith(externalStoragePath) ) { 86 | String targetPath; 87 | targetPath = sourcePath.replace(externalStoragePath ,externalStoragePath + "/Android/data/" + packageName + "/cache/sdcard/"); 88 | if ( new File(targetPath).exists() ) 89 | result = targetPath; 90 | targetPath = sourcePath.replace(externalStoragePath ,externalStoragePath + "/Android/data/" + packageName + "/sdcard/"); 91 | if ( new File(targetPath).exists() ) 92 | result = targetPath; 93 | } 94 | 95 | Log.i(Global.TAG ,sourcePath + " => " + result); 96 | 97 | return result; 98 | } 99 | 100 | public static native IBinder getContextObjectOriginal(); 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/github/kr328/srsf/LocalInterfaceProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.kr328.srsf; 2 | 3 | import android.os.IBinder; 4 | import android.os.IInterface; 5 | import android.util.Log; 6 | 7 | import java.lang.reflect.InvocationHandler; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Proxy; 10 | 11 | @SuppressWarnings("unchecked") 12 | public class LocalInterfaceProxy { 13 | public static IBinder createInterfaceProxyBinder(Interface original , String interfaceName , InterfaceCallback callback) { 14 | IBinder originalBinder = original.asBinder(); 15 | 16 | InvocationHandler interfaceInvocationHandler = (Object thiz ,Method method ,Object[] args) -> callback.onCalled(original , (Interface) thiz ,method ,args); 17 | 18 | InvocationHandler binderInvocationHandler = (Object thiz, Method method, Object[] args) -> { 19 | try { 20 | if ( method.getName().equals("queryLocalInterface") ) { 21 | //Log.i(Global.TAG ,"queryLocalInterface " + args[0] + " == " + interfaceName); 22 | if ( interfaceName.equals(args[0]) ) 23 | return Proxy.newProxyInstance(LocalInterfaceProxy.class.getClassLoader() ,new Class[]{Class.forName(interfaceName)} ,interfaceInvocationHandler); 24 | } 25 | } 26 | catch (Exception ignored) { 27 | Log.w(Global.TAG ,"Proxy " + original.getClass().getName() + " failure."); 28 | } 29 | 30 | return method.invoke(originalBinder ,args); 31 | }; 32 | 33 | return (IBinder) Proxy.newProxyInstance(LocalInterfaceProxy.class.getClassLoader() ,new Class[]{IBinder.class} ,binderInvocationHandler); 34 | } 35 | 36 | public interface InterfaceCallback { 37 | Object onCalled(Interface original ,Interface replaced ,Method method ,Object[] args) throws Throwable; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/raw/magisk/META-INF/com/google/android/update-binary: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | ########################################################################################## 3 | # 4 | # Magisk Module Template Install Script 5 | # by topjohnwu 6 | # 7 | ########################################################################################## 8 | 9 | # Detect whether in boot mode 10 | ps | grep zygote | grep -v grep >/dev/null && BOOTMODE=true || BOOTMODE=false 11 | $BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && BOOTMODE=true 12 | 13 | TMPDIR=/dev/tmp 14 | INSTALLER=$TMPDIR/install 15 | MAGISKBIN=/data/adb/magisk 16 | 17 | # Default permissions 18 | umask 022 19 | 20 | # Initial cleanup 21 | rm -rf $TMPDIR 2>/dev/null 22 | mkdir -p $INSTALLER 23 | 24 | # echo before loading util_functions 25 | ui_print() { echo "$1"; } 26 | 27 | require_new_magisk() { 28 | ui_print "*******************************" 29 | ui_print " Please install Magisk v15.0+! " 30 | ui_print "*******************************" 31 | exit 1 32 | } 33 | 34 | ########################################################################################## 35 | # Environment 36 | ########################################################################################## 37 | 38 | OUTFD=$2 39 | ZIP=$3 40 | 41 | mount /data 2>/dev/null 42 | 43 | # Utility functions must exist 44 | [ -f $MAGISKBIN/util_functions.sh ] || require_new_magisk 45 | # Load utility fuctions 46 | . $MAGISKBIN/util_functions.sh 47 | 48 | # We can't alter magisk image live, use alternative image if required 49 | $BOOTMODE && IMG=/data/adb/magisk_merge.img 50 | # Always mount under tmp 51 | MOUNTPATH=$TMPDIR/magisk_img 52 | 53 | # Preperation for flashable zips 54 | get_outfd 55 | 56 | # Mount partitions 57 | mount_partitions 58 | 59 | # Detect version and architecture 60 | api_level_arch_detect 61 | 62 | # You can get the Android API version from $API, the CPU architecture from $ARCH 63 | # Useful if you are creating Android version / platform dependent mods 64 | 65 | # Setup busybox and binaries 66 | $BOOTMODE && boot_actions || recovery_actions 67 | 68 | ########################################################################################## 69 | # Preparation 70 | ########################################################################################## 71 | 72 | # Extract common files 73 | unzip -o "$ZIP" module.prop config.sh 'common/*' -d $INSTALLER >&2 74 | 75 | [ ! -f $INSTALLER/config.sh ] && abort "! Unable to extract zip file!" 76 | # Load configurations 77 | . $INSTALLER/config.sh 78 | 79 | # Check the installed magisk version 80 | MIN_VER=`grep_prop minMagisk $INSTALLER/module.prop` 81 | [ ! -z $MAGISK_VER_CODE -a $MAGISK_VER_CODE -ge $MIN_VER ] || require_new_magisk 82 | MODID=`grep_prop id $INSTALLER/module.prop` 83 | MODPATH=$MOUNTPATH/$MODID 84 | 85 | # Print mod name 86 | print_modname 87 | 88 | # Please leave this message in your flashable zip for credits :) 89 | ui_print "******************************" 90 | ui_print "Powered by Magisk (@topjohnwu)" 91 | ui_print "******************************" 92 | 93 | ########################################################################################## 94 | # Install 95 | ########################################################################################## 96 | 97 | # Check Riru installed 98 | check_riru_installed 99 | 100 | # Get the variable reqSizeM. Use your own method to determine reqSizeM if needed 101 | request_zip_size_check "$ZIP" 102 | 103 | # This function will mount $IMG to $MOUNTPATH, and resize the image based on $reqSizeM 104 | mount_magisk_img 105 | 106 | # Create mod paths 107 | rm -rf $MODPATH 2>/dev/null 108 | mkdir -p $MODPATH 109 | 110 | # Extract files to system. Use your own method if needed 111 | ui_print "- Extracting module files" 112 | unzip -o "$ZIP" 'system/*' -d $MODPATH >&2 113 | 114 | # Remove placeholder 115 | rm -f $MODPATH/system/placeholder 2>/dev/null 116 | 117 | # Handle replace folders 118 | for TARGET in $REPLACE; do 119 | mktouch $MODPATH$TARGET/.replace 120 | done 121 | 122 | # Auto Mount 123 | $AUTOMOUNT && touch $MODPATH/auto_mount 124 | 125 | # prop files 126 | $PROPFILE && cp -af $INSTALLER/common/system.prop $MODPATH/system.prop 127 | 128 | # Module info 129 | cp -af $INSTALLER/module.prop $MODPATH/module.prop 130 | if $BOOTMODE; then 131 | # Update info for Magisk Manager 132 | mktouch /sbin/.core/img/$MODID/update 133 | cp -af $INSTALLER/module.prop /sbin/.core/img/$MODID/module.prop 134 | fi 135 | 136 | # post-fs-data mode scripts 137 | $POSTFSDATA && cp -af $INSTALLER/common/post-fs-data.sh $MODPATH/post-fs-data.sh 138 | 139 | # service mode scripts 140 | $LATESTARTSERVICE && cp -af $INSTALLER/common/service.sh $MODPATH/service.sh 141 | 142 | # check architecture 143 | check_architecture 144 | 145 | # Config riru module 146 | config_riru_module 147 | 148 | ui_print "- Setting permissions" 149 | set_permissions 150 | 151 | ########################################################################################## 152 | # Finalizing 153 | ########################################################################################## 154 | 155 | # Unmount magisk image and shrink if possible 156 | unmount_magisk_img 157 | 158 | $BOOTMODE || recovery_cleanup 159 | rm -rf $TMPDIR 160 | 161 | ui_print "- Done" 162 | exit 0 163 | -------------------------------------------------------------------------------- /src/main/raw/magisk/META-INF/com/google/android/updater-script: -------------------------------------------------------------------------------- 1 | #MAGISK 2 | -------------------------------------------------------------------------------- /src/main/raw/magisk/common/post-fs-data.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/... 3 | # This will make your scripts compatible even if Magisk change its mount point in the future 4 | MODDIR=${0%/*} 5 | 6 | # This script will be executed in post-fs-data mode 7 | # More info in the main Magisk thread 8 | 9 | RIRU_MODULES_DIR="/data/misc/riru/modules" 10 | DATA_DIRECTORY="$RIRU_MODULES_DIR/srsf" 11 | 12 | if [ ! -d "$RIRU_MODULES_DIR" ];then 13 | exit 1 14 | fi 15 | 16 | mkdir -p "$DATA_DIRECTORY" 17 | mount -o bind "$MODDIR/data" "$DATA_DIRECTORY" 18 | -------------------------------------------------------------------------------- /src/main/raw/magisk/common/service.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/... 3 | # This will make your scripts compatible even if Magisk change its mount point in the future 4 | MODDIR=${0%/*} 5 | 6 | # This script will be executed in late_start service mode 7 | # More info in the main Magisk thread 8 | -------------------------------------------------------------------------------- /src/main/raw/magisk/common/system.prop: -------------------------------------------------------------------------------- 1 | # This targetFile will be read by resetprop 2 | # Example: Change dpi 3 | # ro.sf.lcd_density=320 4 | -------------------------------------------------------------------------------- /src/main/raw/magisk/config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ########################################################################################## 3 | # 4 | # Magisk Module Template Config Script 5 | # by topjohnwu 6 | # 7 | ########################################################################################## 8 | ########################################################################################## 9 | # 10 | # Instructions: 11 | # 12 | # 1. Place your files into system folder (delete the placeholder file) 13 | # 2. Fill in your module's info into module.prop 14 | # 3. Configure the settings in this file (config.sh) 15 | # 4. If you need boot scripts, add them into common/post-fs-data.sh or common/service.sh 16 | # 5. Add your additional or modified system properties into common/system.prop 17 | # 18 | ########################################################################################## 19 | 20 | ########################################################################################## 21 | # Configs 22 | ########################################################################################## 23 | 24 | # Set to true if you need to enable Magic Mount 25 | # Most mods would like it to be enabled 26 | AUTOMOUNT=true 27 | 28 | # Set to true if you need to load system.prop 29 | PROPFILE=false 30 | 31 | # Set to true if you need post-fs-data script 32 | POSTFSDATA=true 33 | 34 | # Set to true if you need late_start service script 35 | LATESTARTSERVICE=false 36 | 37 | ########################################################################################## 38 | # Installation Message 39 | ########################################################################################## 40 | 41 | # Set what you want to show when installing your mod 42 | 43 | print_modname() { 44 | ui_print "******************************" 45 | ui_print " Riru - SRSharedFix " 46 | ui_print "******************************" 47 | } 48 | 49 | ########################################################################################## 50 | # Replace list 51 | ########################################################################################## 52 | 53 | # List all directories you want to directly replace in the system 54 | # Check the documentations for more info about how Magic Mount works, and why you need this 55 | 56 | # This is an example 57 | REPLACE=" 58 | /system/app/Youtube 59 | /system/priv-app/SystemUI 60 | /system/priv-app/Settings 61 | /system/framework 62 | " 63 | 64 | # Construct your own list here, it will override the example above 65 | # !DO NOT! remove this if you don't need to replace anything, leave it empty as it is now 66 | REPLACE=" 67 | " 68 | 69 | ########################################################################################## 70 | # Permissions 71 | ########################################################################################## 72 | 73 | set_permissions() { 74 | # Only some special files require specific permissions 75 | # The default permissions should be good enough for most cases 76 | 77 | # Here are some examples for the set_perm functions: 78 | 79 | # set_perm_recursive (default: u:object_r:system_file:s0) 80 | # set_perm_recursive $MODPATH/system/lib 0 0 0755 0644 81 | 82 | # set_perm (default: u:object_r:system_file:s0) 83 | # set_perm $MODPATH/system/bin/app_process32 0 2000 0755 u:object_r:zygote_exec:s0 84 | # set_perm $MODPATH/system/bin/dex2oat 0 2000 0755 u:object_r:dex2oat_exec:s0 85 | # set_perm $MODPATH/system/lib/libart.so 0 0 0644 86 | 87 | # The following is default permissions, DO NOT remove 88 | set_perm_recursive $MODPATH 0 0 0755 0644 89 | } 90 | 91 | ########################################################################################## 92 | # Custom Functions 93 | ########################################################################################## 94 | 95 | # This file (config.sh) will be sourced by the main flash script after util_functions.sh 96 | # If you need custom logic, please add them here as functions, and call these functions in 97 | # update-binary. Refrain from adding code directly into update-binary, as it will make it 98 | # difficult for you to migrate your modules to newer plugin versions. 99 | # Make update-binary as clean as possible, try to only do function calls in it. 100 | 101 | # Riru 102 | RIRU_MODULE_NAME=srsf 103 | 104 | check_riru_installed() { 105 | if [ ! -d "/data/misc/riru" ];then 106 | ui_print "!Riru not installed" 107 | ui_print "!You *MUST* install it first" 108 | exit 1 109 | fi 110 | } 111 | 112 | check_architecture() { 113 | ui_print "- Check Architecture" 114 | 115 | if [[ "$ARCH" != "arm" ]] && [[ "$ARCH" != "arm64" ]];then 116 | ui_print "- Unspported architecture: $ARCH" 117 | exit 1 118 | fi 119 | } 120 | 121 | config_riru_module() { 122 | ui_print "- Config Riru Module" 123 | 124 | unzip -o "$ZIP" 'data/*' -d "$MODPATH/" > /dev/null 2> /dev/null 125 | ln -s "$MODPATH/module.prop" "$MODPATH/data/module.prop" 126 | } 127 | -------------------------------------------------------------------------------- /src/main/raw/magisk/module.prop: -------------------------------------------------------------------------------- 1 | id=riru_srsf 2 | name=Riru - SR Shared Fix 3 | version=v1 4 | versionCode=1 5 | author=Kr328 6 | description=Fix "Storage Redirect" Shared File Problem [( Riru - Core > 7 && API 26/27/28 ) Required] 7 | minMagisk=17000 8 | --------------------------------------------------------------------------------